Running Travis-CI Locally

Travis CI is now a paid only product, even for open source projects.
We have moved our continuous integration to GitHub actions (see .github folder)

The following steps can be followed to run Travis CI on your development machine, as long as you have Docker installed.

This is obviously not an “officially supported” flow, but it works.

Quick history

I found the information that got me started with this on Stackoverflow. I tried to contribute back by adding a couple observations I made, due to the fact that the Travis CI flows have been subtly changing over time!

The Workflow

Creating a local container

As mentioned, I got the idea from Stackoverflow. I modified some aspects of the flow to use a local, uncommitted branch.

This will download and run the container image:

1DTAG=$(curl -s 'https://hub.docker.com/v2/repositories/travisci/ci-sardonyx/tags/?page_size=1&page=1&ordering=last_updated' | jq -r '.results[].name')
2INSTANCE="travisci/ci-sardonyx:$DTAG"
3docker run --name glauth-travis-work -v "$(pwd)":/home/travis/builds/glauth/ -dit $INSTANCE /sbin/init
4docker exec -it glauth-travis-work bash -l

Using the last command, I entered the container to prepare it.

CI preparation

In the container:

1su - travis
2rvm autolibs enable \
3&& rvm install 2.3.0 \
4&& rvm use 2.3.0 --default \
5&& cd $HOME/builds \
6&& git clone https://github.com/travis-ci/travis-build.git \
7&& cd travis-build/ \
8&& mkdir -p /home/travis/.travis \
9&& ln -s `pwd` ~/.travis/travis-build \
10&& gem update --system \
11&& gem install bundler \
12&& bundle update --bundler \
13&& bundle install \
14&& bundler binstubs travis \
15&& cd $HOME/builds/glauth \
16&& ~/.travis/travis-build/bin/travis compile \
17| awk '!/^travis_cmd travis_wait_for_network/' \
18| awk '/^travis_fold start docker_mtu_and_registry_mirrors/,/travis_time_start/ {next} 1' \
19| awk '{sub(/^travis_run_checkout/, "travis_run_local_clone"); print}' > ~/ci.sh

The last command spit out Travis’ execution script with some unwanted stuff removed.
We are now going to modify it to fit our purpose by adding:

1export TRAVIS_HOME=$HOME
2cat <<'EOFUNC_LOCAL_CLONE' >>${TRAVIS_HOME}/.travis/job_stages
3function travis_run_local_clone() {
4travis_time_start
5echo
6 
7travis_fold start local.clone
8 travis_cmd rm\ -f\ "$HOME/gopath/src/github.com/glauth/glauth/bin/*"
9 if [[ -d "${TRAVIS_BUILD_DIR}/glauth" ]]; then
10 travis_cmd rm\ -rf\ "${TRAVIS_BUILD_DIR}/glauth"
11 fi
12 travis_cmd mkdir\ -p\ "${TRAVIS_BUILD_DIR}/glauth"
13 travis_cmd cp\ -r\ "${TRAVIS_HOME}/builds/glauth"\ "${TRAVIS_BUILD_DIR}/glauth/"
14travis_fold end local.clone
15 
16echo
17 
18travis_time_finish local_clone
19:
20}
21 
22EOFUNC_LOCAL_CLONE

Exit the container, stop it, commit it and finally delete it:

1docker stop glauth-travis-work
2docker commit glauth-travis-work glauth-travis

Using our work image

1BUILDID="build-$RANDOM"
2docker run --rm --name $BUILDID -v "$(pwd)":/home/travis/builds/glauth/ glauth-travis su - travis -c "cd ~/builds/glauth;bash ~/ci.sh"

Dirty speed-up

Note that, if you wish to bypass the whole container setup phase to run CI multiple times during a work session, you can run it interactively and abuse it until you are satisfied:

1BUILDID="build-$RANDOM"
2docker run --rm --name $BUILDID -v "$(pwd)":/home/travis/builds/glauth/ -dit glauth-travis /sbin/init
3docker exec -it $BUILDID bash -l
4su - travis
5bash ~/ci.sh
6# ...
7bash ~/ci.sh
8# etc.
9exit
10exit
11docker stop $BUILDID
Copyright 2021