Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

2022-05-29 - dependabot の auto-merge 用に、PAT(Personal Access Token) 無しの GITHUB_TOKEN だけで GitHub Actions の CI 完了待ち出来るようなのを作ってみた #163

Closed
kachick opened this issue May 28, 2022 · 6 comments

Comments

@kachick
Copy link
Owner

kachick commented May 28, 2022

TL;DR

name: Auto merge dependabot PRs if passed other jobs
on: pull_request

permissions:
  contents: write
  pull-requests: write
  # checks: read # For private repositories
  # actions: read # For private repositories

jobs:
  auto-merge-dependabot-prs:
    runs-on: ubuntu-latest
    if: ${{ github.actor == 'dependabot[bot]' }}
    steps:
      - name: Dependabot metadata
        id: metadata
        uses: dependabot/fetch-metadata@v1.3.1
        with:
          github-token: "${{ secrets.GITHUB_TOKEN }}"
      - name: Wait other jobs are passed or failed
        if: ${{contains(steps.metadata.outputs.dependency-names, 'my-dependency') && steps.metadata.outputs.update-type == 'version-update:semver-patch'}}
        uses: kachick/wait-other-jobs@v1-beta
        timeout-minutes: 30
        with:
          github-token: "${{ secrets.GITHUB_TOKEN }}"
      - name: Enable auto approve and merge for Dependabot PRs
        if: ${{contains(steps.metadata.outputs.dependency-names, 'my-dependency') && steps.metadata.outputs.update-type == 'version-update:semver-patch'}}
        run: gh pr review --approve "$PR_URL" && gh pr merge --auto --squash "$PR_URL"
        env:
          PR_URL: ${{github.event.pull_request.html_url}}
          GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}}

自分はちょっと変えてこうしてる

--squash は自分の好み。普通は? --merge だと思う。

何についてか / About

ref:

経緯 / History

dependabot の auto merge 機能が GitHub の公式提供から外されて、最近でも python のライブラリに悪意あるコード埋め込まれたとかあるししょうが無いよなぁとは思うものの、まーやっぱり無いと現実問題厳しい感じ。(しかしこの ctx の事件は既存のバージョンまで上書きリリースされたみたいだから lock の integrity までみないと verup とか関係ない気もする )
その後幾つか 3rd party の auto merge が乱立してたと思うんだけど、なるべく Official な機能だけで実現したかった。
で、数ヶ月前にうんうん 言いながら唸って 自動で approve した後に @dependabot merge を自動でコメントさせるような GitHub Actions を作った。approve させるようにしたのはそのリポジトリの merge 必須要件に入っていたため。そしてこのコマンドを受け付けた dependabot さんは賢い事に全部の job が通った時にだけ merge してくれるということでやれやれと思ってたんだけど、ネックが幾つか。まず仕様として bot からのコマンドを受け付けないらしく、そのリポジトリに権限を持ったアカウントの PAT(Personal Access Token) を用意して使わないといけないというキモさ。次にそのトークンを読むために pull_request_target を trigger にしないといけなかった。辛い。
ここ最近 permission というのを設定できるようになったみたいで、当時と違い今は pull_request_target を捨てれるだろうけど、 bot からのコマンドを受け付けないという事情は変わってない様子。久しぶりに調べたら同じアプローチを取ってる GitHub Actions も marketplace で見つけたんだけど、やはり PAT が必要な様子。
PAT はアカウントに紐づく為、リポジトリ単位とかで権限のスコープを絞ることが出来ない。これの拡張は GitHub も検討しているみたいだけどまだ実現してない。

そもそも GitHub はこの需要をどう考えているんじゃいと公式ドキュメントを追ってみると、今は流石に声が多すぎるからかオフィシャルにこうするといいよというのを書いてくれてた。 で、はっきりと @dependabot merge のようなコマンド発行自動化は推奨しないと言っている issue も見つけた。
なるほど、このドキュメントだと https://github.com/dependabot/fetch-metadata を使ってバージョンの上がり方を引っ張ってきている。で、 gh コマンドで approve や merge をしている。
それは良いんだけど、どうやらCI待ちをさせていない・・・ repository のマージ要件にCI待ちの設定を入れてしまえば実質待たせることにはなるだろうけど、 dependabot の為にリポジトリ設定を変えたくはない。

というところで、どの方法を選択しようがあちらを選べばこちらがたたずな感じだったので、不慣れながら自作してみた。
最初は dependabot auto-merge だけに絞ったアクションを作ってたんだけど、色んな言語向け version update の正規表現を自前で正確に書くみたいなのは筋が悪い感じだし、merge 部分は gh コマンドに投げてるしで大半はCI(他の job)待ちのコードになってしまったので、単独機能としてリリースして GitHub Official の steps に挟むこむようにした。
action、workflow、job、step、run の定義すらあんま良くわかってないんだけど、今のところちゃんと動いてそうに見える。

自分の要件は満たせてしまったのでこれ以上あんま深追いしたくないんだけど、気になっているのは以下

  • dependabot の config でCI通ったら?ラベルをつけさせて、そのラベルをみてマージするというワーカー的な機能を走らせて置くというもの。PAT や 3rd party アプリへの oauth 不要ならこれもありな気はするけど、特定の dependency に関してはラベルを付けさせないとかまでは dependabot config に無さそうなので劇的に便利とは行かなそうな気が・・・。と思ってたけど https://github.com/marketplace/actions/merge-pull-requests-automerge-action とか PAT 不要そうだし、dependabot 以外で automerge ラベルは無視みたいなとこまで条件書けばこれで良いのかもなー
  • 自分は check-runs を前段の api で run_id 拾った上で叩くみたいにしているんだけど、 https://mixi-developers.mixi.co.jp/github-action-all-check-ci-cad4d862f137#3f63 で書かれていた check-suites とやらがなんでどういう違いがあるのかとかがあんまよくわかってない・・・
  • https://github.com/lewagon/wait-on-check-action も check-runs を叩いているらしいんだけど、name を渡しているみたいなので前段の run_id を引っこ抜く処理とかが無いから設定が増えているのでは・・・と想像しているんだけど追えてない

書いていた時の雑感

  • v3(REST) だけで v4(GraphQL) の api 用意されてない機能が結構ある。
  • REST api に対する TypeScript の型定義がうまい感じで気持ちよく使えた。
  • 初回のポーリングで本当は存在する自分以外の job_id 一個も返さない可能性をどこまで考えれば良いのか、そんな事は起こり得ない作りなのかがよくわかってない。今のところ、30秒間隔取って queued すら返さなかったケースは無いかなー?
  • ページング機能を用意してくれるのはとても嬉しいけど対応させるの面倒だった。というかまず発生しないだろと思ってサボってる。その内実装するかも。
  • 流石に色んなタスクがあるからか実現してない話は一杯あるみたいだけど、 GitHub は色んな要望をちゃんと理解はしてくれて質疑応答をしてくれるので https://github.community/ とかちゃんと追った方が良さそう。全体的に良心的だよなーとは思う。
  • ローカルじゃないところの ENV とかに渡ってくるものに対するコード書くの大変だし意外なところでハマって時間食う。ログは最後の仕上げに出そうと思ってたけど、開発途中でも合ったほうが諸々捗る。
  • Exponential Backoff ぐらいサラッとかけるやろ!とか Promise/await/async 周りも雰囲気で行けるやろ!と思ってたけど一回目に書いたコードは大体バグってた。
  • Ruby でもそうだけど1行に記号を使った計算や条件が詰め込まれているようなコードだと、優先順位的に不要でも () つけまくりたくなるのに eslint-airbnb ? prettier? さんが消しちゃうのでカスタマイズも探さず唯々諾々と消されてたけど納得してない。
  • ECMA Script の Destructuring assignment わかってるつもりだったけど、TypeScript でネストした時に Ruby の dig 的なやつをどこまで柔軟に書けるのかとかがあんま良くわかってなかった。
  • かなり時間費やしたところで自分が取ってたIDは job_id ではなく run_id だったとわかり、肝心の job_id をダイレクトに取る方法がない事がわかりちょっと泣きそうになったけど how get get check run id actions/starter-workflows#292 (comment) に救われた。
  • GitHub marketplace で公開するの簡単。というか action のリポジトリを作るとそうしろと勧めてくる。
  • これまでに大勢挑んでる感がある話なので、どっかに全く同じか上位互換 action がリリースされてて完全に車輪の再発明だった可能性も捨てきれないけど、そしたら勉強になったからよしと思うことにする(嘘、多分凹む)。
  • 🐔 なので v1-beta タグのまま使ってるけど、どっかで v1 にしないとなぁと思っては居る。
  • v1-beta と並行して v1.0.0 とか v1 tag も定義してたら、愛用している package-ecosystem: "github-actions" が beta 取るPR出してきてそれを v1-beta が automerge してしまって面白かった。
  • dependabot/fetch-metadata の出力を取り回す様な action も書こうかと思ったけど、 action だけで types とかの npm 提供無いしまーいっかー?と思っている。
  • dependabot/fetch-metadata の出力を、その後の step 全部の if に同じ取り回しコード書いて skip に使ってるの流石にダサいとは思うけど腰が上がらない。
@kachick
Copy link
Owner Author

kachick commented May 30, 2022

これまでに大勢挑んでる感がある話なので、どっかに全く同じか上位互換 action がリリースされてて完全に車輪の再発明だった可能性も捨てきれない

やはりあったか!?

https://github.com/technote-space/workflow-conclusion-action/blob/858e8f61da203e3c29adf1b7dfbc8a4ce814dd23/src/process.ts#L9-L52

と思ったけど、 workflow の conclusion を取るところまでの action みたいなので check-runs まで叩いての待ち合わせとかはやってないっぽい。実際使用例も同じ workflow 内で jobs を needs で連結して always() で待ち合わせるみたいな感じだった。
個人的には https://github.community/t/depend-on-another-workflow/16311 みたいに workflow 全ての待ち合わせ用が欲しかったので、ゴールは違ってそうな感じ。

ただコードベースがとても勉強になる。。。

octokit.request だけじゃなくて octkit.pagenate とか、route も octokit.rest.actions.listJobsForWorkflowRun とかで取れるのかー。知らんかった・・・

https://github.com/octokit/plugin-paginate-rest.js/

@kachick
Copy link
Owner Author

kachick commented May 31, 2022

雑にこの step 挟むだけで他全ての workflow? job? を待ち合わせられるのが楽で使っているんだけれど、GitHub Actions の制限のかかり方って経過時間なんだよなー
となると最初に起動して他のを待ち合わせるというのは本来あんま筋が良くないのかなぁとも思うんだけど、じゃあイベントフックする手段はなんかあんのかと https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#workflow_run 見てみた。

workflow_run, check_run, check_suite 当たりが使えれば良いんだろうけど、どれもデフォルトブランチだけが対象ってなってるし workflow_run に複数の workflow 名渡すと全ての待ち合わせじゃなくてどれか一個の完了を待つだけらしい。
そもそも待ち合わせたい他の workflow 名全部間違えずに書き入れとくとしてもリポジトリ幾つもあると管理が億劫そうだから、このあたりはなんぞ用意して欲しいなー。まぁ名前指定しないと相関 🍝 になりやすいからあえてやってないのかも?

それはそれとして

🐔 なので v1-beta タグのまま使ってるけど、どっかで v1 にしないとなぁと思っては居る。

なんか大丈夫っぽいのでやっといた。

@kachick
Copy link
Owner Author

kachick commented Jul 6, 2022

リポジトリのアクティビティがあまり無いのでいつまで続くかはわからないものの、取り敢えず dependabot/fetch-metadata@v1.3.3 までは、バージョン情報も、そこからの semver の上がり方も取れていないというか null になるというバグが合った・・・

dependabot が上げてくるPRの title は Bump から始まるものと Update から始まる物がある。なんでもこれは内部でライブラリかアプリかという謎の判別をした上でメッセージを分けてくれているようなのだけれど、このライブラリ側のコミットメッセージをパースする機能が無いので欠けてるようだった。
ということで直るまではこれを組み入れた auto-merge はまともに使えない筈なんだけどなんでみんな困ってないんや・・・
多分だけど圧倒的に多いであろう npm 系は大体 Bump 始まりで、 Ruby とか Python が Update になってる感なのでユーザー比率的に声が上がらないんじゃないかなと・・・

dependabot/fetch-metadata#224

GitHub の official になったから dependabot に寄せてった方が良いのではと思ってたけど、新しい ecosystem の追加もしないメンテナンスモードっぽいし renovate に寄せってった方が幸せになれるのかも・・・?

@kachick
Copy link
Owner Author

kachick commented Jun 28, 2023

GitHub CLI が多機能なので、PRのオートマージ待ちだけなら任せられそうな気もする

gh pr checks <url> --fail-fast --interval --watch

みたいな

gh --version
gh version 2.29.0 (1980-01-01)
https://github.com/cli/cli/releases/tag/v2.29.0gh pr checks --help
Show CI status for a single pull request.

Without an argument, the pull request that belongs to the current branch
is selected.


USAGE
  gh pr checks [<number> | <url> | <branch>] [flags]

FLAGS
      --fail-fast          Exit watch mode on first check failure
  -i, --interval --watch   Refresh interval in seconds when using --watch flag (default 10)
      --required           Only show checks that are required
      --watch              Watch checks until they finish
  -w, --web                Open the web browser to show details about checks

INHERITED FLAGS
      --help                     Show help for command
  -R, --repo [HOST/]OWNER/REPO   Select another repository using the [HOST/]OWNER/REPO format

LEARN MORE
  Use 'gh <command> <subcommand> --help' for more information about a command.
  Read the manual at https://cli.github.com/manual

@kachick
Copy link
Owner Author

kachick commented Apr 5, 2024

微妙に立ち位置がわかってないけどなんとなく半公式みたいな感じだと思ってる octokit でも dependabot ではなく renovatebot をメインで使ってる感。

https://github.com/octokit/graphql-schema/blob/4aa5a4bb12e5dca78e7a782e727ef3b206528261/.github/renovate.json#L3
https://github.com/octokit/.github/blob/ccb3f9cde1dd4af1c3d2e73307327a303e48594a/default.json

@kachick
Copy link
Owner Author

kachick commented Jun 4, 2024

https://cli.github.com/manual/gh_run_watch

gh pr checks

シンプル過ぎて複数走らせたときの deadlock 回避みたいなのは難しそう。
というか自分自身が走ってる所すら回避しない状態なんだけど、これだと action 中で使えない気がするんだが使ってるっぽいワークフローが70ぐらい見つかるのはどういうことなのか・・・ kachick/wait-other-jobs#835 (comment)
基本的に GitHub の話は GitHub 謹製の何かで完結してほしいので、自分で作り込みたいわけではないんだが・・・

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant