Github Actions:inputsの共通化
Github Actions、便利で好きです。
でもドキュメントの分類が理解できておらず、ちょっとすぐに全容が把握できないことがあります。
今回はworkflowを外部からkickしたりするときに使える、inputsの共通化をトライしたのでメモしておきます。
workflowのinputsとは
今回触るのはjobやstepのinputsではなく、workflowのinputsです。
inputsという名前で入力を設定できるtriggerは、現状二つだけです。
-
workflow_dispatch
- 主に手動実行用
- API経由でも実行できる。
- 有効なトークンが必要
- PAT(personal access token)など
-
workflow_call
- 再利用可能なworkflow
- jobs.<job_id>.uses句で指定する。
- stepのusesでは使えない。
- リポジトリ跨ぎも可能
- private repoは同一org/enpのprivate限定
- 要設定
- private repoは同一org/enpのprivate限定
1. workflow_dispath.inputs
Actions画面で手動実行可能なUIを追加するためのトリガーです。
inputsに一番細やかな指定でき、型指定・チェックも可能です。
API経由でもある程度validationされているみたいです。
注意点
- 一つのworkflowに10個まで
- 入力の最大ペイロードは 65,535 文字。
- 型は
boolean
,choice
,number
,environment
,string
の5つ。 - choice型やenvironment型はアクセス時には文字列
また、ややこしいことに、workflow_dispatchトリガーではinputsのアクセス方法がふたつあり、若干の違いがあるようです。
-
${{ github.events.inputs.xxx }}
- 昔からある。
-
${{ inputs.xxx }}
- 後で追加された
- booleanが文字列に変換されない
基本的にinputs.xxx経由でアクセスする方が良いと思います。
例
設定ファイル
on:
workflow_dispatch:
inputs:
logLevel:
description: 'Log level'
required: true
default: 'warning'
type: choice
options:
- info
- warning
- debug
tags:
description: 'Test scenario tags'
required: false
type: boolean
environment:
description: 'Environment to run tests against'
type: environment
required: true
jobs:
log-the-inputs:
runs-on: ubuntu-latest
steps:
- name: access by env
run: |
echo "Log level: $LEVEL"
echo "Tags: $TAGS"
echo "Environment: $ENVIRONMENT"
env:
LEVEL: ${{ inputs.logLevel }}
TAGS: ${{ inputs.tags }}
ENVIRONMENT: ${{ inputs.environment }}
- name: access by inputs
if: inputs.tags # boolはbool
run: |
echo "Log level: ${{ inputs.logLevel }}"
echo "Tags: ${{ inputs.tags }}"
echo "Environment: ${{ inputs.environment }}"
- name: access by github.event.input
if: github.event.inputs.tags == 'true' # boolも文字列
run: |
echo "Log level: ${{ github.event.inputs.logLevel }}"
echo "Tags: ${{ github.event.inputs.tags }}"
echo "Environment: ${{ github.event.inputs.environment }}"
トリガー方法
GUI
https://github.com/wasnot/gh-actions-test/actions/workflows/manual.yml
のような、workflowのURLにアクセスすると、GUI経由で実行できます。
ブランチの指定が可能です。
typeに応じてUIが変更されます。
API
curlでリクエストすることも可能です。
curl -L \
-X POST \
-H "Accept: application/vnd.github+json" \
-H "Authorization: Bearer <YOUR-TOKEN>" \
-H "X-GitHub-Api-Version: 2022-11-28" \
https://api.github.com/repos/OWNER/REPO/actions/workflows/WORKFLOW_ID/dispatches \
-d '{"ref":"main","inputs":{"logLevel":"info","tags":true,"environment":"production"}}'
workflow
github-scriptのactionを使うことで、他のworkflowからリクエストすることもできます。
jobs:
kick_workflow:
runs-on: ubuntu-latest
steps:
- uses: actions/github-script@v7
with:
github-token: ${{ secrets.TOKEN }}
script: |
await github.rest.actions.createWorkflowDispatch({
owner: 'OWNER',
repo: 'REPO',
workflow_id: 'WORKFLOW_ID',
ref: 'main',
inputs: {
logLevel: 'warning',
tags: true,
environment: "production",
},
})
2. workflow_call.inputs
次に、再利用可能なworkflowを使用するときにwith句で渡すことができるinputsについてです。
inputsに型指定ができ、チェックもされます。
ただし使用できる型数はworkflow_dispatchよりも少ないです。
注意点
- 型指定は必須で、指定できる型は
boolean
,number
,string
の3つ。 - デフォルトのパラメータが設定されていない場合、入力のデフォルト値は、ブール値の場合は false、数値の場合は 0、文字列の場合は "" です。
- コンテキスト変数として参照できるので、 コンテキストにアクセスできないところでは使用できない
- 呼び出し元のワークフローが、呼び出されたワークフローで指定されていない入力を渡すと、エラーが発生します。
inputsのアクセス方法はinputs.xxxのみです。
例
設定ファイル
on:
workflow_call:
inputs:
logLevel:
description: "Log level"
required: true
default: "warning"
type: string
tags:
description: "Test scenario tags"
required: false
type: boolean
environment:
description: "Environment to run tests against"
type: string
required: true
jobs:
log-the-inputs:
runs-on: ubuntu-latest
steps:
- name: access by env
run: |
echo "Log level: $LEVEL"
echo "Tags: $TAGS"
echo "Environment: $ENVIRONMENT"
env:
LEVEL: ${{ inputs.logLevel }}
TAGS: ${{ inputs.tags }}
ENVIRONMENT: ${{ inputs.environment }}
- name: access by inputs
if: inputs.tags # boolはbool
run: |
echo "Log level: ${{ inputs.logLevel }}"
echo "Tags: ${{ inputs.tags }}"
echo "Environment: ${{ inputs.environment }}"
- name: access by github.event.input # これは使えない
run: |
echo "Log level: ${{ github.event.inputs.logLevel }}"
echo "Tags: ${{ github.event.inputs.tags }}"
echo "Environment: ${{ github.event.inputs.environment }}"
トリガー方法
workflowファイルからjobs.<job_id>.uses
句で指定して使用します。
jobs.<job_id>.steps[*].uses
では使えません。
on:
workflow_dispatch:
jobs:
kick_reusable:
uses: ./.github/workflows/reusable.yml
with:
logLevel: debug
tags: true
environment: development
番外編: repository_dispatch
workflow_dispatchと同じようにAPIでトリガーできるイベントに、repository_dispatchがあります。
違いはいろいろありますが、下記記事が参考になります。
inputs変数は使えませんが、API経由でpayloadを受け取ることで、似たような役割を果たすことができます。
ただし、変数定義ができないので、型チェックもされません。
なので、そこを気をつければ問題ないかと思います。
受け取った変数は、jsonがオブジェクトにマッピングされ、コンテキスト変数${{github.event.client_payload}}として展開されるので、便利ではあります。
自分はworkflow_dispatchとの違いをみてこちらの使い所がわからなかったので、実運用では使っていません。
もしかしたらハマりポイントが他にもあるかもしれないです。
例
設定ファイル
on:
repository_dispatch:
types: [test_trigger]
jobs:
log-the-inputs:
runs-on: ubuntu-latest
steps:
- name: access by env
run: |
echo "Log level: $LEVEL"
echo "Tags: $TAGS"
echo "Environment: $ENVIRONMENT"
env:
LEVEL: ${{ github.event.client_payload.logLevel }}
TAGS: ${{ github.event.client_payload.tags }}
ENVIRONMENT: ${{ github.event.client_payload.environment }}
- name: access by inputs # これは使えない
if: inputs.tags
run: |
echo "Log level: ${{ inputs.logLevel }}"
echo "Tags: ${{ inputs.tags }}"
echo "Environment: ${{ inputs.environment }}"
- name: access by github.event.client_payload
if: github.event.client_payload.tags # boolはbool
run: |
echo "Log level: ${{ github.event.client_payload.logLevel }}"
echo "Tags: ${{ github.event.client_payload.tags }}"
echo "Environment: ${{ github.event.client_payload.environment }}"
トリガー方法
APIリクエストすることで可能です。
curl -L \
-X POST \
-H "Accept: application/vnd.github+json" \
-H "Authorization: Bearer <YOUR-TOKEN>" \
-H "X-GitHub-Api-Version: 2022-11-28" \
https://api.github.com/repos/OWNER/REPO/dispatches \
-d '{"event_type":"test_trigger","client_payload":{"logLevel":"debug","tags":true,"environment":"staging"}}'
他のワークフローからhookするなども想定されていそうです。
他のトリガーと併用する
inputsを使えるトリガーのみをworkflowのtriggerに指定している場合は、inputs経由でアクセスすれば注意することはあまりありません。
pushやschedule等、他のtriggerも同じworkflowで併用したい場合は、少し注意が必要です。
なぜなら、他のトリガー経由では、inputs.xxxへのアクセスできず、無指定時には型指定にかかわらず必ず空となるからです。
なので、同一のタスクを他のトリガーでも実行したい場合は、下記のどちらかの対応が必要です。
- workflowを分けて、トリガーする
- workflow_callもworkflow_dispatchも可能
- 同期的にやりたいならworkflow_callがおすすめ
- inputs.xxxがないときにデフォルト値を使う
- 使用箇所によってはできないケースもある
workflowを分けるのは簡単なので、ここではデフォルト値を使うケースのみを少し紹介します。
その他のトリガーでデフォルト値を使いたい場合
その他のトリガーの際に、inputs.xxxは型定義が無視されて空オブジェクトが挿入されます。
文字列なら空文字チェックすればいいのですが、数値やbool値だと誤判定になりやすいので、一度文字列に変換すると楽な場合があります。
ここでは環境変数を経由するパターンを紹介します。
環境変数を経由するパターン
例えば、scheduleトリガーとworkflow_dispatchトリガーを使いたい場合、下記のように環境変数を経由すると、scheduleの場合はデフォルト値で、手動実行の場合は実行時のinputsを使うことが可能です。
on:
schedule:
- cron: '0 0 1 * *'
workflow_call:
inputs:
logLevel:
description: 'Log level'
required: true
default: 'warning'
type: choice
options:
- info
- warning
- debug
tags:
description: 'Test scenario tags'
required: false
type: boolean
env:
# schedule実行時の値を入れるため、envを介する.
LOG_LEVEL: ${{ github.event_name == 'schedule' && 'info' || inputs.logLevel }}
TAGS: ${{ github.event_name == 'schedule' && 'false' || inputs.tags }}
jobs:
test_job:
runs-on: ubuntu-latest
steps:
- name: run if tags is true
if: ${{ env.TAGS != 'true' }}
run: echo "$LOG_LEVEL"
この方法の注意点として、inputsは型指定が可能なのに対し、環境変数は文字列しか扱えないので、workflow_dispatchでbooleanが渡ってきた時の処理を考慮する必要があります。
上の例ではif文でtrue
という文字列と一致するかを常に確認しています。
空文字を許容している場合は、気をつけてください。
(自分は結構ハマりました。)
また、コンテキスト変数は、jobs.<job_id>.if等では使えなかったりするので、トリガーが異なる時にjobを切り替えるとかはできないことがあります。
なので、おすすめとしては、普通にworkflowを分ける方法がいいと思います。
まとめ
最後に余計な例をつけましたが、なるべく一つのworkflowに複数triggerを設定せず、workflowを分割するのがいいです。
workflow_callを定義すれば、他のworkflowから簡単に実行できます。
どうしても一緒にしたい場合は、環境変数を経由するのがおすすめです。
ただし、型情報が欠損するので、その点だけ注意しておくといいかなと思いました。
以上です。
参考
- https://docs.github.com/en/actions/learn-github-actions/contexts
- https://docs.github.com/en/actions/learn-github-actions/expressions
- https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions
- https://docs.github.com/en/actions/using-workflows/reusing-workflows
- https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows
- https://stackoverflow.com/questions/72539900/schedule-trigger-github-action-workflow-with-input-parameters
Discussion