Exploring Continuous Integration with CircleCI

Joshua Hall

Most large projects can’t just be built and deployed once and never to be touched again. They require consistent fixes, updates, redesigns. Instead of building one large new version and pushing that monolith to production and hoping for the best, many developers prefer to push features in more manageable, bit-sized, updates to test new ideas and catch any problems early on.

The problem with this approach is if you have many people on a team all creating, pulling, and merging different branches to eventually be pushed to the production site, there are a lot of chances for conflicting changes that can result in breaking features or potentially the whole application. There are two main options to prevent this, hiring someone to manually check every branch for errors before and after merging or to automate the process with a testing framework, like Jest, and a continuous integration (CI) tool like CircleCI, which will prevent any branch merge and alert you to any failing tests on every commit.

Prerequisites

We’re going to be using React along with Jest as the testing framework. We won’t be doing anything too crazy so just knowing how to set them up is fine. If you want to delve a bit deeper into testing itself, you can get started exploring Jest here.

I’m also going to be assuming that you know the basics of git and Github, you can learn enough to get started here.

Workflow

Here’s the basic approach that’ll be enough for most projects. We have a main production branch which is what will be deployed on something like Netlify or AWS. Our team would start every new fix and feature in a new branch off of the development branch. CircleCI is then added so as each feature is completed and merged with the development branch all of our test will be ran to either accept or reject that merge.

Once the development branch is stable enough to be moved to production, all of the tests are ran again and, ideally, the project manager would manually inspect everything along with the tests.

Workflow Diagram

Hopefully it’s already clear the advantages this gives us. Without limiting our merges to stable branches the development branch could quickly become polluted as mistakes are saved and become enmeshed in future branches, possibly only to be caught manually or when pushed to production.

React App

Let’s get started by setting up our React app. We won’t need to change anything in it since it already comes with Jest and a working test by default.

$ npm create-react-app ci-example
$ cd ci-example
$ npm install

As you can see we already have one working test that we can check with the run test script.

App.test.js

it('renders without crashing', () => {
  const div = document.createElement('div');
  ReactDOM.render(<App />, div);
  ReactDOM.unmountComponentAtNode(div);
});
$ npm run test

Once we know it’s set up correctly and our test is working you can push the whole project to a new Github repo, since that’s where CircleCI will get our project from.

↓ Here's a great React course we recommend. Plus, this affiliate banner helps support the site 🙏

CircleCI

Once you’ve created an account at CircleCI and linked it to your Github account, you should have the option to add our new ci-example app.

Back in your base directory, you just need to add a new folder with a config.yml file. This will tell CircleCI exactly how to run or tests.

.circleci/config.yml

version: 2
jobs:
  build:
    docker:
      - image: circleci/node:12

    working_directory: ~/repo

    steps:
      - checkout
      - restore_cache:
          keys:
            - v1-dependencies-{{ checksum "package.json" }}
            - v1-dependencies-

      - run: yarn install

      - save_cache:
          paths:
            - node_modules
          key: v1-dependencies-{{ checksum "package.json" }}

      - run: yarn test

When you go to link-up your repo to CircleCI, it should offer this code to get started. Just make sure you change Node from version 8 to 12.

Let try to understand exactly what’s going on here.

  • docker is installing the Node.js image from DockerHub for the container CircleCI runs our tests in, you can explore what Docker is a bit more here.
  • working_directory just tells docker where to put everything in our container.
  • checkout copies over our project from our repo into the working directory.
  • restore_cache and save_cache checks for and updates unchanged data from past test runs, for the sake of performance.
  • run for running any standard terminal commands.

Once you commit this change to to the repo, CircleCI should run and pass automatically.

Testing

Now let’s break out a feature branch with a failing test to see how CircleCI prevents our pull request.

App.test.js

it('fails successfully', () => expect(true).toBe(false));

Test failing on Github

Not only does it warn you when your tests have failed, it doesn’t allow you to even merge a pull request until it’s fixed. I’m sure many projects have been saved with this feature.

Merge prevented screenshot

Closing Thoughts

Depending on your team and project, your particular repo structure can vary wildly. But this feature to development and then to production workflow is sufficient for most of my own projects, and hopefully yours as well.

  Tweet It

🕵 Search Results

🔎 Searching...

Sponsored by #native_company# — Learn More
#native_title# #native_desc#
#native_cta#