GitHub Actionsにおけるジョブ間のデータの受け渡しに関するすごく細かい疑問
事前情報
恐縮ですが私はCI/CDの素人です。データサイエンスに興味があり、そちらに軸足を置いているのですが、最近は「どれだけ高尚な技術であってもマス層が使ってくれないと意味ないんじゃない?」という考えに至り、そのインタフェースであるアプリに興味を持っています。そんな背景から個人開発を始めた関係でCI/CDを勉強し始めました。
ちなみに勉強には以下の書籍を使っています。
こちらの書籍は特定の言語に縛られないCI/CDの考え方そのものや、言語に関係ないGitHub Actionsの共通構文を扱っており、ある意味抽象化された内容になっています。特定の言語にしぼったネイティブな内容ではないので、どんな言語を使う人にも役立つように設計されていてとてもわかりやすく、おすすめです。
本題
上述した書籍を読んでいる途中なのですが、「5. 複数ジョブの実行制御」において大きく分けて2つ疑問が生じました。ただとても細かいことで、「そんなこと気にしてどうすんの?」って内容ですので、誰かの役に立つ内容でないことは事前にご了承ください。
- <key>と<output-name>は一致させる必要があるのか?
- <key>=<value>という内容をGITHUB_OUTPUTに格納したとき、なぜ<key>がキーとして機能するのか?
1. <key>と<output-name>は一致させる必要があるのか?
以下のコードにおいて"result=Hello"の左辺の変数名とoutputsのキー名はともにresultで一致しています。
# 書籍p.105 コード5.9より抜粋
steps:
- id: generate
run: echo "result=Hello" >> "${GITHUB_OUTPUT}"
outputs:
result: ${{ steps.generate.outputs.result }}
しかしこの構文を一般化すると以下のようになるそうです。
# 書籍p.105より抜粋
steps:
- id: <step-id>
run: echo "<key>=<value>" >> "${GITHUB_OUTPUT}"
outputs:
<output-name>: ${{ steps.<step-id>.outputs.<key> }}
もしGITHUB_OUTPUTへ格納される式の左辺と<output-name>が一致する必要があるなら以下のように書くんじゃないかな?と思いました。
# <output-name>-><key>に変更
steps:
- id: <step-id>
run: echo "<key>=<value>" >> "${GITHUB_OUTPUT}"
outputs:
<key>: ${{ steps.<step-id>.outputs.<key> }}
という細かすぎるポイントが気になってしまったので調べた結果、結論「keyとoutput-nameは一致しなくてもいいけど、敢えて一致させないメリットがないので揃える」ということらしいです。
具体例を挙げると以下のようにしてもエラーにはなりませんが、my_result
の中身はresult
なんですが、my_result
にアクセスするときは${{ steps.<step-id>.outputs.my_result }}
を使用することになり、ちぐはぐな状態になります。たぶんエラーやバグの発生につながってしまうんじゃないかと思います。
# 一致させない場合
steps:
- id: generate
run: echo "result=Hello" >> "${GITHUB_OUTPUT}"
outputs:
my_result: ${{ steps.generate.outputs.result }}
そう考えるとそもそも仕様として一致させるようにしておいた方がよかったのでは?と思ってしまったので、意図的に一致させないユースケースをもしご存じの方がいらっしゃいましたらぜひ教えてください。重ねて申し上げますが、筆者はCI/CD初心者ですので悪しからず。
2. <key>=<value>という内容をGITHUB_OUTPUTに格納したとき、なぜ<key>がキーとして機能するのか?
上述した内容につっかかっていたら、連鎖的にさらに疑問が生じてしまいました。echo "result=Hello" >> "${GITHUB_OUTPUT}"
の部分です。
私のイメージでは"${GITHUB_OUTPUT}"
に"result=Hello"
という式がまるごと格納されているイメージです。しかし、後段の処理で「<output-name>: ${{ steps.<step-id>.outputs.<key> }}
でしれっとに<key>と<value>の紐づけがなされた上にキーとして機能している」ことが引っ掛かりました。引っ掛かったポイントは以下の2点です。
-
"${GITHUB_OUTPUT}"
に格納されているのは"result=Hello"
という文字列でしかないこと - pythonでいうところの辞書のような形でresult:Helloならまだしも代入式でなぜkeyとvalueの関係性が構築されるのか?
結論を雑に言いますと「GitHub Actionsがいい感じに処理してくれているから」でした。
GitHub ACtionsはGITHUB_OUTPUT
に書き込まれた内容(ここではresult=Hello
)を解析し、キーと値のペアとして解釈してくれるそうです。
総括
- GitHub Actionsはすごい便利
- 自動でいい感じに処理してくれる機能がある
- まだ書籍を読み切ってないし、活用はできていないのでそのすごさの一端しか感じられていない
- 「GitHub CI/CD実践ガイド――持続可能なソフトウェア開発を支えるGitHub Actionsの設計と運用」おすすめです!
- 初心者なので当たり前のことに驚いているかもしれませんが、ご容赦ください
Discussion
同じ書籍を購入した者です。
全体的に「3.9 step間でのデータの共有(p.54)」と「Job間のデータの共有」の話が混ざっているようです。両者は別物なので違いを意識すると理解が早いかと思います。
そのうえで、こちらに関しては
一致させるかどうかは状況次第です。例えばGitHubのドキュメントの例では一致していません。
書籍のコード(p.105 コード5.9)の例に話を戻すと私の方では以下のように理解しています。
steps.generate.outputs.result
というデータをstep間で共有しているoutput
の仕組みを使ってJob間のデータ共有としてresult
というkey名でsteps.generate.outputs.result
のデータを共有しているoutputのkey名はJob内でユニークであるため以下のようなケースでは一致させることができません
step1及びstep2の両方で共通の
result
というkey名を使ってStep間のデータ共有を行い、それぞれの値をJob間のデータの共有を使って共有する場合、outputのkey名はユニークである必要があるのでどちらかはresult
以外のkey名を指定する必要がありますはじめまして、このような記事にコメントくださってありがとうございます!
まずは私のような初心者が書評などと大それたことをする意図は薄いのですが、もし本記事で気分を害されたようでしたら申し訳ございませんでした。先んじてお詫び申し上げます。
その上で内容についてです。
私の状況を総括しますと「GitHub Actionsを初めて使うので、慣例のようなものがあるのかもわからずおっかなびっくりで読んでいる」ということです。つまり、「
<key>=<value>
における<key>
と<output-name>
は一致することを強制していない意図を感じるものの、なぜ一致させないのかわからない」という感じです。単純に自分がCI/CDを使った経験値が少ないので、机上では一致させた方がわかりやすいように第一印象では感じてしまいまして、「どういう風に使いこなすのか(key名を一致させない)」のイメージがついていないのがすべての元凶です。とりあえず一致させるのが通例!みたいな断定調の部分は修正致しますね。
次にstep間のデータ共有とJob間のデータ共有についてです。
すごくわかりやすくコメントいただきありがとうございます。たぶんですが、イメージはつかめたと思います。
p.105 コード5.9をベースに考えますと、
before
JOBとafter
JOBの間でsteps.generate.outputs.result
を通じて、データのやりとりがされているのはわかります。私の疑問としましては単純に、「書籍では全て
result
という名前にそろえているけれど、データ共有に使うキー名は別に以下のように書いても問題ないのだろうか?」という一点でした。steps.generate.outputs.result
のresult
はecho "result=Hello" >> "${GITHUB_OUTPUT}"
の"result=Hello"
の左辺と紐づいているneeds.before.outputs.result
のresult
はoutputs
で設定したキーと紐づいているoutputs
で設定するキーをresult
→foo
とすればそれに連動してneeds.before.outputs.result
はneeds.before.outputs.foo
になる要は書籍のresultの統一が必須なのかどうかを知りたかった感じです。
仮に必須じゃない場合、上記のようなすごく意地悪で汚いコードで書いた方が個人的には処理を追いやすかったなあという感想文でした。
詳しい方に対して失礼に値するかもしれないと思いつつ、ビギナーも情報発信しようという気概を見せるべく疑問点を書きましたが、反応をいただけるとは思っていなかったのでとてもありがたいです!
ご返信ありがとうございます!
こちらこそ、私のコメントで不安を感じられたのであれば申し訳ありません、そのような意図は全くありませんでした🙇♂️
素晴らしい記事をありがとうございます。
コメントに記載されたコードを拝見した限りでは疑問点は解消されているように思えましたので、私のコメントが少しでもお役に立てたようでしたら幸いです🙏