This project provides a tool for exercising participating projects with a pinned bleeding-edge ClojureScript compiler version. The goal is to have some smoke tests which allow us to detect issues early before releasing a new ClojureScript version.
If you are using Travis for CI, participating in Canary builds involves a few simple steps. (Before doing this, ask someone in the cljs-oss
organization for commit rights.)
-
Revise your
.travis.yml
to fetch the Canary-built ClojureScript JAR.before_install: - curl -sSL https://raw.githubusercontent.com/cljs-oss/canary/master/scripts/install-canary.sh | bash
-
Configure your project's build so that it honors the
CANARY_CLOJURESCRIPT_VERSION
environment variable. If using Leiningen, this can be accomplished by revising your ClojureScript dependency inproject.clj
to look like:[org.clojure/clojurescript ~(or (System/getenv "CANARY_CLOJURESCRIPT_VERSION") "1.9.946")]
-
Obtain Travis Access token:
Probably the easiest way is to copy it from your Travis UI web interface (look under
Settings/Settings/API authentication
).Note that an alternative way to obtain a Travis Access token is by doing
gem install travis && travis login && travis token
. See their api reference for updated info on how to retrieve access tokens. -
Set up Canary with a Travis access token. Replace
YOUR_PROJECT
with the name of your project anddeadbeef
below with your Travis Token obtained above.git clone --branch jobs [email protected]:cljs-oss/canary.git cd canary travis encrypt CANARY_YOUR_PROJECT_TRAVIS_TOKEN=deadbeef --add env.global git add .travis.yml git commit -m "add CANARY_YOUR_PROJECT_TRAVIS_TOKEN [ci skip]" git push origin jobs
Warning: Please make sure that you run
travis encrypt
inside your canary checkout of the jobs branch as shown above. Running it outside seems to produce some encrypted value, but the result is corrupted when actually used by travis. -
Add a Canary task to trigger CI builds of your project. This is done by adding a
^:task
to a namespace in themaster
branch underrunner/src/canary/projects
, like this (replacinggithub-yourname
,your-project
andYOUR_PROJECT
):(ns canary.projects.github-yourname (:require [canary.runner.travis :as travis])) (defn ^:task your-project [options] (travis/request-build! "github-yourname/your-project" "CANARY_YOUR_PROJECT_TRAVIS_TOKEN" options))
After setting this up, you can force an out-of-cycle test of your job going into the jobs
branch and making a commit like this (replacing your-project
) and pushing it:
git commit --allow-empty -m "job --only your-project"
Canary provides a script which can be used to run a job. Each job is assigned a ClojureScript compiler version. It builds compiler jar, uploads it and then runs exercises of individual projects in parallel (we call them tasks). Finally it waits for task results and generates a report for archiving.
Typically you don't run canary script on your local machine but rather invoke it on some machine in the cloud. For your convenience a new job can be triggered by committing an empty commit into the jobs branch. Travis machine will then execute canary script possibly triggering more child Travis builds for individual project tasks. At the end, results are generated and archived in the results branch. Also look into GitHub releases of this repo where individual built compiler versions get published.
./scripts/docker-build.sh
./scripts/docker-run.sh help
./scripts/docker-run.sh list
./scripts/docker-run.sh job
./scripts/docker-clean.sh # to start from scratch
./runner/run.sh job -v -r master
./scripts/blow-local-caches.sh # to start from scratch
- the script is called
runner
- ClojureScript compiler is usually simply referred to as the
compiler
- a list of relevant projects/libraries is called
projects
- a single request for a complete round of tests is called a
job
- a single project test is called a
task
Instead of maintaining multiple git repos, let's have just a single mono-repo canary
with following branches:
master
where the source code for therunner
livesjobs
where anyone with commit rights can trigger a newjob
(as a new commit)results
where therunner
will produce one commit perjob
All participating project authors will get commit access to this repo and can collaborate on the master
branch.
When a job
is triggered. The runner
goes through following steps:
- prepares
compiler
's jar according to requested parameters (repo/version) - determines which
tasks
should be part of thejob
based on request parameters - spawns all
tasks
(in parallel) instructing them to use thecompiler
- waits for
tasks
results and collects them - generates a report and commits it in the
results
branch
The runner
is implemented in Clojure for convenience. Each project
author gets own place (function/script)
for implementing functionality specific for their project
. Authors are expected to trigger test builds on their own repos
(e.g. via Travis) and simply collect results back. But anyone can use an escape hatch to invoke a shell script or do whatever
they need in Clojure. For example cloning their repo and running tests directly in the context of the runner
.
We wrap runner
in a Docker container to provide well-controlled environment for tasks
(possibly shell scripts).
We are developers and we have git and GitHub which is a great publishing platform on its own. Travis alone will provide some trace
of a job
(depending on what runner
script and individual tasks
output to stdout). But ultimately a commit into results
branch presents all interesting results also for archivation purposes. Then anyone can use their git-fu to follow those or
process them further.
Please read the readme in the jobs branch with details on that.
No problem. You can point Canary to your own fork of ClojureScript by specifying --compiler-repo
and --compiler-rev
parameters.
You will need to write a new task for your project. First look how existing projects are implemented. Ask for commit access. You can write your task as a Clojure function or as a shell script.
In case of a Clojure function you have to annotate it with ^:task
metadata so that runner recognizes it. In general
you can do whatever you need to do in your task (you can block, it is running on a separate thread) - this will depend on your project setup.
To ease some common scenarios we provide some helper functions. For example canary.runner.travis
namespace might be very useful for triggering
a Travis build for your own project.
In case of a shell script. You simply create your_name.sh
in the projects directory. Script has to return with zero exit
code to be considered as passing. Standard outputs will be embedded into the final report, so don't be too verbose there.
You can test your task locally. Running jobs without --production
flag should do no harm. When using travis/request-build!
it will mock it by default. You will have to add --production
as the last step for fine-tuning final version of the code.
For inspiration here
is the task for cljs-devtools, and here
is the adaptation needed in the project itself. Please note that child Travis build triggered by travis/request-build!
is configured with bunch of extra env variables prefixed with CANARY_
- those have to be taken into account by
the participating project (an example here).
Also for us to be able to trigger builds of your Travis projects you will also have to provide a Travis
API token for triggering the builds on your behalf.
You should encrypt your token and commit it into .travis.yml
in jobs branch (replace YOUR_PROJECT
and deadbeef
):
git clone --branch jobs [email protected]:cljs-oss/canary.git
cd canary
travis encrypt CANARY_YOUR_PROJECT_TRAVIS_TOKEN=deadbeef --add env.global
git add .travis.yml
git commit -m "add CANARY_YOUR_PROJECT_TRAVIS_TOKEN [ci skip]"
git push origin jobs
You are on your own. We haven't implemented similar helpers as for Travis yet. Want to contribute them? That would be great.
Inspired by ideas of @deraen and @mfikes.
You might discuss this in #cljs-dev channel on clojurians.net Slack.