背景
以前AWS CodeCommit/CodeBuildを用いたCI/CDを試した際、PRの作成をトリガーにCodeBuildを実行するために、Amazon EventBridgeを使用しました。この時にやりたかったことを並べると、以下のようになります。
- CodeCommitで特定のブランチ宛にPull Requestを作成すると、EventBridgeがそれを検知する
- EventBridgeはPR関連の情報をCodeBuildへ送る
- CodeBuildは受け取ったデータをもとに、PRのコミットに対してビルドを実行する
この時、EventBridgeはCodeCommitの pullRequestCreated
というイベントをトリガーに、CodeBuildのビルドを開始するよう設定しておりました。これにより上記項目の1・2番は実現できています。
またCodeBuildは、Projectの設定を上書きしてビルドを実行できます。この時に特定のブランチやCommit IDを指定することで、Pull Requestに含まれる修正に対してCodeBuildを実行できます(項目の3番に該当)。
しかし以前の投稿時は、CodeBuildのほうは特に何も設定をしていなかったため、PRを作成しても想定通りには動かず、実際はデフォルトで設定された main
ブランチを対象にビルドを実行していました。これにはだいぶ後になって気づいたのですが、今思うと「EventBridgeのほうでPull Requestを検知しているのだから、CodeBuildのほうもいい感じに処理してくれるだろう」と、なにか勘違いをしていたのでしょう。。。
ということで今回は、PR作成時にLambdaからCodeBuildを起動して特定のコミットにビルドを実行する、という方法を試してみました。
方法
大まかな処理の流れは以下になります。
CodeCommit -> EventBridge -> Lambda -> CodeBuild
すでに記載したとおり、CodeBuildはデフォルトの設定を上書きしてビルドを実行できます。CodeBuildの開始は StartBuild というAPIから実行でき、この時に対象のCommit IDを sourceVersion
パラメータに渡せます。なのでこれを使えば今回やりたいことを実現できるのでは、と考えました。
またEventBridgeのターゲットはCodeBuildだけでなくAWSの多様なサービスに対応しており、その中にはAWS Lambdaも含まれます。今回はPythonを使ってLambda関数を定義し、上記 StartBuild
APIを呼び出しました。
なお、Commit IDの情報はEventBridgeから渡されるデータから取り出します。EventBridgeがCodeCommitから渡されるデータには sourceCommit
というパラメータがあり、ここにはPRの作成に使用されたソースブランチのCommit IDが含まれています。これを StartBuild
開始時に渡すことで実現しました。
確認
今回は以下のリソースを用意しました。
Amazon EventBridge
: 後述のイベントパターンを使用します。AWS Lambda
:StartBuild
のため、IAMロールにCodeBuildの実行権限を付与します。AWS CodeBuild
: デフォルトではmain
ブランチをターゲットに設定しました。AWS CodeCommit
: 事前にテスト用のファイルとbuildspec.yml
を用意します。
なお、EventBridgeのイベントパターン、Lambda関数、 buildspec.yml
はそれぞれ以下になります。
EventBridgeイベントパターン
{ "detail-type": ["CodeCommit Pull Request State Change"], "resources": ["arn:aws:codecommit:ap-northeast-1:123456789012:test-codecommit-20230430"], "source": ["aws.codecommit"], "detail": { "pullRequestStatus": ["Open"], "destinationReference": ["refs/heads/main"], "event": ["pullRequestCreated"] } }
Lambda関数
import boto3 # テスト用のCodeBuildプロジェクト名を指定 target_project_name = "test-codebuild-20230430" def lambda_handler(event, context): client = boto3.client('codebuild') response = client.start_build( projectName=target_project_name, sourceVersion=event['detail']['sourceCommit'] ) return { 'projectNameStaticAnalysis': response['build']['projectName'], 'sourceVersionStaticAnalysis': response['build']['sourceVersion'], 'buildStatusStaticAnalysis': response['build']['buildStatus'] }
buildspec.yml
version: 0.2 phases: build: commands: - echo Check test01 - cat test01.txt - echo Check test02 - cat test02.txt
PRを作成した場合の前に、試しにテスト用のCodeBuildプロジェクト上ビルドを実行します。特にパラメータ等を変更しない場合 main
ブランチ上の最新のコミットに対してビルドを実行します。
次にPull Requestを作成した場合です。ここでは test01.txt
に対して以下の修正を加えました。
Pull Requestを作成するとEventBridgeがそれを検知してLambdaが実行され、CodeBuildが開始されます。この時のCodeBuildのログを見ると、確かにPull Requestに含まれる修正内容が反映されています。
またこの時のビルドの情報を見ると、Pull Request作成時のCommit IDが指定されていることも確認できます。
以上の通り、想定通り動作することを確認しました。