🐱

[github actions] Reusable workflowsが実装されたのでざっとまとめ

2021/11/25に公開

追記
年末にこの記事の内容も含めてgithub actionsをどう再利用するか総まとめしたのでそちらも併せてどうぞ!↓↓↓
https://zenn.dev/jerome/articles/cc07ad73e017ad

この記事について

2021/11/24についにgithub actionsにReusable workflowsが実装されました。

まずは簡単にドキュメントをさらいながらポイントをまとめていこうと思います。

そもそも何が嬉しいのか

これまでのgithub actionsではworkflowからactionを呼ぶことは可能だったものの、workflowから別のworkflowを呼ぶことはできませんでした。

workflowがひとつだけの場合そう問題にはならないのですが、同じworkflowの記述を使い回したい場合にはこれが問題になっていました。

例えば下記のようなworkflowを複数のリポジトリで使う場合、actions/checkout@v2actions/setup-node@v2の順序や利用するバージョン、引数などが同じであっても、各リポジトリでそれぞれ記述するしかありませんでした。
もし利用するバージョンに変更がありそれを全てのリポジトリに反映したい場合は、全てのリポジトリに対して横展開のPRを出す必要がありとても煩雑になっていたと思います。

example.yaml
jobs:
  example:
    name: example job
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - name: Use Node.js 14.x
        uses: actions/setup-node@v2
        with:
          node-version: 14.x
          registry-url: "xxxxxxxxx"
          scope: "@xxxxxxxxxx"
      ...

今回の実装でworkflowレベルで共通化できるようになり、一括管理しやすくなったというのが嬉しいポイントでした。

ドキュメントをざっとまとめていく

気になった点をまとめていきます。下記のドキュメントに見出しを揃えているので、気になった方は深掘りしてみてください。
https://docs.github.com/en/actions/learn-github-actions/reusing-workflows

Overview

  • 呼び出す側のworkflowをcaller workflow、呼ばれる側をcalled workflowと呼びます。
  • called workflowcaller workflowのcontextで処理されるため、例えcalled workflowactions/checkoutactionを使っていたとしても、checkoutされるのはcaller workflowのあるリポジトリです。
  • 同様にcalled workflowの中であってもcaller workflowgithubのcontextが引き継がれるので、secrets.GITHUB_TOKENを引き回して使うことができます。
  • 一方でcaller workflowenvを引き継いで使うことはできないので注意が必要そうです。
  • called workflowは必ずworkflow_callonに記述する必要があります。

envの扱いは意識しないとハマりそうかなと思いました。

Access to reusable workflows

  • 下記のいずれかを満たす場合のみworkflowを再利用できる
    • public repoのworkflow
    • 同じrepoのworkflow

同じリポジトリであればprivate repositoryのworkflowを呼び出せるのは嬉しいですね。

Limitations

  • called workflowから別のworkflowを呼び出すことはできません。
  • private repositoryのworkflowは同じrepositoryの中からしか呼び出すことはできません

個人的には後者が特にネックかなと感じました。private repositoryをcheckoutすれば異なるrepositoryからでもreusable workflowを使えるかどうかが気になるので、後ほど検証してみようと思います。 追記しました

Example reusable workflow

再利用されるworkflowの場合on.workflow_callを記述する必要があります。
inputsoutputs, secretsなどworkflow全体に関わる定義はon.workflow_call以下に書くようです。
jobの書き方は特段変わったところはなさそうです。(後述のoutput周りを除く)

reusable_workflow.yaml
name: Reusable workflow example

on:
  workflow_call:
    inputs:
      username:
        required: true
        type: string
    secrets:
      token:
        required: true

jobs:
  example_job:
    name: Pass input and secrets to my-action
    runs-on: ubuntu-latest
    steps:
      - uses: ./.github/actions/my-action@v1
        with:
          username: ${{ inputs.username }}
          token: ${{ secrets.token }}      

Calling a reusable workflow

actionを使うのと同じような記述ですが、steps.foo.usesに記述するのではなく、jobs.foo.usesに記述する点が異なっています。
@以下に使用するバージョンやbranch, commit hashを記述する点や、withに引数を渡すのはaction同様です。

caller_workflow.yaml
name: Call a reusable workflow

on:
  pull_request:
    branches:
      - main

jobs:
  call-workflow:
    uses: octo-org/example-repo/.github/workflows/workflow-A.yml@v1

  call-workflow-passing-data:
    uses: octo-org/example-repo/.github/workflows/workflow-B.yml@main
    with:
      username: mona
    secrets:
      token: ${{ secrets.TOKEN }}

Using outputs from a reusable workflow

reusable workflowから戻り値を得たい場合、
stepのoutput -> jobのoutput -> workflowのoutput
と伝達していく仕組みのようです。

output.yaml
name: Reusable workflow

on:
  workflow_call:
    # Map the workflow outputs to job outputs
    outputs:
      firstword:
        description: "The first output string"
        value: ${{ jobs.example_job.outputs.output1 }}
      secondword:
        description: "The second output string"
        value: ${{ jobs.example_job.outputs.output2 }}  
  
jobs:
  example_job:
    name: Generate output
    runs-on: ubuntu-latest   
    # Map the job outputs to step outputs
    outputs:
      output1: ${{ steps.step1.outputs.firstword }}
      output2: ${{ steps.step2.outputs.secondword }}
    steps:
      - id: step1
        run: echo "::set-output name=firstword::hello"
      - id: step2
        run: echo "::set-output name=secondword::world"

まとめ

  • reusable workflowでより簡単にworkflowを記述できるようになりそうです
  • private repositoryのreusable workflowを(なんとかして)他のrepositoryで使えないかとても気になりました 追記しました

追記 private repositoryのReusable workflowの使用について

actionと同じようにcheckoutして再利用できるか試してみましたがダメでした。

下記のエラーメッセージ的にかなり意図した動きのように見えたので、現時点では利用できないように思えました。(リポジトリ名は適当に置き換えてます)

error parsing called workflow "xxxx": Workflows in 'xxxx' cannot access remote workflows in 'xxxx'. See https://docs.github.com/en/actions/learn-github-actions/reusing-workflows#access-to-reusable-workflows for more information.

Discussion