14

Our ci workflow is this

  • run eslint in precommit
  • push to feature branch
  • open pull request in codecommit
  • trigger aws code build run tests
  • if all tests passed, merge
  • trigger aws code deploy to deploy

For now I noticed that codebuild will trigger on push. How can I make it so that it will trigger on merge request?

2
  • Thanks for using AWS CodeBuild. Do you have pull request checked in your webhook setting? When you talking about "create merge request to source", do you mean opening a pull request? Commented Jul 16, 2018 at 23:48
  • oh yeah sorry i meant pull request and also our source control is CodeCommit. Yeah I meant opening a pull request. Is that possible in CodeCommit and CodeBuild? Sorry I had to rephrase my question to make it more clearer. Commented Jul 17, 2018 at 13:30

2 Answers 2

8

Ok, there is more than one year that the first response was posted on this thread and probably at the time that was the correct answer. But today it not correct anymore.

CodeCommit integrates with CloudWatch Events. It can signal an event when:

  • Pull request is created, updated, or closed.
  • Someone comments on a pull request.
  • Comments and replies are added to commits.

In the CloudWatch you can then create a rule to be evaluated at every new event. If the rule is true you can then start a pipeline execution.

Here is my (simplified) development workflow using CodeCommit, CodeBuild and CodePipeline:

  1. Create a feature branch on local repo;
  2. At commit, run lint and unit tests;
  3. After feature is ready to deployment, I create a pull request;
  4. After pull request approval and merge, CodeCommit sends an event to CloudWatch;
  5. CloudWatch evaluate a rule to check if the change was on master* branch;
  6. If rule were evaluated to true, CloudWatch start the pipeline.

Here is the CloudFormation Template that I use to create and config the CodeCommit repository, the CloudWatch Event, the CodeBuild and CodePipeline. You can find the complete stack here.

{
    "AWSTemplateFormatVersion": "2010-09-09",
        "Description": "Cloud Formation Template for Pipeline/Build/Deploy StaticWebSite on S3",

        "Parameters" : {

            "S3BucketForWebSite" : {
                "Type" : "String",
                "Description" : "The S3 address of Stack Resources and Files"
            }
        },

        "Resources": {

            "S3BucketForArtifacts" : {
                "Type" : "AWS::S3::Bucket",
                "Properties" : {
                  "AccessControl" : "Private"
                }
            },

            "CodeRepository" : {
                "Type" : "AWS::CodeCommit::Repository",
                "Properties" : {
                    "RepositoryName" : { "Fn::Sub": [ "${Stack}-Repo", { "Stack": {"Ref" : "AWS::StackName" }} ]},
                    "RepositoryDescription" : "Repository for S3 Static Web Site"
                }
            },

            "BuildRole" : {
                "Type": "AWS::IAM::Role",
                "Properties": {
                    "RoleName": { "Fn::Sub": [ "${Stack}-CodeBuildExecRole", { "Stack": {"Ref" : "AWS::StackName" }} ]},
                    "AssumeRolePolicyDocument": {
                        "Version": "2012-10-17",
                        "Statement": [{ "Effect": "Allow", "Principal": {"Service": ["codebuild.amazonaws.com"]}, "Action": ["sts:AssumeRole"] }]
                    },
                    "Path": "/",
                    "Policies": [ {
                        "PolicyName": "root",
                        "PolicyDocument": {
                            "Version": "2012-10-17",
                            "Statement": [
                                {
                                    "Sid": "WriteOnWebSiteBucket",
                                    "Action": ["s3:*"],
                                    "Resource": [
                                        { "Fn::Sub": [ "arn:aws:s3:::${BucketName}", { "BucketName": {"Ref" : "S3BucketForWebSite" }} ]},
                                        { "Fn::Sub": [ "arn:aws:s3:::${BucketName}/*", { "BucketName": {"Ref" : "S3BucketForWebSite" }} ]}
                                    ],
                                    "Effect": "Allow"
                                },
                                {
                                    "Sid": "CreateLogGroups",
                                    "Effect": "Allow",
                                    "Action": ["logs:CreateLogGroup"],
                                    "Resource": ["*"]
                                },
                                {
                                    "Sid": "CreateStreamAndPutLogs",
                                    "Effect": "Allow",
                                    "Action": ["logs:CreateLogStream", "logs:PutLogEvents"],
                                    "Resource": ["arn:aws:logs:*"]
                                },
                                {
                                    "Sid": "CheckBuketsInS3",
                                    "Effect": "Allow",
                                    "Action": ["s3:ListAllMyBuckets", "s3:HeadBucket"],
                                    "Resource": ["*"]
                                },
                                {
                                    "Sid": "GetAndPutObjectsInS3ArtifactStore",
                                    "Effect": "Allow",
                                    "Action": ["s3:PutObject", "s3:GetObject", "s3:DeleteObject", "s3:GetObjectVersion", "s3:GetBucketAcl", "s3:PutBucketAcl", "s3:PutObjectAcl", "s3:GetObjectVersion"],
                                    "Resource": [
                                        { "Fn::Sub": [ "arn:aws:s3:::${BucketName}", { "BucketName": {"Ref" : "S3BucketForArtifacts" }} ]},
                                        { "Fn::Sub": [ "arn:aws:s3:::${BucketName}/*", { "BucketName": {"Ref" : "S3BucketForArtifacts" }} ]}
                                    ]
                                }
                            ]
                        }
                    } ]
                }
            },

            "CodeBuild" : {
                "Type" : "AWS::CodeBuild::Project",
                "Properties" : {
                    "Artifacts" : {
                            "Type": "CODEPIPELINE",
                            "Name": { "Fn::Sub": [ "${Stack}-Build", { "Stack": {"Ref" : "AWS::StackName" }} ]},
                            "Packaging": "NONE"
                        },
                    "BadgeEnabled" : false,
                    "Cache" : {"Type": "NO_CACHE"},
                    "Description" : { "Fn::Sub": [ "StaticWebSite Build for ${Stack}", { "Stack": {"Ref" : "AWS::StackName" }} ]},
                    "Environment" : {
                        "Type": "LINUX_CONTAINER",
                        "Image": "aws/codebuild/nodejs:10.1.0",
                        "ComputeType": "BUILD_GENERAL1_SMALL",
                        "EnvironmentVariables": [],
                        "PrivilegedMode": false
                    },
                    "Name" : {"Ref" : "AWS::StackName" },
                    "ServiceRole" : { "Fn::GetAtt" : ["BuildRole", "Arn"] },
                    "Source" : {
                        "Type": "CODEPIPELINE",
                        "InsecureSsl": false
                    },
                    "TimeoutInMinutes" : 60
                }
            },

            "PipelineRole": {
               "Type": "AWS::IAM::Role",
               "Properties": {
                    "RoleName": { "Fn::Sub": [ "${Stack}-CodePipeLineExecRole", { "Stack": {"Ref" : "AWS::StackName" }} ]},
                    "AssumeRolePolicyDocument": {
                        "Version": "2012-10-17",
                        "Statement": [{ "Effect": "Allow", "Principal": {"Service": ["codepipeline.amazonaws.com"]}, "Action": ["sts:AssumeRole"] }]
                    },
                    "Path": "/",
                    "Policies": [ {
                        "PolicyName": "root",
                        "PolicyDocument": {
                            "Version": "2012-10-17",
                            "Statement": [
                                {
                                    "Sid": "WriteOnWebSiteBucket",
                                    "Action": ["s3:*"],
                                    "Resource": [
                                        { "Fn::Sub": [ "arn:aws:s3:::${BucketName}", { "BucketName": {"Ref" : "S3BucketForWebSite" }} ]},
                                        { "Fn::Sub": [ "arn:aws:s3:::${BucketName}/*", { "BucketName": {"Ref" : "S3BucketForWebSite" }} ]}
                                    ],
                                    "Effect": "Allow"
                                },
                                {
                                    "Sid": "InterfaceWithBucketsInS3",
                                    "Action": ["s3:GetObject", "s3:GetObjectVersion", "s3:GetBucketVersioning"],
                                    "Resource": "*",
                                    "Effect": "Allow"
                                },
                                {
                                    "Sid": "InterfaceWithArtifactStoreInS3",
                                    "Effect": "Allow",
                                    "Action": ["s3:PutObject", "s3:GetObject", "s3:DeleteObject", "s3:GetObjectVersion", "s3:GetBucketAcl", "s3:PutBucketAcl", "s3:PutObjectAcl", "s3:GetObjectVersion"],
                                    "Resource": [
                                        { "Fn::Sub": [ "arn:aws:s3:::${BucketName}", { "BucketName": {"Ref" : "S3BucketForArtifacts" }} ]},
                                        { "Fn::Sub": [ "arn:aws:s3:::${BucketName}/*", { "BucketName": {"Ref" : "S3BucketForArtifacts" }} ]}
                                    ]
                                },
                                {
                                    "Sid": "InterfaceWithCodeCommit",
                                    "Action": ["codecommit:CancelUploadArchive", "codecommit:GetBranch", "codecommit:GetCommit", "codecommit:GetUploadArchiveStatus", "codecommit:UploadArchive"],
                                    "Resource": "*",
                                    "Effect": "Allow"
                                },
                                {
                                    "Sid": "InterfaceWithCodeBuild",
                                    "Action": ["codebuild:BatchGetBuilds", "codebuild:StartBuild"],
                                    "Resource": "*",
                                    "Effect": "Allow"
                                }
                            ]
                        }            
                    } ]
               }
            },

            "CodePipeline" : {
                "Type" : "AWS::CodePipeline::Pipeline",
                "Properties" : {
                  "ArtifactStore" : {
                    "Location" : {"Ref": "S3BucketForArtifacts"},
                    "Type" : "S3"
                  },
                  "RestartExecutionOnUpdate" : false,
                  "RoleArn" : { "Fn::GetAtt" : ["PipelineRole", "Arn"] },
                  "Stages" : [
                    {
                        "Name": "Source",
                        "Actions": [
                            {
                                "Name": "Source",
                                "ActionTypeId": {"Category": "Source", "Owner": "AWS", "Provider": "CodeCommit", "Version": "1"},
                                "RunOrder": 1,
                                "Configuration": { "BranchName": "master", "PollForSourceChanges": "false", "RepositoryName": { "Fn::Sub": [ "${Stack}-Repo", { "Stack": {"Ref" : "AWS::StackName" }} ]}},
                                "OutputArtifacts": [ { "Name" : {"Ref" : "AWS::StackName"} } ],
                                "InputArtifacts": []
                            }
                        ]
                    },

                    {
                        "Name": "Build",
                        "Actions": [
                            {
                                "Name": "CodeBuild",
                                "ActionTypeId": { "Category": "Build", "Owner": "AWS", "Provider": "CodeBuild", "Version": "1" },
                                "RunOrder": 1,
                                "Configuration": { "ProjectName": {"Ref" : "AWS::StackName" } },
                                "InputArtifacts": [ { "Name" : {"Ref" : "AWS::StackName"} } ],
                                "OutputArtifacts": [ { "Name": { "Fn::Sub": [ "${Stack}-builded", { "Stack": {"Ref" : "AWS::StackName" }} ]} } ]
                            }
                        ]
                    }

                ]
                }
            },

            "CloudWathEventRole": {

                "Type": "AWS::IAM::Role",
                "Properties": {
                     "RoleName": { "Fn::Sub": [ "${Stack}-CloudWatchEventRole", { "Stack": {"Ref" : "AWS::StackName" }} ]},
                     "AssumeRolePolicyDocument": {
                         "Version": "2012-10-17",
                         "Statement": [{ "Effect": "Allow", "Principal": {"Service": ["events.amazonaws.com"]}, "Action": ["sts:AssumeRole"] }]
                     },
                     "Path": "/",
                     "Policies": [ {
                         "PolicyName": "root",
                         "PolicyDocument": {
                             "Version": "2012-10-17",
                             "Statement": [
                                 {
                                     "Action": ["codepipeline:StartPipelineExecution"],
                                     "Resource": { "Fn::Sub": [ "arn:aws:codepipeline:${Region}:${Account}:${PipelineName}", { "Region": { "Ref" : "AWS::Region" }, "Account": { "Ref" : "AWS::AccountId" }, "PipelineName": {"Ref" : "CodePipeline" }} ]},
                                     "Effect": "Allow"
                                 }
                             ]
                         }            
                     } ]
                }

            },

            "CloudWatchEventRule" : {
                "Type" : "AWS::Events::Rule",
                "Properties" : {

                    "Name" : { "Fn::Sub": [ "${Stack}-Repo-Changes", { "Stack": {"Ref" : "AWS::StackName" }} ]},
                    "Description" : "Check CodeCommit Repo Changes",

                    "EventPattern" : {
                        "detail-type": ["CodeCommit Repository State Change"],
                        "source": ["aws.codecommit"],
                        "resources": [{ "Fn::GetAtt" : [ "CodeRepository", "Arn" ] }],
                        "detail": { "referenceType": ["branch"], "referenceName": ["master"]}
                    },

                    "Targets" : [ {
                            "Id" : "codepipeline",
                            "Arn" : { "Fn::Sub": [ "arn:aws:codepipeline:${Region}:${Account}:${PipelineName}", { "Region": { "Ref" : "AWS::Region" }, "Account": { "Ref" : "AWS::AccountId" }, "PipelineName": {"Ref" : "CodePipeline" }} ]},
                            "RoleArn" : { "Fn::GetAtt" : ["CloudWathEventRole", "Arn"] }
                    } ]

                }
            }

        },

        "Outputs": {
            "RepoName" : {
                "Value" : { "Fn::Sub": [ "${Stack}-Repo", { "Stack": {"Ref" : "AWS::StackName" }} ]},
                "Description" : "CodeCommit Repository Name",
                "Export" : {"Name" : {"Fn::Sub": "${AWS::StackName}-RepoName" }}
            },
            "RepoArn" : {
                "Value" : { "Fn::GetAtt" : [ "CodeRepository", "Arn" ] },
                "Description" : "CodeCommit Repository Arn",
                "Export" : {"Name" : {"Fn::Sub": "${AWS::StackName}-RepoArn" }}
            },
            "RepoCloneSSHUrl" : {
                "Value" : { "Fn::GetAtt" : [ "CodeRepository", "CloneUrlSsh" ] },
                "Description" : "CodeCommit Repository SSH Url to be cloned",
                "Export" : {"Name" : {"Fn::Sub": "${AWS::StackName}-RepoCloneSSHUrl" }}
            },
            "RepoCloneHttpUrl" : {
                "Value" : { "Fn::GetAtt" : [ "CodeRepository", "CloneUrlHttp" ] },
                "Description" : "CodeCommit Repository Http Url to be cloned",
                "Export" : {"Name" : {"Fn::Sub": "${AWS::StackName}-RepoCloneHttpUrl" }}
            }

        }
    }
Sign up to request clarification or add additional context in comments.

4 Comments

that's not ideal, because if someone merges a failing PR (bc you don't know if it's going to fail or pass), you can never push, ideal is testing the PR before it can be merged.
The problem that you described is based on your team workflow. In my case, failed build are not merged in master. We control the process to keep master always with success build. If you control this before merging to master, you'll not have this problem. If you do not control, you'll need to adjust the pipeline to test it before deployment.
Please refer the AWS Blog :- aws.amazon.com/blogs/devops/…
The event rule is matching the event CodeCommit Repository State Change. I'm confused that how it knows if the event is PR created/updated.
1

Unfortunately, CodeCommit pull requests are not yet natively supported in CodeBuild. We're aware of the use case, although I can't provide an exact timeline for official support.

In the meantime, you can look into creating CodeCommit notifications, paired with an AWS Lambda function to run CodeBuild for every pull request.

3 Comments

Broken link. Goes to general CodeCommit documentation, nothing about notifications.
Any news about this after 5 years?
@shamaseen I am not currently working on the AWS CodeBuild team, and cannot speak for them. I do know that AWS has been investing heavily into CodeCatalyst as a development ecosystem, so it may be worthwhile to see if something there addresses your use case.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.