TECHSTEP

ITインフラ関連の記事を公開してます。

【メモ】CodeCommit上でPR作成時にLambdaからCodeBuildを起動して特定のコミットにビルドを実行する

背景

以前AWS CodeCommit/CodeBuildを用いたCI/CDを試した際、PRの作成をトリガーにCodeBuildを実行するために、Amazon EventBridgeを使用しました。この時にやりたかったことを並べると、以下のようになります。

  1. CodeCommitで特定のブランチ宛にPull Requestを作成すると、EventBridgeがそれを検知する
  2. EventBridgeはPR関連の情報をCodeBuildへ送る
  3. 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が指定されていることも確認できます。

以上の通り、想定通り動作することを確認しました。