GitHub process automation: A bot to build pull requests authorized by core maintainers
We are maintaining multiple Open Source projects where we focus on CloudFormation templates. To ensure that the templates are of high quality, we leverage automated testing and pull requests. We could use the CodeBuild GitHub integration to execute yamllint, cfn-lint, and also aws cloudformation validate-template to make sure that a pull request is not breaking the templates. That’s a great way to allow contributions while ensuring high quality. You can also use Travis CI and others to run the static tests on each commit / pull request.
However, the mentioned tools only inspect the templates. They don’t create an actual CloudFormation stack. To be 100% sure that a pull request is not breaking any template, we have to create some CloudFormation stacks with the changes from the pull request. Creating a CloudFormation stack causes AWS costs (the actual AWS resources cause the costs, not CloudFormation). Usually, we spent 500 - 1000 USD per month to run automated tests on our templates.
The problem: If we create stacks automatically for every pull request, someone could open hundreds of pull requests and waste our money.
The solution: Let only core committers trigger the tests by commenting on the pull request.
You might come up with other processes based on GitHub Pull Requests that can be automated. E.g., you might want to push each change to a replication of the GitHub repository to CodeCommit. Read on if you are interested in the implementation using serverless technologies. You can find the full source code on GitHub.
Serverless architecture
The diagram was created with Cloudcraft - Visualize your cloud architecture like a pro.
GitHub triggers an HTTPS request for every comment made in a repository to an endpoint that you can define (aka webhook). You can create an HTTPS endpoint with API Gateway and forward the HTTPS request to a Lambda function.
The Lambda function inspects the GitHub data and kicks off a CodeBuild build.
To provide feedback to GitHub users, we watch CodeBuild with a CloudWatch Event Rule. Whenever a build status changes we trigger another Lambda function and signal the information back to GitHub.
The high-level architecture is described. Now it’s time to turn the plan into reality.
Serverless implementation
We recently released a new open source project to speed up CloudFormation projects in a modular way. I will use cfn-modules in the following implementation. Check out the details if you are interested: cfn-modules: Rapid CloudFormation. I will use cfn-modules in the following implementation.
First, you set up the project.
Create a new directory:
mkdir github-bot |
cfn-modules relies on npm to install and update modules. Initialize the project with the following command:
npm init -y |
Now it’s time to start adding the first modules.
Alerting
You should always monitor your AWS resources. Let’s start with that.
Run the following command to install the first cfn-module:
npm i @cfn-modules/alerting -P |
Create a template.yml
file with the following content:
|
The alerting
module provides an SNS topic with a topic policy that allows most AWS resources to send messages for alerting purposes.
Next, you have to define the CodeBuild project that executes the actual tests.
CodeBuild
I use CodeBuild in an unusual way. Usually, CodeBuild downloads the source for you. In this case, I use a dummy CodeCommit repository to satisfy this requirement. But the actual code for testing is downloaded with git clone
and the commit information are passed in via an environment variables (GITHUB_OWNER
, GITHUB_REPO
, GITHUB_SHA
).
Resources: |
Milestone completed: you can run tests for every commit on GitHub.
API Gateway
Luckily, cfn-modules provide an easy way to create an API Gateway backed by a Lambda function.
npm i @cfn-modules/lambda-event-source-webhook -P |
Append the following to the template.yml
:
Resources: |
Find the source code of the Lambda function to trigger a CodeBuild build on GitHub. Store the webhook.js
inside a new folder called lambda-src
or check out the complete project at once.
Milestone completed: you can now receive GitHub webhooks.
CloudWatch Event Rule
To provide feedback to the contributor we use GitHub status API to update the status of the pull request. For example, a failed build will look like this in the GitHub Pull Request UI:
To provide feedback, you can listen to CodeBuild state changes using a CloudWatch Event Rule. Append the following to the template.yml
:
Resources: |
Find the source code of the Lambda function to update GitHub status on GitHub. Store the rule.js
inside a new folder called lambda-src
or clone the complete project at once.
Finally, append the following to the template.yml
to easily get the API Gateway endpoint URL.
Outputs: |
Find the full source code on GitHub including deployment information.
Summary
You used an API Gateway to receive GitHub webhooks and start CodeBuild builds. Asynchronously, in the background, you listen for build changes with a CloudWatch Event Rule and signal the build changes back to GitHub using the status API. With this pattern, you can implement many custom processes on top of GitHub to improve reliability and security of your software development and delivery capabilities.
Further reading
- Article Rapid CloudFormation: cfn-modules
- Article Introducing AWS Lambda
- Article CloudWatch is neglected: Why is the control room empty?
- Article AWS Security Primer
- Tag cloudformation
- Tag serverless
- Tag cloudwatch