0
Help us understand the problem. What are the problem?

posted at

updated at

Organization

Git HookでSpotlessとktlintを使った自動コードチェック

チームで開発する時に一律でフォーマット揃ってたり、
既存のコードも一律に綺麗にしたりを今後維持できるようにできたらいいなと思ったので
とりあえずやってみました。

Git Hookとは

Gitでコマンドを実行する際に、前後でスクリプトを実行できるGitの機能。

今回使うpre-commitの場合、commitを行うとその前にスクリプトが実行され、
問題があればcommitを中止し、なければcommitを通すといったことが出来ます。

例としては

  • commit時にテストを流す
  • commit時にlinterでチェック、あるいはフォーマッターをかける
  • 特定のブランチへのcommitを禁止(masterやdevelopなど)
  • ...etc

Spotlessとは

Javaのコードチェック、フォーマットが出来るLinterです。
指定したフォーマットに従ってJavaのコードをいい感じにフォーマットしてくれます。

Ktlintとは

こちらはKotlinのコードチェック、フォーマットが出来るLinterです。
公式の規約に沿っていい感じにしてくれるのと先述のSpotlessと連携ができるので、
JavaとKotlin両方をいい感じ(概念)に出来ます。

導入

pre-commit

gitで管理されているプロジェクトであれば .git/hooks ディレクトリの中に、
pre-commit.sample というファイルがあるのでそれをリネームして使うでも作成するでもいいと思います。
pre-commit.git/hooksの中にあればcommit時にスクリプトが呼ばれるようになります。

// 今回はとりあえず作りました
$ touch pre-commit

Spotless,Ktlint

build.gradleにこんな感じで追加すると使えるようになります。
Spotlessの方はここでどのフォーマット形式を使用するかを指定します。
Ktlintは基本的に公式の規約に従うみたいです。

apply plugin: "com.diffplug.spotless"

spotless {

    ratchetFrom 'origin/main'

    java {
        target "**/*.java"
        targetExclude("$buildDir/**/*.java")

        googleJavaFormat("1.14.0")
    }
    kotlin {
        target '**/*.kt'
        targetExclude("$buildDir/**/*.kt")

        ktlint("0.44.0").userData(['disabled_rules': 'no-wildcard-imports'])
    }
}

この状態だとデフォルトのルールが適用されますが、
コード内の下側に書いてある方法や.editorconfigを使うことでもルールのカスタムが出来たりします。

これでフォーマットとコードチェックが出来るようになりました。

// コードのフォーマット
$ ./gradlew spotlessApply
// コードのチェック
$ ./gradlew spotlessCheck

pre-commitのスクリプト

pre-commitに記載するスクリプトですが、
普通に./gradlew spotlessApplyしてしまうと、
既存のコード全てにかかってしまう(ちゃんといつか全部やりたい)ので、
差分だけを抽出したものにフォーマットをかけていくことにしたのが以下。

set -e

# ステージングされた変更のあるファイルを抽出
# java,kotlinが対象
formatFileList="$(git --no-pager diff --name-status --no-color --cached | awk '$1 != "D" && $2 ~ /\.kts|\.java|\.kt/ { print $NF}')"

# 抽出したファイルに対してフォーマットを適用する
echo "spotlesscheck start..."
for filePath in $formatFileList
do
  ./gradlew spotlessApply -PspotlessIdeHook="$(pwd)/$filePath"
  echo "git add $filePath"
  git add "$filePath"
done;
echo "spotlesscheck finish."

これでcommit時に自動でフォーマッタをかけることはできるのですが、
pre-commit.git配下のためgitで管理することができません。
なのでプロジェクトルートにpre-commitファイルを配置しておき、
gradleのタスクに.git/hooksへ配置させることでいい感じにならんかなということでこちら。

task installPreCommitScript(type: Copy) {
    from new File(rootProject.rootDir, './pre-commit')
    into { new File(rootProject.rootDir, '.git/hooks') }
    fileMode 0775
}

これで他の人もリポジトリから取得してきた状態で下記を実行すればpre-commitが使えるようになります。

$ ./gradlew installPreCommitScript

まとめ

今回は自身がAndroidエンジニアだったためKotlinとJava向けの内容でしたが、
他の言語でも同じようなことは出来るのでGitHookは他でもいい感じに使えるんじゃないかなーと思います。

Register as a new user and use Qiita more conveniently

  1. You can follow users and tags
  2. you can stock useful information
  3. You can make editorial suggestions for articles
What you can do with signing up
0
Help us understand the problem. What are the problem?