Continuous integration, or CI, is an automated process that occurs whenever a developer commits code to Cesium or opens a pull request. To help guarantee the quality of the code we are writing before it is merged into master, we build and test the code using a continuous integration service called Travis-CI. Travis is a hosted service that checks out the relevant branch in GitHub, runs the commands to build the code and run tests, and reports these results back to GitHub.
To make it easier to run our tests through Travis, we’ve updated how we run our unit tests with Karma. Karma is a tool that spawns a browser, runs tests against that browser, and displays the results on the command line. Electron is a browser that runs V8 (Chrome) inside of a node process, which has been configured to be run headless. That means that when we run tests, no actual browser window is launched and the output of the tests is sent to the console.
But wait, there’s more! By running the tests using Karma, this opens up new doors for a smoother workflow. If you are developing using Webstorm, you can run the unit tests from within the IDE. There are also options such as showing only failed tests, and automatically re-running failed tests when you make a change.
The Travis build process is defined in
travis.yml, a YAML format file that specifies the options for the build process. Here we define the language
node_js and the correct version, so Travis knows to run
npm install to set up the build environment.
language: node_js node_js: - '4.3'
script option, we include the commands for each step of the build process. Each command is a gulp task
wrapped in an npm script tag. For more information on how the gulp tasks work, check out the
npm run jsHint -- --failTaskOnError
--failTaskOnError flag signals Gulp to fail the task if jsHint detects an error, so that the Travis also fails. Normally, we don’t fail the task on error to avoid a large stack trace when running jsHint manually. However, we need to signal to Travis that there was an error, so we fail the gulp task.
Next, we run our non-WebGL unit tests against the source code with the help of Jasmine, Karma, and Electron. Any failed tests are reported, or when everything passes we see this:
And if any of the tests fail, we get output that looks like this:
The tests are run with the following command:
npm run test -- --exclude WebGL --browsers Electron --failTaskOnError --suppressPassed
--exclude WebGL option excludes any tests that require WebGL. Since the Travis virtual machines do not support the
configurations needed to run a WebGL context, we can’t perform tests that require WebGL.
If Travis ever supports WebGL, we can easily remove the flag and run all tests.
In our Jasmine specs, we can
specify a category for each spec or suite.
--browsers Electron tells Karma which browser to spawn and run test against.
To keep the Travis log brief,
--suppressPassed tells Karma to report only failed tests.
Now, we clean and then build the code.
npm run clean npm run makeZipFile
The build target
makeZipFile actually has many subtasks. To enable traditional non-module based development, it uses the
requirejs optimizer to combine all of Cesium’s AMD modules into a single
Cesium.js file and also generates a combined file for each Web worker. It then creates minified and uglified versions of these same files; these versions provide smaller payloads and faster performance in production deployments. Finally, it generates reference documentation using jsDoc.
Deploy Files to S3
Next, we deploy the build to our S3 bucket so it can be easily accessed by other developers. We deploy the following:
- deployment - A hosted version of the branch complete with Sandcastle and everything else that’s part of a Cesium release.
- npm package - An npm package of the branch that can be included directly into
package.jsonvia the provided url.
- zip file - A complete release of the branch, which you can download and use just as you would from the website.
To access the deployed builds if a pull request for a branch is open, click on the “Details” link next to the displayed check status.
To access the deployed builds of any branch, whether there is a pull request open or not, go to the list of Cesium branches in GitHub and click on the icon next to the branch name.
Each build will automatically be cleaned up after 90 days.
We use our own custom gulp task to upload files to S3, which is run in the
travis.yml with the following commands:
npm run deploy-s3 -- -b cesium-dev -d cesium/$TRAVIS_BRANCH --confirm -c 'no-cache' npm run deploy-status -- --status success --message Deployed
The first command runs the deploy task. We can specify the bucket name, here
cesium-dev with the
-b flag. The relative url is given with the
-d flag. Here we put each build in its own directory under the name of the branch in GitHub with the Travis environment variable
--confirm flag tells the task not to prompt for confirmation, and lastly we can specify a cache option with the
The second command signals GitHub that the deployment is finished, and it sets the deployment status to success.
The build is always deployed, even if the tests fail.
For security reasons, all forks must set up S3 credentials in Travis’s settings for deployment to work. Otherwise this step is simply skipped.
Now we run the unit tests again, this time against the combined and minified version of Cesium, since certain classes of bugs can occur in release form.
npm run test -- --exclude WebGL --browsers Electron --failTaskOnError --release --suppressPassed
Finally we run cloc, which reports statistics about the code base, such as how many files are of each language and how many lines of code there are total, broken down into source code and specs.
npm run cloc
If any of the steps fail, the build itself fails and GitHub will report that the checks have failed. If the build passes, the pull request is marked as good and ready to merge.
There is easily room to grow this process in the future. For example, the next step on our roadmap is to include code coverage with istanbul as part of the Travis process.