3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

個人の小さいプロダクトでも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 fmtgo 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を導入してみてください!

参考リンク

3
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?