12

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?

Karias Bolster
  • 955
  • 3
  • 17
  • 31
  • 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? – Kaixiang-AWS Jul 16 '18 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. – Karias Bolster Jul 17 '18 at 13:30

2 Answers2

7

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" }}
            }

        }
    }
Gustavo Tavares
  • 2,579
  • 15
  • 29
  • 3
    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. – EralpB Sep 23 '19 at 09:52
  • 1
    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. – Gustavo Tavares Sep 23 '19 at 09:58
  • Please refer the AWS Blog :- https://aws.amazon.com/blogs/devops/validating-aws-codecommit-pull-requests-with-aws-codebuild-and-aws-lambda/ – Aniket Kulkarni Feb 29 '20 at 10:06
  • 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. – Kane Mar 19 '20 at 14:33
2

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.

Unsigned
  • 9,640
  • 4
  • 43
  • 72
  • Broken link. Goes to general CodeCommit documentation, nothing about notifications. – Ken Krueger Aug 12 '22 at 02:35
  • Any news about this after 5 years? – shamaseen Feb 02 '23 at 16:51
  • @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](https://aws.amazon.com/codecatalyst/) as a development ecosystem, so it may be worthwhile to see if something there addresses your use case. – Unsigned Feb 08 '23 at 21:48