tech.guitarrapc.cóm

Technical updates

GitHub Actionsのinputsを環境変数で取れるときと取れないとき

GitHub Actionsには、ワークフローの実行時に渡すパラメータを定義するinputsがあります。このinputsを使うことで外部から変数を受け取ることができます。 今回はinputsで渡した変数を環境変数として受け取れる時と受け取れない時の違いについてです。

inputsを環境変数として取得する

inputsのドキュメントに詳細がありますが、カスタムアクションを呼び出す時に指定されたinputsはカスタムアクション内で環境変数INPUT_<VARIABLE_NAME>として取得できます。例えばカスタムアクションが次のinputsを定義している場合、INPUT_NUM-OCTOCATSINPUT_OCTOCAT-EYE-COLORとして環境変数に自動登録されます。

inputs:
  num-octocats:
    description: 'Number of Octocats'
    required: false
    default: '1'
  octocat-eye-color:
    description: 'Eye color of the Octocats'
    required: true

GitHub ActionsのTypeScript SDKであるactions/toolkitはこの仕組みを利用して、core.getInputでinputsを取得できます。

When you specify an input, GitHub creates an environment variable for the input with the name INPUT_<VARIABLE_NAME>. The environment variable created converts input names to uppercase letters and replaces spaces with _ characters.

// これでinputsに対して渡された値を取得できる
core.getInputs('num-octocats')

同SDKのcore.getInputs実装はドキュメントの環境変数変換に沿った実装です。

export function getInput(name: string, options?: InputOptions): string {
  const val: string =
    process.env[`INPUT_${name.replace(/ /g, '_').toUpperCase()}`] || ''
  if (options && options.required && !val) {
    throw new Error(`Input required and not supplied: ${name}`)
  }

  if (options && options.trimWhitespace === false) {
    return val
  }

  return val.trim()
}

inputsが環境変数に自動登録される仕組みは便利です。たとえSDKがなくても、アクションで自前処理を書いたときにinputsをパラメーターとして受けらずに環境変数から取ればよくなります、ラクチン。

// C#なら
Environment.GetEnvironmentVariable("INPUT_NUM-OCTOCATS")
# Bashなら
echo ${INPUT_NUM-OCTOCATS}

inputsを環境変数からとれる場合ととれない場合

inputsコンテキストはGitHub Actions的にはいろいろなトリガーで使われます。

  • カスタムアクション (JavaScript, TypeScript)
  • カスタムアクション (Docker)
  • カスタムアクション (Composite)
  • Workflow Dispatch
  • Workflow Call

この中で、inputsを環境変数が自動登録されるのはカスタムアクション (JavaScript, TypeScript) とカスタムアクション (Docker) だけで、他のトリガーでは環境変数に変換されません。

トリガー inputsをINPUT_環境変数取得
カスタムアクション (JavaScript, TypeScript)
カスタムアクション (Docker)
カスタムアクション (Composite) ×
Workflow Dispatch ×
Workflow Call ×

CompositeアクションでINPUT_環境変数に登録されないことはドキュメントに記載されていますが、Workflow DispatchやWorkflow Callで取得できないことはドキュメントがないので注意しましょう。Composite ActionsでINPUT_環境変数がないIssueはあるのですが、Workflow CallやWorkflow Dispatchに来る日はなさそう。

If the action is written using a composite, then it will not automatically get INPUT_<VARIABLE_NAME>. With composite actions you can use inputs Accessing contextual information about workflow runs to access action inputs.

WorkfloCallやWorkflowDispatchでinputsを環境変数で取得したかった

WorkflowCallで共通化している処理をC#で書いていて、「inputsを引数ではなくSDKからならとれるの!?」と思って試して取れなかったので調べてました。core/toolkitをC#に移植したIEvangelist/dotnet-github-actions-sdkがあるのですが、ICoreService.GetInput("num-octocats")でとれない、悲しい、しょうがない。

カスタムアクション(TS/TS/Docker)に限定しているのは仕様を考えるとしょうがなさそうです。例えば、WorkflowCallからCompositeActionsを呼び出すとき、両方で同じinputstagを定義しているとしましょう。この場合、Composite ActionsのINPUTS_TAGにどの値を入れればいいか決定できないかな、と。後勝ちというルールを設けてもよさそうですが、Issueで何とかしてとかいわれるのが目に見えています。

WorkflowCallやWorkflowDispatchでinputsを使う場合は、引数で渡すか、環境変数に自前で渡すしかないです。

# 引数で渡す
run: dotnet run -- "${{ inputs.tag }}"
# 環境変数で渡す
run: dotnet run
env:
  INPUT_TAG: ${{ inputs.tag }}
# 環境変数で自分で渡すならいっそINPUTなしでもいいのでは
run: dotnet run
env:
  TAG: ${{ inputs.tag }}

それか、カスタムアクション(docker)にするか... というのはやりすぎ感じあるんですよねー。

まとめ

WorkflowCallでinputsが使われたらINPUT_で取りたかった。値の受け渡しが楽になるのになー、と思っていたらだめなのでした。無念。