Using AWS CodeBuild and CodePipeline for Easy Continuous Integration

TAGS:

In a previous post, we setup a Gatsby blog and pushed the codebase to AWS CodeCommit.

This post will primarily focus on adding test coverage to our codebase and integrating AWS CodeBuild and CodePipeline for continuous integration.

Let's get started.

What exactly is AWS CodeBuild?

AWS CodeBuild is a fully managed continuous integration service that compiles source code, runs tests, and produces software packages that are ready to deploy. With CodeBuild, you don’t need to provision, manage, and scale your own build servers. CodeBuild scales continuously and processes multiple builds concurrently, so your builds are not left waiting in a queue. You can get started quickly by using prepackaged build environments, or you can create custom build environments that use your own build tools. With CodeBuild, you are charged by the minute for the compute resources you use.

what exactly is AWS CodePipeline?

AWS CodePipeline is a fully managed continuous delivery service that helps you automate your release pipelines for fast and reliable application and infrastructure updates. CodePipeline automates the build, test, and deploy phases of your release process every time there is a code change, based on the release model you define. This enables you to rapidly and reliably deliver features and updates. You can easily integrate AWS CodePipeline with third-party services such as GitHub or with your own custom plugin. With AWS CodePipeline, you only pay for what you use. There are no upfront fees or long-term commitments.

Our goal -- run our test suite after every commit to the master branch of our remote repository.

Add Test Coverage

add Jest

First, let's install Jest:

npm i -G jest

Lets test the CLI is working correctly:

jest --version

you should see the version number:

1. npm i -G jest 2019-08-29 14-32-00

configure Jest for Gatsby

Please refer to the Jest configuration setup from Gatsby

once you completed the setup, you should have these files:

  • __mocks__/file-mock.js
  • __mocks__/gatsby.js
  • jest-preprocess.js
  • jest.config.js
  • loadershim.js

add our first test

cd src/pages
touch index.test.js

inside src/pages/index.test.js, paste:

import React from "react"
import renderer from "react-test-renderer"
import { useStaticQuery } from "gatsby"
import BlogIndex from "./index"

beforeEach(() => {
  useStaticQuery.mockImplementation(() =>
    ({
      avatar: {
        childImageSharp: {
          fixed: {
            base64: "data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAUABQDASIAAhEBAxEB/8QAGQABAQADAQAAAAAAAAAAAAAAAAUBAgME/8QAFwEBAQEBAAAAAAAAAAAAAAAAAgEAA//aAAwDAQACEAMQAAABtTuWpVlGTeDJ0HAG/wD/xAAbEAACAgMBAAAAAAAAAAAAAAABAgMTABEjJP/aAAgBAQABBQJzpYGe3LyGZxGLsY+mY8Yzof/EABgRAAIDAAAAAAAAAAAAAAAAAAABEBIh/9oACAEDAQE/AcKjj//EABkRAAEFAAAAAAAAAAAAAAAAAAABEBIhMf/aAAgBAgEBPwGyQmN//8QAIBAAAQIFBQAAAAAAAAAAAAAAAQARAgMQEiExQWGBkf/aAAgBAQAGPwItqmMdwNLT4n2JbCwQU/Kl90//xAAaEAEAAwEBAQAAAAAAAAAAAAABABEhMUFR/9oACAEBAAE/IUVXGRfSl5yZEWkVrGwnd6EDTA+sdXqEbIVcO+k//9oADAMBAAIAAwAAABD76AH/xAAZEQACAwEAAAAAAAAAAAAAAAAAAREhMVH/2gAIAQMBAT8QhKbI9NMWH//EABkRAAIDAQAAAAAAAAAAAAAAAAABEBEhUf/aAAgBAgEBPxBNtovyBrT/xAAeEAEBAQACAQUAAAAAAAAAAAABEQAhMUFRYXGBkf/aAAgBAQABPxClwdnV04hQo4lO/wAzyyjjEGw+cZbkILxecbfXBH7zaeBntAmta2n5uEBbXZ4N/9k=",
            height: 50,
            src: "/static/4f27694bd7811d13157e5e488ad64f43/9b664/profile-pic.jpg",
            srcSet: "/static/4f27694bd7811d13157e5e488ad64f43/9b664/profile-pic.jpg 1x,↵/static/4f27694bd7811d13157e5e488ad64f43/06a10/profile-pic.jpg 1.5x,↵/static/4f27694bd7811d13157e5e488ad64f43/f1b5a/profile-pic.jpg 2x",
            width: 50
          }
        }
      },
      site: {
        siteMetadata: {
          title: `Default Starter`,
          description: 'test',
          author: 'Frank',
          social: {
            twitter: 'fjhancock',
          }
        },
      },
    })
  )
})

describe("BlogIndex", () => {
  it("renders correctly", () => {
    const data = {
      site: {
        siteMetadata: {
          author: "Your name",
        },
      },
      allMarkdownRemark: {
        edges: [
          {
            node: {
              excerpt: "Awesome new content goes here…",
              fields: {
                slug: "/my-first-post/"
              },
              frontmatter: {
                date: "August 29, 2019",
                title: "My First Post",
                description: null
              }
            }
          },
        ]
      }
    }
    const tree = renderer.create(<BlogIndex data={data} location={{ pathname: '/' }} />).toJSON()
    expect(tree).toMatchSnapshot()
  })
})


Save the file. Now lets run Jest:

jest

We should now have a passing test suite!

hot-new-blog 2019-08-29 15-42-35

commit our changes

git add -A
git commit -m 'setup jest, added first test'
git push origin master

Update our codebase for CodeBuild

create a buildspec.yml in the root of the repo:

version: 0.2

env:
  variables:
    NODE_ENV: "development"

phases:
  install:
    runtime-versions:
      nodejs: 10
    commands:
      - npm install -g jest
      - npm install -g gatsby

  pre_build:
    commands:
      - npm install

  build:
    commands:
      - gatsby build
      - npm run test:ci

cache:
  paths:
    - './node_modules/**/*'

add a new script to package.json:

package.json — hot-new-blog 2019-08-29 16-19-38

commit our changes

git add -A
git commit -m 'added buildspec for codebuild'
git push origin master

Configure AWS CodeBuild

We need to create a build project -- which we then can include in our pipeline.

CodeBuild - AWS Developer Tools 2019-08-29 15-56-51

CodeBuild - AWS Developer Tools 2019-08-29 15-58-37

CodeBuild - AWS Developer Tools 2019-08-29 16-01-30

CodeBuild - AWS Developer Tools 2019-08-29 16-16-20

You should now see your new build project listed.

CodeBuild - AWS Developer Tools 2019-08-29 16-17-09

Let's add a trigger to automate our builds.

CodeBuild - AWS Developer Tools 2019-08-29 16-21-42

Configure AWS CodePipeline

CodePipeline - AWS Developer Tools 2019-08-29 16-28-44

CodePipeline - AWS Developer Tools 2019-08-29 16-29-37

CodePipeline - AWS Developer Tools 2019-08-29 16-30-27

CodePipeline - AWS Developer Tools 2019-08-29 16-31-22

CodePipeline - AWS Developer Tools 2019-08-29 16-32-50

After a few minutes, we should see the pipeline successfully run:

CodePipeline - AWS Developer Tools 2019-08-29 16-40-24

If we dig into the logs of codebuild, we can see that our test suite has successfully passed:

CodeBuild - AWS Developer Tools 2019-08-29 16-42-00

At this stage, we have successfully created a continuous integration pipeline, using AWS CodeCommit, CodeBuild and CodePipeline!

In a later post, I will show you have to deploy your Gatsby blog using AWS Amplify.