`travis cancel ${TRAVIS_JOB_NUMBER}` from within a running job

I’m trying to produce a matrix for overall coverage with a few production jobs pulled into an earlier Production stage… https://travis-ci.org/bencoman/test-travis-multi/builds/478912051
via this build script… https://github.com/bencoman/test-travis-multi/blob/586bfbc/travis_build.sh

To avoid re-building the production jobs a second time in the Coverage stage, in travis_build.sh I identify double-ups by scanning .travis.yml. Then the aim is for the job to then cancel itself via…

travis cancel ${TRAVIS_JOB_NUMBER}

As a first experiment, in travis_build.sh I run…

   gem travis install
   travis -h

but this gets stuck at an interactive prompt…

Shell completion not installed. Would you like to install it now? |y|

Also the osx jobs get errored by…

“/Users/travis/.rvm/gems/ruby-2.0.0-p648/gems/bundler-1.13.2/lib/bundler/rubygems_ext.rb:45:in `full_gem_path’: uninitialized constant Bundler::Plugin::API::Source”

For the build linked above, these are the pairs…
155.1 <==> 155.9 stuck at interactive prompt, linux
155.2 <==> 155.11 stuck at interactive prompt, linux
155.3 <==> 155.6 stuck at interactive prompt, linux
155.4 <==> 155.17 error full_gem_path, osx
155.5 <==> 155.18 error full_gem_path, osx

So I’m curious to know…

  1. Is this a reasonable approach?
  2. How to resolve the osx error?
  3. How to bypass the interactive prompt?
  4. Which credentials should be used and how to keep them secure? (On the help page I’ve read various topics on securing files and strings for third-party services, but I’m not sure which token I should be working with for the Travis command line client.)

I’m not sure what you mean. Why are you running it a second time? Doesn’t it suffice to have a separate “Coverage” job in the build matrix?

If you feel that you must do it this way, then I don’t think installing and invoking CLI is a good idea; try invoking API to cancel the job. See https://developer.travis-ci.com/

Why are you running it a second time?

That is exactly what I’m trying to avoid, but without having to define every job individually.

Of the 22 jobs defined by the crosstab of ‘os:’ and ‘env:’ like this…

os:
  -       linux
  -       osx 
env:
  - BUILD=64x64/squeak.cog.spur     TESTIMAGE=skip
  - BUILD=64x64/pharo.cog.spur      TESTIMAGE=skip
  - BUILD=64x64/newspeak.cog.spur   TESTIMAGE=skip

  - BUILD=32x86/squeak.cog.spur     TESTIMAGE=Squeak32-5.1
  - BUILD=32x86/squeak.cog.v3       TESTIMAGE=Squeak32-4.6
  - BUILD=32x86/pharo.cog.spur      TESTIMAGE=Pharo32-5.0
  - BUILD=32x86/newspeak.cog.spur   TESTIMAGE="refer newspeakBootstrap.sh"

  - BUILD=32x86/squeak.cog.stack    TESTIMAGE=Squeak32-5.1
  - BUILD=32x86/squeak.stack.v3     TESTIMAGE=Squeak32-4.6
  - BUILD=32x86/pharo.cog.stack     TESTIMAGE=Pharo32-5.0
  - BUILD=32x86/newspeak.cog.stack  TESTIMAGE=skip

five are Production and the rest are Coverage. Production builds are used by the majority of the Squeak and Pharo communities because they have a JIT compiler built-in. The non-JIT Coverage builds aren’t used often, but are important to keep reasonably current for corner cases and research purposes.

So how to split those 22 jobs into a Production stage that must not fail and be built first, and a Coverage stage that allow_failure’s? I’d rather not have to define all 22 jobs individually, especially when that soon multiples by adding Windows. I understand one option is to script generation of .travis.yml, but then later it remains hard to review what the coverage really is.

Defining the Production builds individually and the using that same definition to filter the crosstab-definition of Coverage is my preferred approach since travis.yml remains concise to review.

Even better would be per-stage crosstab definitions. I saw some reference to this as a feature request in the issue tracker but it seems at best WIP, if even that.

try invoking API to cancel the job

Thanks for that guidance. I saw some curl examples so is that what you mean?
I’ll follow up further once I’ve had a chance to look further into that.

cheers -ben

Okay, that does look easier. From the travis web interface, in the build log of my jobs I found the following environment variable defined…

TRAVIS_JOB_WEB_URL=https://travis-ci.org/bencoman/test-travis-multi/jobs/478896877

So in a shell on my local machine I did the following…

$ travis login
$ vi apitest.sh
#!/bin/sh -x
SECRET=`travis token`
TRAVIS_JOB_WEB_URL=https://travis-ci.org/bencoman/test-travis-multi/jobs/479072677
JOB=`echo $TRAVIS_JOB_WEB_URL | rev | cut -d/ -f1 | rev`
curl -H "Travis-API-Version: 3" \
     -H "Authorization: token $SECRET" \
     https://api.travis-ci.org/job/$JOB
$ bash apitest.sh  

which outputs…

{
  "@type": "job",
  "@href": "/job/479072684",
  "@representation": "standard",
  "@permissions": {
    "read": true,
    "delete_log": true,
    "cancel": true,
    "restart": true,
    "debug": true
  },

Now referring to https://developer.travis-ci.com/resource/job#cancel
it looks like I should then be able to just change that last line as follows…

curl -H "Travis-API-Version: 3" \
     -H "Authorization: token $SECRET" \
     https://api.travis-ci.org/job/$JOB/cancel

but that fails with…

{
  "@type": "error",
  "error_type": "method_not_allowed",
  "error_message": "method not allowed"
}

The documentation tells you that you need a POST. For curl, it is -X POST.

thx. I haven’t used curl much and hadn’t understood the implication for it.
Now it worked as I’d hoped.

cheers -ben

btw… I just learnt something else new which might be a good point to go on… https://docs.travis-ci.com/user/best-practices-security/
While dev/testing just now using sh -x I was concerned about the exposing the token,
and I turned up the following article… https://superuser.com/questions/806599/suppress-execution-trace-for-echo-command

So that…

{  SECRET=`travis token`
   curl -X POST \
     -H "Travis-API-Version: 3" \
     -H "Authorization: token $SECRET" \
     https://api.travis-ci.org/job/$JOB/cancel
} 2> /dev/null

prevents code tracing with set -x from revealing SECRET.

Just following up for anyone reading this later.
After getting it working and evaluating it in action, I ended up taking another path.

As described above, my purpose was to have a Coverage matrix of which some were Production jobs that I didn’t want to run a second time. Production jobs can’t fail but the Coverage jobs could. And I wanted to define that without repeating myself, especially since filters ‘env:’ definitions need to match exactly.

I found that aliases together with YAML being a superset of JSON could serve my purpose,
to produce this result https://travis-ci.org/bencoman/test-travis-multi/builds/481382011
from this definition…

stage: Coverage

os:
  -       linux
  -       osx

env: [
  &E01 "BUILD=64x64/squeak.cog.spur     TESTIMAGE=skip" ,
  &E02 "BUILD=64x64/pharo.cog.spur      TESTIMAGE=skip" ,
  &E03 "BUILD=64x64/newspeak.cog.spur   TESTIMAGE=skip" ,

  &E04 "BUILD=64x64/squeak.cog.stack    TESTIMAGE=skip" ,
  &E05 "BUILD=64x64/pharo.cog.stack     TESTIMAGE=skip" ,
  &E06 "BUILD=64x64/newspeak.cog.stack  TESTIMAGE=refer_newspeakBootstrap.sh" ,
]

matrix:
  allow_failures:
  - stage: Coverage
  exclude: [
    &P01 { "os": "linux", "env": *E01 },
    &P02 { "os": "osx",   "env": *E02 },
]

jobs:
  include:
  - stage: Production
    <<: *P01
  - stage: Production
    <<: *P02

script:
  - if [ "${TRAVIS_BUILD_STAGE_NAME}" = "Coverage" ] ; then exit 1 ; fi   # simulate failure
  - exit 0   # simulate success

Imprint