🐙

Github Actions+Gistでカバレッジ可視化~無課金プライベートリポジトリでもカバレッジバッジが欲しい~

2022/05/14に公開

エレベータピッチ

  • Github ActionsとGistだけでREADME.mdにカバレッジバッジを追加
  • プライベートリポジトリやオーガナイゼーションでも無料で導入可能
  • プルリク内でカバレッジを示すコメント追加
  • Pytestを対象に実施
  • 以下のリポジトリに最小ケースの動作確認済みサンプルを掲載

前提事項

  • GitHub ActionsにてPytestのCIを組んでいる
  • プライベートリポジトリや複数人が管理するOSSでカバレッジを可視化したい

モチベーション

実際にチーム開発をしていても、カバレッジを可視化していないと、自然とテストを軽視しがちになってしまいます。TDDなどでも、テスト結果の可視化をCIに組み込むことの重要性が指摘されています。

また何となくですが、テストカバレッジバッジを表示しているリポジトリはしっかりメンテナンスされていてかっこいい印象があります。ポケモンシールをタンスに貼っていた世代としてはぜひ導入したい。

そこで、自分もチームで使っているオーガナイゼーションにカバレッジ可視化SaaSを導入したいと考えていました。

しかしながら、会社で開発しているオーガナイゼーションのプライベートリポジトリに対して、CodecovCoverallsを導入するためには有料プランが必要になります。

著者はケチなのと、社内でのSaaS導入のための事務作業あれこれをするのが嫌なので、出来れば無課金でカバレッジバッジを作りたかったです。

今回は『pytestのCI自体はすでに作ってるよ』という人向けにPytest Coverage CommentDynamic Badgesを使って、GitHubの無料機能だけでREADMEにカバレッジバッジを設定する方法紹介します。

バッジ作成手順

最終的にこんな感じのバッジを自動的にREADME.mdに記載する手順をステップバイステップで説明します。

Coverage

1. GitHub Actionsに書き込み権限を付与

コメント追加のために書き込み権限が必要になります。
ひとまず、既存のpytest-ci用のアクションにpermissions: write-allを追加します。

pytest.yml
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.yml
- 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をアクションに与えるだけす。

pytest.yml
    - 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作成結果
作成されたgist

ここで、Gist IDを控えておく必要があるのですが、遷移先のurlか、画面左上のgist:以降の文字列がGist IDに該当します。

5. GitHub Gistを書き換えるためのトークンを作ろう

次に、GitHub ActionsからGistを書き換えるための権限を付与したパーソナルアクセストークンを作成します。

まず、GitHubの設定からPersonal access tokensに移動して、『Generate new token』を押します。

settings/tokens
トークン作成画面

適切な期間を設定し『select scopes』の中にあるgistにだけチェックを入れます。

gist check
gistにチェックを入れる

すると、パーソナルアクセストークンの文字列が表示されるのでそちらをコピーしておきます。

そして、カバレッジを表示したいリポジトリのsettigs→secretsに移動し、『New repository secret』を押します。

表示されたNew secretページにて、Nameに任意の名前、Valueにコピーしているトークンを貼り付けて保存します。

add token
トークンの追加

ここまでの設定をすると、このトークンを使って、GitHub Actionsから作成したgistの内容を書き換えることができます。

6. Dynamic Badgesでバッジを作ろう

先ほどのコメントにもバッジが表示されていましたが、README.mdには動的にバッジを変更する必要があります。

そのために必要なのがDynamic Badgesです。

Dynamic Badgesでは、バッジの描画に必要な情報(表示内容、色、デザイン)をGist上に格納します。そして、格納したパラメータをShields.ioを使って描画することで、READMEなどに張ったバッジを動的に変更します。

Gistに必要なパラメータを保存するために以下のコードを追加します。

pytest.yml
    - 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データ格納
アクション実行後のgistの状態

この情報をパラメータとして、Shields.ioに与えてバッジを描画することで、gistの内容が更新されれば、自動的に更新されるバッジが完成します。

gistの生データは以下のURLに保存されています。

https://gist.githubusercontent.com/<GitHub-ID>/<Gist-ID>/raw/<File-Name>

自分の場合だとの具体例は以下のような形です。

https://gist.githubusercontent.com/Uno-Takashi/414743cd31dc749ac219beadd781c2b6/raw/pytest-coverage-comment.json

このURLをShields.ioのurlパラメータとして与え、ついでにGitHub Actionへのリンクを張っておいてあげれば、カバレッジバッジの完成です。

以下のコードを皆さんのIDに書き換えてREADME.mdなどに貼り付けてください。

アクションへのリンク付き

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

アクションへのリンク無し

README.md
![Coverage](https://img.shields.io/endpoint?url=https://gist.githubusercontent.com/<GitHub ID>/<Gist ID>/raw/pytest-coverage-comment.json)
  • 完成品
    Coverage

まとめ

無課金ユーザーでも出来るカバレッジバッジの作成方法でした。

やはり有料サービスと比べると、微妙にかゆいところに手が届かない感はありますが、ぜひプライベートリポジトリにも導入して、テストコードへの意識向上を行っていきましょう。

GitHubで編集を提案

Discussion