overcommit 0.7.0 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. checksums.yaml +4 -4
  2. data/config/default.yml +10 -0
  3. data/lib/overcommit.rb +5 -0
  4. data/lib/overcommit/cli.rb +1 -1
  5. data/lib/overcommit/configuration.rb +4 -0
  6. data/lib/overcommit/configuration_loader.rb +30 -28
  7. data/lib/overcommit/exceptions.rb +6 -0
  8. data/lib/overcommit/hook/commit_msg/gerrit_change_id.rb +5 -5
  9. data/lib/overcommit/hook/commit_msg/text_width.rb +1 -1
  10. data/lib/overcommit/hook/post_checkout/bundle_check.rb +5 -1
  11. data/lib/overcommit/hook/pre_commit/author_email.rb +2 -2
  12. data/lib/overcommit/hook/pre_commit/author_name.rb +2 -2
  13. data/lib/overcommit/hook/pre_commit/bundle_check.rb +2 -4
  14. data/lib/overcommit/hook/pre_commit/coffee_lint.rb +2 -1
  15. data/lib/overcommit/hook/pre_commit/css_lint.rb +3 -2
  16. data/lib/overcommit/hook/pre_commit/haml_lint.rb +3 -2
  17. data/lib/overcommit/hook/pre_commit/js_hint.rb +3 -1
  18. data/lib/overcommit/hook/pre_commit/jscs.rb +3 -2
  19. data/lib/overcommit/hook/pre_commit/python_flake8.rb +2 -1
  20. data/lib/overcommit/hook/pre_commit/rubocop.rb +3 -2
  21. data/lib/overcommit/hook/pre_commit/scss_lint.rb +3 -2
  22. data/lib/overcommit/hook/pre_commit/travis_lint.rb +15 -0
  23. data/lib/overcommit/hook/pre_commit/yaml_syntax.rb +3 -3
  24. data/lib/overcommit/hook_context/post_checkout.rb +2 -0
  25. data/lib/overcommit/hook_loader/base.rb +38 -0
  26. data/lib/overcommit/hook_loader/built_in_hook_loader.rb +12 -0
  27. data/lib/overcommit/hook_loader/plugin_hook_loader.rb +51 -0
  28. data/lib/overcommit/hook_runner.rb +43 -61
  29. data/lib/overcommit/hook_signer.rb +73 -0
  30. data/lib/overcommit/installer.rb +28 -8
  31. data/lib/overcommit/user_input.rb +26 -0
  32. data/lib/overcommit/version.rb +1 -1
  33. data/template-dir/hooks/commit-msg +21 -8
  34. data/template-dir/hooks/overcommit-hook +21 -8
  35. data/template-dir/hooks/post-checkout +21 -8
  36. data/template-dir/hooks/pre-commit +21 -8
  37. metadata +12 -7
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 92e61229cb593b12785dc6f250aaf20b59335277
4
- data.tar.gz: 6109a2ebdd9e9ad8fb6612178dc38c919decc366
3
+ metadata.gz: 6030d9d4951a3c37f536bfd4caefc3890c6c4f2d
4
+ data.tar.gz: 04a5f6031e2217c33382a2c034f7670f711dbdbe
5
5
  SHA512:
6
- metadata.gz: 9a30a6cef4ea66c146c536e3868e12e2ce8a80dbc4c10955e3e6f18990dc0f75a21e439032bdcd180086aa6fd47a4a327d9ca36441f654f4e1400777ce333d8c
7
- data.tar.gz: 1d0a931ee95dac1fa0f7bf35f3e154033d831df840f1ba30772108612bc5aafd52315bded077ec359873cc2d3298f76aca2800fec55ae862b89f45867af15b11
6
+ metadata.gz: c6769844c60d201e95417a06610daef7c1a5465184c176423ad7bf9bfb958373116fe8d17085ecc9f2d741677d9a928e28df6ac6b174f5499d8907837eef1305
7
+ data.tar.gz: 49c7bbeafda273737fafc8aba005eda1b5c13774932a143c7c85664ee32f4f84898999c1da2cea9f4b2ffb2eae490386bef0b8c744b76a798a9c90478f859000
@@ -8,6 +8,12 @@
8
8
  # to the root of the repository.
9
9
  plugin_directory: '.git-hooks'
10
10
 
11
+ # Whether to check if a hook plugin has changed since Overcommit last ran it.
12
+ # This is a defense mechanism when working with repositories which can contain
13
+ # untrusted code (e.g. when you fetch a pull request from a third party).
14
+ # See https://github.com/causes/overcommit#security for more information.
15
+ verify_plugin_signatures: true
16
+
11
17
  # Hooks that run after HEAD changes or a file is explicitly checked out. Useful
12
18
  # for updating source tags (e.g. via ctags) or warning about new migrations,
13
19
  # etc.
@@ -105,6 +111,10 @@ PreCommit:
105
111
  TrailingWhitespace:
106
112
  description: 'Checking for trailing whitespace'
107
113
 
114
+ TravisLint:
115
+ description: 'Checking Travis CI configuration'
116
+ include: '.travis.yml'
117
+
108
118
  YamlSyntax:
109
119
  description: 'Checking YAML syntax'
110
120
  include: '**/*.yml'
@@ -5,6 +5,11 @@ require 'overcommit/configuration_loader'
5
5
  require 'overcommit/hook/base'
6
6
  require 'overcommit/hook_context/base'
7
7
  require 'overcommit/hook_context'
8
+ require 'overcommit/user_input'
9
+ require 'overcommit/hook_signer'
10
+ require 'overcommit/hook_loader/base'
11
+ require 'overcommit/hook_loader/built_in_hook_loader'
12
+ require 'overcommit/hook_loader/plugin_hook_loader'
8
13
  require 'overcommit/hook_runner'
9
14
  require 'overcommit/installer'
10
15
  require 'overcommit/logger'
@@ -74,7 +74,7 @@ module Overcommit
74
74
 
75
75
  if @options[:targets].empty?
76
76
  log.warning 'You are not in a git repository.'
77
- log.log 'You must either specify the path to a repository or ' <<
77
+ log.log 'You must either specify the path to a repository or ' \
78
78
  'change your current directory to a repository.'
79
79
  halt 64 # EX_USAGE
80
80
  end
@@ -18,6 +18,10 @@ module Overcommit
18
18
  File.join(Overcommit::Utils.repo_root, @hash['plugin_directory'] || '.githooks')
19
19
  end
20
20
 
21
+ def verify_plugin_signatures?
22
+ @hash['verify_plugin_signatures'] != false
23
+ end
24
+
21
25
  # Returns the built-in hooks that have been enabled for a hook type.
22
26
  def enabled_builtin_hooks(hook_context)
23
27
  @hash[hook_context.hook_class_name].keys.
@@ -6,42 +6,44 @@ module Overcommit
6
6
  DEFAULT_CONFIG_PATH = File.join(OVERCOMMIT_HOME, 'config', 'default.yml')
7
7
  FILE_NAME = '.overcommit.yml'
8
8
 
9
- def self.load_repo_config
10
- overcommit_yml = File.join(Overcommit::Utils.repo_root, FILE_NAME)
9
+ class << self
10
+ def load_repo_config
11
+ overcommit_yml = File.join(Overcommit::Utils.repo_root, FILE_NAME)
11
12
 
12
- if File.exists?(overcommit_yml)
13
- load_file(overcommit_yml)
14
- else
15
- default_configuration
13
+ if File.exist?(overcommit_yml)
14
+ load_file(overcommit_yml)
15
+ else
16
+ default_configuration
17
+ end
16
18
  end
17
- end
18
19
 
19
- def self.default_configuration
20
- @default_config ||= load_from_file(DEFAULT_CONFIG_PATH)
21
- end
20
+ def default_configuration
21
+ @default_config ||= load_from_file(DEFAULT_CONFIG_PATH)
22
+ end
22
23
 
23
- private
24
+ private
24
25
 
25
- # Loads a configuration, ensuring it extends the default configuration.
26
- def self.load_file(file)
27
- config = load_from_file(file)
26
+ # Loads a configuration, ensuring it extends the default configuration.
27
+ def load_file(file)
28
+ config = load_from_file(file)
28
29
 
29
- default_configuration.merge(config)
30
- rescue => error
31
- raise Overcommit::Exceptions::ConfigurationError,
32
- "Unable to load configuration from '#{file}': #{error}",
33
- error.backtrace
34
- end
30
+ default_configuration.merge(config)
31
+ rescue => error
32
+ raise Overcommit::Exceptions::ConfigurationError,
33
+ "Unable to load configuration from '#{file}': #{error}",
34
+ error.backtrace
35
+ end
35
36
 
36
- def self.load_from_file(file)
37
- hash =
38
- if yaml = YAML.load_file(file)
39
- yaml.to_hash
40
- else
41
- {}
42
- end
37
+ def load_from_file(file)
38
+ hash =
39
+ if yaml = YAML.load_file(file)
40
+ yaml.to_hash
41
+ else
42
+ {}
43
+ end
43
44
 
44
- Overcommit::Configuration.new(hash)
45
+ Overcommit::Configuration.new(hash)
46
+ end
45
47
  end
46
48
  end
47
49
  end
@@ -2,6 +2,12 @@ module Overcommit::Exceptions
2
2
  # Raised when a {Configuration} could not be loaded from a file.
3
3
  class ConfigurationError < StandardError; end
4
4
 
5
+ # Raised when trying to read/write to/from the local repo git config fails.
6
+ class GitConfigError < StandardError; end
7
+
8
+ # Raised when a hook run was cancelled by the user.
9
+ class HookCancelled < StandardError; end
10
+
5
11
  # Raised when a hook could not be loaded by a {HookRunner}.
6
12
  class HookLoadError < StandardError; end
7
13
 
@@ -6,13 +6,13 @@ module Overcommit::Hook::CommitMsg
6
6
  # you need to do it in a commit-msg hook. This is because the user could still
7
7
  # edit the message after a prepare-commit-msg hook was run.
8
8
  class GerritChangeId < Base
9
+ SCRIPT_LOCATION = Overcommit::Utils.script_path('gerrit-change-id')
10
+
9
11
  def run
10
12
  result = execute([SCRIPT_LOCATION, commit_message_file])
11
- return (result.success? ? :good : :bad), result.stdout
12
- end
13
+ return :good if result.success?
13
14
 
14
- private
15
-
16
- SCRIPT_LOCATION = Overcommit::Utils.script_path('gerrit-change-id')
15
+ [:bad, result.stdout]
16
+ end
17
17
  end
18
18
  end
@@ -16,7 +16,7 @@ module Overcommit::Hook::CommitMsg
16
16
  commit_message_lines[2..-1].each_with_index do |line, index|
17
17
  chomped = line.chomp
18
18
  if chomped.size > max_body_width
19
- error = "Line #{index + 3} of commit message has > " <<
19
+ error = "Line #{index + 3} of commit message has > " \
20
20
  "#{max_body_width} characters"
21
21
  errors << error
22
22
  end
@@ -7,13 +7,17 @@ module Overcommit::Hook::PostCheckout
7
7
  return :warn, 'bundler not installed -- run `gem install bundler`'
8
8
  end
9
9
 
10
- return :warn if dependencies_changed? && !dependencies_satisfied?
10
+ if dependencies_changed? && !dependencies_satisfied?
11
+ return :warn, "#{LOCK_FILE} is not up-to-date -- run `bundle check`"
12
+ end
11
13
 
12
14
  :good
13
15
  end
14
16
 
15
17
  private
16
18
 
19
+ LOCK_FILE = 'Gemfile.lock'
20
+
17
21
  def dependencies_changed?
18
22
  result = execute(%w[git diff --exit-code --name-only] + [new_head, previous_head])
19
23
 
@@ -6,8 +6,8 @@ module Overcommit::Hook::PreCommit
6
6
  email = result.stdout.chomp
7
7
 
8
8
  unless email =~ /#{@config['pattern']}/
9
- return :bad, "Author has an invalid email address: '#{email}'\n" <<
10
- 'Set your email with ' <<
9
+ return :bad, "Author has an invalid email address: '#{email}'\n" \
10
+ 'Set your email with ' \
11
11
  '`git config --global user.email your_email@example.com`'
12
12
  end
13
13
 
@@ -6,8 +6,8 @@ module Overcommit::Hook::PreCommit
6
6
  name = result.stdout.chomp
7
7
 
8
8
  unless name.split(' ').count >= 2
9
- return :bad, 'Author must have at least first and last name, but ' <<
10
- "was: '#{name}'.\nSet your name with " <<
9
+ return :bad, 'Author must have at least first and last name, but ' \
10
+ "was: '#{name}'.\nSet your name with " \
11
11
  "`git config --global user.name 'Your Name'`"
12
12
  end
13
13
 
@@ -2,6 +2,8 @@ module Overcommit::Hook::PreCommit
2
2
  # Check if local Gemfile.lock matches Gemfile when either changes, unless
3
3
  # Gemfile.lock is ignored by git.
4
4
  class BundleCheck < Base
5
+ LOCK_FILE = 'Gemfile.lock'
6
+
5
7
  def run
6
8
  unless in_path?('bundle')
7
9
  return :warn, 'bundler not installed -- run `gem install bundler`'
@@ -22,9 +24,5 @@ module Overcommit::Hook::PreCommit
22
24
 
23
25
  :good
24
26
  end
25
-
26
- private
27
-
28
- LOCK_FILE = 'Gemfile.lock'
29
27
  end
30
28
  end
@@ -8,7 +8,8 @@ module Overcommit::Hook::PreCommit
8
8
 
9
9
  result = execute(%w[coffeelint --quiet] + applicable_files)
10
10
  return :good if result.success?
11
- return :bad, result.stdout
11
+
12
+ [:bad, result.stdout]
12
13
  end
13
14
  end
14
15
  end
@@ -7,8 +7,9 @@ module Overcommit::Hook::PreCommit
7
7
  end
8
8
 
9
9
  result = execute(%w[csslint --quiet --format=compact] + applicable_files)
10
- output = result.stdout
11
- return (output !~ /Error - (?!Unknown @ rule)/ ? :good : :bad), output
10
+ return :good if result.stdout !~ /Error - (?!Unknown @ rule)/
11
+
12
+ [:bad, result.stdout]
12
13
  end
13
14
  end
14
15
  end
@@ -19,8 +19,9 @@ module Overcommit::Hook::PreCommit
19
19
  end
20
20
 
21
21
  return :bad, error_lines.join("\n") unless error_lines.empty?
22
- return :warn, "Modified files have lints (on lines you didn't modify)\n" <<
23
- warning_lines.join("\n")
22
+
23
+ [:warn, "Modified files have lints (on lines you didn't modify)\n" <<
24
+ warning_lines.join("\n")]
24
25
  end
25
26
  end
26
27
  end
@@ -9,7 +9,9 @@ module Overcommit::Hook::PreCommit
9
9
  result = execute(%w[jshint] + applicable_files)
10
10
  output = result.stdout
11
11
 
12
- return (output.empty? ? :good : :bad), output
12
+ return :good if output.empty?
13
+
14
+ [:bad, output]
13
15
  end
14
16
  end
15
17
  end
@@ -24,8 +24,9 @@ module Overcommit::Hook::PreCommit
24
24
  end
25
25
 
26
26
  return :bad, error_lines.join("\n") unless error_lines.empty?
27
- return :warn, "Modified files have lints (on lines you didn't modify)\n" <<
28
- warning_lines.join("\n")
27
+
28
+ [:warn, "Modified files have lints (on lines you didn't modify)\n" <<
29
+ warning_lines.join("\n")]
29
30
  end
30
31
  end
31
32
  end
@@ -7,8 +7,9 @@ module Overcommit::Hook::PreCommit
7
7
  end
8
8
 
9
9
  result = execute(%w[flake8] + applicable_files)
10
+ return :good if result.success?
10
11
 
11
- return (result.success? ? :good : :bad), result.stdout
12
+ [:bad, result.stdout]
12
13
  end
13
14
  end
14
15
  end
@@ -21,8 +21,9 @@ module Overcommit::Hook::PreCommit
21
21
  end
22
22
 
23
23
  return :bad, error_lines.join("\n") unless error_lines.empty?
24
- return :warn, "Modified files have lints (on lines you didn't modify)\n" <<
25
- warning_lines.join("\n")
24
+
25
+ [:warn, "Modified files have lints (on lines you didn't modify)\n" <<
26
+ warning_lines.join("\n")]
26
27
  end
27
28
  end
28
29
  end
@@ -19,8 +19,9 @@ module Overcommit::Hook::PreCommit
19
19
  end
20
20
 
21
21
  return :bad, error_lines.join("\n") unless error_lines.empty?
22
- return :warn, "Modified files have lints (on lines you didn't modify)\n" <<
23
- warning_lines.join("\n")
22
+
23
+ [:warn, "Modified files have lints (on lines you didn't modify)\n" <<
24
+ warning_lines.join("\n")]
24
25
  end
25
26
  end
26
27
  end
@@ -0,0 +1,15 @@
1
+ module Overcommit::Hook::PreCommit
2
+ # Runs `travis-lint` against any modified Travis CI files.
3
+ class TravisLint < Base
4
+ def run
5
+ unless in_path?('travis-lint')
6
+ return :warn, 'Run `gem install travis-lint`'
7
+ end
8
+
9
+ result = execute(%w[travis-lint] + applicable_files)
10
+ return :good if result.success?
11
+
12
+ [:bad, result.stdout.strip]
13
+ end
14
+ end
15
+ end
@@ -4,7 +4,6 @@ module Overcommit::Hook::PreCommit
4
4
  # Checks the syntax of any modified YAML files.
5
5
  class YamlSyntax < Base
6
6
  def run
7
- clean = true
8
7
  output = []
9
8
 
10
9
  applicable_files.each do |file|
@@ -12,11 +11,12 @@ module Overcommit::Hook::PreCommit
12
11
  YAML.load_file(file)
13
12
  rescue ArgumentError => e
14
13
  output << "#{e.message} parsing #{file}"
15
- clean = false
16
14
  end
17
15
  end
18
16
 
19
- return (clean ? :good : :bad), output
17
+ return :good if output.empty?
18
+
19
+ [:bad, output]
20
20
  end
21
21
  end
22
22
  end
@@ -1,4 +1,6 @@
1
1
  module Overcommit::HookContext
2
+ # Contains helpers related to contextual information used by post-checkout
3
+ # hooks.
2
4
  class PostCheckout < Base
3
5
  # Returns the ref of the HEAD that we transitioned from.
4
6
  def previous_head
@@ -0,0 +1,38 @@
1
+ module Overcommit::HookLoader
2
+ # Responsible for loading hooks from a file.
3
+ class Base
4
+ # @param config [Overcommit::Configuration]
5
+ # @param context [Overcommit::HookContext]
6
+ # @param logger [Overcommit::Logger]
7
+ # @param input [Overcommit::UserInput]
8
+ def initialize(config, context, logger, input)
9
+ @config = config
10
+ @context = context
11
+ @log = logger
12
+ @input = input
13
+ end
14
+
15
+ # When implemented in subclasses, loads the hooks for which that subclass is
16
+ # responsible.
17
+ #
18
+ # @return [Array<Hook>]
19
+ def load_hooks
20
+ raise NotImplementedError
21
+ end
22
+
23
+ private
24
+
25
+ attr_reader :log
26
+
27
+ # Load and return a {Hook} from a CamelCase hook name.
28
+ def create_hook(hook_name)
29
+ Overcommit::Hook.const_get(@context.hook_class_name).
30
+ const_get(hook_name).
31
+ new(@config, @context)
32
+ rescue LoadError, NameError => error
33
+ raise Overcommit::Exceptions::HookLoadError,
34
+ "Unable to load hook '#{hook_name}': #{error}",
35
+ error.backtrace
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,12 @@
1
+ module Overcommit::HookLoader
2
+ # Responsible for loading hooks that ship with Overcommit.
3
+ class BuiltInHookLoader < Base
4
+ def load_hooks
5
+ @config.enabled_builtin_hooks(@context).map do |hook_name|
6
+ underscored_hook_name = Overcommit::Utils.snake_case(hook_name)
7
+ require "overcommit/hook/#{@context.hook_type_name}/#{underscored_hook_name}"
8
+ create_hook(hook_name)
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,51 @@
1
+ require 'digest'
2
+
3
+ module Overcommit::HookLoader
4
+ # Responsible for loading hooks that are specific to the repository Overcommit
5
+ # is running in.
6
+ class PluginHookLoader < Base
7
+ def load_hooks
8
+ directory = File.join(@config.plugin_directory, @context.hook_type_name)
9
+ plugin_paths = Dir[File.join(directory, '*.rb')].sort
10
+
11
+ check_for_modified_plugins(plugin_paths) if @config.verify_plugin_signatures?
12
+
13
+ plugin_paths.map do |plugin_path|
14
+ require plugin_path
15
+
16
+ hook_name = Overcommit::Utils.camel_case(File.basename(plugin_path, '.rb'))
17
+ create_hook(hook_name)
18
+ end
19
+ end
20
+
21
+ private
22
+
23
+ def check_for_modified_plugins(plugin_paths)
24
+ modified_plugins = plugin_paths.
25
+ map { |path| Overcommit::HookSigner.new(path, @config, @context) }.
26
+ select { |signer| signer.signature_changed? }
27
+
28
+ return if modified_plugins.empty?
29
+
30
+ log.bold_warning "The following #{@context.hook_script_name} plugins " \
31
+ "have been added, changed, or had their configuration modified:"
32
+ log.log
33
+
34
+ modified_plugins.each do |signer|
35
+ log.warning " * #{signer.hook_name} in #{signer.hook_path}"
36
+ end
37
+
38
+ log.log
39
+ log.bold_warning 'You should verify the changes before continuing'
40
+ log.log "For more information, see #{Overcommit::REPO_URL}#security"
41
+ log.log
42
+ log.partial 'Continue? (y/n) '
43
+
44
+ unless (answer = @input.get) && answer.strip.downcase.start_with?('y')
45
+ raise Overcommit::Exceptions::HookCancelled
46
+ end
47
+
48
+ modified_plugins.each { |signer| signer.update_signature! }
49
+ end
50
+ end
51
+ end
@@ -4,17 +4,22 @@ module Overcommit
4
4
  # Responsible for loading the hooks the repository has configured and running
5
5
  # them, collecting and displaying the results.
6
6
  class HookRunner
7
- def initialize(config, logger, context)
7
+ # @param config [Overcommit::Configuration]
8
+ # @param logger [Overcommit::Logger]
9
+ # @param context [Overcommit::HookContext]
10
+ # @param input [Overcommit::UserInput]
11
+ def initialize(config, logger, context, input)
8
12
  @config = config
9
13
  @log = logger
10
14
  @context = context
15
+ @input = input
11
16
  @hooks = []
12
17
  end
13
18
 
14
19
  # Loads and runs the hooks registered for this {HookRunner}.
15
20
  def run
16
- load_hooks
17
21
  @context.setup_environment
22
+ load_hooks
18
23
  run_hooks
19
24
  ensure
20
25
  @context.cleanup_environment
@@ -26,7 +31,7 @@ module Overcommit
26
31
 
27
32
  def run_hooks
28
33
  if @hooks.any? { |hook| hook.run? || hook.skip? }
29
- log.bold "Running #{@context.hook_script_name} hooks"
34
+ log.bold "Running #{hook_script_name} hooks"
30
35
 
31
36
  statuses = @hooks.map { |hook| run_hook(hook) }.compact
32
37
 
@@ -35,33 +40,22 @@ module Overcommit
35
40
  run_failed = statuses.include?(:bad)
36
41
 
37
42
  if run_failed
38
- log.error "✗ One or more #{@context.hook_script_name} hooks failed"
43
+ log.error "✗ One or more #{hook_script_name} hooks failed"
39
44
  else
40
- log.success "✓ All #{@context.hook_script_name} hooks passed"
45
+ log.success "✓ All #{hook_script_name} hooks passed"
41
46
  end
42
47
 
43
48
  log.log # Newline
44
49
 
45
50
  !run_failed
46
51
  else
47
- log.success "✓ No applicable #{@context.hook_script_name} hooks to run"
52
+ log.success "✓ No applicable #{hook_script_name} hooks to run"
48
53
  true # Run was successful
49
54
  end
50
55
  end
51
56
 
52
57
  def run_hook(hook)
53
- return unless hook.enabled?
54
-
55
- if hook.skip?
56
- if hook.required?
57
- log.warning "Cannot skip #{hook.name} since it is required"
58
- else
59
- log.warning "Skipping #{hook.name}"
60
- return
61
- end
62
- end
63
-
64
- return unless hook.run?
58
+ return if should_skip?(hook)
65
59
 
66
60
  unless hook.quiet?
67
61
  print_header(hook)
@@ -80,6 +74,32 @@ module Overcommit
80
74
  print_header(hook)
81
75
  end
82
76
 
77
+ print_result(hook, status, output)
78
+
79
+ status
80
+ end
81
+
82
+ def print_header(hook)
83
+ log.partial hook.description
84
+ log.partial '.' * (70 - hook.description.length)
85
+ end
86
+
87
+ def should_skip?(hook)
88
+ return true unless hook.enabled?
89
+
90
+ if hook.skip?
91
+ if hook.required?
92
+ log.warning "Cannot skip #{hook.name} since it is required"
93
+ else
94
+ log.warning "Skipping #{hook.name}"
95
+ return true
96
+ end
97
+ end
98
+
99
+ !hook.run?
100
+ end
101
+
102
+ def print_result(hook, status, output)
83
103
  case status
84
104
  when :good
85
105
  log.success 'OK' unless hook.quiet?
@@ -90,61 +110,23 @@ module Overcommit
90
110
  log.error 'FAILED'
91
111
  print_report(output, :bold_error)
92
112
  end
93
-
94
- status
95
- end
96
-
97
- def print_header(hook)
98
- log.partial hook.description
99
- log.partial '.' * (70 - hook.description.length)
100
113
  end
101
114
 
102
115
  def print_report(output, format = :log)
103
116
  log.send(format, output) unless output.nil? || output.empty?
104
117
  end
105
118
 
106
- # Loads hooks that will be run.
107
- # This is done explicitly so that we only load hooks which will actually be
108
- # used.
109
119
  def load_hooks
110
120
  require "overcommit/hook/#{@context.hook_type_name}/base"
111
121
 
112
- load_builtin_hooks
113
- load_hook_plugins # Load after so they can subclass/modify existing hooks
114
- end
122
+ @hooks += HookLoader::BuiltInHookLoader.new(@config, @context, @log, @input).load_hooks
115
123
 
116
- # Load hooks that ship with Overcommit, ignoring ones that are excluded from
117
- # the repository's configuration.
118
- def load_builtin_hooks
119
- @config.enabled_builtin_hooks(@context).each do |hook_name|
120
- underscored_hook_name = Overcommit::Utils.snake_case(hook_name)
121
- require "overcommit/hook/#{@context.hook_type_name}/#{underscored_hook_name}"
122
- @hooks << create_hook(hook_name)
123
- end
124
- end
125
-
126
- # Load hooks that are stored in the repository's plugin directory.
127
- def load_hook_plugins
128
- directory = File.join(@config.plugin_directory, @context.hook_type_name)
129
-
130
- Dir[File.join(directory, '*.rb')].sort.each do |plugin|
131
- require plugin
132
-
133
- hook_name = Overcommit::Utils.camel_case(File.basename(plugin, '.rb'))
134
- @hooks << create_hook(hook_name)
135
- end
124
+ # Load plugin hooks after so they can subclass existing hooks
125
+ @hooks += HookLoader::PluginHookLoader.new(@config, @context, @log, @input).load_hooks
136
126
  end
137
127
 
138
- # Load and return a {Hook} from a CamelCase hook name and the given
139
- # hook configuration.
140
- def create_hook(hook_name)
141
- Overcommit::Hook.const_get(@context.hook_class_name).
142
- const_get(hook_name).
143
- new(@config, @context)
144
- rescue LoadError, NameError => error
145
- raise Overcommit::Exceptions::HookLoadError,
146
- "Unable to load hook '#{hook_name}': #{error}",
147
- error.backtrace
128
+ def hook_script_name
129
+ @context.hook_script_name
148
130
  end
149
131
  end
150
132
  end
@@ -0,0 +1,73 @@
1
+ module Overcommit
2
+ # Calculates, stores, and retrieves stored signatures of hook plugins.
3
+ class HookSigner
4
+ attr_reader :hook_path, :hook_name
5
+
6
+ # @param hook_path [String] path to the actual hook definition
7
+ # @param config [Overcommit::Configuration]
8
+ # @param context [Overcommit::HookContext]
9
+ def initialize(hook_path, config, context)
10
+ @hook_path = hook_path
11
+ @config = config
12
+ @context = context
13
+
14
+ @hook_name = Overcommit::Utils.camel_case(File.basename(@hook_path, '.rb'))
15
+ end
16
+
17
+ # Return whether the signature for this hook has changed since it was last
18
+ # calculated.
19
+ #
20
+ # @return [true,false]
21
+ def signature_changed?
22
+ signature != stored_signature
23
+ end
24
+
25
+ # Update the current stored signature for this hook.
26
+ def update_signature!
27
+ result = Overcommit::Utils.execute(
28
+ %w[git config --local] + [signature_config_key, signature]
29
+ )
30
+
31
+ unless result.success?
32
+ raise Overcommit::Exceptions::GitConfigError,
33
+ "Unable to write to local repo git config: #{result.stderr}"
34
+ end
35
+ end
36
+
37
+ private
38
+
39
+ # Calculates a hash of a hook using a combination of its configuration and
40
+ # file contents.
41
+ #
42
+ # This way, if either the plugin code changes or its configuration changes,
43
+ # the hash will change and we can alert the user to this change.
44
+ def signature
45
+ hook_config = @config.for_hook(@hook_name, @context.hook_class_name)
46
+
47
+ Digest::SHA256.hexdigest(hook_contents + hook_config.to_s)
48
+ end
49
+
50
+ def hook_contents
51
+ File.open(@hook_path, 'r').read
52
+ end
53
+
54
+ def stored_signature
55
+ result = Overcommit::Utils.execute(
56
+ %w[git config --local --get] + [signature_config_key]
57
+ )
58
+
59
+ if result.status == 1 # Key doesn't exist
60
+ return ''
61
+ elsif result.status != 0
62
+ raise Overcommit::Exceptions::GitConfigError,
63
+ "Unable to read from local repo git config: #{result.stderr}"
64
+ end
65
+
66
+ result.stdout.chomp
67
+ end
68
+
69
+ def signature_config_key
70
+ "overcommit.#{@context.hook_class_name}.#{@hook_name}.signature"
71
+ end
72
+ end
73
+ end
@@ -3,6 +3,9 @@ require 'fileutils'
3
3
  module Overcommit
4
4
  # Manages the installation of Overcommit hooks in a git repository.
5
5
  class Installer
6
+ MASTER_HOOK =
7
+ File.join(OVERCOMMIT_HOME, 'template-dir', 'hooks', 'overcommit-hook')
8
+
6
9
  def initialize(logger)
7
10
  @log = logger
8
11
  end
@@ -11,7 +14,13 @@ module Overcommit
11
14
  @target = target
12
15
  @options = options
13
16
  validate_target
14
- @options[:action] == :uninstall ? uninstall : install
17
+
18
+ case @options[:action]
19
+ when :uninstall then uninstall
20
+ when :update then update
21
+ else
22
+ install
23
+ end
15
24
  end
16
25
 
17
26
  private
@@ -37,11 +46,24 @@ module Overcommit
37
46
  log.success "Successfully removed hooks from #{@target}"
38
47
  end
39
48
 
49
+ # @return [true,false] whether the hooks were updated
50
+ def update
51
+ unless FileUtils.compare_file(MASTER_HOOK, master_hook_install_path)
52
+ install_master_hook
53
+ install_hook_symlinks
54
+ true
55
+ end
56
+ end
57
+
40
58
  def hooks_path
41
59
  absolute_target = File.expand_path(@target)
42
60
  File.join(absolute_target, '.git', 'hooks')
43
61
  end
44
62
 
63
+ def master_hook_install_path
64
+ File.join(hooks_path, 'overcommit-hook')
65
+ end
66
+
45
67
  def ensure_hooks_directory
46
68
  FileUtils.mkdir_p(hooks_path)
47
69
  end
@@ -59,15 +81,12 @@ module Overcommit
59
81
  end
60
82
 
61
83
  def install_master_hook
62
- master_hook = File.join(OVERCOMMIT_HOME, 'template-dir', 'hooks', 'overcommit-hook')
63
- install_location = File.join(hooks_path, 'overcommit-hook')
64
84
  FileUtils.mkdir_p(hooks_path)
65
- FileUtils.cp(master_hook, install_location)
85
+ FileUtils.cp(MASTER_HOOK, master_hook_install_path)
66
86
  end
67
87
 
68
88
  def uninstall_master_hook
69
- install_location = File.join(hooks_path, 'overcommit-hook')
70
- FileUtils.rm_rf(install_location)
89
+ FileUtils.rm_rf(master_hook_install_path)
71
90
  end
72
91
 
73
92
  def install_hook_symlinks
@@ -78,7 +97,8 @@ module Overcommit
78
97
  Overcommit::Utils.supported_hook_types.each do |hook_type|
79
98
  unless can_replace_file?(hook_type)
80
99
  raise Overcommit::Exceptions::PreExistingHooks,
81
- "Hook '#{File.expand_path(hook_type)}' already exists and was not installed by Overcommit"
100
+ "Hook '#{File.expand_path(hook_type)}' already exists and " \
101
+ 'was not installed by Overcommit'
82
102
  end
83
103
  FileUtils.ln_sf('overcommit-hook', hook_type)
84
104
  end
@@ -87,7 +107,7 @@ module Overcommit
87
107
 
88
108
  def can_replace_file?(file)
89
109
  @options[:force] ||
90
- !File.exists?(file) ||
110
+ !File.exist?(file) ||
91
111
  overcommit_symlink?(file)
92
112
  end
93
113
 
@@ -0,0 +1,26 @@
1
+ module Overcommit
2
+ # Encapsulates prompting for and fetching input from a user.
3
+ class UserInput
4
+ # @param io [IO] device to fetch input from
5
+ def initialize(io)
6
+ @io = io
7
+
8
+ reopen_tty
9
+ end
10
+
11
+ # Get a string of input from the user (up to the next newline character).
12
+ def get(&block)
13
+ @io.gets
14
+ end
15
+
16
+ private
17
+
18
+ # Git hooks are not interactive and will close STDIN by default.
19
+ def reopen_tty
20
+ # If the hook isn't interactive, we need to map STDIN to keyboard manually
21
+ STDIN.reopen('/dev/tty') if STDIN.eof?
22
+ rescue
23
+ # Happens in tests run with no console available
24
+ end
25
+ end
26
+ end
@@ -1,4 +1,4 @@
1
1
  # Defines the gem version.
2
2
  module Overcommit
3
- VERSION = '0.7.0'
3
+ VERSION = '0.8.0'
4
4
  end
@@ -5,13 +5,13 @@
5
5
  # to manage your hooks for you.
6
6
 
7
7
  # Required for Ruby 1.8 compatibility (for older OSX versions)
8
- if RUBY_VERSION.split('.')[0..1] == ['1', '8']
8
+ if RUBY_VERSION.split('.')[0..1] == %w[1 8]
9
9
  require 'rubygems'
10
10
  end
11
11
 
12
12
  hook_type = File.basename($0)
13
13
  if hook_type == 'overcommit-hook'
14
- puts "Don't run `overcommit-hook` directly; it is intended to be symlinked " <<
14
+ puts "Don't run `overcommit-hook` directly; it is intended to be symlinked " \
15
15
  "by each hook in a repository's .git/hooks directory."
16
16
  exit 64 # EX_USAGE
17
17
  end
@@ -19,13 +19,14 @@ end
19
19
  begin
20
20
  require 'overcommit'
21
21
  rescue LoadError
22
- puts 'Overcommit is not installed. Install it to manage git hooks for ' <<
22
+ puts 'Overcommit is not installed. Install it to manage git hooks for ' \
23
23
  'this repository? (y/n)'
24
24
 
25
25
  # If the hook isn't interactive, we need to map STDIN to keyboard manually
26
26
  STDIN.reopen('/dev/tty') if STDIN.eof?
27
27
 
28
28
  if (answer = gets) && answer.strip.downcase.start_with?('y')
29
+ puts 'Installing...'
29
30
  if system('gem install overcommit')
30
31
  Gem.clear_paths # Reset load paths so newly installed gem is found
31
32
  require 'overcommit'
@@ -41,21 +42,30 @@ rescue LoadError
41
42
  end
42
43
 
43
44
  if Gem::Version.new(Overcommit::VERSION) < Gem::Version.new('0.6.0')
44
- puts "Installed version of Overcommit (#{Overcommit::VERSION}) is " <<
45
- "incompatible with the installed hooks.\n" <<
46
- 'Run `gem install overcommit && overcommit --install` to ensure ' <<
45
+ puts "Installed version of Overcommit (#{Overcommit::VERSION}) is " \
46
+ "incompatible with the installed hooks.\n" \
47
+ 'Run `gem install overcommit && overcommit --install` to ensure ' \
47
48
  "you're up-to-date."
48
49
  exit 64 # EX_USAGE
49
50
  end
50
51
 
51
52
  begin
53
+ logger = Overcommit::Logger.new(STDOUT)
54
+
55
+ # Ensure master hook is up-to-date
56
+ installer = Overcommit::Installer.new(logger)
57
+ if installer.run(Overcommit::Utils.repo_root, :action => :update)
58
+ exec $0 # Execute the updated hook
59
+ end
60
+
52
61
  config = Overcommit::ConfigurationLoader.load_repo_config
53
62
 
54
63
  context = Overcommit::HookContext.create(hook_type, config, ARGV, STDIN)
55
64
  config.apply_environment!(context, ENV)
56
65
 
57
- logger = Overcommit::Logger.new(STDOUT)
58
- runner = Overcommit::HookRunner.new(config, logger, context)
66
+ input = Overcommit::UserInput.new(STDIN)
67
+
68
+ runner = Overcommit::HookRunner.new(config, logger, context, input)
59
69
 
60
70
  status = runner.run
61
71
 
@@ -67,6 +77,9 @@ rescue Overcommit::Exceptions::HookContextLoadError => error
67
77
  puts error
68
78
  puts 'Are you running an old version of Overcommit?'
69
79
  exit 69 # EX_UNAVAILABLE
80
+ rescue Overcommit::Exceptions::HookCancelled
81
+ puts 'You cancelled the hook run'
82
+ exit 1
70
83
  rescue Overcommit::Exceptions::InvalidGitRepo => error
71
84
  puts error
72
85
  exit 64 # EX_USAGE
@@ -5,13 +5,13 @@
5
5
  # to manage your hooks for you.
6
6
 
7
7
  # Required for Ruby 1.8 compatibility (for older OSX versions)
8
- if RUBY_VERSION.split('.')[0..1] == ['1', '8']
8
+ if RUBY_VERSION.split('.')[0..1] == %w[1 8]
9
9
  require 'rubygems'
10
10
  end
11
11
 
12
12
  hook_type = File.basename($0)
13
13
  if hook_type == 'overcommit-hook'
14
- puts "Don't run `overcommit-hook` directly; it is intended to be symlinked " <<
14
+ puts "Don't run `overcommit-hook` directly; it is intended to be symlinked " \
15
15
  "by each hook in a repository's .git/hooks directory."
16
16
  exit 64 # EX_USAGE
17
17
  end
@@ -19,13 +19,14 @@ end
19
19
  begin
20
20
  require 'overcommit'
21
21
  rescue LoadError
22
- puts 'Overcommit is not installed. Install it to manage git hooks for ' <<
22
+ puts 'Overcommit is not installed. Install it to manage git hooks for ' \
23
23
  'this repository? (y/n)'
24
24
 
25
25
  # If the hook isn't interactive, we need to map STDIN to keyboard manually
26
26
  STDIN.reopen('/dev/tty') if STDIN.eof?
27
27
 
28
28
  if (answer = gets) && answer.strip.downcase.start_with?('y')
29
+ puts 'Installing...'
29
30
  if system('gem install overcommit')
30
31
  Gem.clear_paths # Reset load paths so newly installed gem is found
31
32
  require 'overcommit'
@@ -41,21 +42,30 @@ rescue LoadError
41
42
  end
42
43
 
43
44
  if Gem::Version.new(Overcommit::VERSION) < Gem::Version.new('0.6.0')
44
- puts "Installed version of Overcommit (#{Overcommit::VERSION}) is " <<
45
- "incompatible with the installed hooks.\n" <<
46
- 'Run `gem install overcommit && overcommit --install` to ensure ' <<
45
+ puts "Installed version of Overcommit (#{Overcommit::VERSION}) is " \
46
+ "incompatible with the installed hooks.\n" \
47
+ 'Run `gem install overcommit && overcommit --install` to ensure ' \
47
48
  "you're up-to-date."
48
49
  exit 64 # EX_USAGE
49
50
  end
50
51
 
51
52
  begin
53
+ logger = Overcommit::Logger.new(STDOUT)
54
+
55
+ # Ensure master hook is up-to-date
56
+ installer = Overcommit::Installer.new(logger)
57
+ if installer.run(Overcommit::Utils.repo_root, :action => :update)
58
+ exec $0 # Execute the updated hook
59
+ end
60
+
52
61
  config = Overcommit::ConfigurationLoader.load_repo_config
53
62
 
54
63
  context = Overcommit::HookContext.create(hook_type, config, ARGV, STDIN)
55
64
  config.apply_environment!(context, ENV)
56
65
 
57
- logger = Overcommit::Logger.new(STDOUT)
58
- runner = Overcommit::HookRunner.new(config, logger, context)
66
+ input = Overcommit::UserInput.new(STDIN)
67
+
68
+ runner = Overcommit::HookRunner.new(config, logger, context, input)
59
69
 
60
70
  status = runner.run
61
71
 
@@ -67,6 +77,9 @@ rescue Overcommit::Exceptions::HookContextLoadError => error
67
77
  puts error
68
78
  puts 'Are you running an old version of Overcommit?'
69
79
  exit 69 # EX_UNAVAILABLE
80
+ rescue Overcommit::Exceptions::HookCancelled
81
+ puts 'You cancelled the hook run'
82
+ exit 1
70
83
  rescue Overcommit::Exceptions::InvalidGitRepo => error
71
84
  puts error
72
85
  exit 64 # EX_USAGE
@@ -5,13 +5,13 @@
5
5
  # to manage your hooks for you.
6
6
 
7
7
  # Required for Ruby 1.8 compatibility (for older OSX versions)
8
- if RUBY_VERSION.split('.')[0..1] == ['1', '8']
8
+ if RUBY_VERSION.split('.')[0..1] == %w[1 8]
9
9
  require 'rubygems'
10
10
  end
11
11
 
12
12
  hook_type = File.basename($0)
13
13
  if hook_type == 'overcommit-hook'
14
- puts "Don't run `overcommit-hook` directly; it is intended to be symlinked " <<
14
+ puts "Don't run `overcommit-hook` directly; it is intended to be symlinked " \
15
15
  "by each hook in a repository's .git/hooks directory."
16
16
  exit 64 # EX_USAGE
17
17
  end
@@ -19,13 +19,14 @@ end
19
19
  begin
20
20
  require 'overcommit'
21
21
  rescue LoadError
22
- puts 'Overcommit is not installed. Install it to manage git hooks for ' <<
22
+ puts 'Overcommit is not installed. Install it to manage git hooks for ' \
23
23
  'this repository? (y/n)'
24
24
 
25
25
  # If the hook isn't interactive, we need to map STDIN to keyboard manually
26
26
  STDIN.reopen('/dev/tty') if STDIN.eof?
27
27
 
28
28
  if (answer = gets) && answer.strip.downcase.start_with?('y')
29
+ puts 'Installing...'
29
30
  if system('gem install overcommit')
30
31
  Gem.clear_paths # Reset load paths so newly installed gem is found
31
32
  require 'overcommit'
@@ -41,21 +42,30 @@ rescue LoadError
41
42
  end
42
43
 
43
44
  if Gem::Version.new(Overcommit::VERSION) < Gem::Version.new('0.6.0')
44
- puts "Installed version of Overcommit (#{Overcommit::VERSION}) is " <<
45
- "incompatible with the installed hooks.\n" <<
46
- 'Run `gem install overcommit && overcommit --install` to ensure ' <<
45
+ puts "Installed version of Overcommit (#{Overcommit::VERSION}) is " \
46
+ "incompatible with the installed hooks.\n" \
47
+ 'Run `gem install overcommit && overcommit --install` to ensure ' \
47
48
  "you're up-to-date."
48
49
  exit 64 # EX_USAGE
49
50
  end
50
51
 
51
52
  begin
53
+ logger = Overcommit::Logger.new(STDOUT)
54
+
55
+ # Ensure master hook is up-to-date
56
+ installer = Overcommit::Installer.new(logger)
57
+ if installer.run(Overcommit::Utils.repo_root, :action => :update)
58
+ exec $0 # Execute the updated hook
59
+ end
60
+
52
61
  config = Overcommit::ConfigurationLoader.load_repo_config
53
62
 
54
63
  context = Overcommit::HookContext.create(hook_type, config, ARGV, STDIN)
55
64
  config.apply_environment!(context, ENV)
56
65
 
57
- logger = Overcommit::Logger.new(STDOUT)
58
- runner = Overcommit::HookRunner.new(config, logger, context)
66
+ input = Overcommit::UserInput.new(STDIN)
67
+
68
+ runner = Overcommit::HookRunner.new(config, logger, context, input)
59
69
 
60
70
  status = runner.run
61
71
 
@@ -67,6 +77,9 @@ rescue Overcommit::Exceptions::HookContextLoadError => error
67
77
  puts error
68
78
  puts 'Are you running an old version of Overcommit?'
69
79
  exit 69 # EX_UNAVAILABLE
80
+ rescue Overcommit::Exceptions::HookCancelled
81
+ puts 'You cancelled the hook run'
82
+ exit 1
70
83
  rescue Overcommit::Exceptions::InvalidGitRepo => error
71
84
  puts error
72
85
  exit 64 # EX_USAGE
@@ -5,13 +5,13 @@
5
5
  # to manage your hooks for you.
6
6
 
7
7
  # Required for Ruby 1.8 compatibility (for older OSX versions)
8
- if RUBY_VERSION.split('.')[0..1] == ['1', '8']
8
+ if RUBY_VERSION.split('.')[0..1] == %w[1 8]
9
9
  require 'rubygems'
10
10
  end
11
11
 
12
12
  hook_type = File.basename($0)
13
13
  if hook_type == 'overcommit-hook'
14
- puts "Don't run `overcommit-hook` directly; it is intended to be symlinked " <<
14
+ puts "Don't run `overcommit-hook` directly; it is intended to be symlinked " \
15
15
  "by each hook in a repository's .git/hooks directory."
16
16
  exit 64 # EX_USAGE
17
17
  end
@@ -19,13 +19,14 @@ end
19
19
  begin
20
20
  require 'overcommit'
21
21
  rescue LoadError
22
- puts 'Overcommit is not installed. Install it to manage git hooks for ' <<
22
+ puts 'Overcommit is not installed. Install it to manage git hooks for ' \
23
23
  'this repository? (y/n)'
24
24
 
25
25
  # If the hook isn't interactive, we need to map STDIN to keyboard manually
26
26
  STDIN.reopen('/dev/tty') if STDIN.eof?
27
27
 
28
28
  if (answer = gets) && answer.strip.downcase.start_with?('y')
29
+ puts 'Installing...'
29
30
  if system('gem install overcommit')
30
31
  Gem.clear_paths # Reset load paths so newly installed gem is found
31
32
  require 'overcommit'
@@ -41,21 +42,30 @@ rescue LoadError
41
42
  end
42
43
 
43
44
  if Gem::Version.new(Overcommit::VERSION) < Gem::Version.new('0.6.0')
44
- puts "Installed version of Overcommit (#{Overcommit::VERSION}) is " <<
45
- "incompatible with the installed hooks.\n" <<
46
- 'Run `gem install overcommit && overcommit --install` to ensure ' <<
45
+ puts "Installed version of Overcommit (#{Overcommit::VERSION}) is " \
46
+ "incompatible with the installed hooks.\n" \
47
+ 'Run `gem install overcommit && overcommit --install` to ensure ' \
47
48
  "you're up-to-date."
48
49
  exit 64 # EX_USAGE
49
50
  end
50
51
 
51
52
  begin
53
+ logger = Overcommit::Logger.new(STDOUT)
54
+
55
+ # Ensure master hook is up-to-date
56
+ installer = Overcommit::Installer.new(logger)
57
+ if installer.run(Overcommit::Utils.repo_root, :action => :update)
58
+ exec $0 # Execute the updated hook
59
+ end
60
+
52
61
  config = Overcommit::ConfigurationLoader.load_repo_config
53
62
 
54
63
  context = Overcommit::HookContext.create(hook_type, config, ARGV, STDIN)
55
64
  config.apply_environment!(context, ENV)
56
65
 
57
- logger = Overcommit::Logger.new(STDOUT)
58
- runner = Overcommit::HookRunner.new(config, logger, context)
66
+ input = Overcommit::UserInput.new(STDIN)
67
+
68
+ runner = Overcommit::HookRunner.new(config, logger, context, input)
59
69
 
60
70
  status = runner.run
61
71
 
@@ -67,6 +77,9 @@ rescue Overcommit::Exceptions::HookContextLoadError => error
67
77
  puts error
68
78
  puts 'Are you running an old version of Overcommit?'
69
79
  exit 69 # EX_UNAVAILABLE
80
+ rescue Overcommit::Exceptions::HookCancelled
81
+ puts 'You cancelled the hook run'
82
+ exit 1
70
83
  rescue Overcommit::Exceptions::InvalidGitRepo => error
71
84
  puts error
72
85
  exit 64 # EX_USAGE
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: overcommit
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.0
4
+ version: 0.8.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Causes Engineering
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2014-03-06 00:00:00.000000000 Z
12
+ date: 2014-04-18 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: childprocess
@@ -43,16 +43,16 @@ dependencies:
43
43
  name: image_optim
44
44
  requirement: !ruby/object:Gem::Requirement
45
45
  requirements:
46
- - - '='
46
+ - - ~>
47
47
  - !ruby/object:Gem::Version
48
- version: 0.12.0
48
+ version: 0.13.0
49
49
  type: :development
50
50
  prerelease: false
51
51
  version_requirements: !ruby/object:Gem::Requirement
52
52
  requirements:
53
- - - '='
53
+ - - ~>
54
54
  - !ruby/object:Gem::Version
55
- version: 0.12.0
55
+ version: 0.13.0
56
56
  description: Utility to install, configure, and extend Git hooks
57
57
  email:
58
58
  - eng@causes.com
@@ -71,6 +71,7 @@ files:
71
71
  - lib/overcommit/constants.rb
72
72
  - lib/overcommit/utils.rb
73
73
  - lib/overcommit/hook_runner.rb
74
+ - lib/overcommit/user_input.rb
74
75
  - lib/overcommit/subprocess.rb
75
76
  - lib/overcommit/hook/commit_msg/trailing_period.rb
76
77
  - lib/overcommit/hook/commit_msg/gerrit_change_id.rb
@@ -86,6 +87,7 @@ files:
86
87
  - lib/overcommit/hook/pre_commit/author_email.rb
87
88
  - lib/overcommit/hook/pre_commit/image_optim.rb
88
89
  - lib/overcommit/hook/pre_commit/css_lint.rb
90
+ - lib/overcommit/hook/pre_commit/travis_lint.rb
89
91
  - lib/overcommit/hook/pre_commit/bundle_check.rb
90
92
  - lib/overcommit/hook/pre_commit/yaml_syntax.rb
91
93
  - lib/overcommit/hook/pre_commit/trailing_whitespace.rb
@@ -99,12 +101,16 @@ files:
99
101
  - lib/overcommit/hook/pre_commit/jscs.rb
100
102
  - lib/overcommit/hook/pre_commit/scss_lint.rb
101
103
  - lib/overcommit/hook/pre_commit/base.rb
104
+ - lib/overcommit/hook_signer.rb
102
105
  - lib/overcommit/hook_context/pre_commit.rb
103
106
  - lib/overcommit/hook_context/commit_msg.rb
104
107
  - lib/overcommit/hook_context/base.rb
105
108
  - lib/overcommit/hook_context/post_checkout.rb
106
109
  - lib/overcommit/installer.rb
107
110
  - lib/overcommit/configuration_loader.rb
111
+ - lib/overcommit/hook_loader/built_in_hook_loader.rb
112
+ - lib/overcommit/hook_loader/plugin_hook_loader.rb
113
+ - lib/overcommit/hook_loader/base.rb
108
114
  - lib/overcommit/exceptions.rb
109
115
  - lib/overcommit/configuration.rb
110
116
  - lib/overcommit/logger.rb
@@ -141,4 +147,3 @@ signing_key:
141
147
  specification_version: 4
142
148
  summary: Git hook manager
143
149
  test_files: []
144
- has_rdoc: