GitHub Actions 共通化手法

はじめに
GitHub Actions を利用する際、似たような処理を何度も記述していませんか? ワークフローが複雑になるにつれて、メンテナンスコストが増大し、変更への対応も煩雑になりがちです。
この記事では、GitHub Actions の処理を共通化することで、これらの問題を解決するための手法を、具体的な例を交えながら解説します。
再利用可能なワークフローによる共通化
まずは、ワークフローの再利用を活用した共通化の方法を説明します。
on キーワードで、ワークフローを直接トリガーするイベントの代わりに workflow_call イベントを指定すると、別のワークフローからそのワークフローを呼び出すことができます。
例: .github/workflows/deploy.yml
1name: Deploy to Production 2 3on: 4 workflow_call: # ワークフローを再利用可能にするイベント 5 inputs: # 呼び出し元のワークフローからパラメータを受け取る 6 environment: 7 required: true 8 type: string 9 target_host: 10 required: true 11 type: string 12 13 secrets: # シークレットを受け渡す場合は明示的に指定する必要がある 14 SSH_PRIVATE_KEY: 15 required: true 16 17 outputs: # 処理結果を呼び出し元のワークフローに返す 18 deployment_status: 19 description: "The status of the deployment job" 20 value: ${{ jobs.deploy.outputs.status }} 21 22jobs: 23 deploy: 24 runs-on: ubuntu-latest 25 outputs: 26 status: ${{ job.status }} 27 steps: 28 - name: Checkout code 29 uses: actions/checkout@v4 30 - name: Set up SSH 31 run: | 32 mkdir -p ~/.ssh 33 echo "${{ secrets.SSH_PRIVATE_KEY }}" | tr -d '\r' > ~/.ssh/id_rsa 34 chmod 600 ~/.ssh/id_rsa 35 ssh-keyscan -H ${{ inputs.target_host }} >> ~/.ssh/known_hosts 36 - name: Deploy to server 37 run: rsync -avz -e "ssh -i ~/.ssh/id_rsa" ./ ${{ inputs.environment }}@${{ inputs.target_host }}:/var/www/html
上記のワークフローを呼び出すには、以下のように記述します。
jobs セクションで新しいジョブを定義し、そのジョブ内で uses キーワードを使って、再利用可能なワークフローのパスを指定します。
例: .github/workflows/deploy.yml
1name: Deploy Application 2 3on: 4 push: 5 branches: [main] 6 7jobs: 8 deploy-staging: 9 uses: ./.github/workflows/deploy.yml # 共通化したワークフローのパス 10 with: # 呼び出し元の inputs で定義した値を渡す 11 environment: "staging" 12 target_host: "staging.example.com" 13 secrets: # 呼び出し元の secrets で定義した値を渡す 14 SSH_PRIVATE_KEY: ${{ secrets.STAGING_SERVER_SSH_KEY }} 15 16 deploy-production: 17 uses: ./.github/workflows/deploy.yml 18 with: 19 environment: "production" 20 target_host: "prod.example.com" 21 secrets: 22 SSH_PRIVATE_KEY: ${{ secrets.PRODUCTION_SERVER_SSH_KEY }} 23 24 post-deployment-check: 25 needs: [deploy-staging, deploy-production] 26 runs-on: ubuntu-latest 27 steps: 28 - name: Check deployment status 29 # 呼び出し元の outputs で定義した値を受け取る 30 run: | 31 echo "Staging deployment status: ${{ jobs.deploy-staging.outputs.deployment_status }}" 32 echo "Production deployment status: ${{ jobs.deploy-production.outputs.deployment_status }}"
Composite Action による共通化
次に、Composite Action を活用した共通化の方法を説明します。
Composite Action は、通常のワークフローとは異なり、フォルダ階層は自由ですが、ファイル名は action.yml にする必要があります。 GitHub Docs では、.github/actions/{任意の名前}/action.yml というフォルダ構成で作成することが推奨されています。
また、現時点では secrets の受け渡しはできません。 今後サポートされる予定 のようです。
例: .github/actions/test/action.yml
1name: "Node.js Test" 2description: "Test implemented in node.js" 3inputs: # 呼び出し元のワークフローからパラメータを受け取る 4 working-directory: 5 description: "Path to the working directory" 6 required: true 7 8outputs: # 処理結果を呼び出し元のワークフローに返す 9 test_report_path: 10 description: "Path to the test report file (if generated)" 11 value: ${{ steps.report.outputs.test_report_path }} 12 13runs: 14 using: "composite" # Composite Action であることを宣言 15 steps: 16 - name: Checkout code 17 uses: actions/checkout@v4 18 19 - name: Set up Node.js ${{ inputs.node_version }} 20 uses: actions/setup-node@v4 21 with: 22 node-version: 22.X 23 24 - name: Install dependencies 25 run: npm install 26 shell: bash # コマンド実行には shell を明示的に指定する 27 working-directory: ${{ inputs.working-directory }} 28 29 - name: Run tests 30 run: npm run test --report_output=./test-results.xml 31 shell: bash 32 working-directory: ${{ inputs.working-directory }} 33 34 - name: Set test report output 35 id: report 36 run: echo "test_report_path=$(pwd)/test-results.xml" >> "$GITHUB_OUTPUT" 37 shell: bash 38 working-directory: ${{ inputs.working-directory }}
上記の Composite Action を実行するには、以下のように記述します。
例: .github/workflows/test.yml
1name: Test Application 2 3on: 4 push: 5 branches: [main] 6 7jobs: 8 test-app1: 9 runs-on: ubuntu-latest 10 steps: 11 - name: Test 12 id: test 13 uses: ./.github/actions/test # 実行する Composite Action のディレクトリ 14 with: 15 working-directory: "./app1" # 呼び出し元の inputs で定義した値を渡す 16 17 - name: Output test results 18 # 呼び出し元の outputs で定義した値を受け取る 19 run: cat ${{ steps.test.outputs.test_report_path }} 20 21 test-app2: 22 runs-on: ubuntu-latest 23 steps: 24 - name: Test 25 id: test 26 uses: ./.github/actions/test 27 with: 28 working-directory: "./app2" 29 30 - name: Output test results 31 run: cat ${{ steps.test.outputs.test_report_path }}
どちらの方法を選ぶべきか
再利用可能なワークフローは、ワークフロー全体を共通化する仕組みです。 GitHub Actions は job 単位で別々のコンテナで実行されるため、共通処理内で変更した内容 (生成したファイルやインストールしたパッケージなど) は、後続の処理に引き継ぐことができません。
一方、Composite Action は step 単位で共通化するため、共通処理内で変更した内容は後続の処理に引き継がれます。 また、再利用可能なワークフローは実行のたびに新しいコンテナを立ち上げる必要があるため、単純で実行回数の多い処理の場合は Composite Action を利用することで、処理時間の短縮と料金の節約につながります。
以上の点を考慮すると、以下のように使い分けるのが適切です。
再利用可能なワークフロー
- 共通処理内で変更した内容を後続の処理に引き継ぐ必要がない場合(例: ビルド、デプロイ処理、セキュリティスキャンなど)
- 環境を変えて (Node.js のバージョンなど) 共通処理を実行する場合
Composite Action
- 共通処理内で変更した内容を後続の処理に引き継ぐ必要がある場合(例: 依存関係のインストール、環境設定、複数のコマンド実行など)
- 単純または実行回数の多い処理(例: テスト結果やデプロイ結果の出力、チャット通知など)
まとめ
この記事では、GitHub Actions におけるワークフローの共通化手法として、再利用可能なワークフローと Composite Action の 2 つを紹介しました。
どちらの手法を選択するかは、共通化したい処理の粒度や、処理内で変更した内容を後続の処理で利用する必要があるかどうかなどを考慮して判断する必要があります。 これらの手法を適切に活用することで、ワークフローのメンテナンス性を向上させ、開発効率を高めていきましょう!
参考サイト
Author Profile
AIROU
プログラマーです 猫とラーメンが好きです
SHARE