そういや今年こんなことをやりましたということで一つ
https://github.com/Pctg-x8/peridot では、GitHub Actionsを使用してCI/CDを組んでいます。元はTravis CIを使用していたんですが、ジョブ構成の柔軟さやCI以外の手順自動化に使えそうという点から今年の3月1に一気に移行しました。
そこで、Travis CI時代から使用しているCI結果のSlack通知もActionsに移植しまして、今現在ではこんな感じのAttachmentがついたメッセージが届くようになっています。
このAttachmentの本文には、エラーとなったジョブのコンソール出力の末尾20行が入っています。
この記事では、この出力を混ぜ込むまでにやったことを解説します。
要件と使えそうなコマンド
この機能の要件としては以下の通りです。
- rustcのエラーメッセージの最後の数行をAttachmentに取り込みたい
- ただし、Actionsの画面でもリアルタイムにメッセージが流れた方が楽しいので、メッセージの出力をブロックしたくはない
出力をブロックせずにコンソールの出力をとるとなると使えるのは tee
くらいですかね。
というわけで、teeで出力をしれっと横取りして何らかの形で通知アクションに引き渡せればOKとなります。
といったことを https://github.com/Pctg-x8/peridot/blob/4f59042a29cda434354e8e3f76c303719e90a337/.github/workflows/integrity-test.yml#L76 のあたりでやっています。
...人が書いたyamlファイルのように見えないですか?
そう思った人はすごく鋭くて、PeridotではGitHub Actionsのワークフローファイルを記述するのに Dhall
という別の設定記述言語を使用しています。
詳しい説明は省きますが、500行近いyamlはもはや人間が書くような物ではないので、より高級かつ型安全なDhallを使用するとワークフローの記述でかなり幸せになれます。
オフィシャルなDhallの型定義は存在しませんが、今回のワークフローを書くためにある程度の物を用意したので、よろしければ参考にしてください。
https://github.com/Pctg-x8/gha-schemas
Stepの出力を他Stepに渡す
Stepの出力を他のStepから参照するには、一般的にはGitHub Actionsに備え付けの機能で行えます。
https://docs.github.com/ja/free-pro-team@latest/actions/creating-actions/metadata-syntax-for-github-actions#outputs
一般的にはこれで行えますが、今回はteeで拾ったものを渡す形になります。teeの出力はファイルになっているため steps.<step id>.outputs
を使って内容を渡すことはできません。
そこで、今回はSlack通知Actionで直接teeの出力ファイルを読む形にしました。
PeridotのSlack通知Actionは、個人の他のリポジトリでも使用したいためリポジトリが分けられています。
https://github.com/Pctg-x8/ci-notifications-post-invoker
このアクションはあまり汎用的には作っていないため2Marketplaceには出していませんが、Marketplaceに出さなくてもgitリポジトリのレベルでこういった機能の共有を行うことができるのはActionsの強い利点だと思います。
このリポジトリのREADMEを読めばわかると思いますが、 .buildlog
および .rawbuildlog
といったファイルを $GITHUB_WORKSPACE
に配置することで、その内容をAttachmentの本文として埋め込むようになっています。ファイルが二つ分かれているのは、ファイルの中身をコードブロックにするか否かを簡単に切り分けるためです。
Slack通知Actionについて
このSlack通知ActionはTypeScriptで書かれています。
GitHub ActionsではアクションのランナーとしてDockerかJavaScript(Node.js 10/12系)を使用することができます。Dockerにすると適切なイメージを選択することで任意の言語を使用することができるのですが、Dockerの場合は初回のイメージビルドに時間がかかるのと、今回のように「Payloadを用意してAPIを叩く」だけであればJavaScript(TypeScript)でも全然問題ないのでJavaScriptランナーを選択しました。
TypeScriptはそのままではActionとして動かすことはできないので、JavaScriptにトランスパイルしてからpushしています。本来であればGit Hooksとか導入してコミット時 or push時に自動でトランスパイルできると大変良いのですが、準備がちょっと面倒なので今は yarn build
でトランスパイルできるようにして、必要なタイミングでコマンドを発行する形にしています。
おしまい
かなりざっくりなお話ですが、Slack通知にコンソール出力を混ぜるのは以上が全部となります。
Actionsは実際触っててかなり楽しくて、workflow_dispatchとかを組み合わせれば簡易的なLambdaやCloud FunctionsみたいなこともできてChatOpsとの相性も抜群だと思います。
teeで出力を拾うためにいろいろビルドスクリプトで苦労したお話もあるんですが、あまり覚えていないのとGitHub Actionsの話からは逸れるのでここでは割愛します。
-
内部で呼び出しているプライベートのLambda関数の仕様に激しく依存しているので、そもそも汎用的に作れないです...... ↩