Ktlintで差分のみチェックする

前回の続き。

前回をベースに差分のみチェックするように変更したい。
ktlint-gradleプラグインを使用するとapp/src内のモジュールごとにレポートファイルが生成されてしまうためプラグインを使用しなかったが妥協してmainモジュールのみlintでチェックすることにした。

f:id:kyamashiro:20200429100315p:plain:w300

差分のみcommit時にフォーマットする

ktlint-gradleプラグインを使用すると./gradlew addKtlintCheckGitPreCommitHookコマンドで自動でpre-commitファイルが作成されます。
プラグインなしだと引数にlintでチェックしたいファイルを指定できないので全ファイル対象になってしまいますが、プラグインだと-PinternalKtlintGitFilterオプションでいけるっぽいですね。

#!/bin/sh
set -e
######## KTLINT-GRADLE HOOK START ########

CHANGED_FILES="$(git --no-pager diff --name-status --no-color --cached | awk '$1 != "D" && $2 ~ /\.kts|\.kt/ { print $2}')"

if [ -z "$CHANGED_FILES" ]; then
    echo "No Kotlin staged files."
    exit 0
fi;

echo "Running ktlint over these files:"
echo "$CHANGED_FILES"

./gradlew --quiet ktlintFormat -PinternalKtlintGitFilter="$CHANGED_FILES"

echo "Completed ktlint run."

echo "$CHANGED_FILES" | while read -r file; do
    if [ -f $file ]; then
        git add $file
    fi
done

echo "Completed ktlint hook."
######## KTLINT-GRADLE HOOK END ########

ktlintコマンドだとこれでいけるっぽい

#!/bin/sh
# https://github.com/shyiko/ktlint pre-commit hook
git diff --name-only --cached --relative | grep '\.kt[s"]\?$' | xargs ktlint --relative .
if [ $? -ne 0 ]; then exit 1; fi

github action workflowの設定

name: CI
on:
  pull_request:
    branches:
      - master
      - develop
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v1
      - name: Setup ruby
        uses: actions/setup-ruby@v1
        with:
          ruby-version: '2.6'
          architecture: 'x64'
      - name: install danger
        run: |
          gem install bundler
          bundle install --path vendor/bundle
      - name: run ktlint
        run: git --no-pager diff --name-only origin/master..origin/$GITHUB_HEAD_REF | grep -e '.kt$' -e '.kts$' | xargs -0 -I{} ./gradlew ktlintCheck -PinternalKtlintGitFilter={}
      - name: run danger
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        run: bundle exec danger

git --no-pager diff --name-only origin/master..origin/$GITHUB_HEAD_REF
masterとの差分があるファイル名のみ取得 $GITHUB_HEAD_REFでcompareで指定したブランチ名が取得できます

grep -e '.kt$' -e '.kts$'
.kt, .ktsのファイルのみ抽出

xargs -0 -I{} ./gradlew ktlintCheck -PinternalKtlintGitFilter={}
差分があるファイル名を受け取ってktlintCheckの引数として渡します

これでプルリク時に差分だけktlintにかけてチェックできるようになった感じですね。

github.com

masterにセミコロンをつけたMainActivity.ktをコミットしたあとに、masterから切ったブランチで別ファイルをコミットしてプルリクを送ってみるとTest.ktのファイルのみktlintでチェックされています。

参考

[JavaScript]Circle CIで変更箇所のファイルのみを静的解析(Lint)する① - Qiita