内容
GitHub Actionsを構成するコンポーネントの概要と要点について記載する
イベント
各イベント説明に記載されているGITHUB_REF、GITHUB_SHAは、ブランチ名、コミットIDで、
workflowはそのソースコードの状態で実行される
actions/checkoutでソースコードをcheckoutする際にデフォルトではこのブランチ名、コミットIDが使用される(パラメータrefで変更可能)
Noteに「このイベントは、ワークフローファイルがデフォルト ブランチにある場合にのみワークフローの実行をトリガーします。」とあるイベントは、
デフォルトブランチにworkflowの実装がマージされたあとでしか実行・動作確認できないため注意
pull_request
PRの各種操作をトリガーにworkflowを起動する
以下のようにブランチやファイルパスでイベントのフィルターも可能
on:
  pull_request:
    types:
      - opened
      - synchronize
    branches:
      - 'releases/**'
    paths:
      - '**.js'
使用頻度の高いtypesとしてはopened, closed, synchronize等、
PRのマージ時にworkflowを実行する場合は以下のようにgithub.event.pull_request.mergedと合わせて判定する
on:
  pull_request:
    types:
      - closed
jobs:
  if_merged:
    if: github.event.pull_request.merged == true
    runs-on: ubuntu-latest
    steps:
    - run: |
        echo The PR was merged
typesopened, synchronizeでPR発行時、PRに対してコミットpush時にテストworkflowを実行、
typesclosedでPRマージ時に実環境にデプロイする等の使い分けが考えられる
synchronizeを入れるとコミット頻度が高い場合や、workflowが重い場合にActionsの実行時間が増加して料金への影響もあるため要検討
pull_requestイベントはGITHUB_REF、GITHUB_SHAが特殊で、
PRマージブランチ(PRがマージされた後の状態のソースコード)になる
pull requestのheadブランチへの最後のコミットのコミットIDを取得する場合は、
代わりにgithub.event.pull_request.head.shaを使用する
「このイベントは、ワークフローファイルがデフォルト ブランチにある場合にのみワークフローの実行をトリガーします。」の記載がないため、
pull_requestトリガーのworkflowを新規追加したPRを発行すると、そのPRに対してworkflowがトリガーされる
workflow_dispatch
workflowを手動実行する際に使用する
「このイベントは、ワークフローファイルがデフォルト ブランチにある場合にのみワークフローの実行をトリガーします。」の記載があるが、
デフォルトブランチにdispatch workflowがあり、他ブランチでそのworkflowを変更、pushした場合は、
以下のように他ブランチを選択して実行することで変更が反映された状態で実行することができる
workflow_call
他のworkflowからworkflowを呼び出す際に使用する
他イベントとは用途が違って、workflowの共通化や、冗長性の解消等に使用する
reusable-workflowsで後述
workflows
workflowのトリガーとなるイベントとjob,stepから構成される
name: Run CI
on: [push, pull_request]
jobs:
  normal_ci:
    runs-on: ubuntu-latest
    steps:
      - name: Run normal CI
        run: echo "Running normal CI"
  pull_request_ci:
    runs-on: ubuntu-latest
    if: ${{ github.event_name == 'pull_request' }}  # イベント名を参照
    steps:
      - name: Run PR CI
        run: echo "Running PR only CI"
上記github.event_nameのようにワークフローの実行、変数、ランナーの環境、ジョブ、ステップに関する情報にはコンテキストを使ってアクセスする
github コンテキストのevent
github.eventにはGitHubのWebhookペイロードが含まれる(例:pull_request)
github.eventは、トリガーのイベントによって内容が異なる
そのため、共通処理のreusable-workflowやcomposite-action内でgithub.event.pull_request.head.shaのようなイベント依存の値を参照すると、
pull_request以外のイベントでは参照できないため注意が必要
env
以下のように各階層で環境変数envを定義することができる(変数に情報を格納する抜粋)
name: Greeting on variable day
on:
  workflow_dispatch
env:  # workflowレベルの環境変数
  DAY_OF_WEEK: Monday
jobs:
  greeting_job:
    runs-on: ubuntu-latest
    env:  # jobレベルの環境変数
      Greeting: Hello
    steps:
      - name: "Say Hello Mona it's Monday"
        run: echo "$Greeting $First_Name. Today is $DAY_OF_WEEK!"
        env:  # stepレベルの環境変数
          First_Name: Mona
ただし、workflow_callイベントの場合はトップ階層のenvが使用できない(issues: https://github.com/actions/runner/issues/2372)
on:
  workflow_call:
env:
  env_1: 123
jobs:
  job_1:
    runs-on: ubuntu-latest
    env:
      env_2: ${{ env.env_1 }}  # ERROR (Unrecognized named-value: 'env', Available expression contexts: github, inputs, vars, needs, strategy, matrix, secrets)
    steps:
      - run: echo "hello"
解決方法として、inputsのdefaultで代用することができる
on:
  workflow_call:
    inputs:
      param_1:
        required: false  # 呼び出し元から指定されない前提
        type: string
        default: 123
jobs:
  job_1:
    runs-on: ubuntu-latest
    env:
      env_2: ${{ inputs.param_1 }}
    steps:
      - run: echo "hello"
reusable-workflows
reusable-workflowsはworkflow_callイベントによって実行される
以下、reusable-workflowstest_1.ymlworkflowはusesで呼び出す例
secrets: inheritを指定することで、organization、repository、environmentレベルのシークレットを継承できる
ただし、github.token、secrets.GITHUB_TOKENへのアクセス権は自動的に呼び出し先workflowに付与される(GITHUB_TOKENについてはpermissions参照)
name: 適当なreusable-workflows
on:
  workflow_call:
jobs:
  job_1:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
jobs:
  test_1:
    secrets: inherit # reusable-workflowsへのシークレットの継承
    uses: ./.github/workflows/test_1.yml  # reusable-workflows呼び出し
workflow_dispatch, workflow_callは、workflowに対するパラメータ(inputs)が指定できる
指定できるinputsのtypeはそれぞれ異なり、
workflow_dispatchでinputsに指定できるtype(on.workflow_dispatch.inputs..type)は、boolean、choice、number、environmentまたはstring
workflow_callでinputsに指定できるtype(on.workflow_call.inputs..type)は、boolean、number、または string
また、workflowの出力(outputs)も指定できる
stepの出力をworkflowの出力にする場合、以下のようにsteps → jobs → workflowの順で出力を連携する必要がある
name: Test output
on:
  workflow_call:
    inputs:
      param_1:
        required: true
        type: string
    outputs:
      workflow_output:  # jobsのoutputをworkflowのoutputに連携
        value: ${{ jobs.job_1.outputs.job_output }}
jobs:
  job_1:
    runs-on: ubuntu-latest
    outputs:
      job_output: ${{ steps.output_step.outputs.output_1 }}  # stepsのoutputをjobsのoutputに連携
    steps:
      - uses: actions/checkout@v4
      - id: output_step
        run: |
          output="hello"
          echo "output_1=${output}" >> $GITHUB_OUTPUT
呼び出し元では以下のようにinputsを指定、outputsを参照する
jobs:
  test_1:
    secrets: inherit
    uses: ./.github/workflows/test_1.yml
    with:
      param_1: "test"  # reusable-workflowsのinputs指定
  test_2:
    runs-on: ubuntu-latest
    env:
      test_1_output: ${{ jobs.test_1.outputs.workflow_output }}  # reusable-workflowsのoutputsを参照
    steps:
      - run: |
          echo $test_1_output
job
jobには以下のようにruns-on, permissions, environment, needs, env, steps等を指定できる
jobs:
  test_1:
    ...
  test_2:
    name: Test 2
    runs-on: ubuntu-latest
    permissions:
      id-token: write
      contents: write
      pull-requests: write
    environment:
      name: dev
    needs: [test_1]
    env:
      env_1: "abc"
    steps:
      - uses: actions/checkout@v4
      - name: Build Python
        id: build_python
        ...
各Jobはそれぞれ異なる環境のため、
Jobでcheckoutしたソースコード、インストールしたツール、作成したファイル等は他Jobに引き継がれない
そのため、Jobを分けすぎると無駄に環境構築処理が複数回発生し、処理時間の増加につながる
cache(actions/cache)や、artifact(actions/upload-artifact) を使うことでJob間でファイルを共有することができる
cache、artifactについてはGitHub Actions - cacheとartifact参照
runs-on
runs-onにはランナー(jobの実行に使用するimage)を指定する
ubuntu-latestやwindows-latest等、基本的には標準のGitHubでホストされたランナーにある中から選択する
各ランナーのリンクから、該当のランナーにインストールされているツールの情報が確認できる(例: ubuntu-latest)
ユーザが管理するセルフホステッドランナーを使用することもできる(GitHub Actions - セルフホステッド ランナー(AWS CodeBuild)にて使用方法を記載)
permissions
GitHubの操作を行うActionに使用されるGITHUB_TOKENの権限の変更に使用する
permissionsにある中から選択する
githubコンテキストのtokengithub.tokenとGITHUB_TOKENは同じものである
actions/checkoutもGitHub操作であるため、デフォルトでGITHUB_TOKENを使用している(パラメータtokenで変更可能)
GitHub CLI等でGitHub操作をする場合は、以下のように環境変数でGITHUB_TOKENを渡す必要がある(GITHUB_TOKEN シークレットについて抜粋)
name: Open new issue
on: workflow_dispatch
jobs:
  open-issue:
    runs-on: ubuntu-latest
    permissions:
      contents: read
      issues: write
    steps:
      - run: |
          gh issue --repo ${{ github.repository }} \
            create --title "Issue title" --body "Issue body"
        env:
          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
environment
GitHub Actions - environment と Deployment protection rules参照
needs
workflow内に複数のJobが存在する場合、既定では全Jobは並列実行される
Jobの実行順番を制御するためにはneedsを使用してJobの依存関係を指定する
needsに指定されたJobが成功した場合のみJobが実行される
jobs:
  job1:
  job2:
    needs: job1
  job3:
    needs: [job1, job2]
needsに指定したJobの成功/失敗問わずJobを実行したい場合は以下のようにalways()を使用する
jobs:
  job1:
  job2:
    needs: job1
  job3:
    if: ${{ always() }}
    needs: [job1, job2]
needsに指定したJobの出力(jobs..outputs)は以下のようにアクセスできる
jobs:
  job1:
    runs-on: ubuntu-latest
    # Map a step output to a job output
    outputs:
      output1: ${{ steps.step1.outputs.test }}
      output2: ${{ steps.step2.outputs.test }}
    steps:
      - id: step1
        run: echo "test=hello" >> "$GITHUB_OUTPUT"
      - id: step2
        run: echo "test=world" >> "$GITHUB_OUTPUT"
  job2:
    runs-on: ubuntu-latest
    needs: job1
    steps:
      - env:
          OUTPUT1: ${{needs.job1.outputs.output1}}
          OUTPUT2: ${{needs.job1.outputs.output2}}
        run: echo "$OUTPUT1 $OUTPUT2"
step
ステップでは、コマンドを実行する、設定タスクを実行する、
あるいはactions/checkoutのような公開されたアクションを実行することができる
composite-action
複数stepからなる処理を共通化したい場合等に使用する
実装したcomposite-actionは、.github/actions/{任意の名前}/action.ymlに格納しておく
以下、AWS認証を行うcomposite-actionと実行例
name: AWS Credentials Setting
description: Configure AWS credentials
inputs:
  region:
    description: AWS region
    required: true
  account_id:
    description: AWS account
    required: true
  role_name:
    description: Role to assume
    required: true
runs:
  using: "composite"  # composite-action指定
  steps:
    - uses: aws-actions/configure-aws-credentials@v4
      with:
        aws-region: ${{ inputs.region }}
        role-to-assume: arn:aws:iam::${{ inputs.account_id }}:role/${{ inputs.role_name }}
        role-duration-seconds: 3600
jobs:
  aws_:
    runs-on: ubuntu-latest
    permissions:
      id-token: write
    environment:
      name: dev
    steps:
      - uses: actions/checkout@v4  # composite-action実行前にcheckoutが必須
      - uses: ./.github/actions/aws-credential
        with:
          account_id: ${{ vars.ACCOUNT_ID }}
          region: ${{ vars.REGION }}
          role_name: ${{ secrets.ASSUME_ROLE_NAME }}
composite-action実行前にcheckoutが必須となる
composite-action内ではsecretsが参照できない、そのためsecretsを使用する場合はinputsで渡す必要がある
composite-action内ではコマンド実行(run)を行う際に、shell: bashのようにshell指定が必須となる
