Cesium Continuous Integration
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.
Build Process
The Travis build process is defined intravis.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'
Under the 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 package.json and gulpfile.js.
JSHint
First, we run JSHint, a static code analysis tool for JavaScript. It scans the code and reports any commonly made mistakes such as syntax errors.
npm run jsHint -- --failTaskOnError
The --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.
Unit Tests
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
The --exclude WebGLoption 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 Electrontells Karma which browser to spawn and run test against. To keep the Travis log brief, --suppressPassedtells Karma to report only failed tests.
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.json via 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 TRAVIS_BRANCH. The --confirm flag tells the task not to prompt for confirmation, and lastly we can specify a cache option with the -c flag.
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.
Release Tests
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
Cloc
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.