Sansan Tech Blog

Sansanのものづくりを支えるメンバーの技術やデザイン、プロダクトマネジメントの情報を発信

【後編】24新卒開発研修で新しいツールを導入した話 〜pre-commit の導入方法と使い方など〜

こんにちは、研究開発部 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前の自動化されたコードチェックを通じて、品質管理を強化しました。経験豊富な開発者にとってもプロジェクトの初期段階からコードの品質を維持するための手間が大幅に削減され、より多くの時間を実際の開発作業に費やすことが可能になりました。

このようなツールの導入は、新入社員の教育だけでなく、プロジェクト全体の品質や効率にもプラスの影響を与えました。今後も、研修プログラムや開発プロセスの改善に向けて、さらなるツールやプロセスの導入を検討していきたいと考えています。

© Sansan, Inc.