タイトルの通り自作Actionを運用して3年経ったので、運用回りのあれこれを書いてみようと思います。運用というのはGitHubActionをただ使っているというだけではなく、OSSとして公開してメンテナンスも続けているという感じの意味も入ってます
いろいろと詰め込むことになると思うので、詳細書いてほしいとかあったらコメントにリクエスト書いてください
前段
初期のGitHub ActionsはHCLという記法が採用されてました。自分はその頃使っていなかったのでHCLの頃の説明を省きますが、2019年夏ごろにHCLからYAML記法に変わりました。これは内部的にAzure Pipelinesのコードを利用する形に変更された影響ですね
前年にAzure PipelinesがOSS向けに無料公開されていたということもあり、自分のCI/CD環境はAzure Pipelinesがメインでした。Azure Pipelinesでは自分用にCustomTask1を作ったりと、まぁまぁ楽しませていただきましたが、GitHub Actionsの仕様変更を聞くと「このブルーオーシャンには乗るしかねぇええ」ということでMeilCli/danger-actionを作りました。これが始まりの動機になりますね(笑)
自作ActionをOSSとして運用する
自作Actionをpublic repositoryにしておいて放置するということもできましたが、作って満足して放置するのは卒業しないといけないなぁと思っていた頃合いだったということもあり、OSSとして運用することにしました
自作Actionを運用するにあたってしなければいけないことは
- 依存ライブラリーのアップデートに追従する
- 定期的にpack2してReleaseを作成する
- IssueやPullRequestへの対応
の3つですね。使う人が少ないうちは前2つが特にコストのかかるところかなと思います
依存ライブラリーのアップデートに追従する
GitHub ActionのActionはnode.jsで動作します。自分はJavaScriptが書けないのでTypeScriptでActionを作成しています。そうなってくると、依存ライブラリーはactions/toolkitだけに収まらず、TypeScriptやeslintやjestなどなど多数のライブラリーに依存することになります
Dependabotを使うと、自動でライブラリーのアップデートを行うPullRequestを作成してくれます。ただeslintやjest周りはアップデートの頻度が高いため、真っ先に自動化の対象になりました
Workflowとしては、DependabotがPullRequestを作成する→自動でApproveする→すべてのStatusCheckが通るとマージする、の流れですね
ref:
- https://github.com/MeilCli/danger-action/blob/master/.github/workflows/ci-pr.yml
- https://github.com/MeilCli/danger-action/blob/master/.github/workflows/merge.yml
定期的にpackする
手動運用できる状態(すなわち、npm scriptにpackするコマンドがある)ならば、Master/Mainブランチへpushされるたびにpackし、差分があればPullRequestを作成するというWorkflowを作れば、常に最新の実行ファイル(.js)を用意することができます
つい最近まではPullRequestを作るところまでは自動で、手動でApproveすることによって自動でマージが行われるというフローにしていました。ただ、それも面倒なのでPullRequest作成からマージまで自動化を行っています(ちゃんと動いてくれるかは当分観察します)
ref:
- https://github.com/MeilCli/danger-action/blob/master/.github/workflows/ci-master.yml
- https://github.com/MeilCli/danger-action/blob/master/.github/workflows/ci-pr.yml
定期的にリリースを作成する
ActionをWorkflowで利用するには、uses: owner/repository@branch_or_tag_or_commit
のような形で指定します。Master/Mainブランチで開発を行うならば、別のブランチやタグをStableVersionとする必要がありますね
一方で、定期的にリリースするには自動でバージョン情報が更新される仕組みが欲しいです
諸所の運用を自動で行いたい願望が出たので、諸所をいい感じにやってくれるActionを自作しました。そのため、MeilCliが作成しているActionはすべてMeilCli/bump-release-actionによる自動リリースを行っています
このActionを使うと
- Commit messageやPullRequestのラベルからメジャー・マイナー・パッチアプデを算出し、最新のリリースから次のバージョンを決定
- Commit messageやPullRequestからリリースノート作成
- リリースの作成
-
v1
,v1.1
のようなバージョンブランチの作成・プッシュ - ファイルに書かれているバージョン情報を書き換え
をやってくれます。Action用に作成したActionですが、使い方次第ではライブラリーやアプリのバージョンアップフローにも使えると思います
ref:
- https://github.com/MeilCli/danger-action/blob/master/.github/workflows/release.yml
- https://github.com/MeilCli/danger-action/blob/master/.github/bump.yml
IssueやPullRequestへの対応
DependabotのPullRequestを放置せずにちゃんとアップデートしていると、だんだん使ってくれる人が増え、IssueやPullRequestが作られたりし始めました
IssueはIssueTemplateを用意し、PullRequestはCONTRIBUTING.mdを用意しています
ref:
- https://github.com/MeilCli/danger-action/tree/master/.github/ISSUE_TEMPLATE
- https://github.com/MeilCli/danger-action/blob/master/.github/CONTRIBUTING.md
ただ、eslintやprettierでコードフォーマットしているので、PullRequestではちゃんとコードフォーマットした状態にしてほしいところではあります。コードレビュー用のbotやactionはいろいろありますが、ちょっとした野望もあり、自分は自作のMeilCli/common-lint-reporterを使っています
ref:
- https://github.com/MeilCli/danger-action/blob/master/.github/workflows/ci-base-build.yml
- https://github.com/MeilCli/danger-action/blob/master/.github/workflows/report.yml
Tips
リポジトリーが多すぎて管理しきれない
現在自分は十数個の自作Actionを運用しています。そうなってくると可能な限り自動化をしないと、手に負えません
そのため2つの自動化をしています
- 新規Action作成はtemplate repositoryを使う
- リポジトリーの設定はterraformを使う
まだまだ自動化具合は足りませんが、これで最低限の管理はできています。ただ新規ActionのSecret設定が面倒3だったりと、terraformを辞めようかなぁという気持ちは徐々に抱いています(このあたりおすすめのツールがあったら教えていただけると助かります)
dependabotやforked repositoryからのpull_requestにはreadonly tokenが入っている
Keeping your GitHub Actions and workflows secure: Preventing pwn requestsで書かれていることです
どういうことかというと、外部からのPullRequest自体にtokenを露出させるコードが仕込まれていると、そのPullRequestにおいてのCI/CDでtokenが盗まれてしまうので、外部からのPullRequestではreadonly tokenにしたりsecretsを入れなかったりをしてセキュアな状態にするよという感じの内容です
OSSやpublic repositoryでのGitHub Actionsではこのあたりのセキュリティーを考慮したWorkflowを作らないといけないのですが、ぶっちゃけ面倒ですねw
"外部からのPullRequestのCIが完了した"というトリガーで動くworkflow_run
なWorkflowを定義すると、そのWorkflowは内部扱いでsecretsとかを使うことができるのですが、元となったWorkflowのevent payloadを受け渡すのが面倒だったりします
そのためMeilCli/common-lint-reporterにはDependabotやOSS向けのActionを用意しています
1Repository=1Actionではない
MeilCli/common-lint-reporterには複数のActionが存在しています。WorkflowでActionを参照する場合はuses: owner/repository@branch_or_tag_or_commit
なので1Repository=1Actionと思われがちかと思いますが、正確にはuses: owner/repository/path/to/action@branch_or_tag_or_commit
の形式なので、Repositoryのroot以外に置いているaction.ymlを使うことができます
※ただし、Marketplaceで公開できるActionはRepositoryのrootにあるaction.ymlだけです
Repository内に複数のActionを定義することで、多種多様な挙動を取れるようにすることができます。(そうできなかったらcommon-lint-reporterのような複合ActionはRepositoryの管理がやばいですよね)
自分が運用している他のActionはvercel/nccでpackしていますが、base libraryをそれぞれのaction用のjsに含めるとRepositoryの容量が増えてしまうので、Webpackを使用して、base library部分は共有する構成にしています
ref: https://github.com/MeilCli/common-lint-reporter/blob/master/webpack.config.js
fine-grained personal access tokenを使う
ついこないだ知ったのですが、より細かいScopeで区切ったPATを作成できるようになったようです(Beta)
複数のpublic repositoryがある中で、使用するGitHub ActionsにPATを使うと漏洩リスクがつきまといます。GitHub Actionsにおいてはそこそこ気を付けたWorkflowを作成していますが、より細かいScopeに区切れるなら区切っておいたほうが安心ですね
今のところREST APIにしか対応していないようなので、GraphQLを使ったActionを使うことはできないので注意です
Repositoryの言語集計でAction用に用意する.jsファイルを無視できる
小ネタです
.gitattributes
に*.js linguist-language=TypeScript
を宣言すると.jsをTypeScript扱いできます。Repositoryの言語集計にJSが入るのが許せない人はTS扱いさせてみるといいでしょう。たしか同様な方法で完全にignoreもできたんじゃないかなと思います
ref: https://github.com/MeilCli/danger-action/blob/master/.gitattributes
action.ymlでGitHub Tokenをデフォルト値にできる
小ネタです
GitHubのTokenが必要なActionで、inputとしてtokenを引き受けるけどデフォルト値設定していないActionを見かけることがあるので書いておきます
github-actions[bot]のTokenでいい場合はdefault: ${{ github.token }}
と記述することでデフォルト値にしておくことができます。利用側の設定を1つ省くことができるのでおすすめです
ref: https://github.com/MeilCli/common-lint-reporter/blob/master/action.yml
おわりに
3年ほど十数個の自作Actionを運用してきましたが、ただただ面倒でつらいだけです。Dependabotは毎週のように数個ずつPullRequestを作ってくるので、自動化していたとしても通知が埋まってしまいます
唯一よかったことといえば、GitHubがお小遣いをくれたことですね(絶賛GitHub Sponsorになってくれるひと募集中です: https://github.com/sponsors/MeilCli)
運用中のAction
よかったらStarください
- https://github.com/MeilCli/danger-action
- https://github.com/MeilCli/common-lint-reporter
- https://github.com/MeilCli/bump-release-action
- https://github.com/MeilCli/action-template
- https://github.com/MeilCli/slack-upload-file
- https://github.com/MeilCli/setup-crystal-action
- https://github.com/MeilCli/hidable-comment-action
- https://github.com/MeilCli/nuget-update-check-action
- https://github.com/MeilCli/gradle-update-check-action
- https://github.com/MeilCli/swiftpm-update-check-action
- https://github.com/MeilCli/carthage-update-check-action
- https://github.com/MeilCli/cocoapods-update-check-action
- https://github.com/MeilCli/npm-update-check-action
- https://github.com/MeilCli/detekt-statistics
- https://github.com/MeilCli/android-lint-statistics
- https://github.com/MeilCli/test-command-action
- https://github.com/MeilCli/regex-match
- https://github.com/MeilCli/check-run-auto