GitHub ネイティブ版 Dependabot で Preview 版の compatibility badge を取り戻す

**2021/05/12 追記:**

[Preview 版 Dependabot は 2021/08/03 にサービス終了することが発表されました](https://github.blog/2021-04-29-goodbye-dependabot-preview-hello-dependabot/)。
こちらの記事で紹介している手法は Preview 版の機能を利用しているため、サービス終了に伴い動作しなくなるものと思われます。
GitHub ネイティブ版 Dependabot の compatibility score に関する問題が改善されることを期待しましょう。

## 前置き

リポジトリの依存関係を自動的に更新してくれる大変便利な [Dependabot](https://dependabot.com/) ですが、先日 [GitHub ネイティブ統合版 (Beta) が発表](https://github.blog/2020-06-01-keep-all-your-packages-up-to-date-with-dependabot/)され、利用可能となりました :tada: 

~~Preview 版の Config Variables に相当する機能がまだ提供されていないため、プライベートな依存関係を持つリポジトリではまだ利用することができませんが~~ ([プライベートな依存関係も解決できるようになりました！](https://github.blog/2021-03-15-dependabot-private-dependencies/))、進化している点もいくつかあります。
特に (個人的に) アツいのは reviewer に team を設定できるようになった点です。これにより GitHub の [Code review assginment](https://help.github.com/en/github/setting-up-and-managing-organizations-and-teams/managing-code-review-assignment-for-your-team) と組み合わせることで Dependabot が作成した Pull Request に team のメンバーを自動で割り当てることができるようになりました。こういった仕組み、チーム開発では地味にありがたいですよね。

さて、そんな GitHub ネイティブ版 Dependabot ですが、移行してみると思わぬ罠が待ち受けていました。

## compatibility score: unknown が多発する

compatibility score というのは、Dependabot が作成する PR のメッセージ内に貼られている、
![dependabot1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/586035/b9277837-7f52-da64-8b57-2f494f2fd263.png)
この badge で示されている数値のことです。

この数値は世界中の Dependabot が導入されているリポジトリのうち、同じ内容の更新 PR で CI が成功した割合を意味しています。
この数値が高ければ前のバージョンに対して互換性が保たれている可能性が高いので安心して更新できるというわけです。逆にこの数値が低ければ何かしらの破壊的変更があったりバグがある可能性が高いので、更新前に調査を行うなどの対応を取ることができます。

Dependabot の PR をレビューする上で重要な判断基準の1つとなる compatibility score ですが、GitHub ネイティブ版では次のようにやたらと `unknown` となってしまいます。
![dependabot2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/586035/ecd050cb-5f9f-b31e-a8b4-0437b6696592.png)
どうやらネイティブ版と Preview 版では compatibility score が別管理になっているらしく、ネイティブ版を導入しているリポジトリがまだ少ないので score を算出できない状態となってしまっているようです。

## badge をクリックしても詳細ページに飛べない

さらに残念なことに、Preview 版の compatibility score badge はクリックすると compatibility score の詳細ページに飛べたのですが ([こんなページ](https://dependabot.com/compatibility-score/?dependency-name=eslint&package-manager=npm_and_yarn&previous-version=7.2.0&new-version=7.3.0)) 、ネイティブ版では GitHub のドキュメントに飛ばされてしまいます。
この詳細ページには CI に失敗したリポジトリの一覧が載せられていて、score が低いときの調査に役立っていました。

## GitHub Actions で Preview 版の badge を取り戻す

せっかくなので GitHub ネイティブ版 Dependabot を使い続けたいところなのですが、compatibility badge が役に立たないのは困りものです。
どうにかしてネイティブ版を使い続けながら Preview 版の compatibility score badge を確認したい。。。

というわけで、Dependabot の PR に反応して Preview 版の badge を生成してくれる workflow を GitHub Actions で作ってみました。

2021/03/16 追記:
[2021年3月から Dependabot によってトリガーされた workflow は read-only 権限で実行されるようになった](https://github.blog/changelog/2021-02-19-github-actions-workflows-triggered-by-dependabot-prs-will-run-with-read-only-permissions/)ため、[`pull_request`](https://docs.github.com/en/actions/reference/events-that-trigger-workflows#pull_request) イベントではなく [`pull_request_target`](https://docs.github.com/en/actions/reference/events-that-trigger-workflows#pull_request_target) イベントを使うように修正しました。
また、[`actions/github-script@v3`](https://github.com/actions/github-script/tree/v3) での動作を確認したので v3 を使用するように修正しています。

```yaml:.github/workflows/compatibility-badge.yml
name: Compatibility Score Badge
on:
  pull_request_target:
    types:
      - opened

jobs:
  badge:
    runs-on: ubuntu-latest
    steps:
      - name: Badge compatibility score
        uses: actions/github-script@v3
        with:
          script: |
            const pr = context.payload.pull_request;
            if (pr.user.type !== 'Bot' || pr.user.login !== 'dependabot[bot]') {
              console.log('author is not dependabot');
              return;
            }
            const badgeRegex =
              /\[!\[Dependabot compatibility score\]\(https:\/\/dependabot-badges.githubapp.com\/badges\/compatibility_score\?(.*)\)\]/;
            const match = pr.body.match(badgeRegex);
            if (match == null || match.length < 2) {
              console.log('compatibility badge is not found');
              return;
            }
            const query = match[1];
            const badgeURL = `https://api.dependabot.com/badges/compatibility_score?${query}`;
            const detailURL = `https://dependabot.com/compatibility-score/?${query}`;
            const badge = `[![Dependabot compatibility score](${badgeURL})](${detailURL})`;
            const body = `Dependabot-Preview score\n\n${badge}`;
            await github.issues.createComment({
              issue_number: pr.number,
              owner: context.repo.owner,
              repo: context.repo.repo,
              body
            })
```

badge の URL のクエリ部分がネイティブ版と Preview とで共通であることを利用しています。

実際に動作させると次のような感じです。

![dependabot3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/586035/062df74c-a20a-158e-44e5-7d9f484af83b.png)

Dependabot が作った PR (メジャーな npm なのに案の定 `unknown`) に反応して、Preview 版の badge を貼ってくれます。
クリックすれば Preview 版の詳細ページに飛ぶこともできます。

compatibility score の問題はすぐに改善されるとは思いますが、それまでの間役に立ってくれそうです。