🌍

プライベートリポジトリも見れる GitHub Warp で今年を振り返る

2021/12/16に公開

クソアプリ Advent Calendar 2021 その2」の16日目の記事です。

ちなみに、とくに振り返ってはません。

GitHub Wrap

GitHub が GitHub Wrap というのをツイートしてました:

どうやら、2021年のパブリックなコントリビュートをいい感じなカードっぽい画像で出力してくれるそうです:

さて、OSS活動を主な仕事にしてる方なら、この結果イコール今年の活動になると思いますが、職業プログラマーであればプライベートリポジトリが主な活動拠点な方もいると思います。僕もそうです。できればプライベートリポジトリのコントリビュートも出したいです。

ということで

作りました。

残念ながら僕には「いい感じなカードっぽい画像で出力」する能力はないので、CLI です。ただし、流行り(?)に乗って GitHub CLI の Extension にしました:

https://github.com/matsubara0507/gh-wrap

$ gh extension install matsubara0507/gh-wrap
...
$ gh wrap
{
  "GitHub CLI Wrap 🚀": "matsubara0507's 2021 GitHub ALL Stats",
  "Commits": 2653,
  "PullRequests": 420,
  "Issues": 112,
  "NewRepos": 19
}

NewRepos が減ってるのは、フォークを弾いたからです)

中身

どうやって各種総数を取ってくるかですが、GitHub GraphQL API でささっと取ってこれるもんだと思いますよね?

ドキュメントを漁ると、確かに viewer クエリ(user クエリ)の結果に ContributionsCollection オブジェクトなるものがあります:

$ gh api graphql -f query='query{ viewer{ login, contributionsCollection(from:"2021-01-01T00:00:00"){ totalCommitContributions, totalIssueContributions, totalPullRequestContributions } } }'
{
  "data": {
    "viewer": {
      "login": "matsubara0507",
      "contributionsCollection": {
        "totalCommitContributions": 456,
        "totalIssueContributions": 9,
        "totalPullRequestContributions": 61
      }
    }
  }
}

しかし、どうやらこれはパブリックなコントリビューションのみみたいです。目を皿にしてドキュメントを漁り、あの手この手で試しましたが、User オブジェクトからプライベート込みの各種総数を取得することは無理そうでした。。。(あったら教えてください)

ちなみに、本家 GitHub Wrap は ContributionsCollection を使っていそうです(ソースコードは探したけど見つからなかった)。

便利な search クエリ

search クエリというのを使います。これは、GitHub の Web UI の左上の検索っぽいやつをそのまま API にしたようなやつです。例えば、自身がオープンした PR の総数を取得するにはこうします:

$ gh api graphql -f query='query{ search(query: "type:pr author:matsubara0507 created:2021-01-01..2021-12-31", type: ISSUE) { issueCount } }'
{
  "data": {
    "search": {
      "issueCount": 420
    }
  }
}

これの欠点は、PR 数や Reposiotry 数などをそれぞれ別のクエリで取得する必要がある点です(バイバイ GraphQL の旨味)。なので、gh wrap はめっちゃ遅いです。
それと、GitHub の検索ではコミットも検索できるのですが、GraphQL では(なぜか)対応していません。なので、コミット数はふつーの REST API を使いました:

$ gh api -X GET search/commits -f q='author:matsubara0507 author-date:2021-01-01..2021-12-31' -f per_page=1 --jq .total_count
2653

あとはこれをそれっぽい JSON にして表示してるだけです。

おまけ:GitHub Actions

GitHub Actions で gh 拡張の動作確認がしたいですよね。ということで足しました:

name: Run Extension Command
on:
  pull_request: null
  push:
    branches:
    - main
jobs:
  run:
    runs-on: ubuntu-18.04
    env:
      GH_TOKEN: ${{ secrets.GH_PAT }}
    steps:
    - uses: actions/checkout@v2

    - name: Install extension
      run: gh extension install .

    - name: Run extension
      id: gh
      run: |
        result=$(gh wrap)
        result=${result//$'\n'/\\n}
        result=${result//$'"'/\\\"}
        echo "::set-output name=wrap::${result}"
    - name: Comment result
      uses: actions/github-script@v5
      with:
        github-token: ${{secrets.GITHUB_TOKEN}}
        script: |
          github.rest.issues.createComment({
            issue_number: context.issue.number,
            owner: context.repo.owner,
            repo: context.repo.repo,
            body: "Run `gh wrap` at workflow:\n```\n${{ steps.gh.outputs.wrap }}\n```\n"
          })

実際に gh コマンドを実行して、その結果を PR へコメントするだけです。コメントには actions/github-script を利用しています。

ちなみに、いくつか罠がありまして。まず、GitHub Actions 組み込みの GITHUB_SECRET では動きません。以下のようなエラーが出ます:

gh: Resource not accessible by integration (HTTP 403)

GitHub Actions 組み込みの GITHUB_SECRET は、そのリポジトリに特化した権限しか持っていないため、うまく実行できなそうです。
仕方がないので、パブリックリポジトリへの権限だけを持った個人トークンを利用することにしました。

また、actions/github-script へのエスケープ処理が厄介でした。
GitHub Actions の ${{ ... }} は、変数の中身をそのままそこに貼り付けるので、body の文字列へ埋め込むには、" や改行をエスケープする必要がありました。

おしまい

ちなみに、引数に「年」を渡すと2021年以外も出してくれます:

$ gh wrap 2021
{
  "GitHub CLI Wrap 🚀": "matsubara0507's 2021 GitHub ALL Stats",
  "Commits": 2653,
  "PullRequests": 420,
  "Issues": 112,
  "NewRepos": 19
}
$ gh wrap 2020
{
  "GitHub CLI Wrap 🚀": "matsubara0507's 2020 GitHub ALL Stats",
  "Commits": 3447,
  "PullRequests": 587,
  "Issues": 155,
  "NewRepos": 30
}
$ gh wrap 2019
{
  "GitHub CLI Wrap 🚀": "matsubara0507's 2019 GitHub ALL Stats",
  "Commits": 3332,
  "PullRequests": 590,
  "Issues": 140,
  "NewRepos": 51
}

あれ。。。今年だけまぁまぁコントリビュートが少ない。。??

Discussion