Webエンジニア向けプログラミング解説動画をYouTubeで配信中!
▶ チャンネル登録はこちら

【ITニュース解説】Pre-commit Hooks for Terraform and Python: 6 Tips That Stick

2026年10月19日に「Dev.to」が公開したITニュース「Pre-commit Hooks for Terraform and Python: 6 Tips That Stick」について初心者にもわかりやすく解説しています。

作成日: 更新日:

ITニュース概要

Pre-commit hooksは、TerraformやPythonコードの品質をコミット前に自動チェックする仕組み。フォーマットやリンティング、秘密情報の検出などを開発者のローカルで早期に修正し、CI/CDのエラーを減らす。高品質なコードを保ち、開発効率を高めるのに役立つ。

ITニュース解説

ソフトウェア開発において、チームでコードを共同で開発する際、コードの品質や統一性を保つことは非常に重要である。しかし、多くの開発者がそれぞれ異なるスタイルでコードを書いたり、小さなミスを見落としたりすることはよくある。その結果、プルリクエスト(コード変更をチームに提案する仕組み)が出された後、多くのレビューコメントが「コードの整形を行ってください」や「使われていない変数を削除してください」といった内容で溢れてしまうことがある。このようなコメントのやり取りは時間の無駄であり、本来の機能レビューに集中できなくなる。Pre-commit Hooksは、このような問題を解決するための強力なツールである。これは、開発者がGitのコミット操作(コード変更をローカルリポジトリに記録する操作)を行う前に、特定のチェックや処理を自動的に実行させる仕組みのことである。つまり、コードがリポジトリに記録される前に、問題点を自動で検出し、修正を促すことで、未完成なコードやスタイル違反のコードがコミットされることを防ぐ。これにより、コードレビューの負担を減らし、コード品質を向上させ、開発プロセス全体の効率を高めることができる。特に、Terraform(インフラをコードで管理するツール)とPython(アプリケーション開発で広く使われる言語)が混在するようなプロジェクトでは、それぞれのコードに対して適切なチェックを行うことが求められるため、Pre-commit Hooksは非常に有効となる。

Pre-commit Hooksの動作は、プロジェクトのルートディレクトリにある.pre-commit-config.yamlという設定ファイルで定義される。このファイルには、どのツール(フック)を、どのような順番で、どのバージョンで実行するかといった情報が記述される。重要な点の一つは、各フックのバージョンを具体的に固定すること(revフィールドにタグやコミットハッシュを指定すること)である。例えば、「最新バージョン」や「開発ブランチ」を指定してしまうと、いつの間にかフックの挙動が変わってしまい、ローカル環境では問題なく通ったのに、継続的インテグレーション(CI)環境では失敗するというような、「私の環境では動くのに!」という問題が発生しやすくなる。バージョンを固定することで、すべての開発者のローカル環境やCI環境で同じバージョンのフックが実行されることを保証し、環境による挙動の違いに悩まされることなく、安定した開発が可能となる。フックのバージョンアップはpre-commit autoupdateコマンドを使って意図的に行い、変更内容を通常の依存関係の更新と同様に確認することが推奨される。

Terraformコードを扱うプロジェクトでは、以下のようなフックが特に有用である。まず、「terraform_fmt」は、標準のterraform fmtコマンドを実行し、Terraformコードの記述スタイルを自動的に整形する。これにより、コードの見た目が常に統一され、可読性が高まる。「terraform_tflint」は、Terraformコードの静的解析ツールであり、使われていない宣言や設定ミス、プロバイダー固有のルール違反などを検出する。これにより、潜在的なエラーや脆弱性を早期に発見できる。「terraform_docs」は、Terraformモジュールの入力変数や出力変数を記述したREADMEファイルを自動的に生成・更新する。これにより、ドキュメントと実際のコードとの乖離を防ぎ、手作業での更新漏れを防ぐことができる。これらのフックは、誤検知が少なく、実行も高速なため、最初に導入するのに適している。一方で、「terraform_validate」は、Terraformの設定ファイルの構文や論理的な整合性を検証するフックだが、実行にはプロバイダーの初期化が必要な場合があり、初回実行時やキャッシュがない場合に時間がかかることがある。また、古い.terraformディレクトリが原因でエラーが発生することもあるため、安定した運用が確認できてから導入することが推奨される。特に重要な注意点として、terraform planのような、クラウド認証情報やネットワークアクセスを必要とするフックは、Pre-commit Hooksとして実行すべきではない。これらの操作は、通常CI環境で適切に管理された認証情報の下で実行されるべきであり、ローカルのPre-commit Hooksで実行しようとすると、設定が複雑になったり、開発者がフックをスキップする習慣がついてしまったりする可能性が高い。

Pythonコードの品質管理には、「Ruff」というツールが非常に役立つ。Ruffは、これまでのflake8、isort、Blackといった複数のツールが担っていたコードリンティング(構文やスタイルのチェック)とフォーマット(コード整形)の機能を一つに統合した高速なツールである。これにより、設定ファイルがシンプルになり、実行速度も向上するため、開発者の負担を減らすことができる。Ruffの設定はpyproject.tomlファイルに記述することで、開発環境のエディタ、CI、そしてPre-commit Hooksがすべて同じルールを参照し、一貫したチェックが可能となる。Ruffには--fix引数を指定できるフックがあり、これは安全な修正を自動的に適用する機能である。例えば、未使用のインポート文を削除したり、フォーマットを修正したりする。この自動修正によってファイルが変更された場合、Pre-commit Hookは意図的にコミットを失敗させる。これはバグではなく、開発者に変更された内容を確認し、再度ステージングしてコミットすることを促すための仕様である。また、mypyのような型チェックツールを使用している場合、Pre-commit Hookの隔離された環境ではプロジェクトの依存関係が利用できないため、サードパーティ製のパッケージのインポートがエラーとして扱われることがある。この問題は、additional_dependenciesにスタブやライブラリを追加することで解決できるが、mypyは実際のプロジェクト環境を持つCIで実行する方が一般的で簡単な方法とされている。

Pre-commit Hooksが効果的に機能するためには、実行速度が非常に重要である。もしフックの実行に数秒以上かかるようだと、開発者はコミットのたびに待たされることにストレスを感じ、「git commit --no-verify」オプションを使ってフックをスキップしてしまう習慣がついてしまう可能性がある。フックがチェックする対象はステージングされたファイルに限定されるため、ある程度の高速化は期待できるが、セキュリティスキャナーや多くのTerraformルートに対する完全なバリデーションなど、本質的に時間がかかるチェックも存在する。このような時間のかかるチェックは、コミット時ではなく、Gitのプッシュ操作(ローカルリポジトリの変更をリモートリポジトリに送信する操作)の前に実行される「pre-push」ステージに移動することが推奨される。これにより、開発者は小さなコミットを頻繁に行う際にも高速なフィードバックを得られ、一方でコードがリモートリポジトリに送られる前には、より徹底的なチェックが実行されるというバランスの良い運用が可能となる。pre-pushフックを有効にするには、.pre-commit-config.yamlファイルの冒頭でdefault_install_hook_typesにpre-pushを追加し、個々のフックのエントリでstages: [pre-push]と指定する必要がある。設定変更後は、pre-commit installコマンドを再度実行して、.git/hooksディレクトリにフックが正しくインストールされていることを確認することが重要である。

ソースコードの履歴に誤って機密情報(APIキーやパスワードなど)がコミットされてしまうことは、非常にコストのかかる問題である。たとえ次のコミットでその情報が削除されたとしても、Gitの履歴には残ってしまい、フォークやクローンを通じて広がる可能性があるため、根本的な解決策としては、その機密情報をすべて無効化し、新しいものに交換するしかない。コミットをブロックすることで、このようなコストのかかる事態を未然に防ぐことが最も安価な解決策である。この対策には、複数のフックを組み合わせることが効果的である。公式のpre-commit-hooksリポジトリに含まれる「detect-private-key」フックは、秘密鍵のパターンを検出する。「check-added-large-files」フックは、大きなファイルが追加された場合に警告を発し、意図しない設定ファイルやアーカイブのコミットを防ぐ。さらに、「Gitleaks」のような専用のスキャナーを導入すれば、クラウドサービスのキーやトークンなど、より多様な機密情報のパターンを検出できるようになる。これらのフックはすべて同じ設定ファイルに追加できる。しかし、フックはあくまで安全網であり、主要な制御ではないことを理解しておく必要がある。例えば、.tfstateファイル(Terraformの状態を記録するファイル)や、機密情報を含む.tfvarsファイルは、そもそも.gitignoreに追加してGit管理対象から除外しておくべきである。また、テストデータなどで一時的に機密情報と似たパターンが現れ、誤検知が発生することもある。その場合は、フックを無効にするのではなく、スキャナーが提供する許可リストの仕組みを利用して、特定のファイルやパターンを無視するように設定することが推奨される。

Pre-commit Hooksは非常に便利だが、開発者が「git commit --no-verify」オプションを使うことで、簡単にスキップできてしまうという性質を持つ。そのため、ローカルフックが完全に適用されることを保証する最終的な手段として、継続的インテグレーション(CI)環境でのフック実行が不可欠となる。CIパイプラインにおいて、「pre-commit run --all-files」コマンドを実行することで、リポジトリ内のすべてのファイルに対してフックが適用され、すべての変更がルールに準拠していることを強制できる。これは、ローカルにフックをインストールしていないコントリビューターからの変更に対しても有効であり、設定ファイル自体のバリデーションも兼ねる。CIでフックを実行する際には、フックが依存する外部ツール(Terraform本体、TFLint、terraform-docsなど)がCI環境にインストールされている必要があることに注意が必要である。Pre-commit Hooksは、これらのツールを自身でインストールするのではなく、既存の実行ファイルを呼び出すだけだからである。ローカルでは問題なく動くのに、CIで「コマンドが見つかりません」というエラーが出た場合、CI環境に必要なツールがインストールされていないことが原因であることが多い。GitHub ActionsのようなCIサービスを利用する場合は、適切なセットアップアクションを使用するか、ベースイメージに必要なツールを含める必要がある。最後に、新しい開発者がプロジェクトに参加した際のオンボーディングプロセスを簡素化することも重要である。例えば、pip install pre-commit && pre-commit installといった一連のコマンドをまとめたセットアップスクリプト(make setupのようなターゲット)を用意し、たった一行のコマンドで必要なフックがすべてインストールできるようにすると良い。pre-commit installステップは、Gitがリポジトリをクローンする際にフックファイルを自動的にコピーしないため、手動での実行が必要となる唯一のステップである。この点を明確にすることで、開発者はスムーズにプロジェクトに貢献できるようになる。

関連コンテンツ

関連IT用語