As backend engineers at Instrument, one of our duties is to streamline the development process for our teams. Our team needs to deliver websites and software at a high velocity without sacrificing performance or security. One of the ways we accomplish this goal is to setup a continuous integration and continuous delivery pipeline.
We normally use CircleCI, a named leader in the cloud-native continuous integration. At the end of 2019, GitHub Actions announced that it was releasing its beta to the public. Switching to GitHub Actions and GitHub secrets would give us the luxury of having our repository, pipeline and sensitive information under one platform. This streamlines our standard pipeline commands. We switched to GitHub Actions on our next project and documented the differences between the tools, CircleCI and GitHub Actions.
Continuous Integration and Continuous Delivery
Continuous integration and continuous delivery are best practices for software development. Continuous integration is the software development practice of merging code changes into the project early and often. Instead of building out features in isolation and then integrating them at the end of a development cycle, code integrates with the shared repository multiple times throughout the day.
Continuous Integration (CI) grew out of a need to have developers working on features in parallel and on separate branches without fear of conflict. CI pipelines include automatic tools and processes (i.e. unit tests, linting tools) that automatically verify the code changes before merging it into the repository. Developers are less likely to be blocked by another developer’s work. CI results in changes that are easier to test and to revert. New work is introduced quickly in smaller bites. This also creates easier to review pull requests. These practices lead to a reduction in the time it takes to review PRs, find bugs and QA changes, while also maintaining the integrity and stability of the project.
Continuous Delivery (CD) ensures code changes are tested and ready for production deployment as soon as they are merged into the project. While the code does not have to be deployed to production, it should have been tested on a staging or a production environment. Our CI pipeline also includes automatic tools and processes (i.e. integration tests, end-to-end tests) that automatically test that the code is production-ready before releasing it to the repository.
When CD and CI are done in tangent, developers can rapidly push quality features and bug fixes. The automation of this requires a robust pipeline.
GitHub Actions in Action
We decided to use GitHub Actions on our next greenfield project, which included Craft CMS hosted on Heroku and a front-end component system.
Building a component system with multiple developers working on database schema changes in parallel is an extremely sticky situation, and building a website with multiple developers and writers working on it simultaneously would be even more difficult. This would be a great case study for a CI/CD tool like GitHub Actions.
We utilized both GitHub branch rules and GitHub Actions to create a pipeline that would fit our workflow.
Unreliability of GitHub Actions in Beta
GitHub Actions during its initial beta release was fairly unstable. There were many changes throughout the first few months of the initial release. Thankfully, GitHub switched from HCL over to YAML before we began our project, but we still experienced other breaking changes such as updates to the check-out process, pushes and workflow syntaxes. GitHub Actions was also down for frequent half-days in its infancy, although it seems to have stabilized toward the end of our project timeline. The GitHub Actions dashboard, which is crucial to development as it is the only way to get our jobs’ logs or statuses, proved to be unreliable throughout the beginning months.
As shown in our pipeline diagram above, this is why we took GitHub Actions out of automating anything for production and relied on a manual process that our cloud platform, Heroku, provided instead.
GitHub Actions vs CircleCI
Github actions did not provide all the niceties that CircleCI had:
- Re-running a GitHub Action (update: you can now re-run a failed GitHub Action, but not a successful one like you can in CircleCI.)
- Manual approval/trigger
- SSH into the GitHub Action environment
- Caching dependencies to speed up workflows (update: now allowed as of 11/04/2019)
However, GitHub has been steadily releasing features since the beta. To get an idea of their velocity, below are some features that rolled out in the two months between our project launch and this article:
- Proxy support for self-hosted runners
- GitHub CLI beta released
- GitHub Actions API released (runner is now open sourced)
- Caching dependencies to speed up workflows
- Ability to use GitHub Packages with Actions to simplify package management
GitHub Actions prides itself on being “community-powered”. Anyone can publish an Action and any repository can use a published Action. Many have been using GitHub’s millions of open source libraries or their own repositories to create new Actions. There are now over 1000 community actions available.
Features like waiting on a manual trigger to run the next job (readily available by a single command in CircleCI) can be implemented by including another user’s published GitHub Action or creating your own using GitHub’s REST API to check for PR approval on every PR review update. It’s not quite as ready out-of-the box as CircleCI, but what it lacks in ease, it makes up in customization and control. There are Actions for popular vendors such as Netlify and Heroku, and it’s easy to add your own using any client CLI. These actions are continuing to grow as GitHub Actions gains more traction in the market.
Both CircleCI and GitHub Actions jobs are written in YAML, but the way to approach both are starkly different. CircleCI expects one config file in each repository, while GitHub Actions works best with multiple files. Our CircleCI config files span hundreds of lines, but CircleCI supports anchors and aliases to DRY up the config file.
The dashboard on GitHub Actions is sparse compared to CircleCI. CircleCI provides in-depth project insights and works well with integrations like Sumo Logic to better track analytical data on all of the jobs. GitHub Actions only showed the build for a week before deleting the build log. GitHub Actions is still rolling out new features. Since the project’s launch, it has added the artifacts, annotations and workflow file to the dashboard (not shown in the image below).
The purpose of a CI/CD pipeline is to have a high development velocity while maintaining the same stability that our clients have come to expect from us. GitHub Actions succeeds in this purpose. It increases our productivity, code quality and delivery. The amount of custom code needed to get a workflow in place for GitHub Actions is surprisingly more than needed for CircleCI, but conversely, adding more scripts for GitHub Actions is more intuitive than adding the extra YAML lines needed for CircleCI.
Although CircleCI currently has more features built in, provides better analytics and is more reliable than GitHub Actions, GitHub Actions’ ability to house our code repository and pipeline under the same platform and its ability to have multiple pipeline config files are noteworthy conveniences. GitHub Actions is a strong contender when considering a CI/CD tool.
Header image by Lizelle Galaz, UX Strategist at Instrument.