個人の小さいプロダクトでもCIでコードチェックをしたいなと思ったのですが、GitHub Actionsを使うのもめんどくさいし、ローカルでちょっと確かめたいくらいだったので、Gitのフックを簡単に管理できるツール「lefthook」を導入してみました。
導入したプロジェクト
lefthookとは?
lefthookは、Gitのフックを簡単に管理できるツールです。
Gitのフックは、コミットやプッシュなどの操作が行われる前に特定のスクリプトを実行するための仕組みですが、lefthookを使うことで、これらのフックを簡単に設定・管理できます。
lefthookの特徴
- 簡単な設定: YAML形式の設定ファイルでフックを定義できます。
- 多言語対応: Ruby、Python、Node.jsなど、さまざまな言語でスクリプトを実行できます。
- 高速: 並列実行やキャッシュ機能により、フックの実行が高速化されます。
- 柔軟なフック管理: プロジェクトごとに異なるフックを設定できます。
lefthookの導入手順
1. インストール
今回はMac環境かつモノレポ構成なので、Homebrewでインストールしました。
Homebrewを使ってインストールする場合、以下のコマンドを実行します。
brew install lefthook
フロントのリポジトリで使う場合は、npm経由でも良さそうです。
npm install lefthook --save-dev
その他のインストール方法にGo・Ruby・Pythonなどもあります。
Go (>= 1.25)
go install github.com/evilmartians/lefthook/v2@v2.0.3
go tool
go get -tool github.com/evilmartians/lefthook
Ruby
gem install lefthook
Python
pip install lefthook
2. 初期化
プロジェクトのルートディレクトリで以下のコマンドを実行して、lefthookを初期化します。
lefthook install
lefthook.ymlがプロジェクトのルートディレクトリに作成され、Gitフックが設定されます。
EXAMPLE USAGEが作成され、pre-commitとpre-pushのサンプル設定が含まれています。
3. 設定ファイルの作成
プロジェクトのルートディレクトリにlefthook.ymlという名前の設定ファイルができます。
今回はGoとReactのプロジェクトで、コミット前にコードフォーマットなどを実行する設定を追加しました。
Goの部分に関しては以下の記事を参考にしました。
golangci-lintを中心に設定しています。
lefthookの設定ファイルでは、以下のような方法で特定のファイルが指定することもできます。
glob: "*.拡張子" - 指定した拡張子のファイルすべて
{staged_files} - staged されたファイルで glob パターンにマッチするもの)
{all_files} - すべてのファイル(staged されていないものも含む)
lefthookの細かい指定は公式ドキュメントを参照してください。
作成したReactとGoでのモノレポ構成でのlefthook.yml例
go-mod-tidy:に関しては、root:でbackendディレクトリを指定しないと、go.modが見つからないエラーが出たので注意してください。
# Lefthook Configuration for Go and Node.js Projects
# https://lefthook.dev/configuration/
pre-commit:
parallel: true # 並列実行を有効化
commands:
# Node.js/TypeScript checks
eslint: # コマンド名
root: [frontendのディレクトリ名] # ルートディレクトリを指定
glob: "*.{js,ts,jsx,tsx}" # 対象ファイルのパターンを指定
run: npx eslint {staged_files} --fix # 実行するコマンドを指定
stage_fixed: true # フォーマットされたファイルをステージングに追加
prettier:
root: [frontendのディレクトリ名]
glob: "*.{js,ts,jsx,tsx,json,md,yml,yaml}"
run: npx prettier --write {staged_files}
stage_fixed: true
typescript:
root: [frontendのディレクトリ名]
glob: "*.{ts,tsx}"
run: npx tsc --noEmit --skipLibCheck
# Go checks (Consolidated with golangci-lint)
go-lint-fix:
root: [backendのディレクトリ名]
glob: "*.go"
# --fix でフォーマット(gofmt)や他の修正を自動実行
run: golangci-lint run ./... --tests --fix
stage_fixed: true
skip:
- merge
- rebase
go-mod-tidy:
root: [backendのディレクトリ名]
glob: "go.{mod,sum}"
run: go mod tidy
stage_fixed: true
pre-push:
parallel: false
commands:
# Node.js tests and security
node-test:
root: [frontendのディレクトリ名]
glob: "*.{js,ts,jsx,tsx}"
run: npm test
skip:
- merge
- rebase
npm-audit:
root: [frontendのディレクトリ名]
glob: "package*.json"
run: npm audit --audit-level=moderate
# Go tests and checks
go-test:
root: [backendのディレクトリ名]
glob: "*.go"
run: go test ./... -race -coverprofile=coverage.out
skip:
- merge
- rebase
go-build:
root: [backendのディレクトリ名]
glob: "*.go"
run: go build -v ./...
skip:
- merge
- rebase
go-lint-check:
root: [backendのディレクトリ名]
glob: "*.go"
run: golangci-lint run ./... --tests
skip:
- merge
- rebase
4. フックの実行
コミットやプッシュなどの操作を行うと、設定したフックが自動的に実行されます。
goのファイルをコミットしようとした際に、go fmtやgo vetが実行され、コードのフォーマットや静的解析が行われます。
# ファイルをコミットする
$ git add .
$ git commit -m "Your commit message"
# lefthookでGoのフックが実行される例
╭──────────────────────────────────────╮
│ 🥊 lefthook v2.0.3 hook: pre-commit │
╰──────────────────────────────────────╯
│ typescript (skip) no matching staged files
│ eslint (skip) no files for inspection
│ go-mod-tidy (skip) no matching staged files
│ prettier (skip) no files for inspection
┃ go-fmt ❯
┃ go-vet ❯
┃ go-lint ❯
examples/advanced_queries.go:40:2: printf: fmt.Println arg list ends with redundant newline (govet)
fmt.Println("=== 高度なクエリとリレーションの例 ===\n")
^
examples/advanced_queries.go:140:3: printf: fmt.Println arg list ends with redundant newline (govet)
fmt.Println("✅ トランザクションが成功しました\n")
^
examples/advanced_queries.go:152:2: printf: fmt.Println arg list ends with redundant newline (govet)
fmt.Println("✅ レベル10未満のユーザーに経験値100を付与しました\n")
3 issues:
* govet: 3
Printlnの引数リストの最後に余分な改行があるという警告を出してしまいました。
このように、lefthookを使うことで、Gitのフックを簡単に管理でき、コード品質の向上や開発プロセスの効率化が期待できます。
まとめ
lefthookを導入することで、CIにするほどでもないことをGitのフックで簡単に管理でき、コード品質の向上や開発プロセスの効率化が期待できます。
また、個人的にはハッカソンの時にこまめなPRを投げまくる時にPRのCI待ちがなくなって早く作れるという点で使えそうだなと思いました。
ぜひ、プロジェクトにlefthookを導入してみてください!
参考リンク