Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationEventAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
20
Help us understand the problem. What are the problem?

More than 5 years have passed since last update.

@shoito

Gitフックを仕込むgrunt-githooksについて紹介するよ

本投稿について

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.samplecommitする直前にフックされるスクリプトのサンプル、pre-push.samplepushする直前にフックされるスクリプトのサンプル(Git 1.8.2以降対応)になります。
pre-commitpre-pushという.sampleを除いた名前のファイルを作ると、commitpushの各操作から呼ばれます。

導入

インストール

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

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
20
Help us understand the problem. What are the problem?