GitHub ActionsとCodecovでテスト・カバレッジ計測を自動化、README.mdに結果をバッジ表示する。

# 目的

- Pythonの各バージョンごとのテストを自動化する。
- カバレッジを計測できるようにする。
- テスト結果、カバレッジ計測結果をリポジトリのREADME.mdでバッジ表示し可視化する。

# 背景

OSS開発に向けた勉強の一環でPythonのライブラリを開発したが、サポートバージョンのテストを全て手動で回すのは現実的ではないため、CI等を導入しテスト、カバレッジ計測の自動化を検討していた。

調べた際、テスト実行等のworkflowを定義できる`GitHub Actions`、テスト時に計測したカバレッジを受け取り可視化する`Codecov`というサービスを見つけた。

# GitHub Actionsとは

GitHubが提供する`CI/CDサービス`です。
様々なworkflowをGitHub内のイベントに応じて実行できます。
実行されるworkflowは様々なものが用意されており、自身で1から作ることもできますが、既存のworkflowを利用、改良することも可能です。

https://ja.wikipedia.org/wiki/GitHub_Actions

リポジトリの公開設定によって利用制限があります。
publicリポジトリやセルフホストランナーの場合は無料のようです。privateリポジトリについては一定の制限があります。
支払いにも関わり、本投稿では鮮度を保てないため下記公式ページを参照とします。

https://docs.github.com/ja/billing/managing-billing-for-github-actions/about-billing-for-github-actions#about-spending-limits

https://docs.github.com/ja/actions

# Codecovとは

CIで実行したテストカバレッジの計測結果を受け取り、それを`可視化するサービス`です。
このサービス自体がテストの実行やカバレッジの計測をするわけではなく、結果を受け取りそれを可視化するというやりとりが行われます。

こちらもオープンソースについては無料のようです。

https://about.codecov.io/pricing/

https://about.codecov.io/

https://docs.codecov.com/docs

# 全体像

こんなことをします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/38724/940ff0b6-b072-9370-31e5-b56394ce2e23.png)

# テストの自動化

workflowが用意されているためそれを改良し利用します。

## テストを実行するworkflowを追加

GitHubリポジトリのActionsタブで、`New workflow`ボタンを押します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/38724/862f9097-2243-e12a-852d-46dfe0d34a01.png)
`python test`で検索し、検索結果から赤枠のworkflowの`Configure`ボタンを押します。見つからない場合は条件を追加し絞り込んでください。
他にも似たようなworkflowがありますが、説明文をよく確認しましょう。今回はサポートするバージョン全てに対してテストを行いたいため、`複数のPythonバージョンでパッケージの試験`と説明があるworkflowを選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/38724/137cd93c-5634-0c23-273e-343fa9ef6b22.png)

## 追加したworkflowを編集

**workflow名称、テスト対象Pythonバージョンに変更がない場合は本項の内容は不要です。**
その場合、後続の説明にて`unit-test`というworkflow名称が出てきますが、読み替えて手順を操作してください。

下記のような画面が表示されるため、任意のファイル名（今回はunit-testにしました）に変更しコードを編集します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/38724/f2de5f91-3274-41dc-0fed-5ad30875c529.png)
コードの編集箇所は下記です。冒頭の`name`についても任意ですが、今回は`unit-test`にしました。
テスト対象のPythonバージョンはお好きに編集してください。私は3.7でもテストしたかったため追加してあります。

本投稿では変更しませんが、冒頭の`on:`の箇所がworkflowの実行タイミングです。
このworkflowの実行タイミングはmasterブランチへのpush、pull_requestマージが指定されています。
ブランチについてはお使いのリポジトリに合わせ編集願います。
```diff_yaml:python-package.yml
# This workflow will install Python dependencies, run tests and lint with a variety of Python versions
# For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions

- name: Python package
+ name: unit-test

on:
  push:
    branches: [ "master" ]
  pull_request:
    branches: [ "master" ]

jobs:
  build:

    runs-on: ubuntu-latest
    strategy:
      fail-fast: false
      matrix:
-         python-version: ["3.8", "3.9", "3.10"]
+         python-version: ["3.7", "3.8", "3.9", "3.10"]

（省略）
```
編集が完了したら右上の`Start commit`ボタンを押しコミットします。
コミットメッセージ等求められますが、任意で入力願います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/38724/f7ef38b5-19b3-dc35-e73c-0442cdf0a313.png)

## workflowの実行結果を確認

`Actions`タブを表示し、作成したworkflowを選択すると、結果が表示されます。実行中の場合はしばらく待つと反映されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/38724/b0c10e0b-9971-a416-27ea-587e93cea0ec.png)

## workflowの実行結果をバッジで表示

（2022/8/28追記　workflowの実行結果画面からバッジ作成方法を追記）

workflowの実行結果画面にバッジ作成メニューがあります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/38724/dd2d8ab2-4a40-8447-ea7d-44da18d44274.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/38724/5c1165ad-dfaf-ae2e-b5f8-b78c861d75fb.png)

公式にもバッジの追加方法があります。

https://docs.github.com/ja/actions/monitoring-and-troubleshooting-workflows/adding-a-workflow-status-badge

README.md等に下記を追加することでバッジ表示できます。

```md:例
[![unit-test](https://github.com/{ユーザ}/{リポジトリ}/actions/workflows/unit-test.yml/badge.svg)](https://github.com/{ユーザ}/{リポジトリ}/actions/workflows/unit-test.yml)
```

こんな感じで表示されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/38724/149f83aa-2d94-db04-8d75-2f3fdd3ba264.png)

# カバレッジの計測、連携

事前にCodecovへのユーザ登録を行なった上で以降の操作を行います。
未登録の方は登録をお願いします。

CodecovとGitHub Actionsとの連携については下記にチュートリアルがあります。
本手順はチュートリアルに沿って、必要な操作のみを行います。

https://docs.codecov.com/docs/github-tutorial

## Codecov GitHubアプリのインストール

Codecovチュートリアルページのリンク先からインストールします。

https://docs.codecov.com/docs/github-2-getting-a-codecov-account-and-uploading-coverage

赤枠のリンクをクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/38724/6c58a96b-2eec-b544-1993-e31178ffd9e7.png)
インストールページが表示されるためインストールします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/38724/157e2140-f693-03fc-48bc-9fcbd99b12d2.png)

## Codecov GitHubアプリのインストール確認

GitHubの右上ユーザアイコンからメニューを開き、`Settings`＞`Applications`＞`Installed GitHub Apps`と辿ります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/38724/9a248104-1ffa-63d1-fde2-0bff38f0c58c.png)
一覧に`Codecov`が表示されていればインストール成功です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/38724/c030b6b6-243b-dc51-32c5-129f158885bd.png)

## workflowにカバレッジ計測、計測結果アップロード処理を追加

コードの編集箇所は下記です。
カバレッジ計測ライブラリの`pytest-cov`のインストール、pytestへカバレッジ計測、レポート出力の指定を追加、計測結果のアップロード処理を追加します。

```diff_yaml:unit-test.yml
# This workflow will install Python dependencies, run tests and lint with a variety of Python versions
# For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions

name: unit-test

（省略）

    - name: Install dependencies
      run: |
        python -m pip install --upgrade pip
-         python -m pip install flake8 pytest
+         python -m pip install flake8 pytest pytest-cov
        if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
    - name: Lint with flake8
      run: |
        # stop the build if there are Python syntax errors or undefined names
        flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics
        # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide
        flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics
    - name: Test with pytest
      run: |
-         pytest
+         pytest --cov=./テスト対象のディレクトリ --cov-report=xml
+     - name: Upload coverage reports to Codecov with GitHub Action
+       uses: codecov/codecov-action@v3
```
:::note warn
pytest実行時のオプション`--cov`に指定するパスを限定的にしなかった場合（`./`等の上位のディレクトリを指定した場合）、ディレクトリ構造にもよりますが、pypiへの登録スクリプト`setup.py`等の意図していないソースも対象となってしまい、カバレッジ100%とならない場合があります。
その際はテスト対象のソースが置かれたディレクトリを指定する等、限定的な指定とするか、`pytest-cov`の設定で除外設定を指定する等対応をしてください。
:::

## workflowの実行結果を確認

下記ページにアクセスし結果を確認します。

https://app.codecov.io/gh

カバレッジ計測結果が右側赤枠に表示されます。リポジトリ名のリンクを辿れば、計測結果の詳細を確認できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/38724/282ce525-f7cb-8751-4bac-2e07bc5ee724.png)

## Codecovに連携したカバレッジ測定結果をバッジで表示

前項の一覧画面でリポジトリ名をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/38724/5dafe993-98a4-2e3a-23ea-403248264df0.png)
`Settings`タブを選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/38724/0425c33a-f299-b6f5-7156-5f750d2163db.png)
`Badges & Graphs`メニューを選択するとバッジ表示のコードが表示されます。お好きな形式をコピーし利用してください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/38724/cebf58d0-3c85-abfa-fc54-a02f5974a2a6.png)
こんな感じで表示されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/38724/4ce742b6-9a99-fb6c-4136-b723e3a34f5a.png)

# 参考

参考となるリポジトリを掲載します。勉強のために作成したもののため、OSS自体の質は気にしないでください。
レイアウト崩れが発生してしまったため、バッジの表示コードは本投稿とは少し違いますがご了承願います。

https://github.com/MamedenQ/function-burger

# 最後に

実務でCIが導入されているプロジェクトに配置されたことはあったが、自身で構築やカスタマイズをした経験はなかった。
本投稿で構築した内容は簡単なものではあるが、どのCIにおいても目的や本質部分は同じのため、入門知識としてはいいものが得られたと思う。

pipyへのデプロイについても`GitHub Actions`で自動化ができるらしいので、今後他のworkflowも構築し自動化や効率化をしたい。