overcommit 0.22.0 → 0.23.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. checksums.yaml +4 -4
  2. data/config/default.yml +169 -41
  3. data/lib/overcommit/configuration.rb +0 -2
  4. data/lib/overcommit/git_repo.rb +10 -3
  5. data/lib/overcommit/hook/base.rb +4 -0
  6. data/lib/overcommit/hook/post_checkout/index_tags.rb +2 -19
  7. data/lib/overcommit/hook/post_commit/base.rb +10 -0
  8. data/lib/overcommit/hook/post_commit/git_guilt.rb +39 -0
  9. data/lib/overcommit/hook/post_commit/index_tags.rb +9 -0
  10. data/lib/overcommit/hook/post_merge/base.rb +10 -0
  11. data/lib/overcommit/hook/post_merge/index_tags.rb +9 -0
  12. data/lib/overcommit/hook/post_rewrite/base.rb +10 -0
  13. data/lib/overcommit/hook/post_rewrite/index_tags.rb +12 -0
  14. data/lib/overcommit/hook/pre_commit/css_lint.rb +20 -2
  15. data/lib/overcommit/hook/pre_commit/es_lint.rb +18 -0
  16. data/lib/overcommit/hook/pre_commit/html_tidy.rb +35 -0
  17. data/lib/overcommit/hook/pre_commit/image_optim.rb +1 -1
  18. data/lib/overcommit/hook/pre_commit/java_checkstyle.rb +19 -0
  19. data/lib/overcommit/hook/pre_commit/js_hint.rb +9 -3
  20. data/lib/overcommit/hook/pre_commit/pep257.rb +19 -0
  21. data/lib/overcommit/hook/pre_commit/pep8.rb +19 -0
  22. data/lib/overcommit/hook/pre_commit/pyflakes.rb +28 -0
  23. data/lib/overcommit/hook/pre_commit/pylint.rb +28 -0
  24. data/lib/overcommit/hook/pre_commit/python_flake8.rb +18 -1
  25. data/lib/overcommit/hook/pre_commit/scalastyle.rb +26 -0
  26. data/lib/overcommit/hook/pre_commit/semi_standard.rb +17 -0
  27. data/lib/overcommit/hook/pre_commit/standard.rb +17 -0
  28. data/lib/overcommit/hook/pre_commit/w3c_css.rb +77 -0
  29. data/lib/overcommit/hook/pre_commit/w3c_html.rb +74 -0
  30. data/lib/overcommit/hook/pre_commit/xml_lint.rb +20 -0
  31. data/lib/overcommit/hook_context/post_commit.rb +31 -0
  32. data/lib/overcommit/hook_context/post_merge.rb +35 -0
  33. data/lib/overcommit/hook_context/post_rewrite.rb +18 -0
  34. data/lib/overcommit/hook_context/run_all.rb +12 -9
  35. data/lib/overcommit/utils.rb +25 -6
  36. data/lib/overcommit/version.rb +1 -1
  37. data/template-dir/hooks/post-commit +81 -0
  38. data/template-dir/hooks/post-merge +81 -0
  39. data/template-dir/hooks/post-rewrite +81 -0
  40. metadata +48 -10
  41. data/lib/overcommit/hook/pre_commit/jsx_hint.rb +0 -13
  42. data/lib/overcommit/hook/pre_commit/jsxcs.rb +0 -20
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: be12e52142407d34b856e8cf7c3b9e1743f9318b
4
- data.tar.gz: cbbf986c4d3e2a45d26b281e9716de2ef15cd2c2
3
+ metadata.gz: cc7753466602537df2c08569c1758136eec9f90b
4
+ data.tar.gz: 67ed7c78239ba382a78e9f6f976ec113dc4bff67
5
5
  SHA512:
6
- metadata.gz: 9ccfb37216d910e8c14b7d935c42a74b2ab372016bfe2b3e8eee4f63195028db62d34dbedec808d9b704d49f75991951eeabcdc3a857bbddccd8ebd55c4f00ee
7
- data.tar.gz: 2fe6b8c2563e6f709e7d844f4055386fd8a60f4239e82dedf9792b8efeb59d46ecf761c4f2c28998d1628cab1452c35cb125226090c29e35359776ebf83bbfe0
6
+ metadata.gz: 28bba28fd0dae45783ff7c43a7d0b847547b2680e7b900569d5d4b8ba8ef0c831ae3db30391154e7e04b100fcd2818e7b66ca7ed2ef247a035a0ffccf54b85cd
7
+ data.tar.gz: d7fb90d9cb74df2e57deea38fabadba464328ac8f1b445847c6c51ad7fa8a7f542c338f92d0ae1d7d115a21fdea0f9f191d94d6d3efa222d96f2567edb7e1b69
data/config/default.yml CHANGED
@@ -14,16 +14,36 @@ plugin_directory: '.git-hooks'
14
14
  # See https://github.com/causes/overcommit#security for more information.
15
15
  verify_plugin_signatures: true
16
16
 
17
- # Hooks that run after HEAD changes or a file is explicitly checked out. Useful
18
- # for updating source tags (e.g. via ctags) or warning about new migrations,
19
- # etc.
20
- PostCheckout:
17
+ # Hooks that are run against every commit message after a user has written it.
18
+ # These hooks are useful for enforcing policies on commit messages written for a
19
+ # project.
20
+ CommitMsg:
21
21
  ALL:
22
- required: false
22
+ requires_files: false
23
23
  quiet: false
24
- IndexTags:
24
+
25
+ GerritChangeId:
25
26
  enabled: false
26
- description: 'Generating tags file from source'
27
+ description: 'Ensuring Gerrit Change-Id is present'
28
+ required: true
29
+
30
+ HardTabs:
31
+ description: 'Checking for hard tabs'
32
+
33
+ RussianNovel:
34
+ description: 'Checking length of commit message'
35
+ quiet: true
36
+
37
+ SingleLineSubject:
38
+ description: 'Checking subject line'
39
+
40
+ TextWidth:
41
+ description: 'Checking text width'
42
+ max_subject_width: 60
43
+ max_body_width: 72
44
+
45
+ TrailingPeriod:
46
+ description: 'Checking for trailing periods in subject'
27
47
 
28
48
  # Hooks that are run after `git commit` is executed, before the commit message
29
49
  # editor is displayed. These hooks are ideal for syntax checkers, linters, and
@@ -105,6 +125,13 @@ PreCommit:
105
125
  install_command: 'npm install -g csslint'
106
126
  include: '**/*.css'
107
127
 
128
+ EsLint:
129
+ description: 'Analyzing with ESLint'
130
+ required_executable: 'eslint'
131
+ flags: ['--format=compact']
132
+ install_command: 'npm install -g eslint'
133
+ include: '**/*.js'
134
+
108
135
  GoLint:
109
136
  description: 'Analyzing with golint'
110
137
  required_executable: 'golint'
@@ -127,6 +154,13 @@ PreCommit:
127
154
  - '**/Makefile'
128
155
  - '.gitmodules'
129
156
 
157
+ HtmlTidy:
158
+ enabled: false
159
+ description: 'Analyzing HTML with tidy'
160
+ required_executable: 'tidy'
161
+ flags: ['-errors', '-quiet', '-utf8']
162
+ include: '**/*.html'
163
+
130
164
  ImageOptim:
131
165
  description: 'Checking for optimizable images'
132
166
  include:
@@ -135,6 +169,12 @@ PreCommit:
135
169
  - '**/*.jpeg'
136
170
  - '**/*.png'
137
171
 
172
+ JavaCheckstyle:
173
+ description: 'Analyzing with checkstyle'
174
+ required_executable: 'checkstyle'
175
+ flags: ['-c', '/sun_checks.xml']
176
+ include: '**/*.java'
177
+
138
178
  Jscs:
139
179
  description: 'Analyzing with JSCS'
140
180
  required_executable: 'jscs'
@@ -142,16 +182,10 @@ PreCommit:
142
182
  install_command: 'npm install -g jscs'
143
183
  include: '**/*.js'
144
184
 
145
- Jsxcs:
146
- description: 'Analyzing with JSXCS'
147
- required_executable: 'jsxcs'
148
- flags: ['--reporter=inline']
149
- install_command: 'npm install -g jsxcs'
150
- include: '**/*.jsx'
151
-
152
185
  JsHint:
153
186
  description: 'Analyzing with JSHint'
154
187
  required_executable: 'jshint'
188
+ flags: ['--verbose']
155
189
  install_command: 'npm install -g jshint'
156
190
  include: '**/*.js'
157
191
 
@@ -159,12 +193,6 @@ PreCommit:
159
193
  description: 'Validating JSON syntax'
160
194
  include: '**/*.json'
161
195
 
162
- JsxHint:
163
- description: 'Analyzing with JSXHint'
164
- required_executable: 'jsxhint'
165
- install_command: 'npm install -g jsxhint'
166
- include: '**/*.jsx'
167
-
168
196
  LocalPathsInGemfile:
169
197
  description: 'Checking for local paths in Gemfile'
170
198
  required_executable: 'grep'
@@ -177,6 +205,19 @@ PreCommit:
177
205
  required_executable: 'grep'
178
206
  flags: ['-IHn', '^<<<<<<<\s']
179
207
 
208
+ Pep257:
209
+ description: 'Analyzing docstrings with pep257'
210
+ required_executable: 'pep257'
211
+ install_command: 'pip install pep257'
212
+ include: '**/*.py'
213
+
214
+ Pep8:
215
+ enabled: false
216
+ description: 'Analyzing with pep8'
217
+ required_executable: 'pep8'
218
+ install_command: 'pip install pep8'
219
+ include: '**/*.py'
220
+
180
221
  PryBinding:
181
222
  description: 'Checking for instances of binding.pry'
182
223
  quiet: true
@@ -184,6 +225,23 @@ PreCommit:
184
225
  - '**/*.rb'
185
226
  - '**/*.rake'
186
227
 
228
+ Pyflakes:
229
+ enabled: false
230
+ description: 'Analyzing with pyflakes'
231
+ required_executable: 'pyflakes'
232
+ install_command: 'pip install pyflakes'
233
+ include: '**/*.py'
234
+
235
+ Pylint:
236
+ description: 'Analyzing with Pylint'
237
+ required_executable: 'pylint'
238
+ install_command: 'pip install pylint'
239
+ flags:
240
+ - '--msg-template="{path}:{line}:{C}: {msg} ({symbol})"'
241
+ - '--reports=n'
242
+ - '--persistent=n'
243
+ include: '**/*.py'
244
+
187
245
  PythonFlake8:
188
246
  description: 'Analyzing with flake8'
189
247
  required_executable: 'flake8'
@@ -222,18 +280,39 @@ PreCommit:
222
280
  - '**/Gemfile'
223
281
  - '**/Rakefile'
224
282
 
283
+ Scalastyle:
284
+ description: 'Analyzing with Scalastyle'
285
+ required_executable: 'scalastyle'
286
+ include: '**/*.scala'
287
+
225
288
  ScssLint:
226
289
  description: 'Analyzing with scss-lint'
227
290
  required_executable: 'scss-lint'
228
291
  install_command: 'gem install scss-lint'
229
292
  include: '**/*.scss'
230
293
 
294
+ SemiStandard:
295
+ enabled: false
296
+ description: 'Analyzing with semistandard'
297
+ required_executable: 'semistandard'
298
+ flags: ['--verbose']
299
+ install_command: 'npm install -g semistandard'
300
+ include: '**/*.js'
301
+
231
302
  ShellCheck:
232
303
  description: 'Analyzing with ShellCheck'
233
304
  required_executable: 'shellcheck'
234
305
  flags: ['--format=gcc']
235
306
  include: '**/*.sh'
236
307
 
308
+ Standard:
309
+ enabled: false
310
+ description: 'Analyzing with standard'
311
+ required_executable: 'standard'
312
+ flags: ['--verbose']
313
+ install_command: 'npm install -g standard'
314
+ include: '**/*.js'
315
+
237
316
  TrailingWhitespace:
238
317
  description: 'Checking for trailing whitespace'
239
318
  required_executable: 'grep'
@@ -248,37 +327,86 @@ PreCommit:
248
327
  install_command: 'gem install travis'
249
328
  include: '.travis.yml'
250
329
 
330
+ W3cCss:
331
+ enabled: false
332
+ description: 'Analyzing with W3C CSS validation service'
333
+ validator_uri: 'http://jigsaw.w3.org/css-validator/validator'
334
+ language: 'en'
335
+ profile: 'css3'
336
+ warn_level: 2
337
+ include:
338
+ - '**/*.css'
339
+
340
+ W3cHtml:
341
+ enabled: false
342
+ description: 'Analyzing with W3C HTML validation service'
343
+ validator_uri: 'http://validator.w3.org/check'
344
+ charset: 'utf-8'
345
+ doctype: 'HTML5'
346
+ include:
347
+ - '**/*.html'
348
+
349
+ XmlLint:
350
+ description: 'Analyzing with xmllint'
351
+ required_executable: 'xmllint'
352
+ flags: ['--noout']
353
+ include: '**/*.xml'
354
+
251
355
  YamlSyntax:
252
356
  description: 'Checking YAML syntax'
253
- include: '**/*.yml'
357
+ include:
358
+ - '**/*.yaml'
359
+ - '**/*.yml'
254
360
 
255
- # Hooks that are run against every commit message after a user has written it.
256
- # These hooks are useful for enforcing policies on commit messages written for a
257
- # project.
258
- CommitMsg:
361
+ # Hooks that run after HEAD changes or a file is explicitly checked out.
362
+ PostCheckout:
363
+ ALL:
364
+ required: false
365
+ quiet: false
366
+
367
+ IndexTags:
368
+ enabled: false
369
+ description: 'Generating tags file from source'
370
+ required_executable: 'ctags'
371
+
372
+ # Hooks that run after a commit is created.
373
+ PostCommit:
259
374
  ALL:
260
375
  requires_files: false
376
+ required: false
261
377
  quiet: false
262
378
 
263
- GerritChangeId:
379
+ GitGuilt:
264
380
  enabled: false
265
- description: 'Ensuring Gerrit Change-Id is present'
266
- required: true
381
+ description: 'Calculating changes in blame since last commit'
382
+ requires_files: true
383
+ required_executable: 'git-guilt'
384
+ flags: ['HEAD~', 'HEAD']
385
+ install_command: 'npm install -g git-guilt'
267
386
 
268
- HardTabs:
269
- description: 'Checking for hard tabs'
387
+ IndexTags:
388
+ enabled: false
389
+ description: 'Generating tags file from source'
390
+ required_executable: 'ctags'
270
391
 
271
- RussianNovel:
272
- description: 'Checking length of commit message'
273
- quiet: true
392
+ # Hooks that run after `git merge` executes successfully (no merge conflicts).
393
+ PostMerge:
394
+ ALL:
395
+ requires_files: false
396
+ quiet: false
274
397
 
275
- SingleLineSubject:
276
- description: 'Checking subject line'
398
+ IndexTags:
399
+ enabled: false
400
+ description: 'Generating tags file from source'
401
+ required_executable: 'ctags'
277
402
 
278
- TextWidth:
279
- description: 'Checking text width'
280
- max_subject_width: 60
281
- max_body_width: 72
403
+ # Hooks that run after a commit is modified by an amend or rebase.
404
+ PostRewrite:
405
+ ALL:
406
+ requires_files: false
407
+ quiet: false
282
408
 
283
- TrailingPeriod:
284
- description: 'Checking for trailing periods in subject'
409
+ IndexTags:
410
+ enabled: false
411
+ description: 'Generating tags file from source'
412
+ required_executable: 'ctags'
@@ -170,8 +170,6 @@ module Overcommit
170
170
  def smart_merge(parent, child)
171
171
  parent.merge(child) do |_key, old, new|
172
172
  case old
173
- when Array
174
- old + Array(new)
175
173
  when Hash
176
174
  smart_merge(old, new)
177
175
  else
@@ -20,8 +20,10 @@ module Overcommit
20
20
  lines = Set.new
21
21
 
22
22
  flags = '--cached' if options[:staged]
23
+ refs = options[:refs]
24
+ subcmd = options[:subcmd] || 'diff'
23
25
 
24
- `git diff --no-ext-diff -U0 #{flags} -- #{file_path}`.
26
+ `git #{subcmd} --no-ext-diff -U0 #{flags} #{refs} -- '#{file_path}'`.
25
27
  scan(DIFF_HUNK_REGEX) do |start_line, lines_added|
26
28
  lines_added = (lines_added || 1).to_i # When blank, one line was added
27
29
  cur_line = start_line.to_i
@@ -42,9 +44,13 @@ module Overcommit
42
44
  # @return [Array<String>] list of absolute file paths
43
45
  def modified_files(options)
44
46
  flags = '--cached' if options[:staged]
47
+ refs = options[:refs]
48
+ subcmd = options[:subcmd] || 'diff'
45
49
 
46
- `git diff --name-only -z --diff-filter=ACM --ignore-submodules=all #{flags}`.
50
+ `git #{subcmd} --name-only -z --diff-filter=ACM --ignore-submodules=all #{flags} #{refs}`.
47
51
  split("\0").
52
+ map(&:strip).
53
+ reject(&:empty?).
48
54
  map { |relative_file| File.expand_path(relative_file) }
49
55
  end
50
56
 
@@ -54,7 +60,8 @@ module Overcommit
54
60
  def all_files
55
61
  `git ls-files`.
56
62
  split(/\n/).
57
- map { |relative_file| File.expand_path(relative_file) }
63
+ map { |relative_file| File.expand_path(relative_file) }.
64
+ reject { |file| File.directory?(file) } # Exclude submodule directories
58
65
  end
59
66
 
60
67
  # Returns whether the current git branch is empty (has no commits).
@@ -111,6 +111,10 @@ module Overcommit::Hook
111
111
  Overcommit::Utils.execute(cmd)
112
112
  end
113
113
 
114
+ def execute_in_background(cmd)
115
+ Overcommit::Utils.execute_in_background(cmd)
116
+ end
117
+
114
118
  def required_executable
115
119
  @config['required_executable']
116
120
  end
@@ -1,26 +1,9 @@
1
1
  module Overcommit::Hook::PostCheckout
2
- # Scans source code each time HEAD changes to generate an up-to-date index of
3
- # all function/variable definitions, etc.
2
+ # Updates ctags index for all source code in the repository.
4
3
  class IndexTags < Base
5
4
  def run
6
- unless in_path?('ctags')
7
- return :pass # Silently ignore
8
- end
9
-
10
- index_tags_in_background
11
-
5
+ execute_in_background([Overcommit::Utils.script_path('index-tags')])
12
6
  :pass
13
7
  end
14
-
15
- private
16
-
17
- SCRIPT_LOCATION = Overcommit::Utils.script_path('index-tags')
18
-
19
- def index_tags_in_background
20
- ctags_args = config['ctags_arguments']
21
-
22
- # TODO: come up with Ruby 1.8-friendly way to do this
23
- Process.detach(Process.spawn("#{SCRIPT_LOCATION} #{ctags_args}"))
24
- end
25
8
  end
26
9
  end
@@ -0,0 +1,10 @@
1
+ require 'forwardable'
2
+
3
+ module Overcommit::Hook::PostCommit
4
+ # Functionality common to all post-commit hooks.
5
+ class Base < Overcommit::Hook::Base
6
+ extend Forwardable
7
+
8
+ def_delegators :@context, :modified_lines_in_file, :initial_commit?
9
+ end
10
+ end
@@ -0,0 +1,39 @@
1
+ module Overcommit::Hook::PostCommit
2
+ # Calculates the change in blame since the last revision.
3
+ class GitGuilt < Base
4
+ PLUS_MINUS_REGEX = /^(.*?)(?:(\++)|(-+))$/
5
+ GREEN = 32
6
+ RED = 31
7
+
8
+ def run
9
+ return :pass if initial_commit?
10
+ result = execute(command)
11
+ return :fail, result.stderr unless result.success?
12
+
13
+ return :pass if result.stdout.strip.empty?
14
+
15
+ output = []
16
+ result.stdout.scan(PLUS_MINUS_REGEX) do |user, plus, minus|
17
+ plus = color(GREEN, plus)
18
+ minus = color(RED, minus)
19
+ output << "#{user}#{plus}#{minus}"
20
+ end
21
+
22
+ [:warn, output.join("\n")]
23
+ end
24
+
25
+ private
26
+
27
+ # Returns text wrapped in ANSI escape code necessary to produce a given
28
+ # color/text display.
29
+ #
30
+ # Taken from Overcommit::Logger as a temporary workaround.
31
+ # TODO: expose logger instance to hooks for colorized output
32
+ #
33
+ # @param code [String] ANSI escape code, e.g. '1;33' for "bold yellow"
34
+ # @param str [String] string to wrap
35
+ def color(code, str)
36
+ STDOUT.tty? ? "\033[#{code}m#{str}\033[0m" : str
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,9 @@
1
+ module Overcommit::Hook::PostCommit
2
+ # Updates ctags index for all source code in the repository.
3
+ class IndexTags < Base
4
+ def run
5
+ execute_in_background([Overcommit::Utils.script_path('index-tags')])
6
+ :pass
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,10 @@
1
+ require 'forwardable'
2
+
3
+ module Overcommit::Hook::PostMerge
4
+ # Functionality common to all post-merge hooks.
5
+ class Base < Overcommit::Hook::Base
6
+ extend Forwardable
7
+
8
+ def_delegators :@context, :modified_lines_in_file, :squash?, :merge_commit?
9
+ end
10
+ end
@@ -0,0 +1,9 @@
1
+ module Overcommit::Hook::PostMerge
2
+ # Updates ctags index for all source code in the repository.
3
+ class IndexTags < Base
4
+ def run
5
+ execute_in_background([Overcommit::Utils.script_path('index-tags')])
6
+ :pass
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,10 @@
1
+ require 'forwardable'
2
+
3
+ module Overcommit::Hook::PostRewrite
4
+ # Functionality common to all post-rewrite hooks.
5
+ class Base < Overcommit::Hook::Base
6
+ extend Forwardable
7
+
8
+ def_delegators :@context, :amend?, :rebase?
9
+ end
10
+ end
@@ -0,0 +1,12 @@
1
+ module Overcommit::Hook::PostRewrite
2
+ # Updates ctags index for all source code in the repository.
3
+ class IndexTags < Base
4
+ def run
5
+ # Ignore unless this is a rebase (amends are covered by post-commit hook)
6
+ return :pass unless rebase?
7
+
8
+ execute_in_background([Overcommit::Utils.script_path('index-tags')])
9
+ :pass
10
+ end
11
+ end
12
+ end
@@ -1,11 +1,29 @@
1
1
  module Overcommit::Hook::PreCommit
2
2
  # Runs `csslint` against any modified CSS files.
3
3
  class CssLint < Base
4
+ MESSAGE_REGEX = /
5
+ ^(?<file>[^:]+):\s
6
+ (?:line\s(?<line>\d+)[^EW]+)?
7
+ (?<type>Error|Warning)
8
+ /x
9
+
4
10
  def run
5
11
  result = execute(command + applicable_files)
6
- return :pass if result.stdout !~ /Error - (?!Unknown @ rule)/
12
+ output = result.stdout.chomp
13
+ return :pass if result.success? && output.empty?
14
+
15
+ extract_messages(
16
+ output.split("\n").collect(&method(:add_line_number)),
17
+ MESSAGE_REGEX,
18
+ lambda { |type| type.downcase.to_sym }
19
+ )
20
+ end
21
+
22
+ private
7
23
 
8
- [:fail, result.stdout]
24
+ # Hack to include messages that apply to the entire file
25
+ def add_line_number(message)
26
+ message.sub(/(?<!\d,\s)(Error|Warning)/, 'line 0, \1')
9
27
  end
10
28
  end
11
29
  end
@@ -0,0 +1,18 @@
1
+ module Overcommit::Hook::PreCommit
2
+ # Runs `eslint` against any modified JavaScript files.
3
+ class EsLint < Base
4
+ def run
5
+ result = execute(command + applicable_files)
6
+ output = result.stdout.chomp
7
+ return :pass if result.success? && output.empty?
8
+
9
+ # example message:
10
+ # path/to/file.js: line 1, col 0, Error - Error message (ruleName)
11
+ extract_messages(
12
+ output.split("\n").grep(/Warning|Error/),
13
+ /^(?<file>[^:]+):[^\d]+(?<line>\d+).*?(?<type>Error|Warning)/,
14
+ lambda { |type| type.downcase.to_sym }
15
+ )
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,35 @@
1
+ module Overcommit::Hook::PreCommit
2
+ # Runs `tidy` against any modified HTML files.
3
+ class HtmlTidy < Base
4
+ MESSAGE_REGEX = /
5
+ ^(?<file>[^:]+):\s
6
+ line\s(?<line>\d+)\s
7
+ column\s(?<col>\d+)\s-\s
8
+ (?<type>Error|Warning):\s(?<message>.+)$
9
+ /x
10
+
11
+ def run
12
+ # example message:
13
+ # line 4 column 24 - Warning: <html> proprietary attribute "class"
14
+ messages = collect_messages
15
+
16
+ return :pass if messages.empty?
17
+
18
+ messages
19
+ end
20
+
21
+ private
22
+
23
+ def collect_messages
24
+ applicable_files.collect do |file|
25
+ result = execute(command + [file])
26
+ output = result.stderr.chomp
27
+ extract_messages(
28
+ output.split("\n").collect { |msg| "#{file}: #{msg}" },
29
+ MESSAGE_REGEX,
30
+ lambda { |type| type.downcase.to_sym }
31
+ )
32
+ end.flatten
33
+ end
34
+ end
35
+ end
@@ -5,7 +5,7 @@ module Overcommit::Hook::PreCommit
5
5
  begin
6
6
  require 'image_optim'
7
7
  rescue LoadError
8
- return :warn, 'image_optim not installed -- run `gem install image_optim`'
8
+ return :fail, 'image_optim not installed -- run `gem install image_optim`'
9
9
  end
10
10
 
11
11
  optimized_images =
@@ -0,0 +1,19 @@
1
+ module Overcommit::Hook::PreCommit
2
+ # Runs `checkstyle` against any modified Java files.
3
+ class JavaCheckstyle < Base
4
+ MESSAGE_REGEX = /^(?<file>[^:]+):(?<line>\d+)/
5
+
6
+ def run
7
+ result = execute(command + applicable_files)
8
+ output = result.stdout.chomp
9
+ return :pass if result.success?
10
+
11
+ # example message:
12
+ # path/to/file.java:3:5: Error message
13
+ extract_messages(
14
+ output.split("\n").grep(MESSAGE_REGEX),
15
+ MESSAGE_REGEX
16
+ )
17
+ end
18
+ end
19
+ end
@@ -3,11 +3,17 @@ module Overcommit::Hook::PreCommit
3
3
  class JsHint < Base
4
4
  def run
5
5
  result = execute(command + applicable_files)
6
- output = result.stdout
6
+ output = result.stdout.chomp
7
7
 
8
- return :pass if output.empty?
8
+ return :pass if result.success? && output.empty?
9
9
 
10
- [:fail, output]
10
+ # example message:
11
+ # path/to/file.js: line 1, col 0, Error message (E001)
12
+ extract_messages(
13
+ output.split("\n").grep(/E|W/),
14
+ /^(?<file>[^:]+):[^\d]+(?<line>\d+).+\((?<type>E|W)\d+\)/,
15
+ lambda { |type| type.include?('W') ? :warning : :error }
16
+ )
11
17
  end
12
18
  end
13
19
  end
@@ -0,0 +1,19 @@
1
+ module Overcommit::Hook::PreCommit
2
+ # Runs `pep257` against any modified Python files.
3
+ class Pep257 < Base
4
+ def run
5
+ result = execute(command + applicable_files)
6
+ return :pass if result.success?
7
+
8
+ output = result.stderr.chomp
9
+
10
+ # example message:
11
+ # path/to/file.py:1 in public method `foo`:
12
+ # D102: Docstring missing
13
+ extract_messages(
14
+ output.gsub(/:\s+/, ': ').split("\n"),
15
+ /^(?<file>[^:]+):(?<line>\d+)/
16
+ )
17
+ end
18
+ end
19
+ end