CI for CesiumJS: A Deep Dive into Our GitHub Actions Workflow
Pull requests and code reviews are an intrinsic part of software development at Cesium, but they can also be one of the most challenging and time-consuming aspects. Our continuous integration (CI) processes aim to automate developer overhead, improve code quality, and increase confidence in our monthly releases before any code goes into the main branch. Every code commit is automatically built and tested, catching conflicts or errors early in development so developers can resolve them quickly.
As maintainers of a large open-source project like CesiumJS, we face somewhat unique challenges in comparison to most codebases. To start, the JavaScript library for 3D geospatial visualization is extensive–just under 250,000 lines of source code and over 275,000 lines of test code. We must ensure code quality and consistency across contributions from a diverse group of external developers, and across a heterogeneous codebase consisting of JavaScript, HTML, GLSL, TypeScript definitions, API reference docs, developer docs, and more.
Evolution of CesiumJS's CI Process
Since we initially set up the first CesiumJS CI pipeline using Travis CI, the demands on that pipeline have grown. We’ve replaced outdated build tooling, expanded quality checks, and added additional workflows. While Travis CI served us well in the early stages, Cesium grew as an organization and we started to run into scalability challenges: cost, speed, and fragmentation in CI tools used across different teams.
Since Cesium was already deeply integrated with GitHub for issue tracking and code reviews, switching to GitHub Actions streamlined our processes. This move across the organization allowed the CesiumJS repo in particular to speed up our CI runs and to implement reusable actions across our repositories.
CI Workflow
In our CI workflow, we focus on efficiency by running multiple jobs in parallel. This approach helps us speed up the integration process and ensures comprehensive coverage across key areas of development.
The status of each job is shown in the PR using commit statuses, signaling to the reviewer that the PR should not be merged until all jobs pass. Build artifacts such as logs, coverage results, and deployments are linked for easy access by the developer and reviewer.
1. Build Processes
Automated builds confirm the project's stability.
We bundle the JavaScript source code into two main distributions that are shipped with CesiumJS: 1) a developer build, unminified and designed for debugging, and 2) the production release build, which is fine-tuned for performance, including minification and stripping debug pragmas. Using esbuild for bundling allows us to reduce our build times, enabling quicker iterations without sacrificing quality.
Running the custom script to generate the release zip file is valuable as it contains the two distributions, developer documentation, and tools like Sandcastle, helpful for developers to test functionality and experiment with CesiumJS.
We also generate the npm package for distribution via package managers.
2. Testing
Tests validate functionality across supported environments.
We use Jasmine and Karma for unit testing, which helps verify that each component of our software performs as expected. Tests are run against both the development and release builds.
Additionally, we conduct smokescreen tests on the build artifacts to confirm package.json configurations. This lets us catch compatibility issues across various platforms, such as Node.js LTS and web browsers early in the process.
3. Static Analysis and Code Quality Metrics
Static analysis and formatting checks ensure code consistency and quality.
We use tools like ESLint for JavaScript linting and markdownlint for Markdown files to catch syntactic and stylistic errors before they are merged. Prettier enforces a uniform code format across all contributions. Additionally, we track code coverage by instrumenting the code using istanbul to ensure that tests adequately cover new and existing code, and finally count the lines of source and test code using cloc.
4. Continuous Deployment (CD)
Automatic deployments make the latest builds readily available for testing and review. Each build is uploaded to an S3 bucket, allowing developers to access and review functionality and documentation without needing to build locally. We publish build artifacts, the zip file, and npm package, which simplifies integration testing with other applications such as Cesium ion.
Keeping security in mind, we need to make sure only authorized sources deploy to AWS, so these deployment steps are restricted based on the author’s commit status.
Future Roadmap
Looking ahead, we plan to enhance our CI process with several key improvements. We’d like to incorporate end-to-end screenshot tests using Playwright to ensure visual consistency across releases, which developers currently run locally. Additionally, we aim to improve code quality through inline documentation linting, spellcheck, and other static validations to catch errors before they make it to production. We are also exploring the numerous potential integrations with GitHub Actions to further automate our release processes.
Conclusion
We are committed to continuously improving the CesiumJS CI process and value input from the developer community. If you have suggestions or would like to contribute, please start a conversation on GitHub. Your insights can help improve our workflows.