Software developers tend to come up with complicated names for simple topics. Examples of this include Dependency Injection, Orthogonality, and Lexical Binding. While these terms sound impressive, they often produce an adverse side effect; novice developers assume the subjects they describe are complicated and unapproachable.
The above proved to be true for me when I first learned about Continuous Integration (CI). I thought CI sounded like a complex topic, one that I would never be able to understand let alone master. In reality however, the opposite was true. CI is straightforward to integrate into any development process, especially in this day-and-age when there are many fantastic CI hosting providers available to choose from.
In this post, I’ll explain what CI is and demonstrate how you can add a CI pipeline to an existing project. I’ll also demonstrate how we can integrate that pipeline with GitHub so that the CI process automatically runs any time a developer opens a pull request, or commits to a pull request. We will also branch protection that prohibits merges to master unless the CI build has passed.
Lastly, I’ll show how we can add CI reporting notifications to everyone’s favorite chat app, Slack.
What is CI?
CI is the process of building and testing a code base whenever an individual developer pushes their contributions to a repository. This process needs to be automated, meaning a system is responsible for building and testing the code base, not a human.
At Mesh Studio, we are huge proponents of CI as it is a potent tool that helps development teams ensure the stability of their code base at all times. When we engage with a new customer, we will often instrument a CI pipeline before we start writing any feature code.
For this tutorial, we are going to use the following sample project:
Fork the repository, clone it onto your local machine and CD into the directory.
$ git clone email@example.com:<YOUR_GITHUB_HANDLE>/circle-node-sample.git && cd circle-node-sample
Our CI build process is going to consist of the following two steps:
- Install dependencies
- Execute the test suite
Our sample project provides simple
npm commands for each of these steps. These commands are
npm install and
npm test. We will use both commands in our CircleCI build configuration.
Setting up CircleCI
Our CI provider of choice at Mesh is CircleCI. To run builds on Circle, we need to create a new directory in the root of our project called
$ mkdir .circleci
Next, we need to create a file called
circle.yml inside of the new
.circleci directory. (oh — I didn’t know you could do a directory)
$ touch .circleci/circle.yml
circle.yml file will contain the build instructions that CircleCI follows for your build. For this tutorial, we will use the
circle.yml file below. Copy and paste the following code into your
— image: circleci/node:7.10 working_directory: ~/repo steps:
— checkout - run: npm install
— run: npm test
The circle.yml File
Let’s dive into each section of the
circle.yml file and examine what each entry means.
jobs section of the circle.yml defines a task or set of tasks to be run for the CI process. CircleCI allows you to configure multiple jobs for more complex CI processes, but for our purposes, a single
job task is all we need.
build section defines the name for the
job. So in this case, the name of the
job is simply
docker section defines an executor for the build process. An executor is a place where build steps will occur. By specifying
docker, we are telling Circle that we want our build steps to take place inside of a Docker container. For comparison sake, if we were building an
iOS application instead of a
node.js application, we would replace `docker` with
macos. This would tell Circle that we want our tests to take place on a MacOS machines as opposed to a Docker image.
When we use the
docker executor, we must define the
image that we want to use for the
executor. Circle offers many images that we can use for a variety of runtimes. In this case, we have decided to use a Circle image that supports
steps section defines a list of steps that need to be executed to complete the build process. Each of these steps must pass without failure; otherwise, the CI process will fail. We describe the steps, and their functionality below:
- checkout — A CircleCI built in command which is responsible for checking out the project’s source code into the Job’s
working_directorywe discussed above.
- run: npm install — Installs all project dependencies listed in the
- run: npm test — Executes the automated test suite.
Running the build locally
One of the fantastic features of CircleCI is that they distribute a command-line interface (CLI) tool which provides for running build locally on a developer’s machine. Now that we have our
circle.yml file configured, we can run the build locally and ensure that the build process passes.
To do so, we first need to install the CircleCI command-line tool. We can do this with the following curl command which will download and install the cli.
$ curl -o /usr/local/bin/circleci https://circle-downloads.s3.amazonaws.com/releases/build_agent_wrapper/circleci && chmod +x /usr/local/bin/circleci
To validate your installation, type
circleci -h. You should see the following output.
$ circleci -hThe CLI tool to be used in CircleCI.Usage:
circleci [command]Available Commands:
build run a full build locally
config validate and update configuration files
help Help about any command
step execute steps
tests collect and split files with tests
version output version infoFlags:
-c, — config string config file (default is .circleci/config.yml)
-h, — help help for circleci
— taskId string TaskID
— verbose emit verbose logging outputUse “circleci [command] — help” for more information about a command.
Once the CLI is installed, we can kick off a local build with the following command:
$ circleci build
Your build process should begin executing and pass successfully! Congratulations, you have configured your build with CircleCI!
Integrating CircleCI and GitHub
Now that we have our CircleCI build configured and passing locally, the next step is to take our build process and make it continuous. We do so by telling Circle to run our CI process anytime a developer opens a Pull Request (PR) or makes a commit to an open PR.
We are also going to protect the master branch of our repository to prevent code from being merged unless it has passed CI. We can set this up with the following steps:
Navigate to your project’s repository and click on `Settings.`
Click on “Branches” in the left-hand navigation menu.
Under “Protected Branches” click on the “Choose a branch” drop-down and select “master”.
Click the checkbox next to “Protect this branch”.
Click the checkbox next to “Require status checks to pass before merging”.
Click the checkbox next to “Require branches to be up to date before merging”.
At this point, you should see the dialog box above which says Sorry, we couldn’t find any status checks in the last week for the repository. This is expected.
Leave this browser window open for the time being. For the next steps, we need to head over to CircleCI.
Adding project to CircleCI
Head over to www.circleci.com and login with your GitHub account. Once logged in, you should see the circle CI dashboard.
We need to tell Circle that it should start building our GitHub project. We can do this with the following steps:
Click on “Projects” in the left navigation bar.
Click the “Add Project” button in the upper right-hand corner.
Find your repository and click the “Setup Button” on the far right-hand side of the screen.
Scroll past the setup information and click the “Start Building” button.
This will kick off your first build process with CircleCI!
Completing the GitHub Setup
Next, lets go back to our open GitHub browser window and refresh the screen. We should now see the CircleCI option. Make sure the checkbox next to
ci/circleci is checked and click Save Changes.
Pushing our configuration
At this point, your github repo is configured to automatically run your CI process. Lets go ahead and create a branch, commit the changes and push up to Github.
$ git checkout -b feature/circle-ci-configuration
$ git add -a
$ git commit -m "Adding CI to my project"
$ git push origin feature/circle-ci-configuration
After pushing, go to GitHub and open up a PR for your branch.
If you navigate to the PR screen, you will be able to see the CircleCI build process information directly from the pull request window.
Once the build process finishes, everything will be green and you will be able to merge your pull request to master!
CONGRATULATIONS, your CI build pipeline with CircleCI and Github is now complete! That wasn’t too difficult was it?
Adding CI notifications to Slack
Now that we have our CI pipeline all hooked up, its time to show off to the rest of the development team! Lets integrate build status notification into Slack.
First we will need to enable CircleCI from within Slack. To do so visit the following URL:
Select the channel that you would like notifications to be sent to and click Add CircleCI Integration
In the next window, copy the link displayed under Step 2.
Navigate back to the CircleCI dashboard and click on your project, then the setting gear icon in the upper right corner. Under the Notifications section in the left hand navigation, click on Chat Notifications.
Enter the link you copied from Slack into the link into the input bar and click Save.
And that is it! Your CircleCI build pipeline is now fully integrated with Slack! Check the Slack channel that you selected and should be able to see a test notification.
Continuous integration is a fantastic tool that helps developers build reliable, dependable and predictable applications. We would encourage everyone to add CI and branch protection to all of their software projects.
If you ever need help setting up your CI build process, please don’t hesitate to reach out!
Mesh is a software development consultancy located in Fremont, WA. Sign up for our monthly newsletter here. Get in touch firstname.lastname@example.org.