├── lambda ├── requirements.txt └── index.py ├── .gitignore ├── images ├── deploy-to-aws.png ├── example-status.png └── webhook-events.png ├── create_deployment_package.sh ├── README.md └── cloudformation └── codebuild-ci.json /lambda/requirements.txt: -------------------------------------------------------------------------------- 1 | github3.py>=1.0.0a4 2 | boto3 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | *.pyc 3 | __pycache__ 4 | lambda/export 5 | **.zip 6 | -------------------------------------------------------------------------------- /images/deploy-to-aws.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gkrizek/codebuild-ci-sample/HEAD/images/deploy-to-aws.png -------------------------------------------------------------------------------- /images/example-status.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gkrizek/codebuild-ci-sample/HEAD/images/example-status.png -------------------------------------------------------------------------------- /images/webhook-events.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gkrizek/codebuild-ci-sample/HEAD/images/webhook-events.png -------------------------------------------------------------------------------- /create_deployment_package.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | if command -v python3 > /dev/null 2>&1; then 6 | 7 | echo "" 8 | echo "Creating Lambda Deployment Package..." 9 | echo "" 10 | 11 | # Remove old export directory if it exists 12 | EXPORT_DIR="./lambda/export" 13 | if [ -d "$EXPORT_DIR" ] 14 | then 15 | rm -rf $EXPORT_DIR 16 | fi 17 | # Make new export directory 18 | mkdir -p ./lambda/export 19 | # Copy our code 20 | cp ./lambda/index.py ./lambda/export 21 | # Install our modules 22 | pip3 install -r ./lambda/requirements.txt -t ./lambda/export 23 | # Create ZIP file 24 | cd ./lambda/export 25 | zip -r ../../codebuild-ci-lambda.zip . 26 | cd - 27 | # Clean Up export 28 | rm -rf ./lambda/export 29 | 30 | echo "" 31 | echo "Create Deployment Package: 'codebuild-ci-lambda.zip'" 32 | echo "" 33 | 34 | else 35 | 36 | echo "" 37 | echo "Error:" 38 | echo " python3 is required for this Lambda function." 39 | echo " Please install python3 then try again." 40 | echo "" 41 | exit 1 42 | 43 | fi 44 | -------------------------------------------------------------------------------- /lambda/index.py: -------------------------------------------------------------------------------- 1 | import boto3 2 | from github3 import login 3 | import os 4 | import json 5 | import sys 6 | codebuild = boto3.client('codebuild') 7 | 8 | 9 | def handler(event, context): 10 | if event: 11 | 12 | token = os.environ['GITHUB_TOKEN'] 13 | gh = login(token=token) 14 | 15 | # Check if request is from GitHub 16 | if 'X-GitHub-Event' in event['headers']: 17 | body = event['body'] 18 | if type(body) is str: 19 | body = json.loads(body) 20 | 21 | # Respond if it's GitHub's Webhook Test 22 | if event['headers']['X-GitHub-Event'] == 'ping': 23 | return { 24 | 'statusCode': 200, 25 | 'body': 'It Works!' 26 | } 27 | 28 | repo = body['pull_request']['base']['repo']['name'] 29 | owner = body['pull_request']['base']['repo']['owner']['login'] 30 | head_sha = body['pull_request']['head']['sha'] 31 | 32 | if event['headers']['X-GitHub-Event'] == 'pull_request' and body['action'] in ['synchronize', 'opened', 'reopened']: 33 | build = codebuild.start_build( 34 | projectName=repo, 35 | sourceVersion=head_sha 36 | ) 37 | build_id = build['build']['id'] 38 | repository = gh.repository(owner, repo) 39 | status = repository.create_status( 40 | sha=head_sha, 41 | state="pending", 42 | target_url="https://us-west-2.console.aws.amazon.com/codebuild/home?region=us-west-2#/builds/" + build_id + "/view/new", 43 | description="Build is running...", 44 | context="CodeBuild" 45 | ) 46 | return { 47 | 'statusCode': 200, 48 | 'body': "Created Status 'pending' - ID: " + str(status.id) 49 | } 50 | 51 | # Check if request is from CloudWatch Event 52 | elif 'detail-type' in event: 53 | project = event['detail']['project-name'] 54 | build_id = event['detail']['build-id'].split('/')[1] 55 | status = event['detail']['build-status'] 56 | state = { 57 | "FAILED": 'failure', 58 | "STOPPED": 'error', 59 | "SUCCEEDED": 'success' 60 | } 61 | build = codebuild.batch_get_builds( 62 | ids=[build_id] 63 | ) 64 | sha = build['builds'][0]['sourceVersion'] 65 | owner = build['builds'][0]['source']['location'].split('/')[3] 66 | repository = gh.repository(owner, project) 67 | result = repository.create_status( 68 | sha=sha, 69 | state=state[status], 70 | target_url="https://us-west-2.console.aws.amazon.com/codebuild/home?region=us-west-2#/builds/" + build_id + "/view/new", 71 | description="Build was a " + state[status] + ".", 72 | context="CodeBuild" 73 | ) 74 | return { 75 | 'statusCode': 200, 76 | 'body': "Created Status '" + state[status] + "' - ID: " + str(result.id) 77 | } 78 | 79 | else: 80 | return { 81 | 'statusCode': 400, 82 | 'body': 'unknown command' 83 | } 84 | 85 | else: 86 | return { 87 | 'statusCode': 400, 88 | 'body': 'missing event data' 89 | } 90 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Using AWS CodeBuild as a CI Service in GitHub 2 | 3 | [AWS CodeBuild](https://aws.amazon.com/codebuild/) is a fully managed build service that offers flexibility, continuous scaling, and metered pricing. This repository is an example application to integrate CodeBuild with GitHub. This project will allow you to run builds on every pull request automatically using CodeBuild. 4 | 5 | #### Advantages of CodeBuild 6 | 7 | - Metered pricing (pay for build time, not subscription) 8 | - Free Tier eligible 9 | - Default limit of 20 concurrent builds 10 | - Unlimited build minutes per month 11 | - Integration into other AWS Services 12 | 13 | ![](images/example-status.png) 14 | 15 | ## Infrastructure 16 | 17 | The included CloudFormation template creates: 18 | 19 | - Lambda Function 20 | - API Gateway 21 | - CodeBuild Project 22 | - CloudWatch Event Rule 23 | - IAM Roles for Lambda Function, CodeBuild Project, and API Gateway 24 | 25 | _All of these service are [Free Tier](https://aws.amazon.com/free/) eligible_ 26 | 27 | ## Setup 28 | 29 | **Step 1: Create Deployment Package** 30 | 31 | First, we have to create a deployment package for Lambda and upload it to S3. You can create a deployment package by navigating to the root of the repository and running the `create_deployment_package.sh` script. 32 | 33 | ``` 34 | $ ./create_deployment_package.sh 35 | ``` 36 | 37 | This will output a zip file called `codebuild-ci-lambda.zip`. Upload that to any S3 bucket in the same region that you will be creating your infrastructure in. 38 | 39 | **Step 2: Get API Token** 40 | 41 | We must get an API token to authenticate with GitHub. We will reference this in our CloudFormation template so our Lambda function can create Statuses. 42 | 43 | To create an API token [See the GitHub documentation.](https://help.github.com/articles/creating-a-personal-access-token-for-the-command-line/) 44 | 45 | _Creating a [GitHub App](https://developer.github.com/apps/) or something similar is best practice. We are using a personal token to easily run this sample. Personal tokens are not recommended in production._ 46 | 47 | **Step 3: Link CodeBuild to GitHub** 48 | 49 | _If you have used CodeBuild with GitHub previously you can skip this step_ 50 | 51 | We must authenticate CodeBuild to our GitHub account so it can see our repositories. It requires read only access in order to pull code during a run. 52 | 53 | 1. Login to your AWS Account and go to the CodeBuild Console. 54 | 2. If you have never used CodeBuild, click the "Get Started". If you have used it before, click "Create Project". 55 | 3. Under the heading **"Source: What to build"**, select `GitHub` as your _Source provider_. 56 | 4. Click the button that says **"Connect to GitHub"** 57 | 5. Allow CodeBuild access to your repositories. Then you should get redirected back to the CodeBuild page. 58 | 6. Click "Cancel" at the very bottom. 59 | 60 | We can just cancel out of our project creation because our CloudFormation project will create the project for us. We simply needed to establish an OAuth relationship with CodeBuild. 61 | 62 | 63 | **Step 4: Create Infrastructure** 64 | 65 | We can now create our infrastructure in AWS. I have provided a CloudFormation template in this repository that creates everything required. 66 | 67 | Click _Deploy to AWS_ to launch the template in your account. 68 | 69 | Region | Launch Template 70 | ------------ | ------------- 71 | **N. Virginia** (us-east-1) | [![Launch Stack into N. Virginia with CloudFormation](/images/deploy-to-aws.png)](https://console.aws.amazon.com/cloudformation/home?region=us-east-1#/stacks/new?stackName=CodeBuild-CI-Sample&templateURL=https://s3.amazonaws.com/codebuild-ci-sample-us-east-1/codebuild-ci.json) 72 | **Ohio** (us-east-2) | [![Launch Stack into Ohio with CloudFormation](/images/deploy-to-aws.png)](https://console.aws.amazon.com/cloudformation/home?region=us-east-2#/stacks/new?stackName=CodeBuild-CI-Sample&templateURL=https://s3-us-east-2.amazonaws.com/codebuild-ci-sample-us-east-2/codebuild-ci.json) 73 | **N. California** (us-west-1) | [![Launch Stack into Oregon with CloudFormation](/images/deploy-to-aws.png)](https://console.aws.amazon.com/cloudformation/home?region=us-west-1#/stacks/new?stackName=CodeBuild-CI-Sample&templateURL=https://s3-us-west-1.amazonaws.com/codebuild-ci-sample-us-west-1/codebuild-ci.json) 74 | **Oregon** (us-west-2) | [![Launch Stack into Oregon with CloudFormation](/images/deploy-to-aws.png)](https://console.aws.amazon.com/cloudformation/home?region=us-west-2#/stacks/new?stackName=CodeBuild-CI-Sample&templateURL=https://s3-us-west-2.amazonaws.com/codebuild-ci-sample-us-west-2/codebuild-ci.json) 75 | 76 | The template has the follow Parameters: 77 | 78 | - `RepositoryUrl` - HTTPS Clone URL of the repository in GitHub. Example: 'https://github.com/owner/repo.git' 79 | - `GithubToken` - GitHub API Token used for Status creation. 80 | - `ProjectName` - Name to give the CodeBuild Project. For this sample, use the same name as your repository. 81 | - `S3Key` - S3 Key for Lambda Function Zip 82 | - `S3Bucket` - S3 Bucket name for Lambda Function Zip 83 | - `BuildImage` - Docker Image to use in CodeBuild Project 84 | 85 | Once you have created your infrastructure via CloudFormation, navigate to the **Outputs** tab in your CloudFormation Stack. There will be an Output called "WebhookUrl". This is your API Gateway endpoint to use in GitHub. Copy this for use in the next step. 86 | 87 | _In this template, we are passing the GitHub API Token into Lambda via an Environment Variable. While this is good for keep it out of code, you should encrypt this value if you plan to use this sample beyond testing. Possible solutions are [Encryption Helpers](http://docs.aws.amazon.com/lambda/latest/dg/tutorial-env_console.html) or [Parameter Store](http://docs.aws.amazon.com/systems-manager/latest/userguide/systems-manager-paramstore.html)._ 88 | 89 | **Step 5: Setup GitHub** 90 | 91 | Now we can navigate to our repository in GitHub and go to the Settings page. Under the "Webhooks" section, we can click _Add webhook_ in the upper right. Here we can paste in the https url for our API Gateway endpoint that we grabbed from Step 4. Change the _content-type_ to `application/json`. 92 | 93 | Under the _Which events would you like to trigger this webhook?_ heading, select the "Let me select individual events." option. Then check the `Pull Request` box and deselect the `Push` box. Make sure the 'Active' box is checked then click "Add webhook". 94 | 95 | ![](images/webhook-events.png) 96 | 97 | You should then see a green checkmark by your webhook url. 98 | 99 | _To learn more about adding webhooks to a repository, [see the GitHub documentation](https://developer.github.com/webhooks/creating/)_ 100 | 101 | **Step 6: Open a Pull Request** 102 | 103 | That should be all we need! To try it out, simply open a new pull request in your repository. You should see a Status of `pending` appear with a link to CodeBuild. The Status will be updated once the build completes. A build will be triggered whenever a pull request is Opened, Reopened, or Synchronized (pushed to). 104 | 105 | **Don't forget to add a [buildspec.yml](http://docs.aws.amazon.com/codebuild/latest/userguide/build-spec-ref.html) file to your repository.** This is required by CodeBuild to know what commands to run. 106 | -------------------------------------------------------------------------------- /cloudformation/codebuild-ci.json: -------------------------------------------------------------------------------- 1 | { 2 | "AWSTemplateFormatVersion": "2010-09-09", 3 | "Description": "CodeBuild CI Sample", 4 | "Parameters": { 5 | "BuildImage": { 6 | "AllowedValues": [ 7 | "aws/codebuild/ubuntu-base:14.04", 8 | "aws/codebuild/android-java-8:24.4.1", 9 | "aws/codebuild/android-java-7:24.4.1", 10 | "aws/codebuild/android-java-6:24.4.1", 11 | "aws/codebuild/docker:1.12.1", 12 | "aws/codebuild/golang:1.7.3", 13 | "aws/codebuild/golang:1.6.3", 14 | "aws/codebuild/golang:1.5.4", 15 | "aws/codebuild/java:openjdk-8", 16 | "aws/codebuild/java:openjdk-7", 17 | "aws/codebuild/java:openjdk-6", 18 | "aws/codebuild/nodejs:7.0.0", 19 | "aws/codebuild/nodejs:6.3.1", 20 | "aws/codebuild/nodejs:5.12.0", 21 | "aws/codebuild/nodejs:4.4.7", 22 | "aws/codebuild/nodejs:4.3.2", 23 | "aws/codebuild/python:3.5.2", 24 | "aws/codebuild/python:3.4.5", 25 | "aws/codebuild/python:3.3.6", 26 | "aws/codebuild/python:2.7.12", 27 | "aws/codebuild/ruby:2.3.1", 28 | "aws/codebuild/ruby:2.2.5", 29 | "aws/codebuild/ruby:2.1.10", 30 | "aws/codebuild/dot-net:core-1" 31 | ], 32 | "Description": "Docker Image to use in CodeBuild Project", 33 | "Type": "String" 34 | }, 35 | "GithubToken": { 36 | "Description": "GitHub API Token used for Status creation.", 37 | "Type": "String" 38 | }, 39 | "ProjectName": { 40 | "AllowedPattern": "^[a-zA-Z0-9-_]*$", 41 | "Description": "Name to give the CodeBuild Project. For this sample, use the same name as your repository.", 42 | "MaxLength": "255", 43 | "MinLength": "2", 44 | "Type": "String" 45 | }, 46 | "RepositoryUrl": { 47 | "Description": "HTTPS Clone URL of the repository in GitHub. Example: 'https://github.com/owner/repo.git'", 48 | "Type": "String" 49 | }, 50 | "S3Bucket": { 51 | "Description": "S3 Bucket name for Lambda Function Zip", 52 | "Type": "String" 53 | }, 54 | "S3Key": { 55 | "Description": "S3 Key for Lambda Function Zip", 56 | "Type": "String" 57 | } 58 | }, 59 | "Resources": { 60 | "ApiRole": { 61 | "Properties": { 62 | "AssumeRolePolicyDocument": { 63 | "Statement": [ 64 | { 65 | "Action": [ 66 | "sts:AssumeRole" 67 | ], 68 | "Effect": "Allow", 69 | "Principal": { 70 | "Service": [ 71 | "apigateway.amazonaws.com" 72 | ] 73 | } 74 | } 75 | ], 76 | "Version": "2012-10-17" 77 | }, 78 | "Path": "/", 79 | "Policies": [ 80 | { 81 | "PolicyDocument": { 82 | "Statement": [ 83 | { 84 | "Action": [ 85 | "logs:Put*", 86 | "lambda:Invoke*", 87 | "iam:PassRole" 88 | ], 89 | "Effect": "Allow", 90 | "Resource": "*" 91 | } 92 | ], 93 | "Version": "2012-10-17" 94 | }, 95 | "PolicyName": "codebuild-ci-sample-ApiPolicy" 96 | } 97 | ], 98 | "RoleName": "codebuild-ci-sample-ApiRole" 99 | }, 100 | "Type": "AWS::IAM::Role" 101 | }, 102 | "CodeBuildRole": { 103 | "Type": "AWS::IAM::Role", 104 | "Properties": { 105 | "AssumeRolePolicyDocument": { 106 | "Statement": [ 107 | { 108 | "Action": [ 109 | "sts:AssumeRole" 110 | ], 111 | "Effect": "Allow", 112 | "Principal": { 113 | "Service": [ 114 | "codebuild.amazonaws.com", 115 | "events.amazonaws.com" 116 | ] 117 | } 118 | } 119 | ], 120 | "Version": "2012-10-17" 121 | }, 122 | "Path": "/", 123 | "Policies": [ 124 | { 125 | "PolicyDocument": { 126 | "Statement": [ 127 | { 128 | "Action": [ 129 | "events:Put*", 130 | "logs:Put*", 131 | "logs:Create*", 132 | "s3:Put*", 133 | "lambda:Invoke*" 134 | ], 135 | "Effect": "Allow", 136 | "Resource": "*" 137 | } 138 | ], 139 | "Version": "2012-10-17" 140 | }, 141 | "PolicyName": "codebuild-ci-sample-CodeBuildPolicy" 142 | } 143 | ], 144 | "RoleName": "codebuild-ci-sample-CodeBuildRole" 145 | } 146 | }, 147 | "LambdaRole": { 148 | "Type": "AWS::IAM::Role", 149 | "Properties": { 150 | "AssumeRolePolicyDocument": { 151 | "Statement": [ 152 | { 153 | "Action": [ 154 | "sts:AssumeRole" 155 | ], 156 | "Effect": "Allow", 157 | "Principal": { 158 | "Service": [ 159 | "lambda.amazonaws.com" 160 | ] 161 | } 162 | } 163 | ], 164 | "Version": "2012-10-17" 165 | }, 166 | "Path": "/", 167 | "Policies": [ 168 | { 169 | "PolicyDocument": { 170 | "Statement": [ 171 | { 172 | "Action": [ 173 | "codebuild:BatchGetBuilds", 174 | "codebuild:StartBuild" 175 | ], 176 | "Effect": "Allow", 177 | "Resource": { 178 | "Fn::Sub": "arn:aws:codebuild:${AWS::Region}:${AWS::AccountId}:project/${ProjectName}" 179 | } 180 | } 181 | ], 182 | "Version": "2012-10-17" 183 | }, 184 | "PolicyName": "codebuild-ci-sample-LambdaPolicy-codebuild" 185 | }, 186 | { 187 | "PolicyDocument": { 188 | "Statement": [ 189 | { 190 | "Action": [ 191 | "logs:*" 192 | ], 193 | "Effect": "Allow", 194 | "Resource": "arn:aws:logs:*:*:*" 195 | } 196 | ], 197 | "Version": "2012-10-17" 198 | }, 199 | "PolicyName": "codebuild-ci-sample-LambdaPolicy-cloudwatch" 200 | } 201 | ], 202 | "RoleName": "codebuild-ci-sample-LambdaRole" 203 | } 204 | }, 205 | "LambdaFunction": { 206 | "Type": "AWS::Lambda::Function", 207 | "Properties": { 208 | "Code": { 209 | "S3Bucket": { 210 | "Ref": "S3Bucket" 211 | }, 212 | "S3Key": { 213 | "Ref": "S3Key" 214 | } 215 | }, 216 | "Description": "Connects GitHub to CodeBuild for CI", 217 | "Environment": { 218 | "Variables": { 219 | "GITHUB_TOKEN": { 220 | "Ref": "GithubToken" 221 | } 222 | } 223 | }, 224 | "FunctionName": "CodeBuild-CI-Sample", 225 | "Handler": "index.handler", 226 | "MemorySize": 128, 227 | "Role": { 228 | "Fn::GetAtt": [ 229 | "LambdaRole", 230 | "Arn" 231 | ] 232 | }, 233 | "Runtime": "python3.6", 234 | "Timeout": "30" 235 | } 236 | }, 237 | "StatusPermission": { 238 | "Type": "AWS::Lambda::Permission", 239 | "Properties": { 240 | "Action": "lambda:InvokeFunction", 241 | "FunctionName": { 242 | "Ref": "LambdaFunction" 243 | }, 244 | "Principal": "events.amazonaws.com", 245 | "SourceArn": { 246 | "Fn::GetAtt": [ 247 | "CodeBuildStatus", 248 | "Arn" 249 | ] 250 | } 251 | } 252 | }, 253 | "RestApi": { 254 | "Type": "AWS::ApiGateway::RestApi", 255 | "Properties": { 256 | "Name": "codebuild-ci-sample" 257 | } 258 | }, 259 | "ApiDeployment": { 260 | "Type": "AWS::ApiGateway::Deployment", 261 | "DependsOn": "ApiMethod", 262 | "Properties": { 263 | "RestApiId": { 264 | "Ref": "RestApi" 265 | } 266 | } 267 | }, 268 | "ApiKey": { 269 | "Type": "AWS::ApiGateway::ApiKey", 270 | "Properties": { 271 | "StageKeys": [ 272 | { 273 | "RestApiId": { 274 | "Ref": "RestApi" 275 | }, 276 | "StageName": { 277 | "Ref": "ApiStage" 278 | } 279 | } 280 | ] 281 | } 282 | }, 283 | "ApiMethod": { 284 | "Type": "AWS::ApiGateway::Method", 285 | "DependsOn": "LambdaFunction", 286 | "Properties": { 287 | "AuthorizationType": "NONE", 288 | "HttpMethod": "ANY", 289 | "Integration": { 290 | "Credentials": { 291 | "Fn::GetAtt": [ 292 | "ApiRole", 293 | "Arn" 294 | ] 295 | }, 296 | "IntegrationHttpMethod": "ANY", 297 | "Type": "AWS_PROXY", 298 | "Uri": { 299 | "Fn::Join": [ 300 | "", 301 | [ 302 | "arn:aws:apigateway:", 303 | { 304 | "Ref": "AWS::Region" 305 | }, 306 | ":lambda:path/2015-03-31/functions/", 307 | { 308 | "Fn::GetAtt": [ 309 | "LambdaFunction", 310 | "Arn" 311 | ] 312 | }, 313 | "/invocations" 314 | ] 315 | ] 316 | } 317 | }, 318 | "ResourceId": { 319 | "Ref": "ApiResource" 320 | }, 321 | "RestApiId": { 322 | "Ref": "RestApi" 323 | } 324 | } 325 | }, 326 | "ApiPermission": { 327 | "Type": "AWS::Lambda::Permission", 328 | "Properties": { 329 | "Action": "lambda:InvokeFunction", 330 | "FunctionName": { 331 | "Ref": "LambdaFunction" 332 | }, 333 | "Principal": "apigateway.amazonaws.com" 334 | } 335 | }, 336 | "ApiResource": { 337 | "Type": "AWS::ApiGateway::Resource", 338 | "Properties": { 339 | "ParentId": { 340 | "Fn::GetAtt": [ 341 | "RestApi", 342 | "RootResourceId" 343 | ] 344 | }, 345 | "PathPart": "{proxy+}", 346 | "RestApiId": { 347 | "Ref": "RestApi" 348 | } 349 | } 350 | }, 351 | "ApiStage": { 352 | "Type": "AWS::ApiGateway::Stage", 353 | "Properties": { 354 | "DeploymentId": { 355 | "Ref": "ApiDeployment" 356 | }, 357 | "RestApiId": { 358 | "Ref": "RestApi" 359 | }, 360 | "StageName": "v1" 361 | } 362 | }, 363 | "CodeBuildProject": { 364 | "Type": "AWS::CodeBuild::Project", 365 | "Properties": { 366 | "Artifacts": { 367 | "Type": "NO_ARTIFACTS" 368 | }, 369 | "Description": "GitHub CI Build Project Sample", 370 | "Environment": { 371 | "ComputeType": "BUILD_GENERAL1_SMALL", 372 | "Image": { 373 | "Ref": "BuildImage" 374 | }, 375 | "Type": "LINUX_CONTAINER" 376 | }, 377 | "Name": { 378 | "Ref": "ProjectName" 379 | }, 380 | "ServiceRole": { 381 | "Ref": "CodeBuildRole" 382 | }, 383 | "Source": { 384 | "Auth": { 385 | "Type": "OAUTH" 386 | }, 387 | "Location": { 388 | "Ref": "RepositoryUrl" 389 | }, 390 | "Type": "GITHUB" 391 | }, 392 | "TimeoutInMinutes": "30" 393 | } 394 | }, 395 | "CodeBuildStatus": { 396 | "Type": "AWS::Events::Rule", 397 | "Properties": { 398 | "Description": "Update GitHub Status after CodeBuild completes", 399 | "EventPattern": { 400 | "detail": { 401 | "build-status": [ 402 | "SUCCEEDED", 403 | "FAILED", 404 | "STOPPED" 405 | ], 406 | "project-name": [ 407 | { 408 | "Ref": "ProjectName" 409 | } 410 | ] 411 | }, 412 | "detail-type": [ 413 | "CodeBuild Build State Change" 414 | ], 415 | "source": [ 416 | "aws.codebuild" 417 | ] 418 | }, 419 | "Name": "codebuild-ci-sample-notification", 420 | "RoleArn": { 421 | "Fn::GetAtt": [ 422 | "CodeBuildRole", 423 | "Arn" 424 | ] 425 | }, 426 | "State": "ENABLED", 427 | "Targets": [ 428 | { 429 | "Arn": { 430 | "Fn::GetAtt": [ 431 | "LambdaFunction", 432 | "Arn" 433 | ] 434 | }, 435 | "Id": "Update-GitHub-Status" 436 | } 437 | ] 438 | } 439 | } 440 | }, 441 | "Outputs": { 442 | "WebhookUrl": { 443 | "Description": "URL for GitHub Webhook", 444 | "Value": { 445 | "Fn::Join": [ 446 | "", 447 | [ 448 | { 449 | "Ref": "RestApi" 450 | }, 451 | ".execute-api.", 452 | { 453 | "Ref": "AWS::Region" 454 | }, 455 | ".amazonaws.com/", 456 | "v1", 457 | "/webhook" 458 | ] 459 | ] 460 | } 461 | } 462 | } 463 | } 464 | --------------------------------------------------------------------------------