Continuous integration, and automation in general, is arguably extra important when working on an open source project that anyone can contribute to. Especially if a project starts gaining momentum, automating different kinds of tasks — from building and testing the project, to ensuring a consistent code style — can be truly essential in order for all contributors and maintainers to stay productive.
Preserving the passion
In many cases, the process of creating, maintaining and evolving an open source project comes down to individuals spending their free time working on something they’re passionate about. As the creator and maintainer of a project, you might’ve chosen to open source a utility from one of your apps, or you’ve built something new by following your curiosity. And as a contributor, you might be fixing a bug that you encountered, or adding a feature that you think would be useful to the community.
Since so much of the work that goes into open source is fueled not by business motives, but by passion, preserving that passion is incredibly important — and that’s something that automation and continuous integration can really help with.
By automating tasks that are both time-consuming and repetitive, we can enable both maintainers and contributors to focus on actually working on the projects they’re passionate about — rather than having to spend their time configuring build settings, pointing out code style deviations, or figuring out why the tests started failing after a series of changes were merged.
Building and testing
The first task that we’ll most likely want to automate is to make sure that every Pull Request that is opened against one of our projects is built and tested. That way we’re much less likely to accidentally introduce a breaking change, and we can ensure that all of our existing functionality that’s covered by tests is unaffected by a merged contribution.
Bitrise is completely free for any open source project that takes less than 45 minutes to build and test, and setting it up for most Swift projects couldn’t be easier. If the project we’re looking to build contains an Xcode project, all we have to do is to add the “Xcode Test for iOS” (or Mac if we’re building a macOS project) step within our project’s Workflow Editor:
Adding the above step will make Bitrise first build our project, and then run all of its tests, using Xcode’s built-in testing command. If our project doesn’t contain an Xcode project — for example if we’re using the Swift Package Manager to build and distribute it — we can instead manually invoke swift test using a “Do anything with Script” step:
The set -e and set -x commands that we execute before running our tests ensure that the overall build will fail in case there are any test failures, and that we’ll get as much debug information as possible within our build log.
We can of course also combine the above two build steps, in case we’re working on a project that both uses an Xcode project and supports the Swift Package Manager, or if we want to test our project on both iOS and macOS.
Regardless of how our project is configured, by performing any of the above steps to build and test our project, we’ll give each contributor (including ourselves) immediate feedback on their Pull Requests. If a change causes a test to fail, or if the contributor forgot to include a certain file in the submitted commits, the author will be notified, and able to correct those mistakes — before a maintainer has even reviewed the code — making the process faster and smoother for everyone involved.
Besides verifying that each change successfully builds and that all tests pass, most projects have various coding conventions and styles that we want each contributor to follow. While these things could be pointed out in manual code reviews, if we’d instead automate as many of them as possible, we’d both free up time for maintainers to instead focus their reviews on things like architecture and API design — and we’d also be able to automatically give each contributor feedback much quicker, without having to wait for a human to sit down and manually review their code.
One tool that makes adding these kinds of conventional checks much easier is Danger, which provides a DSL (Domain Specific Language) in a number of different languages (including Swift) to define rules and checks that we wish to apply to our project’s code base. These rules are defined within a Dangerfile, which is placed in the given repository’s root folder.
For example, here’s how SwiftLint can be triggered using Danger, through a Ruby-based Dangerfile — which causes each linting violation to be shown inline within a Pull Request’s diff:
Even though the name might suggest it, Danger can be used for many more things than just avoiding danger. For example, here’s how we could display a friendly welcoming message to anyone who contributes to our project for the first time:
To configure Danger within Bitrise, we simply need to add a Run Danger step to our project’s workflow:
To enable Danger to add comments to our project’s Pull Requests, we need to give it a GitHub API token that it can use to make requests on our behalf. While we can generate API tokens for any GitHub account by going to Settings > Developer settings > Personal access tokens, it’s usually a good idea to create a separate account for this kind of automation — since Danger will post comments directly on behalf of the account that its API token is for.
For example, here’s how we could set up an API token to let Danger post comments on public repositories, as well as modify their status:
For more examples of what Danger can do and how to configure it, check out the official documentation. To see an example of how one of my personal open source projects uses it, check out the Dangerfile for Imagine Engine, my Core Animation-based game engine.
Setting up continuous integration and automation can at first seem like a really huge task that requires lots of knowledge about Xcode build settings, bash scripting, and using tools like the GitHub API — but thanks to both Bitrise and Danger, many kinds of automation can be created with very little effort.
Having the right automation in place can make a huge difference as to how fun and efficient maintaining and contributing to a project is. When code reviews are no longer about pointing out stylistic mistakes, or that a change is too large to be merged in as a single unit, we can focus on what’s actually important for our project — making sure that it keeps evolving to become the best it can be.
What do you think? Do you currently use continuous integration for your open source projects, or is it something you’ll try out? Let me know on Twitter @johnsundell. And if you’re looking for a service to use for your continuous integration and automation needs, look no further than Bitrise — it’s my personal favorite.
Thanks for reading! 🚀