はじめまして。株式会社iimonでバックエンドエンジニアを担当している玉山です。
では早速始めていきます。
前置き
今回はiimonで使っているリンターとフォーマッターをgitの機能でcommitをフックし、レビューのコストを下げてしまおうというお話です。
gitの機能でcommitをフックするには.git/hooks/pre-commitを言うファイルにシェルスクリプトで書けば機能します。
ですが、.git/hooks/pre-commitはgitでの管理対象外の為、履歴が残りません。
そこで今回はpre-commitというフレームワークを使います。
pre-commitのメリットとデメリット
pre-commitは.pre-commit-config.yamlというファイルでgit/hooks/pre-commitを管理しGit管理下におけるというメリットがあります。
デメリットとしてはチーム開発の時にリポジトリをクローン等した時チーム全員がpre-commitを入れ、後述するコマンドを打たないといけないことがあります。
されど、その為だけにCIへわざわざいれなくても個人のローカル環境でリンター、フォーマッターをかけることで開発スピードが上がるので導入を決めました。
iimonではテストはGitHubActionsを使っているのですが、やろうと思えばpre-commitでやることも可能です。
しかし、毎回commit時にテストがかかると時間がかかるのでそこはCIに任せています。
インストール
まずは下記コマンドでインストールしましょう。
$ pip install pre-commit
or
$ brew install pre-commit
参考:https://pre-commit.com/#install
無事インストールできたらバージョンが表示されます。
$ pre-commit --version pre-commit 3.0.4
試しにつかってみよう
次はサンプルの設定ファイルを作って見ましょう。
プロジェクト直下で下記コマンドを実行して下さい。
$ pre-commit sample-config > .pre-commit-config.yaml
プロジェクト直下に.pre-commit-config.yamlができると思います
中身はこんな感じで基本的なものしか入っていません。
# See https://pre-commit.com for more information # See https://pre-commit.com/hooks.html for more hooks repos: - repo: https://github.com/pre-commit/pre-commit-hooks rev: v3.2.0 hooks: - id: trailing-whitespace - id: end-of-file-fixer - id: check-yaml - id: check-added-large-files
デフォルトでフック時にチェックしているものはこちらに説明があります。
https://pre-commit.com/hooks.html
適当なファイルの末尾にスペースを追加し、commitしてみましょう。
すると下記のようなエラーが出てcommitできないと思います。
画面はSourceTreeのものになります。
Trim Trailing Whitespace.................................................Failed
この部分がFailedなのでコミットできないことが分かります。
iimonではどうしてる?
最後にiimonで使っている設定を載せておきます。
# See https://pre-commit.com for more information # See https://pre-commit.com/hooks.html for more hooks exclude: /migrations/|/static/ repos: - repo: https://github.com/pre-commit/pre-commit-hooks rev: v4.4.0 hooks: - id: trailing-whitespace - id: end-of-file-fixer - id: check-yaml - id: check-added-large-files - id: detect-aws-credentials - id: detect-private-key - repo: https://github.com/Yelp/detect-secrets rev: v1.4.0 hooks: - id: detect-secrets - repo: https://github.com/pycqa/flake8 rev: 6.0.0 hooks: - id: flake8 args: ["--ignore=E203,E501,W503,W504"] - repo: https://github.com/pre-commit/mirrors-mypy rev: v1.0.1 hooks: - id: mypy args: [--ignore-missing-imports] # pythonの外部ライブラリを読み込むため additional_dependencies: ["types-all"] - repo: https://github.com/psf/black rev: 23.1.0 hooks: - id: black language_version: python39 - repo: https://github.com/pycqa/isort rev: 5.12.0 hooks: - id: isort args: ["--profile", "black"]
注意
ハマった所としてはYAMLの記法ではあっていても、ハイフンの後に半角スペースを3つ入れないとエラーになった所です。
解説
下記、それぞれ追加したものを解説していきます。
なお追加したものは全て最新のrevにしています。(2022/02/22現在)
- excludeはprecommitでチェックするディレクトリを除外したいものをパイプ(|)つなぎで
- detect-aws-credentials
- 自分のAWSCLIのクレデンシャル情報が入っていないか
- detect-private-key
- 秘密鍵が入っていないか
- detect-secrets
- flake8
--max-line-lengthで88をよく設定に加えているのを見たりしますが、iimonでは特定のキーだったりの文字列が長いものがあり、これがあると文字列連結等で対応が必要となり、可読性が下がるということで文字列の長さはblackに任せることにしました。blackドキュメントだとflake8のBugbearプラグインでB950をE501の代わりに使うようにともありますが、BugbearのREADME.mdに下記のように今後明示的な独自の警告は将来的に削除予定の為、不採用としました。
Note: Bugbear's enforcement of explicit opinionated warning selection is deprecated and will be removed in a future release. It is recommended to use extend-ignore and extend-select in your flake8 configuration to avoid implicitly altering selected and/or ignored codes.
- https://black.readthedocs.io/en/stable/the_black_code_style/current_style.html#line-length
- https://github.com/PyCQA/flake8-bugbear
- blackとflake8の干渉について
- ドキュメントには--ignore=E203しか記載ありませんが、W503,W504がblackで整形してくれる為、追加しています。また、E501は干渉はしませんがiimonでは上述の通りblackに任せることになっていますので加えてます。
- https://github.com/psf/black/blob/06ccb88bf2bd35a4dc5d591bb296b5b299d07323/docs/guides/using_black_with_other_tools.md#flake8
- mypy
- -ignore-missing-importsは解決できないモジュール(スクリプト)のインポートを無視する。ただし、解決できない関数のインポートエラーは例外搬出される。
- https://qiita.com/keng000/items/8e55e3cfdba888fba290
- additional_dependencies: ["types-all"]はこのプラグインを入れないと外部のライブラリの型付けを全て行うことを自動でやってくれます。
- https://pypi.org/project/types-all/
- black
- コードを自動的に整形
- PEP8で決められていないものも厳格に定められており、オプションも少ない。
- isort
- PEP8に準拠したimport文にする。
余談
どうしてもシェルスクリプトで管理したいんだ!という方は別の方法としてこんな方法もあるみたいです。