BEACHSIDE BLOG

Azure と GitHub と C# が好きなエンジニアの個人メモ ( ・ㅂ・)و ̑̑

GitHub Actions の composite action で YAML を再利用する (2021年9月版)

GitHub Actions では、共通化したい処理を composite action として YAML に書いておき、composite action を自身の workflow から呼び出すことで再利用することができます。

Composite action (composite run steps と書かれていることもあり) は昨年くらいからあったけどイマイチでした。2021年の8月のアップデートで実用的になったと思ってます。以前にさらっと見ていまいちって思ってる方はこの機能自体を見直す価値ありです(←このブログに価値があるかはさておき)

Azure Pipelines を使ったことがある方向けにいうと template 機能に似た機能です。Azure Pipelines の template については昔ブログで触れましたので興味があればご参照ください。

プロダクション運用するシステムなら、例えば Azure の Functions や Web Apps を複数使ってる時点で GitHub Actions も冗長なコードになるので共通化できるのは運用的に良きです。

Composite action 自体のざっくりな概要なら以下の公式ブログを見るのが良いです。

github.blog

今回のブログでは、9月に composite action を色々試しまくっておかしな挙動に遭遇したり (多分バグ) で心折れるくらい actions を動かし気づいたことの一部をメモしておきます。

ここで書かなかったダークサイドは、改善されるのを待ちながら非公開ブログにそっとしまっています。

composite action を書いてみる

まずは composite action、つまり共通化したい処理の部分を書いてみましょう。

composite action のサンプル

雑な例として "hello-action2"という composite action を作るときは、repo の任意の場所で "hello-action2" フォルダとその直下に action.yml を置きます。今回は以下のように "hello-action2" フォルダをおきましたがどこでも大丈夫です。

./.github/workflows/composite/hello-action2/action.yml

action.yml の中身はこんな感じにしました。

name: "Hello Action 2"
description: "Greet someone"
inputs:
  name:
    description: "Who to greet"
    required: true
    default: "World"
outputs:
  random-number:
    description: "Random number"
    value: ${{ steps.random-number-generator.outputs.random-id }}
runs:
  using: "composite"
  steps:
    - run: echo Hello ${{ inputs.name }} v1.0 !!
      shell: bash
    - id: random-number-generator
      run: echo "::set-output name=random-id::$(echo $RANDOM)"
      shell: bash

Azure Functions のデプロイを共通化したいなら必要な変数を inputs で受け取ってここで利用するって感じですね。そのとき何かの出力結果を返したいなら outputs を使う感じです。

一応 GitHub の画面キャプチャも貼っておくとこんな感じ。

f:id:beachside:20210924155911p:plain

大して難しい内容はないですが、構文についてちょっとだけ補足しておきます。

inputs

inputs は、見た目通りですが引数が欲しいときに設定できるやつです。default でデフォルト値を設定したり、required で入力必須かを設定できます。この inputs 自体の syntax は composite action に限ったものではなく GitHub Actions の Metadata syntax になります。

各 input はここではケバブケースで定義しました。GitHub Actions の marketplace に出てるソースコードをみると、パスカルケースのサンプルとケバブケースのサンプルが散見されていますのでどっちでもって感じはあります。運用時は開発チームで命名規約を決めて統一しておいた方がいいかなって感じです。

あと、あまり触れたくない点のひとつですが... requiredtrue にすることで呼び出し側でその input を指定しないとエラーになる気がしてましたが、私が試した時点では何も指定しなくてもエラーにならないので注意しましょう...

runs

前述のサンプルに書いた通り runsusing には "composite" を指定する必要あります。これで composite action として動作します。

あとは steps の中に step を書いてくだけとなります。ポイントをいくつか挙げておくと、

  • もちろん Marketplace に公開されている action も呼ぶことができます (一昔前はできなかったやつ)。
  • 現時点では、steps の中で run を使う際は必ず shell を指定する必要があります。defaults の設定はできないので毎回書くのはちょっと面倒と感じたり...
  • 以下のような | を使った multi line でのコマンドも実行もできないってのも注意ですね。
# "|" を使うと syntax error になる
run: |
  echo hello
  echo world

Composite action の呼び出し方

Composite action を呼び出すのは workflow template と同じ感じかなと思ったら微妙に異なるので気になる点をメモししました。

同一 repo 内の composite action を呼ぶ場合

Composite action 自体と Composite action を呼び出す側の workflow が同一の repo にあるときの呼び出す際のポイントは以下です。

  • 相対パスで composite action を指定します。具体的な書き方は後述します。
  • バージョンの指定は不要 (逆にいうと指定できない、指定するとエラーになる)
  • 呼ぶ前に actions/checkout が必要。action 呼び出すために checkout 書く必要があるのは個人的にかなりうざい (←例えば deploy 専用の job とか artifacts の download だけですむ job で、checkout がいることになるとか)。

今回のサンプルだと ./.github/workflows/composite/hello-action2/action.yml においてるので、こんな感じに呼び出せます。相対パスだから先頭の ./ が無くても呼べそうな気がしますが無いとエラーになります。

 # steps の中の想定で以下のように書く 
       # 相対パスで composite action を呼ぶなら  checkout が必要
      - uses: actions/checkout@v2
      - id: hello2
        uses: ./.github/workflows/composite/hello-action2
        with:
          name: 'AY'
          num-octocats: 3
      # output の呼び出しはこんな感じ
      - run: echo hello2 random-number ${{ steps.hello2.outputs.random-number }}

inputs の値の設定方法は普通に with で指定して呼びます。

外部の repo の composite action を呼ぶ場合

Composite action 自体と Composite action を呼び出す側の workflow が別々の repo にあるときの呼び出し方のポイントは以下です。とは書きましたが同一の場合でもこの書き方が可能です。ただし呼び出す際のポイントが以下に示すように同一 repo の時と異なります。異なる点を加味してどっちで書くか選択する感じでしょうかね。

  • フルパスっぽい書き方?を指定すればよいです。具体的な指定方法は後述します。
  • composite action を呼ぶ前に actions/checkout は不要。
  • 外部の repo は"基本的"に public である必要がある。(同一 repo の場合は internal/private でも OK)
  • バージョンの指定が必須。Marketplace の action でのバージョン指定方法と一緒。

composite action の指定方法は、例えば呼びたい composite action が前述のサンプルのように "beachside-project" の "github-actions-sandbox" repo にあり、./.github/workflows/composite/hello-action2/action.yml を使いたいなら以下のように呼びます。

 # steps の中の想定で以下のように書く
      # checkout 不要♪
      - name: hello 2
        uses: beachside-project/github-actions-sandbox/.github/workflows/composite/hello-action2@main
        with:
          name: 'AY'

バージョンの指定について、上記ではブランチを指定してますが、以下リンクに書かれてる通りtag でつけたバージョンやブランチ名、コミットハッシュが指定できる。ここら辺は Actions 全体的な話でドキュメントがまとまって探しにくいところって印象ありますね。

ポイントにあげましたが、自分自身の repo 内にある composite action も上記のように指定して呼ぶことができます。そうすると checkout が不要にはなるけど version の指定が必須になります。何が面倒って、composite action の変更があった際の pull request では変更した repo を指定しつつ、その後もう一度 main ブランチ指定の PR を出す?とかコミットハッシュを指定してあげる(それはそれで変更頻度が少ないなら管理的に見通しが悪そう) とかで悩ましいです。

現時点で Composite action を呼べないパターン

  • 外部の private repo の composite action は呼べないでです。private repo でもその同一 repo の composite action なら前述の2通りの呼び方どちらでも呼び出せます。自分自身なら普通に見えるってやつですね。
  • GitHub Enterprise で Organization を使っていれば同一 organization の internal の repo の action は参照できるかなーと思ったらできませんでした。これは呼べるようになってほしいところ。

まとめ

なんか気にしなくていいことをグダグダ書いてまとまりのないブログになりました..ぐぬぬ。

今回いろんなことしたので 1 - 2min/1回 程度のGitHub Actions の実行時間が700 minを超え、Actions の storage は容量オーバーになりその数字だけ見ると頑張った感はありました 。色々トラブっただけなので成果や生産性がいいとは言えない.....。

(スクショを張ろうと思ったらもうリセットされてた...

あ、ここら辺の確認方法はまた別のブログで紹介しようと思います。