pre-commit と GitHub Actions で実行する flake8 と black の設定を共有する方法


:::note info
これは [ZOZO Advent Calendar 2022](https://qiita.com/advent-calendar/2022/zozo) カレンダー Vol.2の9日目の記事です。昨日の投稿は @light0w0 さんの 「[Vertex Piplinesのコンポーネントのスキップ処理](https://zenn.dev/light0w0/articles/b1c5b5c57d0a62)」でした。
:::

# 概要
[pre-commit](https://pre-commit.com/) と [Github Actions](https://docs.github.com/ja/actions) で実行する flake8 と black の設定を共有する方法を紹介します。
具体例としてPythonのリンタ・フォーマッタである flake8 と black を扱っていますが[他の言語の様々な hook ](https://pre-commit.com/hooks.html)で応用可能です。

# なぜ pre-commit と GitHub Actions で二重チェックするのか？
以下2つの理由から二重チェックを行なっています。
- pre-commit を使う理由： 「コミットする前にリンタ・フォーマッタを自動実行することができ、開発者が意識せずともコミットするコードの健全性を保てるため」と「Github Actions などのCIでリンタ・フォーマッタを実行すると時間がかかり開発スピードが損なわれるため」
- Github Actions を使う理由： pre-commit を設定し忘れた開発者のコードについても強制的にリンタ・フォーマッタを実行することができ、マージブロックなどでマージ先ブランチの健全性を保てるため。

# 二重チェックの注意点
Github Actions での flake8 と black の設定としては [Flake8 action](https://github.com/marketplace/actions/flake8-action) と [Black Check](https://github.com/marketplace/actions/black-check) を利用することが考えられますが、これらでは pre-commit の flake8 と black などのオプション設定を共有することはできません。 もし pre-commit と GitHub Actions で実行するリンタ・フォーマッタの設定を共有することができないと Github Actions のリンタ・フォーマッタの設定とは異なる設定で pre-commit による自動フォーマットが実行されてしまいます。 このことによって Github Actions のチェックを通すことができず開発が止まってしまう可能性があります。

そこで下記では pre-commit はどういうものかを紹介するためにその使い方を簡単に説明した後に、pre-commit と Github Actions の設定を共有する方法を紹介します。

# pre-commitの使い方
まず pre-commit を以下のように`pip`でインストールします。
```
$ pip install pre-commit
```
そして、 pre-commit の設定ファイル .pre-commit-config.yaml をGitで管理するディレクトリ配下に作成します。具体例として flake8, black の .pre-commit-config.yaml の設定を以下に書いています。特にオプション設定として flake8 の `args` で1行あたりの文字数制限88文字（デフォルトは79文字だが black の文字数制限88文字に合わせる）を指定しています。
``` yaml
repos:
  - repo: https://github.com/ambv/black
    rev: "22.3.0"
    hooks:
      - id: black
        language_version: python3
  - repo: https://github.com/pycqa/flake8
    rev: "4.0.1"
    hooks:
      - id: flake8
        args: "--max-line-length=88"
```

そして、以下のコマンドを実行することで .pre-commit-config.yaml の設定を反映したリンタ・フォーマッタがコミット時に自動実行されます。
```
$ pre-commit install
```

# pre-commit と Github Actions の設定を共有する方法
pre-commit と Github Actions の設定を共有する方法として pre-commit のコマンド実行を利用する方法を紹介します。pre-commit は自動実行だけでなく以下のコマンドで任意のタイミングで実行することが可能です。
```
pre-commit run --all-files
```
一方で、 Github Actions の設定ファイルでは`on`で push などのトリガーを指定して、`run`で実行したいコマンドを設定することができます。 Github Actions の詳細設定は[公式ドキュメント](https://docs.github.com/ja/actions)に譲りますが、以下の設定ファイルの概要のように`run`にコマンド`pre-commit run --all-files`を指定することも可能です。これによって、Github Actions でも .pre-commit-config.yaml の設定を反映したリンタ・フォーマッタを自動実行することができます。

``` yaml: Github Actionsの設定ファイル概要
name: sample_ci

# push をトリガーとする
on:
  push:

jobs:
    lint-and-format:
        name: lint-and-format
        runs-on: ubuntu-latest
        strategy:
            matrix:
                python-version: [3.9.0]
        steps:
          - name: Checkout
            uses: actions/checkout@v2
          - name: Set up Python ${{ matrix.python-version }}
            uses: actions/setup-python@v2
            with:
              python-version: ${{ matrix.python-version }}
          # 依存関係を考慮したライブラリのインストールstepの記載は省略しています。
          # 実際にGithub Actionsを実行したい場合は適切に記入して下さい。
          # 以下、pre-commitの実行
          - name: Run pre-commit
            run: pre-commit run --all-files
```



# 備考
サンプルのPythonファイルを用意して上記の具体例で示した .pre-commit-config.yaml での pre-commit の実行確認を行いました。
``` python: pre-commit 実行前の sample.py
def sample(a, aa, aaa, aaaa, aaaaa, aaaaaa, aaaaaaa, aaaaaaaa, aaaaaaaaa, aaaaaaaaaa, aaaaaaaaaaa):
    return
```
``` python: pre-commit 実行後の sample.py
def sample(
    a,
    aa,
    aaa,
    aaaa,
    aaaaa,
    aaaaaa,
    aaaaaaa,
    aaaaaaaa,
    aaaaaaaaa,
    aaaaaaaaaa,
    aaaaaaaaaaa,
):
    return
```
実行前は1行目が99文字記述されていましたが、上記のように期待通りフォーマットされていることを確認しました。