こんにちは、研究開発部 Automationグループで研究員をしている李です。
本ブログでは、前編 に続き、新卒開発研修*1 *2に導入したpre-commitの使い方などを共有します。
目次
pre-commit とは?
- pre-commit はコードをリポジトリにコミットする前に特定のチェックを自動で実行するためのフレームワークです。
- コードの品質を保持し、一般的な問題やスタイル違反をいち早く検出するのに役立ちます。
- さまざまなプログラミング言語で使用できるフック(スクリプトやコマンド)をサポートします。
pre-commitを導入した経緯
背景:
- プロジェクトの成長に伴い、コードの品質を一貫して維持することが難しくなってきました。
- 異なる開発者が書いたコードのスタイルがバラバラで、レビュープロセスにも多くの時間が費やされるようになりました。
- また、文法のミスやフォーマットの問題など、小さなエラーが頻繁に発生し、これがバグにつながることもありました。
- 他に、API keyをpushしてしまったなどのまれに起きてしまう最悪の事態を事前に防ぐ必要があります。
目的:
- コードの品質を自動的に保証し、コーディングスタイルの一貫性を確保することで、開発プロセスを効率化します。
- また、コードレビューの贅沢な時間を削減し、より重要な設計やロジックの議論に集中できる環境を作り出すことが目的です。
- さらに、新しい開発者がチームのコーディング標準をすばやく理解し、遵守することを助けるためです。
対策法:
- pre-commitを導入し、コードをリポジトリにコミットする前に自動で複数のチェックを行うようにしました。
- これには、コードフォーマッターの実行、構文チェック、コーディング規約の遵守チェックなどが含まれます。
- 前編 で説明したRuffを利用して、開発者がコミットを行うたびに自動で実行されます。
導入手順
1. インストール
通常は以下のコマンドでインストールしますが、
$ pip install pre-commit
今回は、別のリポジトリの環境とバッティングしないため、poetry環境にinstallします。
$ poetry add -G dev pre-commit
2. yamlファイルの設定
repos: - repo: https://github.com/pre-commit/pre-commit-hooks rev: v4.4.0 hooks: - id: check-added-large-files - id: check-merge-conflict - id: check-json - id: check-toml - id: check-xml - id: check-yaml - id: debug-statements - id: detect-private-key - id: end-of-file-fixer - id: fix-byte-order-marker - id: trailing-whitespace - repo: https://github.com/charliermarsh/ruff-pre-commit rev: # versionを指定する hooks: - id: ruff args: ["--fix"] - repo: https://github.com/pre-commit/mirrors-mypy rev: # versionを指定する hooks: - id: mypy additional_dependencies: ["types-requests"] - repo: local hooks: - id: git-secrets name: git secrets entry: git secrets --scan language: system types: [text]
このyamlファイルでできること
- check-added-large-files
- 特定のサイズを超えるファイルのコミットを防ぎます。
- check-json・check-toml・check-xml・check-yaml
- 構文をチェックします。
- check-merge-conflict
- マージコンフリクトのマーカー(
<<<<<<<
,=======
,>>>>>>>
)がファイルに残っていないかチェックします。
- マージコンフリクトのマーカー(
- debug-statements
- コードからデバッグ用のステートメント(例:
pdb.set_trace()
,console.log()
)が削除されているかチェックします。
- コードからデバッグ用のステートメント(例:
- detect-private-key
- 一部の秘密鍵が検出できます。
- end-of-file-fixer
- ファイルが適切な改行文字で終了しているかチェックします。
- 自動で修正できます。
- fix-byte-order-marker
- ファイルの先頭にある不要なバイトオーダーマークを削除します。
- trailing-whitespace
- 行末の不要な空白文字(スペースやタブ)を検出し、削除します。
注意してほしいこと
- mypyは
additional_dependencies
を適切に書かないといけません。 - Ruff、Black、mypyなどはpoetry内のversionに合わせなければなりません。
3. git-secretsの導入と設定
- パスワードが検知できるように git-secrets も導入しました。
- 大再前提として、
.env
ファイルや、インシデント情報になりそうなファイルは.gitignore
をきちんと書くことです。 git-secretsで検知できた時点では、もうすでに危険です。インシデントを起こさないように、細心の注意をはらってください。
git-secretsとは?
- 機密情報が誤ってgitリポジトリにcommitされるのを防ぐためのツールです。
- commit、commit message、または
git diff
の出力をスキャンし、高エントロピー文字列やパスワード、SSHキー、AWSアクセスキーなどの機密情報を示す可能性のあるパターンを検出します。 - 事前に設定されたパターン以外では、カスタムパターンのスキャンにも対応しており、さまざまな種類の秘密情報が検出できます。
- 検出された場合、commitは強制的に中断され、warning messageが表示されます。
導入
$ cd /tmp $ git clone https://github.com/awslabs/git-secrets $ cd git-secrets/ $ sudo make install
ここで、cd /tmp
の理由:cloneしたgit-secretsのファイルは、基本的に本リポジトリには使わないので、あまり触らないファイルに置いておくためです。
設定
# aws クレデンシャル $ git secrets --register-aws # slack api $ git secrets --add 'xoxb-[0-9]{13}-[0-9]{13}-[a-zA-Z0-9]{24}' $ git secrets --add 'xapp-[0-9]{1}-[a-zA-Z0-9]{11}-[0-9]{13}-[a-zA-Z0-9]{64}' # azure openai api $ git secrets --add '[a-zA-Z0-9]{32}'
注意してほしいこと
- リポジトリがないとできません
- pre-commitの
detect-private-key
と、git secrets --register-aws
で、カバーできないものをgit secrets --add
で対応します。しかし、書かれている正規表現以外は検知できません。
4. 反映
- 設定を有効化するために、↓ のコマンドを実行します:
# gitファイルにpre-commitを適用する $ pre-commit install pre-commit installed at .git/hooks/pre-commit
注意してほしいこと
- .gitファイル生成できていないと、↑ の反映ができないので、必ず
git clone
してから、pre-commit install
するようにしてください。
5. 実行結果
- commitすると、↓ のoutputが出ます。
- コマンドラインcommitも、拡張機能を用いたcommitなども ↓ は走れます。
- 全てのerrorを解決しないとcommitができません。
2024-03-15 16:26:48.882 [info] > git ...... ...... ...... 2024-03-15 16:26:48.882 [info] [WARNING] Unstaged files detected. [INFO] Stashing unstaged files to /home/hogehoge@gees.local/.cache/pre-commit/patch1710487608-2247946. check for added large files..............................................Passed check json...........................................(no files to check)Skipped check for merge conflicts................................................Passed check toml...........................................(no files to check)Skipped check xml............................................(no files to check)Skipped check yaml...........................................(no files to check)Skipped debug statements (python)................................................Passed detect private key.......................................................Passed fix end of files.........................................................Passed fix utf-8 byte order marker..............................................Passed trim trailing whitespace.................................................Passed Detect secrets...........................................................Passed black....................................................................Passed ruff.....................................................................Passed
pre-commit のメリットとデメリット
メリット
- API keyがpushするかもしれない不安はある程度軽減できます。
- commitする時に自動でRuffのエラーもチェックしてくれます。
デメリット
-(当然ですが)事前に想定されていないAPI keyの検知はできません。 - ダミーのkeyも引っかかります。 - リンター周りは、versionを合わせるための設定が複雑です。
まとめ
pre-commitは、前編で説明したRuffと同様に、新卒メンバーだけでなく、R&D全体にも導入しました。これにより、commit前の自動化されたコードチェックを通じて、品質管理を強化しました。経験豊富な開発者にとってもプロジェクトの初期段階からコードの品質を維持するための手間が大幅に削減され、より多くの時間を実際の開発作業に費やすことが可能になりました。
このようなツールの導入は、新入社員の教育だけでなく、プロジェクト全体の品質や効率にもプラスの影響を与えました。今後も、研修プログラムや開発プロセスの改善に向けて、さらなるツールやプロセスの導入を検討していきたいと考えています。