Push時はCIのみ、Merge時はCIおよびCDを実行するGitHub Actionsを作る(単一のWorkflowで)

2022.04.21

こんにちは、CX事業本部 IoT事業部の若槻です。

前回の下記エントリでは、Push時はCIのみ、Merge時はCIおよびCDを実行するGitHub Actionsの作成において、「Workflowの再使用」を活用し、Workflowを分けた場合でもCI処理の記述の重複が無いようにしてみました。

今回は、同じくPush時はCIのみ、Merge時はCIおよびCDを実行するGitHub Actionsの作成を、単一のWorkflowでやってみました。

やってみた

前提

  • feature/****というブランチでPull Requestを作成して開発を行い、レビューがOKならmainブランチにマージするというフローで考えてみます。
  • Pull Requestでの開発中にPushをするとCIが実行され、mainブランチにマージをするとCIおよびCIが行われるようにしたいです。
  • AWS CDkプロジェクトのCI/CDを行うWorkflowで考えてみます。
    • 認証に必要なAssumeRoleは、AWS_OIDC_ROLE_ARNから取得したロールを使用してOIDCにより行っています。

Workflow fileの作成

下記のような1つのWorkflow fileを作成します。

.github/workflows/cicd.yaml

on: 
  push:
    paths-ignore:
      - '**/*.md'

jobs:
  integration:
    runs-on: ubuntu-latest
    steps: 
      - name: Checkout
        uses: actions/checkout@v3

      - name: Cache CDK Dependency
        uses: actions/cache@v3
        id: cache_cdk_dependency_id
        env:
          cache-name: cache-cdk-dependency
        with:
          path: node_modules
          key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('package-lock.json') }}
          restore-keys: ${{ runner.os }}-build-${{ env.cache-name }}-

      - name: Install CDK Dependency
        if: ${{ steps.cache_cdk_dependency_id.outputs.cache-hit != 'true' }}
        run: npm ci --cache .npm --no-audit --progress=false --silent

      - name: CDK Test
        run: npm run test

  deploy:
    runs-on: ubuntu-latest
    if: ${{ github.ref_name == 'main' }}
    needs: integration
    env:
      AWS_OIDC_ROLE_ARN: ${{ secrets.AWS_OIDC_ROLE_ARN }}
      AWS_REGION: us-east-1
    permissions:
      id-token: write
      contents: read
    steps:
      - name: Checkout
        uses: actions/checkout@v3

      - name: Assume Role
        uses: aws-actions/configure-aws-credentials@v1
        with:
          role-to-assume: ${{ env.AWS_OIDC_ROLE_ARN }}
          aws-region: ${{env.AWS_REGION}}

      - name: Cache CDK Dependency
        uses: actions/cache@v3
        id: cache_cdk_dependency_id
        env:
          cache-name: cache-cdk-dependency
        with:
          path: node_modules
          key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('package-lock.json') }}

      - name: Deploy
        run: npm run deploy

ポイントとしては、まずトリガーはすべてのブランチでのアクション時に動作するようにしています。

.github/workflows/cicd.yaml

on: 
  push:
    paths-ignore:
      - '**/*.md'

そしてCDを行うジョブのif条件を${{ github.ref_name == 'main' }}とし、mainブランチへのマージ時のみCDが行われるようにしています。

.github/workflows/cicd.yaml

  deploy:
    runs-on: ubuntu-latest
    if: ${{ github.ref_name == 'main' }}
    needs: integration

動作確認

PushをするとCIだけ実行されました!

MergeをするとCIおよびCDが実行されました!

ハマった箇所

Workflowのトリガーですが、本来ならこのようにpushpull_requestを組み合わせて使用したかったです。これによりmainブランチではPushによるトリガーされなくなり、マージ時のみトリガーされるようになります。mainブランチへのPushを想定していないならこれでも良いはずです。

on: 
  push:
    paths-ignore:
      - '**/*.md'
    branches-ignore:
      - main

  pull_request:
    types:
      - closed
    branches:
      - main

ではトリガーをこのようになぜしなかったかと言うと、pull_request使用時にaws-actions/configure-aws-credentialsによる認証がなぜか失敗してしまうためです。

例えば次のWorkflowで試してみます。

.github/workflows/cicd.yaml(Assume Roleが落ちる)

on: 
  pull_request:
    types:
      - closed
    branches:
      - main

jobs:
  integration:
    runs-on: ubuntu-latest
    steps: 
      - run: echo "中略"

  deploy:
    runs-on: ubuntu-latest
    if: ${{ github.ref_name == 'main' }}
    needs: integration
    env:
      AWS_OIDC_ROLE_ARN: ${{ secrets.AWS_OIDC_ROLE_ARN }}
      AWS_REGION: us-east-1
    permissions:
      id-token: write
      contents: read
    steps:
      - name: Assume Role
        uses: aws-actions/configure-aws-credentials@v1
        with:
          role-to-assume: ${{ env.AWS_OIDC_ROLE_ARN }}
          aws-region: ${{env.AWS_REGION}}

マージをするとAssumeRoleがエラーとなりました。上手くトークンを渡せていないような動作です。

Not authorized to perform sts:AssumeRoleWithWebIdentity

ここら辺の設定がいるのかなあと試しに有効にしてみましたが変化はありませんでした。

解決策が分かったらまた共有をしたいと思います。

ただ、直接pushする運用をしないmainブランチはブランチ保護ルールでpush制限をするかと思うので、pushトリガーだけの使用でもさほど不便は無いかと思います。

参考

以上