GitHub Actions のローカル実行ツール(nektos/act)を便利にする gh extension を作った
gh-act をリリースしました
まだ開発途中ではありますがとりあえず v0.1 をリリースしました。
gh をインストール済みであれば、 gh extension install srz-zumix/gh-act
でインストールできます。
使い方は README にも一応書いてありますが、この記事でも後述します。
その前にそもそも nektos/act とは?から説明します。
nektos/act とは?
GitHub Actions の Workflow をローカル実行するツールです。
GitHub 公式のツールではなく、イベントをエミュレートしています。
手軽に Workflow をローカル実行できるのでワークフローをデバッグしたいときにはとても便利です。
ただし、このツールでは本家と完全に同じ環境・状態では実行できません。
act の注意点
雪猫 さんが act について書いているのでそちらも参考にしてください。
GitHub Actions のデバッグをローカルで行う
あと個人ブログにも act の記事を投稿しました。こちらもよろしければ是非。
ブログズミ: nektos/act で GitHub Actions のワークフローをローカル実行
- 実行環境
- act が使用する Docker image に依存
- https://github.com/nektos/act#runners
-
act が提供するイメージは
ubuntu
のみサポート - Medium だと hosted runner と比べてインストール済みパッケージが少ない
- Large だと image サイズが大きい (image is extremely big, 20GB compressed, ~60GB extracted)
- 利用用途別にある程度 image は用意されている
- 任意のイメージを使うこともできるが runner の環境としてある程度整っている必要がある
- サービスコンテナは使えません
-
services
の内容は無視される
-
- act が使用する Docker image に依存
- secrets.GITHUB_TOKEN が未定義
- https://github.com/nektos/act#github_token
-
act -s GITHUB_TOKEN=<token>
のように-s
オプションで設定が必要
-
github コンテキストの event の中身がほぼ空っぽ
- https://github.com/nektos/act#events
- github.event.* を参照しているワークフローは失敗する可能性がある
-
act pull_request -e pull-request.json
のように-e
オプションで event の JSON をセットできる
- 挙動が本家と同じとは限らない
- 環境や機能はもちろんのこと、挙動に関してもエミュレートなので全く同じではない
-
ACT
環境変数が定義されている- この環境変数の有無で処理分け可能(e.g.
if: ${{ env.ACT }}
) - これにより本家でも act でも実行可能なワークフローを記述可能ではある
- しかし、当然ながら本家との差分が大きくなるため、本末転倒な感じ
- この環境変数の有無で処理分け可能(e.g.
この中でも特に GITHUB_TOKEN と event JSON を設定するのが面倒くさいです。
そこで gh-act を書きました。
gh-act ができること
secrets.GITHUB_TOKEN の自動設定
GITHUB_TOKEN / GH_TOKEN / GH_ENTERPRISE_TOKEN が定義されていれば、gh-act が -s
オプションをセットします。
環境変数が定義されていない場合、 gh のコンフィグディレクトリにある hosts.yml
から TOKEN を取得してセットします。
gh 使っているのであればおそらく auth login 状態だと思うので、オプション指定を書く必要なく TOKEN が設定される想定です。
event JSON の生成
gh act pull_request
のように指定されたトリガーイベントに沿った event JSON を gh-act が生成します。JSON の内容はローカルリポジトリの状態を参照して設定されます。
gh act pull_request -e pull_request.json
のように -e
オプションでパスが指定された場合は、そのパスが存在すれば gh-act は何もせずにそのファイルが使用されます。
そのパスが存在しない場合は gh-act が生成し、指定されたパスに保存します。
つまり pull_request.json
が存在しなかった場合、1回目の実行でファイルが作成され act が実行。2回目以降は最初に生成したファイルを使用して act が実行されます。
gh-act が生成する event JSON も本家とは全く同じではありません。
なにもしなくても大抵のケースはカバーできる気はしてますが、不備不足があれば都合が良い JSON に書き換えて使ってください。
それでも 0 から作成したり、他のワークフローの実行結果からコピペやダウンロードしたりするよりかは楽になると思います。
また、event JSON 生成する際に参照する PR 番号とかを指定できるようにもしてます。
gh-act が対応している event や環境変数の詳細は README を確認してください。
act vs gh-act
参考までに act と gh-act で実行したときの差分を画像を貼っておきます。
左が act 、右が gh-act です。
実行したワークフローはこちら
こちらはコンテキストをダンプするワークフローになっており、スクリーンショットは ${{ toJson(github) }}
をダンプしているところです。小さくてわかりにくいですが、 act の方は event が空なのに対し、gh-act の方は中身があることがわかると思います。この部分を gh-act が生成してます。
gh-act の注意点
- gh-act が生成する event JSON は本家のもとは完全一致ではない
- event 中の action の type によって中身が変わるものに未対応
- value の記述が若干違ったりする場合がある(時刻と null とか)
- 固定値しか入ってないものがある
- いくつかの event は gh-act のリポジトリで実行した差分を出してるので参考までに
https://github.com/srz-zumix/gh-act/actions/workflows/main.yml
- GitHub Actions や act の更新追従が手動
- テンプレートを自動生成しているわけじゃないので、本家の変更についていける気がしません・・
- テストもちゃんとしてるわけじゃないので、壊れても多分気付かない・・
- 筆者が gh extension 作ってみたくて書いただけなので、モチベーション依存
-
GraphQL rate limit
- 5,000ポイント/1h
- gh-act のリポジトリで検証してた際にも何回か超えることがありました
- gh-act は内部で何回か gh コマンドを実行するので最適化の余地はあるかも
- ちょっと遅い
- ちょっと遅いです
- gh コマンドの呼び出し回数が少なくなるように、と思って書いてはいますが最適化の余地はあるかも
- shell 芸じゃなくて go とかで書き直したほうがいいのかも?
- (今のところ筆者は書き直す気はありません)
-
-e
オプションで一度書き出して使うのをオススメ
最後に
要望とかあれば対応するつもりなので、なにかあれば issue なり PR なりいただければ幸いです。
Discussion