ほたてメモ

日々学んだことをメモメモ

overcommitでgitのhookを設定した

概要

gitのcommit前に、構文チェックをするため、overcommitを入れてみたときのまとめ。

hookの確認

まずは現状のhookの状態を確認。

.git/hooks/以下に*.sample以外のファイルがあるかを見る。

$ ls .git/hooks/ | grep -v '.sample'

空なら何も設定されていない。

overcommitのinstall

続いてovercommitを入れる。

参考にしたところ
* https://github.com/brigade/overcommit
* http://qiita.com/kompiro/items/6d3b3f2a3836472e1eb8

インストール

$ gem install overcommit

とりあえずヘルプ

$ overcommit --help
Usage: overcommit [options] [target-repo]
    -u, --uninstall                  Remove Overcommit hooks from a repository
    -i, --install                    Install Overcommit hooks in a repository
    -f, --force                      Overwrite any previously installed hooks
    -r, --run                        Run pre-commit hook against all git tracked files
    -s, --sign [hook]                Update hook signatures
    -t, --template-dir               Print location of template directory
    -h, --help                       Show this message
    -v, --version                    Show version
    -l, --list-hooks                 List installed hooks

全体的に短い形式のオプションが使えるので、以下は短い方を使っています。

バージョン確認

$ overcommit -v
overcommit 0.33.0

デフォルト設定の確認

$ overcommit -l
CommitMsg:
  CapitalizedSubject: enabled
  EmptyMessage: enabled
  GerritChangeId: disabled
  HardTabs: disabled
  MessageFormat: disabled
  RussianNovel: disabled
  SingleLineSubject: enabled
....

ずらずらと表示される。
デフォルトでも色々有効(enabled)になっている。
この中でPreCommitの部分が今回やりたいところ。

設定

rubocopを追加する

プロジェクトのルートディレクトリに.overcommit.ymlを作成して、下記を記述する。
自分はbundle execしたかったが、不要なら外す。

PreCommit:
  RuboCop:
    enabled: true
    command: ['bundle', 'exec', 'rubocop', '-c', './.rubocop.yml']

再度overcommit -lで確認してみる。

エラー(なんでや)

$ overcommit -l
/Users/xxxx/.rbenv/versions/2.3.0/lib/ruby/gems/2.3.0/gems/overcommit-0.33.0/lib/overcommit/configuration_loader.rb:81:in `verify_signatures': Unable to load configuration from '/Users/xxxx/project/business.jobtalk.jp/.overcommit.yml': No previously recorded signature for configuration file. (Overcommit::Exceptions::ConfigurationError)
Run `overcommit --sign` if you trust the hooks in this repository.
    from /Users/xxxx/.rbenv/versions/2.3.0/lib/ruby/gems/2.3.0/gems/overcommit-0.33.0/lib/overcommit/configuration_loader.rb:67:in `load_file'
    from /Users/xxxx/.rbenv/versions/2.3.0/lib/ruby/gems/2.3.0/gems/overcommit-0.33.0/lib/overcommit/configuration_loader.rb:55:in `load_repo_config'
    from /Users/xxxx/.rbenv/versions/2.3.0/lib/ruby/gems/2.3.0/gems/overcommit-0.33.0/lib/overcommit/cli.rb:215:in `config'
    from /Users/xxxx/.rbenv/versions/2.3.0/lib/ruby/gems/2.3.0/gems/overcommit-0.33.0/lib/overcommit/cli.rb:152:in `print_installed_hooks'
    from /Users/xxxx/.rbenv/versions/2.3.0/lib/ruby/gems/2.3.0/gems/overcommit-0.33.0/lib/overcommit/cli.rb:75:in `block in add_information_options'
    from /Users/xxxx/.rbenv/versions/2.3.0/lib/ruby/2.3.0/optparse.rb:1571:in `block in parse_in_order'
    from /Users/xxxx/.rbenv/versions/2.3.0/lib/ruby/2.3.0/optparse.rb:1527:in `catch'
    from /Users/xxxx/.rbenv/versions/2.3.0/lib/ruby/2.3.0/optparse.rb:1527:in `parse_in_order'
    from /Users/xxxx/.rbenv/versions/2.3.0/lib/ruby/2.3.0/optparse.rb:1521:in `order!'
    from /Users/xxxx/.rbenv/versions/2.3.0/lib/ruby/2.3.0/optparse.rb:1613:in `permute!'
    from /Users/xxxx/.rbenv/versions/2.3.0/lib/ruby/2.3.0/optparse.rb:1635:in `parse!'
    from /Users/xxxx/.rbenv/versions/2.3.0/lib/ruby/gems/2.3.0/gems/overcommit-0.33.0/lib/overcommit/cli.rb:43:in `parse_arguments'
    from /Users/xxxx/.rbenv/versions/2.3.0/lib/ruby/gems/2.3.0/gems/overcommit-0.33.0/lib/overcommit/cli.rb:18:in `run'
    from /Users/xxxx/.rbenv/versions/2.3.0/lib/ruby/gems/2.3.0/gems/overcommit-0.33.0/bin/overcommit:45:in `<top (required)>'
    from /Users/xxxx/.rbenv/versions/2.3.0/bin/overcommit:23:in `load'
    from /Users/xxxx/.rbenv/versions/2.3.0/bin/overcommit:23:in `<main>'

よく見るとovercommit --signしろと書いてあるので実行。

$ overcommit -s

もう一度確認。

$ overcommit -l
....
  RailsBestPractices: disabled
  RailsSchemaUpToDate: disabled
  Reek: disabled
  RuboCop: enabled
  RubyLint: disabled
  Scalariform: disabled
  Scalastyle: disabled
....

RuboCopが有効になった♪

他のhookも追加する

同じ感じで、.overcommit.ymlに追加していく。 自分は、EsLint、ScssLintを追加した。

(2016/6/23追記) EsLintをnpmで実行する場合は、['npm', 'run', 'lint']だけでは動かなかった。
(実際には動いているように見えて常にOKになっていた)ので修正。

PreCommit:
  RuboCop:
    enabled: true
    command: ['bundle', 'exec', 'rubocop', '-c', './.rubocop.yml']
  EsLint:
    enabled: true
    required_executable: 'npm'
    include: ''
    requires_files: false
    command: ['npm', 'run', 'lint', '--', '-f', 'compact']
  ScssLint:
    enabled: true
    command: ['bundle', 'exec', 'scss-lint', '-c', './.scss-lint.yml']

overcommit -sは忘れずに。

EsLintの補足

eslintをnpmを使って、かつ対象を一部のディレクトリに絞って実行する場合、
command: ['npm', 'run', 'lint']だけでは動作しなかった。
例えばpackage.jsonは下記のような設定の場合。

  "scripts": {
    "lint": "eslint app/assets/javascripts/xxx*"
  }

この場合、npm run lintは動作するが、overcommit経由だと動作しない。

以下追加した設定について

required_executable と command

オリジナルのソースを見るとコメントにちゃんと書いてあるのでマネをした。

https://github.com/brigade/overcommit/blob/9258dc16223a54823f131fa4c839b008a2be683a/lib/overcommit/hook/pre_commit/es_lint.rb

include

https://github.com/brigade/overcommit/blob/v0.33.0/config/default.yml#L218-224

EsLintのデフォルトの設定を見ると、includeで全ての*.jsが対象となっている。
そのため、npm(pakage.json)で対象を絞っていても、他のjsも追加されてしまう。
overcommitに追加してもらう必要はないため、include: '' とした。

requires_files

includeで対象ファイルを無しにしたが、デフォルトでは(overcommitから見て)対象ファイルが無いと、そもそもコマンドが実行されない。
ファイルがなくても実行されるように、requires_files: falseとした。

その他

command'-f', 'compact'について、オリジナルソースのコメントに書いてあるので追加したが、デフォルトの設定でflags: ['--format=compact']が付いているので、実際にはcommandに付けなくても動作する。
付けても害は無いので、今回はコメントに従った。

その他詳細は公式のドキュメントを参照した。

https://github.com/brigade/overcommit

hookを有効にする

overcommit -iで設定できる。

$ overcommit -i
Installing hooks into /xxxx
Successfully installed hooks into /xxxx

再度、.git/hooks以下を確認

$ ls .git/hooks/ | grep -v '.sample'
commit-msg
overcommit-hook
post-checkout
post-commit
post-merge
post-rewrite
pre-commit
pre-push
pre-rebase

なんか色々入った。
各ファイルはovercommitへシンボリックリンクを張っているだけみたい。

動作確認

overcommit -rでpre-commit時のフックを実行できるので試してみる。

$ overcommit -r
Running pre-commit hooks
Analyze with RuboCop........................................[RuboCop] OK
Analyze with ESLint..........................................[EsLint] OK
Analyze with scss-lint.....................................[ScssLint] OK

✓ All pre-commit hooks passed

実行できた♪

overcommit -rはpre-commitのみ動く。
実際のcommit時は他のフックも動くので注意。
今回はpre-commitが目的だったので、これでいったん完了。

アンインストール

最後に、アンイストールしたい場合。

$ overcommit -u

これだけで外せる。簡単♪