Multibranch CI system for GitHub Repositories using CodeBuild

--

Motivation

One of the major drawbacks while using CodePipeline is that it is triggered by a single branch. This could come as surprise for someone who had just switched from other CI systems such as Jenkins or GitHub Actions where multibranch pipelines come out of the box.

Although AWS does suggest this work around to trigger a pipeline for each branch, I found it very cumbersome and a bit of overkill. In most of the cases, a deployment through a feature branch is not necessary. It is enough to just run tests, linter and if the build works.

Solution

The way I do it is by creating an additional CodeBuild project alongside my pipeline which is triggered by any push or PR event to the all branches other than main branch. This CodeBuild Project (let’s call it CI from hereafter) does more or less the same thing as the other CodeBuild Project in the CodePipeline with one major difference. The CI does not create any build artifacts. It does not upload anything to S3 or push docker images, just like when Jenkins is used with a feature branch.

One important note though, this approach only works with GitHub and Bitbucket where the integration is done with a Webhook. The reason is, the implementation is based on filtering the webhook events. With AWS native CodeCommit, there is no Webhook involved and this approach does not work.

  1. Create a github token that can be used with CodeBuild. Generate a Personal Access Token on GitHub: Go to settings — Developer Settings — Personal Access Tokens. Store this in SecretsManager. I named mine as github and the key as token. Create a stack with Source Credential.

This needs to be created only once. For the consequent CodeBuild Projects, this step is not necessary.

2. Include a second buildspec file in the root of your repository and name it as buildspec-ci.yml. For one of my TypeScript projects, I have it like this

version: 0.2

phases:
install:
runtime-versions:
nodejs: 18
commands:
# Install the dependencies
- npm ci
build:
commands:
- npm test # Run unit tests
- npm run lint # Run linter
- npm run build # Build the application

3. Create a CodeBuild Project like shown below. This is done alongside my CodePipeline (not covered in this post). So for each application repository, there will be two CodeBuild Projects, one integrated in CodePipeline and one not integrated aka CI. The integrated one is triggered by commits on the main branch and the CI is triggered by commits on every other branch and PRs. In the triggers section, there is a pattern to match the events from main branch. This instructs CodeBuild NOT to trigger a build whenever the event comes from the main branch.

This can be very well included in the same IaC file which also creates the CodePipeline to have everything in one place, but I did this as an additional stack to only expose the CI resources.

On my repository, I can now see the build status on the branch

May the Cloud be with you

If you find my article helpful, buy me a coffee

👋 If you find this helpful, please click the clap 👏 button below a few times to show your support for the author 👇

🚀Join FAUN Developer Community & Get Similar Stories in your Inbox Each Week

--

--