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
@@ -0,0 +1,19 @@
1
+ module Overcommit::Hook::PreCommit
2
+ # Runs `pep8` against any modified Python files.
3
+ class Pep8 < Base
4
+ def run
5
+ result = execute(command + applicable_files)
6
+ output = result.stdout.chomp
7
+
8
+ return :pass if result.success? && output.empty?
9
+
10
+ # example message:
11
+ # path/to/file.py:88:5: E301 expected 1 blank line, found 0
12
+ extract_messages(
13
+ output.split("\n"),
14
+ /^(?<file>[^:]+):(?<line>\d+):\d+:\s(?<type>E|W)/,
15
+ lambda { |type| type.include?('W') ? :warning : :error }
16
+ )
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,28 @@
1
+ module Overcommit::Hook::PreCommit
2
+ # Runs `pyflakes` against any modified Python files.
3
+ class Pyflakes < Base
4
+ MESSAGE_REGEX = /^(?<file>[^:]+):(?<line>\d+):/
5
+
6
+ def run
7
+ result = execute(command + applicable_files)
8
+ return :pass if result.success?
9
+
10
+ errors = get_messages(result.stderr, :error)
11
+ warnings = get_messages(result.stdout, :warning)
12
+
13
+ errors + warnings
14
+ end
15
+
16
+ private
17
+
18
+ def get_messages(output, type)
19
+ # example message:
20
+ # path/to/file.py:57: local variable 'x' is assigned to but never used
21
+ extract_messages(
22
+ output.split("\n").grep(MESSAGE_REGEX),
23
+ MESSAGE_REGEX,
24
+ proc { type }
25
+ )
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,28 @@
1
+ module Overcommit::Hook::PreCommit
2
+ # Runs `pylint` against any modified Python files.
3
+ class Pylint < Base
4
+ MESSAGE_REGEX = /^(?<file>.+):(?<line>\d+):(?<type>[CEFRW])/
5
+
6
+ # Classify 'E' and 'F' message codes as errors,
7
+ # everything else as warnings.
8
+ # http://pylint.readthedocs.org/en/latest/tutorial.html#getting-started
9
+ MESSAGE_TYPE_CATEGORIZER = lambda do |type|
10
+ 'EF'.include?(type) ? :error : :warning
11
+ end
12
+
13
+ def run
14
+ result = execute(command + applicable_files)
15
+ return :pass if result.success?
16
+
17
+ output = result.stdout.chomp
18
+
19
+ # example message:
20
+ # path/to/file.py:64:C: Missing function docstring (missing-docstring)
21
+ extract_messages(
22
+ output.split("\n").grep(MESSAGE_REGEX),
23
+ MESSAGE_REGEX,
24
+ MESSAGE_TYPE_CATEGORIZER
25
+ )
26
+ end
27
+ end
28
+ end
@@ -1,11 +1,28 @@
1
1
  module Overcommit::Hook::PreCommit
2
2
  # Runs `flake8` against any modified Python files.
3
3
  class PythonFlake8 < Base
4
+ MESSAGE_REGEX = /^(?<file>.+):(?<line>\d+):\d+:\s(?<type>\w\d+)/
5
+
6
+ # Classify 'Exxx' and 'Fxxx' message codes as errors,
7
+ # everything else as warnings.
8
+ # http://flake8.readthedocs.org/en/latest/warnings.html
9
+ MESSAGE_TYPE_CATEGORIZER = lambda do |type|
10
+ 'EF'.include?(type[0]) ? :error : :warning
11
+ end
12
+
4
13
  def run
5
14
  result = execute(command + applicable_files)
6
15
  return :pass if result.success?
7
16
 
8
- [:fail, result.stdout]
17
+ output = result.stdout.chomp
18
+
19
+ # example message:
20
+ # path/to/file.py:2:13: F812 list comprehension redefines name from line 1
21
+ extract_messages(
22
+ output.split("\n").grep(MESSAGE_REGEX),
23
+ MESSAGE_REGEX,
24
+ MESSAGE_TYPE_CATEGORIZER
25
+ )
9
26
  end
10
27
  end
11
28
  end
@@ -0,0 +1,26 @@
1
+ module Overcommit::Hook::PreCommit
2
+ # Runs `scalastyle` against any modified Scala files.
3
+ class Scalastyle < Base
4
+ MESSAGE_REGEX = /
5
+ ^(?<type>error|warning)\s
6
+ file=(?<file>.+)\s
7
+ message=.+\s
8
+ line=(?<line>\d+)
9
+ /x
10
+
11
+ def run
12
+ result = execute(command + applicable_files)
13
+ output = result.stdout.chomp
14
+ messages = output.split("\n").grep(MESSAGE_REGEX)
15
+ return :pass if result.success? && messages.empty?
16
+
17
+ # example message:
18
+ # error file=/path/to/file.scala message=Error message line=1 column=1
19
+ extract_messages(
20
+ messages,
21
+ MESSAGE_REGEX,
22
+ lambda { |type| type.to_sym }
23
+ )
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,17 @@
1
+ module Overcommit::Hook::PreCommit
2
+ # Runs `semistandard` against any modified JavaScript files.
3
+ class SemiStandard < Base
4
+ def run
5
+ result = execute(command + applicable_files)
6
+ output = result.stderr.chomp
7
+ return :pass if result.success? && output.empty?
8
+
9
+ # example message:
10
+ # path/to/file.js:1:1: Error message (ruleName)
11
+ extract_messages(
12
+ output.split("\n")[1..-1], # ignore header line
13
+ /^(?<file>[^:]+):(?<line>\d+)/
14
+ )
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,17 @@
1
+ module Overcommit::Hook::PreCommit
2
+ # Runs `standard` against any modified JavaScript files.
3
+ class Standard < Base
4
+ def run
5
+ result = execute(command + applicable_files)
6
+ output = result.stderr.chomp
7
+ return :pass if result.success? && output.empty?
8
+
9
+ # example message:
10
+ # path/to/file.js:1:1: Error message (ruleName)
11
+ extract_messages(
12
+ output.split("\n")[1..-1], # ignore header line
13
+ /^(?<file>[^:]+):(?<line>\d+)/
14
+ )
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,77 @@
1
+ module Overcommit::Hook::PreCommit
2
+ # Runs `w3c_validators` against any modified CSS files.
3
+ class W3cCss < Base
4
+ def run
5
+ begin
6
+ require 'w3c_validators'
7
+ rescue LoadError
8
+ return :fail, 'w3c_validators not installed -- run `gem install w3c_validators`'
9
+ end
10
+
11
+ result_messages =
12
+ begin
13
+ collect_messages
14
+ rescue W3CValidators::ValidatorUnavailable => e
15
+ return :fail, e.message
16
+ rescue W3CValidators::ParsingError => e
17
+ return :fail, e.message
18
+ end
19
+
20
+ return :pass if result_messages.empty?
21
+
22
+ result_messages
23
+ end
24
+
25
+ private
26
+
27
+ def collect_messages
28
+ applicable_files.collect do |path|
29
+ results = validator.validate_file(path)
30
+ messages = results.errors + results.warnings
31
+ messages.collect do |msg|
32
+ # Some warnings are not per-line, so use 0 as a default
33
+ line = Integer(msg.line || 0)
34
+
35
+ # Build message by hand to reduce noise from the validator response
36
+ text = "#{msg.type.to_s.upcase}; URI: #{path}; line #{line}: #{msg.message.strip}"
37
+ Overcommit::Hook::Message.new(msg.type, path, line, text)
38
+ end
39
+ end.flatten
40
+ end
41
+
42
+ def validator
43
+ unless @validator
44
+ @validator = W3CValidators::CSSValidator.new(opts)
45
+ @validator.set_language!(language) unless language.nil?
46
+ @validator.set_profile!(profile) unless profile.nil?
47
+ @validator.set_warn_level!(warn_level) unless warn_level.nil?
48
+ end
49
+ @validator
50
+ end
51
+
52
+ def opts
53
+ @opts ||= {
54
+ validator_uri: config['validator_uri'],
55
+ proxy_server: config['proxy_server'],
56
+ proxy_port: config['proxy_port'],
57
+ proxy_user: config['proxy_user'],
58
+ proxy_pass: config['proxy_pass']
59
+ }
60
+ end
61
+
62
+ def language
63
+ @language ||= config['language']
64
+ end
65
+
66
+ # Values specified at
67
+ # http://www.rubydoc.info/gems/w3c_validators/1.2/W3CValidators#CSS_PROFILES
68
+ def profile
69
+ @profile ||= config['profile']
70
+ end
71
+
72
+ # One of 0, 1, 2, 'no'
73
+ def warn_level
74
+ @warn_level ||= config['warn_level']
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,74 @@
1
+ module Overcommit::Hook::PreCommit
2
+ # Runs `w3c_validators` against any modified HTML files.
3
+ class W3cHtml < Base
4
+ def run
5
+ begin
6
+ require 'w3c_validators'
7
+ rescue LoadError
8
+ return :fail, 'w3c_validators not installed -- run `gem install w3c_validators`'
9
+ end
10
+
11
+ result_messages =
12
+ begin
13
+ collect_messages
14
+ rescue W3CValidators::ValidatorUnavailable => e
15
+ return :fail, e.message
16
+ rescue W3CValidators::ParsingError => e
17
+ return :fail, e.message
18
+ end
19
+
20
+ return :pass if result_messages.empty?
21
+
22
+ result_messages
23
+ end
24
+
25
+ private
26
+
27
+ def collect_messages
28
+ applicable_files.collect do |path|
29
+ results = validator.validate_file(path)
30
+ messages = results.errors + results.warnings
31
+ messages.collect do |msg|
32
+ # Some warnings are not per-line, so use 0 as a default
33
+ line = Integer(msg.line || 0)
34
+
35
+ # Build message by hand to reduce noise from the validator response
36
+ text = "#{msg.type.to_s.upcase}; URI: #{path}; line #{line}: #{msg.message.strip}"
37
+ Overcommit::Hook::Message.new(msg.type, path, line, text)
38
+ end
39
+ end.flatten
40
+ end
41
+
42
+ def validator
43
+ unless @validator
44
+ @validator = W3CValidators::MarkupValidator.new(opts)
45
+ @validator.set_charset!(charset, true) unless charset.nil?
46
+ @validator.set_doctype!(doctype, true) unless doctype.nil?
47
+ @validator.set_debug!
48
+ end
49
+ @validator
50
+ end
51
+
52
+ def opts
53
+ @opts ||= {
54
+ validator_uri: config['validator_uri'],
55
+ proxy_server: config['proxy_server'],
56
+ proxy_port: config['proxy_port'],
57
+ proxy_user: config['proxy_user'],
58
+ proxy_pass: config['proxy_pass']
59
+ }
60
+ end
61
+
62
+ # Values specified at
63
+ # http://www.rubydoc.info/gems/w3c_validators/1.2/W3CValidators#CHARSETS
64
+ def charset
65
+ @charset ||= config['charset']
66
+ end
67
+
68
+ # Values specified at
69
+ # http://www.rubydoc.info/gems/w3c_validators/1.2/W3CValidators#DOCTYPES
70
+ def doctype
71
+ @doctype ||= config['doctype']
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,20 @@
1
+ module Overcommit::Hook::PreCommit
2
+ # Runs `xmllint` against any modified XML files.
3
+ class XmlLint < Base
4
+ MESSAGE_REGEX = /^(?<file>[^:]+):(?<line>\d+):/
5
+
6
+ def run
7
+ result = execute(command + applicable_files)
8
+ output = result.stderr.chomp
9
+
10
+ return :pass if result.success? && output.empty?
11
+
12
+ # example message:
13
+ # path/to/file.xml:1: parser error : Error message
14
+ extract_messages(
15
+ output.split("\n").grep(MESSAGE_REGEX),
16
+ MESSAGE_REGEX
17
+ )
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,31 @@
1
+ module Overcommit::HookContext
2
+ # Contains helpers related to contextual information used by post-commit
3
+ # hooks.
4
+ class PostCommit < Base
5
+ # Get a list of files that were added, copied, or modified in the last
6
+ # commit. Renames and deletions are ignored, since there should be nothing
7
+ # to check.
8
+ def modified_files
9
+ subcmd = 'show --format=%n'
10
+ @modified_files ||= Overcommit::GitRepo.modified_files(subcmd: subcmd)
11
+ end
12
+
13
+ # Returns the set of line numbers corresponding to the lines that were
14
+ # changed in a specified file.
15
+ def modified_lines_in_file(file)
16
+ subcmd = 'show --format=%n'
17
+ @modified_lines ||= {}
18
+ @modified_lines[file] ||=
19
+ Overcommit::GitRepo.extract_modified_lines(file, subcmd: subcmd)
20
+ end
21
+
22
+ # Returns whether the commit that triggered this hook is the first commit on
23
+ # the branch.
24
+ #
25
+ # @return [true,false]
26
+ def initial_commit?
27
+ return @initial_commit unless @initial_commit.nil?
28
+ @initial_commit = !Overcommit::Utils.execute(%w[git rev-parse HEAD~]).success?
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,35 @@
1
+ module Overcommit::HookContext
2
+ # Contains helpers related to contextual information used by post-merge
3
+ # hooks.
4
+ class PostMerge < Base
5
+ attr_accessor :args
6
+ # Get a list of files that were added, copied, or modified in the merge
7
+ # commit. Renames and deletions are ignored, since there should be nothing
8
+ # to check.
9
+ def modified_files
10
+ staged = squash?
11
+ refs = 'HEAD^ HEAD' if merge_commit?
12
+ @modified_files ||= Overcommit::GitRepo.modified_files(staged: staged, refs: refs)
13
+ end
14
+
15
+ # Returns the set of line numbers corresponding to the lines that were
16
+ # changed in a specified file.
17
+ def modified_lines_in_file(file)
18
+ staged = squash?
19
+ refs = 'HEAD^ HEAD' if merge_commit?
20
+ @modified_lines ||= {}
21
+ @modified_lines[file] ||=
22
+ Overcommit::GitRepo.extract_modified_lines(file, staged: staged, refs: refs)
23
+ end
24
+
25
+ # Returns whether this merge was made using --squash
26
+ def squash?
27
+ @args[0].to_i == 1
28
+ end
29
+
30
+ # Returns whether this merge was made without --squash
31
+ def merge_commit?
32
+ !squash?
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,18 @@
1
+ module Overcommit::HookContext
2
+ # Contains helpers for contextual information used by post-rewrite hooks.
3
+ class PostRewrite < Base
4
+ # Returns whether this post-rewrite was triggered by `git commit --amend`.
5
+ #
6
+ # @return [true,false]
7
+ def amend?
8
+ @args[0] == 'amend'
9
+ end
10
+
11
+ # Returns whether this post-rewrite was triggered by `git rebase`.
12
+ #
13
+ # @return [true,false]
14
+ def rebase?
15
+ @args[0] == 'rebase'
16
+ end
17
+ end
18
+ end
@@ -6,16 +6,18 @@ module Overcommit::HookContext
6
6
  # This results in pre-commit hooks running against the entire repository,
7
7
  # which is useful for automated CI scripts.
8
8
  class RunAll < Base
9
- EMPTY_SET = Set.new
10
-
11
9
  def modified_files
12
- all_files
10
+ @modified_files ||= Overcommit::GitRepo.all_files
13
11
  end
14
12
 
15
- # Return an empty set since in this context the user didn't actually touch
16
- # any lines.
17
- def modified_lines_in_file(_file)
18
- EMPTY_SET
13
+ # Returns all lines in the file since in this context the entire repo is
14
+ # being scrutinized.
15
+ #
16
+ # @param file [String]
17
+ # @return [Set]
18
+ def modified_lines_in_file(file)
19
+ @modified_lines_in_file ||= {}
20
+ @modified_lines_in_file[file] ||= Set.new(1..(count_lines(file) + 1))
19
21
  end
20
22
 
21
23
  def hook_class_name
@@ -32,8 +34,9 @@ module Overcommit::HookContext
32
34
 
33
35
  private
34
36
 
35
- def all_files
36
- @all_files ||= Overcommit::GitRepo.all_files
37
+ def count_lines(file)
38
+ result = Overcommit::Utils.execute(%w[wc -l] + [file])
39
+ result.success? ? result.stdout.to_i : 0
37
40
  end
38
41
  end
39
42
  end
@@ -101,19 +101,38 @@ module Overcommit
101
101
  false
102
102
  end
103
103
 
104
- # Wrap external subshell calls. This is necessary in order to allow
105
- # Overcommit to call other Ruby executables without requiring that they be
106
- # specified in Overcommit's Gemfile--a nasty consequence of using
107
- # `bundle exec overcommit` while developing locally.
104
+ # Execute a command in a subprocess, capturing exit status and output from
105
+ # both standard and error streams.
106
+ #
107
+ # This is intended to provide a centralized place to perform any checks or
108
+ # filtering of the command before executing it.
109
+ #
110
+ # @param args [Array<String>]
111
+ # @return [Overcommit::Subprocess::Result] status, stdout, and stderr
108
112
  def execute(args)
109
113
  if args.include?('|')
110
114
  raise Overcommit::Exceptions::InvalidCommandArgs,
111
115
  'Cannot pipe commands with the `execute` helper'
112
116
  end
113
117
 
114
- with_environment 'RUBYOPT' => nil do
115
- Subprocess.spawn(args)
118
+ Subprocess.spawn(args)
119
+ end
120
+
121
+ # Execute a command in a subprocess, returning immediately.
122
+ #
123
+ # This provides a convenient way to execute long-running processes for
124
+ # which we do not need to know the result.
125
+ #
126
+ # @param args [Array<String>]
127
+ # @return [Thread] thread watching the resulting child process
128
+ def execute_in_background(args)
129
+ if args.include?('|')
130
+ raise Overcommit::Exceptions::InvalidCommandArgs,
131
+ 'Cannot pipe commands with the `execute_in_background` helper'
116
132
  end
133
+
134
+ # Dissociate process from parent's input/output streams
135
+ Process.detach(Process.spawn({}, *args, [:in, :out, :err] => '/dev/null'))
117
136
  end
118
137
 
119
138
  # Calls a block of code with a modified set of environment variables,
@@ -1,4 +1,4 @@
1
1
  # Defines the gem version.
2
2
  module Overcommit
3
- VERSION = '0.22.0'
3
+ VERSION = '0.23.0'
4
4
  end
@@ -0,0 +1,81 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # Entrypoint for Overcommit hook integration. Installing Overcommit will result
4
+ # in all of your git hooks being symlinked to this file, allowing the framework
5
+ # to manage your hooks for you.
6
+
7
+ # Prevent a Ruby stack trace from appearing when we interrupt the hook.
8
+ # Note that this will be overridden when Overcommit is loaded, since the
9
+ # InterruptHandler will redefine the trap at that time.
10
+ Signal.trap('INT') do
11
+ puts 'Hook run interrupted'
12
+ exit 130
13
+ end
14
+
15
+ # Allow hooks to be disabled via environment variable so git commands can be run
16
+ # in scripts without Overcommit running hooks
17
+ if ENV['OVERCOMMIT_DISABLE'].to_i != 0 || ENV['OVERCOMMIT_DISABLED'].to_i != 0
18
+ exit
19
+ end
20
+
21
+ hook_type = File.basename($0)
22
+ if hook_type == 'overcommit-hook'
23
+ puts "Don't run `overcommit-hook` directly; it is intended to be symlinked " \
24
+ "by each hook in a repository's .git/hooks directory."
25
+ exit 64 # EX_USAGE
26
+ end
27
+
28
+ begin
29
+ require 'overcommit'
30
+ rescue LoadError
31
+ puts 'This repository contains hooks installed by Overcommit, but the ' \
32
+ "overcommit gem is not installed.\n" \
33
+ 'Install it with `gem install overcommit`.'
34
+ exit
35
+ end
36
+
37
+ begin
38
+ logger = Overcommit::Logger.new(STDOUT)
39
+
40
+ # Ensure master hook is up-to-date
41
+ installer = Overcommit::Installer.new(logger)
42
+ if installer.run(Overcommit::Utils.repo_root, action: :update)
43
+ exec($0, *ARGV) # Execute the updated hook with all original arguments
44
+ end
45
+
46
+ config = Overcommit::ConfigurationLoader.load_repo_config
47
+
48
+ context = Overcommit::HookContext.create(hook_type, config, ARGV)
49
+ config.apply_environment!(context, ENV)
50
+
51
+ printer = Overcommit::Printer.new(logger, context)
52
+ runner = Overcommit::HookRunner.new(config, logger, context, printer)
53
+
54
+ status = runner.run
55
+
56
+ exit(status ? 0 : 65) # 65 = EX_DATAERR
57
+ rescue Overcommit::Exceptions::ConfigurationError => error
58
+ puts error
59
+ exit 78 # EX_CONFIG
60
+ rescue Overcommit::Exceptions::HookContextLoadError => error
61
+ puts error
62
+ puts 'Are you running an old version of Overcommit?'
63
+ exit 69 # EX_UNAVAILABLE
64
+ rescue Overcommit::Exceptions::HookSetupFailed,
65
+ Overcommit::Exceptions::HookCleanupFailed => error
66
+ puts error.message
67
+ exit 74 # EX_IOERR
68
+ rescue Overcommit::Exceptions::HookCancelled
69
+ puts 'You cancelled the hook run'
70
+ exit 130 # Ctrl-C cancel
71
+ rescue Overcommit::Exceptions::InvalidGitRepo => error
72
+ puts error
73
+ exit 64 # EX_USAGE
74
+ rescue Overcommit::Exceptions::InvalidHookSignature
75
+ exit 1
76
+ rescue => error
77
+ puts error.message
78
+ puts error.backtrace
79
+ puts "Report this bug at #{Overcommit::BUG_REPORT_URL}"
80
+ exit 70 # EX_SOFTWARE
81
+ end