Reusable workflows / Composite action を用いて GitHub Actions の処理を再利用する
自前で書いた GitHub Actions の処理を再利用化する方法として、おおまかに以下の2通りの方法があります。
GitHub Actions の yaml ファイルは放っておくと肥大化し、可読性も保守性も落ちてしまうため、平和な空間を保つためにも適度なサイズに保つ努力、適切なモジュールの分解と再利用化が欠かせません。
というような事例に今年はそれなりに遭遇したため、記事としてまとめてみました。
Reusable workflows とは?
言葉の通り、再利用可能な workflows です。
GitHub Actions の定義を各リポジトリごとに記載していくと冗長な記載が散在しコピペ天国になってしまうため、共通的な定義については切り出して外だしすることが望まれます。そのための仕組みが reusable workflows になります。
いくつかの仕様・環境の変遷を経て、現在(2022年12月以降)は 別の private repository に置かれている Actions を呼び出すことができる ようになっています。このドキュメントはその状況を前提に記載をします。
Reusable workflows の設定
repository
Reusable workflows で使用する GitHub Actions ファイルを設置するリポジトリについては、以下の設定を行う必要があります。
こちらを行わないと、Actions の呼び出しが行えません
Accessible from repositories in the ~
に変更する
GitHub Actions の Access 設定を https://github.com/(organization)/(repository)/settings/actions
上記のURL経由でアクセスできる設定画面から設定が可能です。
Access の設定はデフォルトでは Not accessible
となっているので、こちらを Accessible from repositories in the 'xxxxxx' organization
に変更します
Github Actions ファイル
Actions ファイルも Reusable workflows の仕様にあわせて記述する必要があります。
- .github/workflows 配下に設置する必要がある
- サブディレクトリの作成も基本的に不可
- 呼び出しの定義として
on: workflow_call:
の定義を必ずつける必要がある
on:
workflow_call:
- その他、Reusable workflows の詳細な仕様については公式ドキュメントを参照ください
記述例
ここでは、GitHub Actions の Lint ツールである actionlint を実行する Reusable wofkflows をサンプルとして掲載します。
on:
workflow_call:
inputs:
os:
default: ubuntu-latest
required: false
type: string
jobs:
actionlint:
runs-on: ${{ inputs.os }}
steps:
- uses: actions/checkout@v4
- name: Run actionlint
shell: bash
run: |
bash <(curl https://raw.githubusercontent.com/rhysd/actionlint/main/scripts/download-actionlint.bash)
./actionlint -color
inputs で指定された OS 環境(デフォルトでは ubuntu-latest)の上で rhysd/actionlint
を実行する、という例になっています。
上述の通り Reusable workflows として使用するためには on: workflow_call
の指定が必要なので、そのような記述をしています。
Reusable workflows の呼び出し
記述例
上記の actionslint 向けの Reusable workflows が (organization)/github-actions/.github/workflows/actionlint.yml
に置かれている、とした場合、以下のような形で呼び出すことができます。
name: Actionlint
on:
pull_request:
jobs:
actionlint:
uses: (organization)/github-actions/.github/workflows/actionlint.yml@main
uses
には、以下のようなフォーマットで呼び出す Actions ファイルを指定します
(organization)/(repository)/.github/workflows/(reusable workflows file)@(branch name)
reusable workflows に値を渡す場合は、 with
や secrets
などを指定して渡します。
こんな形で、色々な箇所で実施される共通処理を Reusable workflows として切り出すことが可能です。
Reusable workflows は以前から有った機能ですが、2023年(2022年12月〜)のトピックとしては 「別の Private Repository に置かれている workflow も呼び出すことができる」 ようになったことが利便性の向上という意味で大きな点かなと思います。
Composite action とは?
直訳すると「複合アクション」となります。複数の step からなる処理を切り出して、再利用可能な形にした Action です。
Reusable workflows と同様、 別の private repository に置かれている Actions を呼び出すことができる ようになっています。このドキュメントはその状況を前提に記載をします。
なお、Reusable workflows と Composite action の違いは以下のようにまとめられると思います。
- Reusable workflows: workflow の処理を切り出して再利用化できる。
- Composite action: 複数の step の処理を切り出して再利用化できる。
Composite action の設定
Github Actions ファイル
Actions ファイルも Composite action の仕様にあわせて記述する必要があります。
- 呼び出しの定義として
runs: using:composite
の定義を必ずつける必要がある
runs:
using: composite
- Reusable workflow と異なり、Composite action は所定のディレクトリを作成し、その中に単一もしくは複数の Action 定義 yaml を設置する形になる。
- Composite action へ値を渡す時は Composite action 側で
inputs
を定義する。
inputs:
some_value:
required: true
- Reusable workflow と異なり、Composite action では secrets を指定することはできない
- その他、Composite actions の仕様については公式ドキュメントを参照ください
conventions (organization specific)
これは私の組織の固有の事情ですが、対象となる Composite action のファイルは .github/composite
配下に設置するようにしています。
その理由は、現時点で actionlint が Composite action 形式をサポートしておらず、 actionlint に読み込ませるとエラーとなってしまうためです。
.github/workflows
については actionlint の対象としたいため、その回避策として上記のような運用をしています。
記述例
terraform の環境を初期化して、plan を実行する Composite action を例に挙げます。
name: terraform-plan
description: terraform-plan
inputs:
terraform_version:
required: true
runs:
using: composite
steps:
- name: setup terraform
uses: hashicorp/setup-terraform@v2
with:
terraform_version: ${{ inputs.terraform_version }}
- name: terraform fmt
id: fmt
shell: bash
run: terraform fmt -check
- name: terraform init
id: init
shell: bash
run: terraform init
- name: terraform validate
id: validate
shell: bash
run: terraform validate -no-color
- name: terraform plan
id: plan
shell: bash
run: terraform plan -no-color
terraform をインストールした上で、以下のコマンドを実行しています。
- terraform fmt
- terraform init
- terraform validate
- terraform plan
Composite action の呼び出し
記述例
上記の terraform 関連の Composite Action を例にすると、呼び出し側では以下のような記述で呼び出しを行うことができます
- name: terraform plan
uses: (organization)/github-actions/.github/composite/terraform-plan@main
with:
terraform_version: 1.6.5
uses
に以下のようなフォーマットで呼び出す Actions ファイルを指定します。
(organization)/(repository)/.github/composite/(composite action dir)@(branch name)
大きな注意点として、Composite action に値を渡す場合は、 with
を指定して渡します。
理由としては secrets
は現時点では Composite action ではサポートされていないため、値渡しは with
のみで実現可能なためです。
現時点では、社内ではそこまでセキュアな値をやり取りする要件に遭遇してはいませんが、上記の仕様を嫌って Composite Action を採用しない、という選択肢も実際のところはありえるかなと感じます。
Discussion