Codecov非対応の言語でもCodecovみたいなことをしたい時
Codecov は、PR へのコメントや README のバッジのような方法でコードのカバレッジを可視化できるツールです。
カバレッジを開発者に対して頻繁にフィードバックすることで、開発者はテストを意識するようになります。
一方で世の中には星の数ほど言語がありますが Codecov がサポートしているものは意外と少ないです。
また色々な理由で Codecov を使いたくない / 使えないという場合もあるかと思います。
この記事では Codecov 非対応の言語でも Codecov みたいなことをしたいなと思ってやったことを共有します。
記事の前提としてあなたは何らかの方法を用いて GitHub Actions でカバレッジを計測することはできていると仮定します。
今回私は Open Policy Agent (OPA) を例にしていますが、この条件を満たしていれば言語には依存しないはずです。
PR へのカバレッジのコメント
結論
name: comment-coverage
on:
pull_request:
branches:
- master
jobs:
comment-coverage:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Setup
uses: open-policy-agent/setup-opa@v2
- name: Export coverage
run: |
echo "COVERAGE=$(opa test policy -c | jq .coverage)" >> $GITHUB_ENV
- name: Format comment
run: |
echo "coverage: ${{ env.COVERAGE }}%" >> comment
- name: Comment coverage to PR
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
URL: ${{ github.event.pull_request.html_url }}
run: |
gh pr comment -F ./comment "${URL}"
方針
コメントは GitHub CLI を使って投稿します。
内容は文字列でもファイルでも良いみたいです。
各ステップ
-
Export coverage
ステップでカバレッジを計測し、環境変数に追加します
opa test policy -c | jq .coverage
の部分は言語に合わせて変えてください -
Format comment
ステップでは 1 つ前に環境変数に追加したカバレッジを取り出し、コメントの内容を整形します
ここではcoverage: 90%
のようなシンプルな内容ですが、ファイルに書き出す形にしているので内容は自由です - 最後に
Comment coverage to PR
のステップでコメントを投稿します
なお、コメント投稿のステップでは一見GITHUB_TOKEN
というシークレットを設定しておく必要があるように見えますが不要です。
At the start of each workflow run, GitHub automatically creates a unique GITHUB_TOKEN secret to use in your workflow. You can use the GITHUB_TOKEN to authenticate in a workflow run.
結果
このジョブが走ると以下のようなコメントが投稿されます。
README へのバッジの追加
結論
name: coverage-badge
on:
push:
branches:
- master
jobs:
coverage-badge:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Setup
uses: open-policy-agent/setup-opa@v2
- name: Export coverage
run: echo "COVERAGE=$(opa test policy -c | jq .coverage)" >> $GITHUB_ENV
- name: Upload JSON
uses: schneegans/dynamic-badges-action@v1.6.0
with:
auth: ${{ secrets.GIST_SECRET }}
gistID: 0c2e618c502912eff6e83e26b24e5c82
filename: opa-coverage-badge.json
label: Coverage
message: ${{ env.COVERAGE }}%
valColorRange: ${{ env.COVERAGE }}
minColorRange: 50
maxColorRange: 90
方針
バッジの作成には Shields.io がよく使われるのでここでも使いたいです。
Shields.io を利用するためにはカバレッジをどこかに保存しておく必要があります。
また数値に応じて色も変えたいです。
ここでは Dynamic Badges という Action を使います。
Dynamic Badges は Gist に Shields.io リクエスト用の JSON をアップロードします。
またオプショナルなパラメータを設定することでカバレッジに応じた色の計算もしてくれます。
準備
こちらは準備が必要です。
- Gist を作成し、JSON ファイルを追加
- GitHub の設定から Gist の権限を持ったトークンを生成
- 2.で生成したトークンをリポジトリのシークレットに追加
詳細は Dynamic Badges のドキュメントを参照してください。
各ステップ
-
コメントの場合と同様に
Export coverage
ステップでカバレッジを計測し、環境変数に追加します -
Upload JSON
で Dynamic Badges を使って JSON をアップロードします
必須のパラメータは以下です- auth: 準備で作成したシークレット
- gistID: 準備で作成した Gist の ID
- filename: 準備で追加した JSON ファイルの名前
- label: バッジのラベル
- message: バッジのメッセージ
色の計算をする場合は valColorRange, minColorRange, maxColorRange も必要になります
結果
このジョブが走ると以下のような JSON が Gist にアップロードされます。
この JSON を Shields.io のリクエストで指定することでカバレッジバッジを表示することができました。
余談ですが、Gist も GitHub CLI で編集可能なので色の計算さえ自前でやれば Dynamic Badges は不要です。
追記
Dynamic Badges 使わない版も確認しました。
Dynamic Badges の実装を参考に Bash で HSL を計算し、gh gist edit
で JSON を更新します。
name: coverage-badge
on:
push:
branches:
- master
pull_request:
branches:
- master
jobs:
coverage-badge:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Setup
uses: open-policy-agent/setup-opa@v2
- name: Export coverage
run: echo "COVERAGE=$(opa test policy -c | jq .coverage)" >> $GITHUB_ENV
- name: Calc color
run: |
coverage=${{ env.COVERAGE }}
floor=${coverage:0:2}
min=50
max=90
round=$((max < floor ? max : floor < min ? min : floor))
hue=$(((round - min) * 120/ (max - min)))
echo "COLOR=hsl($hue, 100%, 40%)" >> $GITHUB_ENV
- name: Upload JSON
env:
GITHUB_TOKEN: ${{ secrets.GIST_SECRET }}
run: |
echo '{"schemaVersion":1,"label":"Coverage","message":"${{ env.COVERAGE }}%","color":"${{ env.COLOR }}"}' >> test.json
gh gist edit 6641f83484aca3643c1f6d9ddee38260 test.json
まとめ
今回の記事ではそれぞれのジョブを独立したものとして設定しましたが、実際にはテストを 2 回以上実行するのは無駄なので改善の余地があります。
一方でジョブをまとめる場合でもコメントは PR の場合のみ、JSON アップロードは master への push の場合のみで十分ですが、そうなるとステップに対して条件を設定する必要があります。
面倒くさいので Codecov が使えるなら使った方が良いかと。
Discussion