In this post we will review how to trigger an AWS CodeBuild project as an automatic response to AWS CodeCommit push. See also my previous posts:
Personally, I've found it weird that this is not a builtin functionality in AWS system. I also found the documentation about it lacking a simple straight forward description of how to do it. I did found this post, but it was complicated, and a bit out of scope.
The general idea is to run a lambda that is triggered by a push to the CodeCommit. The lambda runs a NodeJS code that will lunch our CodeBuild project
We will use a CloudFormation stack to accomplish this. First we create a role. In the AssumeRolePolicyDocument element, we allow the AWS lambda service to use this role, and in the Policies element we grant the role permission to start any CodeBuild project.
triggerLambdaRole:
Type: AWS::IAM::Role
Properties:
Tags:
- Key: Name
Value: codecommit-trigger
Path: "/"
ManagedPolicyArns:
- arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
- Sid: AllowLambdaServiceToAssumeRole
Effect: Allow
Action:
- sts:AssumeRole
Principal:
Service:
- lambda.amazonaws.com
Policies:
- PolicyName: build-starter
PolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Action:
- codebuild:StartBuild
Resource:
- "*"
Next we create a lambda function, that uses the role mentioned above. The lambda function in this example starts 2 CodeBuild projects.
triggerBuildLambda:
Type: AWS::Lambda::Function
Properties:
Description: Start build upon CodeCommit trigger
Runtime: nodejs12.x
Role: !GetAtt triggerLambdaRole.Arn
Tags:
- Key: Name
Value: codecommit-trigger
Handler: index.handler
Code:
ZipFile: |
const AWS = require('aws-sdk')
const codeBuild = new AWS.CodeBuild()
exports.handler = async function(event, context) {
console.log("event received:\n" + JSON.stringify(event))
var promises = []
promises.push(codeBuild.startBuild({projectName: "my-project-1"}).promise());
promises.push(codeBuild.startBuild({projectName: "my-project-2"}).promise());
const results = await Promise.all(promises);
console.log("response is " + JSON.stringify(results));
}
The last section of the CloudFormation stack is to grant the CodeCommit permission to run the lambda function.
Parameters:
ParameterAccountId:
Type: String
Default: "123456789012"
Resources:
permitCodeCommitToRunLambda:
Type: AWS::Lambda::Permission
Properties:
FunctionName: !GetAtt triggerBuildLambda.Arn
Action: lambda:InvokeFunction
Principal: codecommit.amazonaws.com
SourceAccount: !Ref ParameterAccountId
SourceArn: !Join
- ":"
- - arn:aws:codecommit:us-east-1
- !Ref ParameterAccountId
- my-code-commit
Once this is done, we need to add trigger in the CodeCommit project to run the lambda function. I prefer not to update the CodeCommit project by a CloudFormation stack because I want to avoid removal of the stack by mistake. Unlike other stacks that can be easily recovered by rerunning them, a CodeCommit repo sources are lost forever.
To update the CodeCommit project, click on the CodeCommit project in AWS console, and click on settings on the left menu, and click on the Create Trigger button.
Next, select the events that you want to activate the lambda. I have chosen only the Push existing branch event. In the service section select AWS Lambda, and select the lambda that we have created. I strongly recommend using the Test Trigger button to check that all these components play well together.
Final Note
As a side comment, Google cloud does provide this functionality builtin.
In general Google cloud supplies an easy way to do simple things, and AWS supplies a complicated way to do anything. I believe this is the key difference between these two cloud platforms.