本投稿について
Gruntプラグインを紹介していくGrunt Plugins Advent Calendar 2013の12/1の投稿です。
さっき作ったばかりなので、まだすっきりさっぱりしたカレンダーになってますので、どうぞよろしくお願いします。
http://qiita.com/advent-calendar/2013/grunt-plugins
grunt-githooksとは
GitフックでGruntタスクを実行する仕込みをしてくれるGruntプラグインです。
https://npmjs.org/package/grunt-githooks
https://github.com/rhumaric/grunt-githooks
Gitフックとは
Gitではcommitやpush, rebase, checkoutなどいくつかの操作ができますが、それらの特定の操作を行ったときに、スクリプトを実行することができる仕組みがあり、それをGitフックと呼びます。
どんな種類のフックがあるのか
まずはソースコードをGitバージョン管理するために、git initで初期化してください。
% git init
すると、カレントディレクトリに.gitディレクトリが作られますが、その中の.git/hooksディレクトリにGitのクライアントサイドフックのサンプルが提供されています。
% tree -L 3 -a
.
|-- .git
| |-- HEAD
| |-- config
| |-- description
| |-- hooks
| | |-- applypatch-msg.sample
| | |-- commit-msg.sample
| | |-- post-update.sample
| | |-- pre-applypatch.sample
| | |-- pre-commit.sample
| | |-- pre-push.sample
| | |-- pre-rebase.sample
| | |-- prepare-commit-msg.sample
| | `-- update.sample
| |-- info
| | `-- exclude
| |-- objects
| | |-- info
| | `-- pack
| `-- refs
| |-- heads
| `— tags
ファイル名を見ると想像できるように、pre-commit.sampleはcommitする直前にフックされるスクリプトのサンプル、pre-push.sampleはpushする直前にフックされるスクリプトのサンプル(Git 1.8.2以降対応)になります。
pre-commitやpre-pushという.sampleを除いた名前のファイルを作ると、commitやpushの各操作から呼ばれます。
導入
インストール
npm installでgrunt-githooksをインストールします。package.jsonのdevDependenciesに追加されるように--save-devオプションを忘れずに。
% npm install grunt-githooks --save-dev
Gruntfile.js
grunt-githooks タスクをロードするように追記し、githooksタスクを定義します。
以下はシェルスクリプトのテンプレートを使ったタスク定義の例です。
他にもtemplateにはNodeで定義できるnode_modules/grunt-githooks/templates/node.js.hbテンプレートを指定可能です。
module.exports = function(grunt) {
grunt.initConfig({
githooks: {
options: {
dest: '.git/hooks', //省略可
hashbang: '#!/bin/sh',
template: './node_modules/grunt-githooks/templates/shell.hb',
startMarker: '## GRUNT-GRUNTHOOKS START',
endMarker: '## GRUNT-GRUNTHOOKS END'
},
setup: {
'pre-commit': 'git-pre-commit'
}
}
});
grunt.registerTask('git-pre-commit', [“jshint"]); // jshintタスクの定義は省略
grunt.loadNpmTasks('grunt-githooks');
};
実行
% grunt githooks
Running "githooks:setup" (githooks) task
Binding `git-pre-commit` to `pre-commit` Git hook.
OK
Done, without errors.
% tree -L 3 -a
.
|-- .git
| |-- HEAD
| |-- config
| |-- description
| |-- hooks
| | |-- applypatch-msg.sample
| | |-- commit-msg.sample
| | |-- post-update.sample
| | |-- pre-applypatch.sample
| | |-- pre-commit
| | |-- pre-commit.sample
| | |-- pre-push.sample
| | |-- pre-rebase.sample
| | |-- prepare-commit-msg.sample
| | `-- update.sample
| |-- info
| | `-- exclude
| |-- objects
| | |-- info
| | `-- pack
| `-- refs
| |-- heads
| `— tags
すると.git/hooks/pre-commit ファイルが生成されています。
% less .git/hooks/pre-commit
# !/bin/sh
## GRUNT-GRUNTHOOKS START
(cd /Users/shoito/workspaces/gac2013 && grunt git-pre-commit)
## GRUNT-GRUNTHOOKS END
pre-commitフックが仕込まれたので、さっそくgit commitして動作確認してみます。
% git commit
Running "jshint:gruntfile" (jshint) task
>> 1 file lint free.
Running "jshint:lib_test" (jshint) task
Linting lib/htmlparser.js ...ERROR
[L65:C35] W116: Expected '===' and instead saw '=='.
if ( html.indexOf("<!--") == 0 ) {
[L70:C15] W116: Expected '{' and instead saw 'handler'.
handler.comment( html.substring( 4, index ) );
(略)
Warning: Task "jshint:lib_test" failed. Use --force to continue.
Aborted due to warnings.
このケースでは、git commitしたがpre-commitフックで呼ばれるGruntタスクのjshintタスクによるコーディングルールのチェックをパスできず、git commitが失敗に終わりました。
警告に従い、コードを修正した後に再度git commitしましょう。
まとめ
このように、grunt-githooksプラグインを使い、チーム内で共通のGitフックを仕込んでおくことができます。
例えば、pre-commitフックにコーディングルールのチェックやテストのGruntタスクが呼ばれるように仕込んでおくと「誰だよ、テスト通ってないコードをpushしたやつは!?」という事態が防止できます。
Tips
コーディングルールのチェックやテスト(軽いもの)のGruntタスクの実行はファイル変更の監視を行っているwatchタスクに仕込んでおいて、PhantomJS/CasperJSなどを使ったUIテストのタスク(重いもの)はpre-commitフックから呼び出すようにしておくなどすると良いと思います。
Q&A
Q. なぜ、githooksタスクからわざわざgit-pre-commitを呼ぶようにしているか?
setup: {
'pre-commit': 'git-pre-commit'
}
(略)
grunt.registerTask('git-pre-commit', ['jshint']);
A. このようにしておくと、pre-commitタスクで実行したいGruntタスクに変更があっても、Gruntfile.jsの定義を更新すればよく、grunt githooksを実行して.git/hooks/pre-commitを更新する必要がないためです。この例のjshintだと軽すぎますが、うちではcasperjsが含まれた定義になってます。
Appendix
Grunt Plugins
http://gruntjs.com/plugins