1 | # grunt-githooks
|
2 |
|
3 | > A Grunt plugin to help bind Grunt tasks to Git hooks
|
4 |
|
5 | ## Getting Started
|
6 | This plugin requires Grunt `~0.4.1`
|
7 |
|
8 | If you haven't used [Grunt](http://gruntjs.com/) before, be sure to check out the [Getting Started](http://gruntjs.com/getting-started) guide, as it explains how to create a [Gruntfile](http://gruntjs.com/sample-gruntfile) as well as install and use Grunt plugins. Once you're familiar with that process, you may install this plugin with this command:
|
9 |
|
10 | ```shell
|
11 | npm install grunt-githooks --save-dev
|
12 | ```
|
13 |
|
14 | Once the plugin has been installed, it may be enabled inside your Gruntfile with this line of JavaScript:
|
15 |
|
16 | ```js
|
17 | grunt.loadNpmTasks('grunt-githooks');
|
18 | ```
|
19 |
|
20 | ## The "githooks" task
|
21 |
|
22 | ### Overview
|
23 | In your project's Gruntfile, add a section named `githooks` to the data object passed into `grunt.initConfig()`.
|
24 |
|
25 | ```js
|
26 | grunt.initConfig({
|
27 | githooks: {
|
28 | options: {
|
29 | // Task-specific options go here.
|
30 | },
|
31 | all: {
|
32 | options: {
|
33 | // Target-specific options go here
|
34 | },
|
35 | // Hook definitions go there
|
36 | }
|
37 | },
|
38 | })
|
39 | ```
|
40 |
|
41 | #### Defining a few hooks
|
42 |
|
43 | Hooks are listed as keys of your target configuration.
|
44 | **Any key other than `option`** is considered the name of a hook you want to create.
|
45 | The simplest way to define a hook is to provide a **space-separated list of the tasks you want the hook to run as the value**.
|
46 |
|
47 | For example:
|
48 | ```js
|
49 | grunt.initConfig({
|
50 | githooks: {
|
51 | all: {
|
52 | // Will run the jshint and test:unit tasks at every commit
|
53 | 'pre-commit': 'jshint test:unit',
|
54 | }
|
55 | }
|
56 | });
|
57 | ```
|
58 |
|
59 | The plugin warns you if the name matches one of the [hooks announced in the Git documentation](https://www.kernel.org/pub/software/scm/git/docs/githooks.html).
|
60 | It will still create the hook, though, in case Git introduces new hooks in the future.
|
61 |
|
62 | #### Hook specific options
|
63 |
|
64 | If you need to override a few options for a given hook only, you can *use and Object instead of a String*.
|
65 | The `taskNames` property will then correspond to the tasks you want to run.
|
66 | Any other key will be merged into the options.
|
67 |
|
68 | ```js
|
69 | grunt.initConfig({
|
70 | githooks: {
|
71 | all: {
|
72 | options: {
|
73 | template: 'path/to/a/template'
|
74 | },
|
75 | // Will bind the jshint and test:unit tasks
|
76 | // with the template specified above
|
77 | 'pre-commit': 'jshint test:unit',
|
78 |
|
79 | // Will bind the bower:install task
|
80 | // with a specific template
|
81 | 'post-merge': {
|
82 | taskNames: 'bower:install',
|
83 | template: 'path/to/another/template'
|
84 | }
|
85 | }
|
86 | }
|
87 | })
|
88 | ```
|
89 |
|
90 | #### Working with existing hooks
|
91 |
|
92 | If you happen to have existing hooks in your hook folder, the plugin *appends the code launching Grunt* at the end of your hooks.
|
93 | You can also insert marker comments in your hooks to specify exactly where you want them inserted.
|
94 | Your existing hook would look something like this:
|
95 |
|
96 | ```js
|
97 | // Some code run before Grunt starts
|
98 |
|
99 | // GRUNT-GITHOOKS START // GRUNT-GITHOOKS END
|
100 |
|
101 | // Some code run after Grunt starts
|
102 | ```
|
103 |
|
104 | The markers get automatically inserted when the plugin appends code, so hooks get updated cleanly the next time you run `grunt githooks`.
|
105 |
|
106 | #### Customising hook output
|
107 |
|
108 | By default, the plugin generate NodeJS scripts for the hooks.
|
109 | Reasonning behind this is that creating Shell scripts won't work well for people using Windows.
|
110 | Plus, NodeJS is already installed as Grunt kinda needs it.
|
111 | However, you're not tied to it and you can customise the generated script entirely. In case of a Shell script:
|
112 |
|
113 | ```js
|
114 | grunt.initConfig({
|
115 | githooks: {
|
116 | all: {
|
117 | options: {
|
118 | // Customize the hashbang to say 'Shell script'
|
119 | hashbang: '#!/bin/sh',
|
120 | // Plugin comes in with a sheel script template already. Handy, innit?
|
121 | template: './node_modules/grunt-githooks/templates/shell.hb',
|
122 | // Customize the markers so comments start with #
|
123 | startMarker: '## LET THE FUN BEGIN',
|
124 | endMarker: '## PARTY IS OVER'
|
125 | }
|
126 | }
|
127 | }
|
128 | });
|
129 | ```
|
130 |
|
131 | In the template, you've got access to the following variables:
|
132 |
|
133 | - *task*: String with the name of the tasks to be run
|
134 | - *args*: String with the list of arguments to provide to the task
|
135 | - *gruntfileDirectory*: Absolute path to the directory containing the Gruntfile
|
136 | - *preventExit*: Flag telling if the hook should avoid exiting after the grunt task
|
137 |
|
138 | #### Extending the plugin
|
139 |
|
140 | Pretty annoying when you're using a library that's missing the exact extension point you need to tweak its functionalities?
|
141 | `grunt-githooks` is based on a lot of small functions and most of them are exposed so you can override them.
|
142 | If you need feel, free to tinker with the internals (at your own risk though ;)). Could be something along:
|
143 |
|
144 | ```js
|
145 | var gruntGithooks = require('grunt-githooks/tasks/githooks');
|
146 |
|
147 | var originalFunction = gruntGithooks.internals.Hook.prototype.getHookContent;
|
148 | gruntGithooks.internals.Hook.prototype.getHookContent = function () {
|
149 | console.log('Loading content of an existing hook');
|
150 | originalFunction.apply(this, arguments);
|
151 | };
|
152 | ```
|
153 |
|
154 | ### Options
|
155 |
|
156 | #### hashbang
|
157 | Type: `String`
|
158 | Defaults: `'#!/usr/bin/env node'`
|
159 |
|
160 | The hashbang that will be used at the top of the hook script file. If a hook
|
161 | already exist, the hashbang will be used to check if its ok to append/insert
|
162 | code in it (to avoid inserting Node code in a Python hook for example).
|
163 |
|
164 | #### template
|
165 | Type: `String`
|
166 |
|
167 | Path to the Handlebars template used to generate the code that will run Grunt
|
168 | in the hook. Default template is the `node.js.hb` file located in the `templates` folder of the plugin.
|
169 | It also contains a `shell.hb` file with the template for a shell script hook.
|
170 |
|
171 | #### startMarker
|
172 | Type: `String`
|
173 | Default: `'// GRUNT-GITHOOKS START'`
|
174 |
|
175 | #### endMarker
|
176 | Type: `String`
|
177 | Default: `'// GRUNT-GITHOOKS END'`
|
178 |
|
179 | `startMarker` and `endMarker` are markers the plugin use to know where to insert code if a hook already exist.
|
180 | If the existing hook doesn't have these markers, the code will simply be appended.
|
181 |
|
182 | #### preventExit
|
183 | Type: `Boolean`
|
184 | Default `false`
|
185 |
|
186 | By default, the inserted code will exit the process after Grunt has run, using a -1 exit code if the task(s) failed.
|
187 | If you're inserting the code running Grunt in the middle of an existing hook,
|
188 | you might want to disable this so any code after what was inserted by the plugin runs.
|
189 |
|
190 | #### dest
|
191 | Type: `String`
|
192 | Default value: `'.git/hooks'`
|
193 |
|
194 | You probably won't use this one much, but in case you need to put the hooks somewhere else than in the `.git/hooks` folder, this is the option to use.
|
195 |
|
196 |
|
197 | ## Contributing
|
198 |
|
199 | In lieu of a formal styleguide, take care to maintain the existing coding style. Add unit tests for any new or changed functionality. Lint and test your code using [Grunt](http://gruntjs.com/).
|
200 |
|
201 |
|
202 | ## Release History
|
203 |
|
204 | - 2013-10-05 v0.2.0 New *args* option to specify arguments to hooked task. Bugfix to allow running grunt when the Gruntfile is not at the root of the project.
|
205 | - 2013-09-02 v0.1.0 Initial functionnalities
|