全てのブランチでCodeBuildを実行する方法

全てのブランチでCodeBuildを実行する方法

データエンジニアだったりデータアナリストだったりします。 @kazasiki です。

みなさんのプロジェクトでは自動テストは日々動いてるでしょうか。

AWS CodeBuildとAWS CodeCommitを連携させる場合、デフォルトではソース及びトリガとなるブランチは一つしか指定できません。殆どの場合はmasterやmainブランチなどが指定されていると思いますが、自動テストを動かしてる場合、他の feature/hogehoge ブランチやなんだったら全てのブランチでテストを実行したいと思うこともあると思います。

やってみたら案外サクッと出来たので、ここで方法を紹介しておこうと思います。

やり方

ざっくりいうと単にEventBridgeでCodeCommitの変更イベントを取得して、CodeBuildを起動するだけです。(画面を弄るのはしんどいので)CloudFormationのテンプレートのサンプルをお見せします。

まずはCodeBuildのテンプレートです。

CodeBuildProject:
  Type: AWS::CodeBuild::Project
  Properties:
    ...
    Source:
      Type: CODECOMMIT
      Location: !Sub https://git-codecommit.${AWS::Region}.amazonaws.com/v1/repos/${RepositoryName}
      BuildSpec: buildspec.yml
    SourceVersion: refs/heads/master # 実際はeventからoverrideされる

重要なのは、ソースとしてCodeCommitおよび対象となるリポジトリを指定することと、SourceVersionを何でも良いので指定することです。SourceVersionは実際はeventからoverrideされるので、ここで書いたものは使われません。

次に、EventBridgeのテンプレートです。

CodeBuildRule:
  Type: "AWS::Events::Rule"
  Properties:
    State: "ENABLED"
    EventPattern:
      source:
        - "aws.codecommit"
      detail-type:
        - "CodeCommit Repository State Change"
      resources:
        - !Sub arn:aws:codecommit:${AWS::Region}:${AWS::AccountId}:${RepositoryName}
      detail:
        event:
          - "referenceCreated"
          - "referenceUpdated"
    Targets:
      - Id: code_build
        Arn: !GetAtt CodeBuildProject.Arn
        RoleArn: !GetAtt EventInvokeRole.Arn
        InputTransformer:
          InputPathsMap:
            sourceVersion: "$.detail.referenceFullName"
          InputTemplate: |
            {"sourceVersion": "<sourceVersion>"}

EventPatternの部分で、イベントのソースとしてCodeCommitおよび対象のリポジトリを指定します。ここでdetailにいろいろ指定すれば更に特定のブランチやprefixでの指定も出来ますが、今回はやってません。全てのブランチを対象にします。

Targetsの部分で、↑のテンプレートで作成されるCodeBuildのプロジェクトを指定します。さらに、InputTransformerでは入力されたイベントを変換して、CodeBuildを起動する際のパラメタ(?)を上書きします。

CodeCommitから発行されるイベントの例は以下です。

{
  "version": "0",
  "id": "01234567-0123-0123-0123-012345678901",
  "detail-type": "CodeCommit Repository State Change",
  "source": "aws.codecommit",
  "account": "123456789012",
  "time": "2017-06-12T10:23:43Z",
  "region": "us-east-1",
  "resources": ["arn:aws:codecommit:us-east-1:123456789012:myRepo"],
  "detail": {
    "event": "referenceUpdated",
    "repositoryName": "myRepo",
    "repositoryId": "12345678-1234-5678-abcd-12345678abcd",
    "referenceType": "branch",
    "referenceName": "myBranch",
    "referenceFullName": "refs/heads/myBranch",
    "commitId": "26a8f2EXAMPLE",
    "oldCommitId": "3e5983EXAMPLE"
  }
}

ここで使うのはbranch名にあたるreferenceFullNameだけです。それでCodeBuildのSourceVersionを上書きしてCodeBuildを起動します。

あとはRoleなどを適宜作成する必要がありますが、その辺りは特に変わったことはありません。

まとめ

Codebuildの標準機能では実現できないことも、他のサービスを使えば意外に簡単に実現できます。特にEventBridgeはAWS上のちょっとした困りごとを解決するのに最適です。CircleCIだったら設定ファイルにちょっと書けば済むし便利なのになぁ〜と思わなくないですが、仕方ないのであるもので頑張っていきましょう。

参考にした記事

dev.classmethod.jp

やってることはほぼ一緒です。上記の記事ではEventBridgeからCodeBuildを起動するときのパラメタを弄るのにStepFunctionを使ってますが、私の実装ではEventBridgeのInput Transformerを使ってます。基本的にはInput Transformerで十分だと思います。

aws.amazon.com

上記の記事ではPull Requestの変更イベントをトリガにして全体を動かしています。そういった要件であればその方法もありですが、個人的には所定のブランチでのテストは常にパスしてて欲しいのでブランチベースで良いかなと思います。レビューするときも直近のコミットでエラーがなければ基本的に問題ありません。githubであればPRにテストorビルド結果をいい感じに統合して表示してくれますが、自力でわざわざそこまでしなくても...という印象です。

alt

@kazasiki

デジタルテクノロジー統括部 デジタルソリューション部 Webアプリエンジニアグループ リードエンジニア

バックエンドエンジニア。VRゲームとダンスミュージックが好き。都内のクラブによく行く。

※2023年3月現在の情報です。