Github Actions+Gistでカバレッジ可視化~無課金プライベートリポジトリでもカバレッジバッジが欲しい~
エレベータピッチ
- Github ActionsとGistだけでREADME.mdにカバレッジバッジを追加
- プライベートリポジトリやオーガナイゼーションでも無料で導入可能
- プルリク内でカバレッジを示すコメント追加
- Pytestを対象に実施
- 以下のリポジトリに最小ケースの動作確認済みサンプルを掲載
前提事項
- GitHub ActionsにてPytestのCIを組んでいる
- プライベートリポジトリや複数人が管理するOSSでカバレッジを可視化したい
モチベーション
実際にチーム開発をしていても、カバレッジを可視化していないと、自然とテストを軽視しがちになってしまいます。TDDなどでも、テスト結果の可視化をCIに組み込むことの重要性が指摘されています。
また何となくですが、テストカバレッジバッジを表示しているリポジトリはしっかりメンテナンスされていてかっこいい印象があります。ポケモンシールをタンスに貼っていた世代としてはぜひ導入したい。
そこで、自分もチームで使っているオーガナイゼーションにカバレッジ可視化SaaSを導入したいと考えていました。
しかしながら、会社で開発しているオーガナイゼーションのプライベートリポジトリに対して、CodecovやCoverallsを導入するためには有料プランが必要になります。
著者はケチなのと、社内でのSaaS導入のための事務作業あれこれをするのが嫌なので、出来れば無課金でカバレッジバッジを作りたかったです。
今回は『pytestのCI自体はすでに作ってるよ』という人向けにPytest Coverage CommentとDynamic Badgesを使って、GitHubの無料機能だけでREADMEにカバレッジバッジを設定する方法紹介します。
バッジ作成手順
最終的にこんな感じのバッジを自動的にREADME.mdに記載する手順をステップバイステップで説明します。
1. GitHub Actionsに書き込み権限を付与
コメント追加のために書き込み権限が必要になります。
ひとまず、既存のpytest-ci用のアクションにpermissions: write-all
を追加します。
on:
pull_request:
permissions: write-all
2. pytest-Covの導入
pytestの実行環境にpytest-covをインストールする必要があります。
pytest-covをインストールすると、カバレッジを算出可能になります。
Python環境をどのように構築しているかは、人それぞれではありますがもっとも単純な導入方法は以下のコマンドを入力することです。
pip install python-cov
次に、Pytestを実行しているアクションにて、--cov --junitxml=pytest.xml --cov-report=term-missing:skip-covered
オプションを付与します。
このオプションを付与することで、標準出力にカバレッジを表示し、ファイルに結果を保存できます。
それらを基に、カバレッジを示すコメントを作成するため、コマンドラインの出力結果をテキストファイルに保存します。
- pytest tests/
+ pytest tests/ --cov --junitxml=pytest.xml --cov-report=term-missing:skip-covered | tee pytest-coverage.txt
3. Pytest Coverage Commentを実行
Pytest Coverage CommentはPytestのカバレッジ結果をプルリクエストにコメントしてくれるアクションです。
実際にプルリクエスト時にCIが走ると、以下のようなコメントをしてくれるようになります。
カバレッジをコメントしてくれている様子
また、アコーディオンを開くとテストケースがカバーできていないソースへのリンクも提示してくれます。
pytest-covを正しく導入できていれば、使い方は簡単で先ほどのコマンドライン出力結果(pytest-coverage.txt)と実行結果を格納しているpytest.xmlをアクションに与えるだけす。
- name: Create Coverage Comment
id: coverageComment
uses: MishaKav/pytest-coverage-comment@main
with:
pytest-coverage-path: pytest-coverage.txt
junitxml-path: ./pytest.xml
上記のコードは結果ファイル(pytest.xml pytest-coverage.txt)がトップディレクトリに格納されている前提ですが、適宜修正してGitHub Actionsにコードを追記してください。
4. GitHub Gistの設定をしよう
次に、GitHub Gistにアクセスして格納場所を作ります。
まず、以下のリンクにアクセスしてください。
次にとりあえず、Public GistのIDが必要なので、何らかの内容を入れてCreate public Gistを押します。
空のgistを作成
すると、先ほどのデータを格納したgistが作られます。
作成されたgist
ここで、Gist IDを控えておく必要があるのですが、遷移先のurlか、画面左上のgist:以降の文字列がGist IDに該当します。
5. GitHub Gistを書き換えるためのトークンを作ろう
次に、GitHub ActionsからGistを書き換えるための権限を付与したパーソナルアクセストークンを作成します。
まず、GitHubの設定からPersonal access tokensに移動して、『Generate new token』を押します。
トークン作成画面
適切な期間を設定し『select scopes』の中にあるgistにだけチェックを入れます。
gistにチェックを入れる
すると、パーソナルアクセストークンの文字列が表示されるのでそちらをコピーしておきます。
そして、カバレッジを表示したいリポジトリのsettigs→secretsに移動し、『New repository secret』を押します。
表示されたNew secretページにて、Nameに任意の名前、Valueにコピーしているトークンを貼り付けて保存します。
トークンの追加
ここまでの設定をすると、このトークンを使って、GitHub Actionsから作成したgistの内容を書き換えることができます。
6. Dynamic Badgesでバッジを作ろう
先ほどのコメントにもバッジが表示されていましたが、README.mdには動的にバッジを変更する必要があります。
そのために必要なのがDynamic Badgesです。
Dynamic Badgesでは、バッジの描画に必要な情報(表示内容、色、デザイン)をGist上に格納します。そして、格納したパラメータをShields.ioを使って描画することで、READMEなどに張ったバッジを動的に変更します。
Gistに必要なパラメータを保存するために以下のコードを追加します。
- name: Create Coverage Badge
uses: schneegans/dynamic-badges-action@v1.3.0
with:
auth: ${{ secrets.BADGE_GIST }} # 名前は適宜変更:手順5で決めたトークン名
gistID: xxxxxxxxxxx #先ほど控えたGist ID
# 以降はコピペ可
# cerverageCommentはPytest Coverage CommentのID
# 書き換えた場合は変更が必要
filename: pytest-coverage-comment.json
label: Coverage
message: ${{ steps.coverageComment.outputs.coverage }}
color: ${{ steps.coverageComment.outputs.color }}
namedLogo: python
ここまで完成していると、GitHub Actionsでの処理は完成です。ひとまず1度アクションを実行してください。
7. READMEにバッジを張ろう
READMEにバッジを張ります。そもまえに、格納先として指定したGistにpytest-coverage-comment.jsonというファイルが出来ていることを確認してください。
以下のリンクは実際に稼働しているサンプルです。
参照するとpytest-coverage-comment.jsonというファイルにカバレッジや色などの情報が保存されていることが見て取れます。
アクション実行後のgistの状態
この情報をパラメータとして、Shields.ioに与えてバッジを描画することで、gistの内容が更新されれば、自動的に更新されるバッジが完成します。
gistの生データは以下のURLに保存されています。
https:/<GitHub-ID>/<Gist-ID>/raw/<File-Name>
自分の場合だとの具体例は以下のような形です。
このURLをShields.ioのurlパラメータとして与え、ついでにGitHub Actionへのリンクを張っておいてあげれば、カバレッジバッジの完成です。
以下のコードを皆さんのIDに書き換えてREADME.mdなどに貼り付けてください。
アクションへのリンク付き
[![Coverage](https://img.shields.io/endpoint?url=https://gist.githubusercontent.com/<GitHub ID>/<Gist ID>/raw/pytest-coverage-comment.json)](githubアクションへのURL)
アクションへのリンク無し
![Coverage](https://img.shields.io/endpoint?url=https://gist.githubusercontent.com/<GitHub ID>/<Gist ID>/raw/pytest-coverage-comment.json)
- 完成品
まとめ
無課金ユーザーでも出来るカバレッジバッジの作成方法でした。
やはり有料サービスと比べると、微妙にかゆいところに手が届かない感はありますが、ぜひプライベートリポジトリにも導入して、テストコードへの意識向上を行っていきましょう。
Discussion