overcommit 0.13.0 → 0.14.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: f50342c0638e20584a726340b172131a24085be4
4
- data.tar.gz: 64cb433bf1f877cda8257ae840bed4588594ca2b
3
+ metadata.gz: fb17024356867bde9bd05acbeee3d3e21d1c2c4d
4
+ data.tar.gz: 6d0e29731c275e36832826d17b9261a256f75738
5
5
  SHA512:
6
- metadata.gz: 8520683843161c250dba3e94fb15e4222cc6f0e2d3d8c8e63763e2a6837a50c30ce478f6d86699817950f120fdb472eef0cd9816f48cbfc23876d2355bacec84
7
- data.tar.gz: c961cadf99ce02e0766f68ea53b6bd4f7b403ecfa0c048821c130d38b4778066a70ae7945b27e6a3342b0271ba7014a56a4920722c7b594809c4a7b8772c7ce1
6
+ metadata.gz: fc9754e4d5eeed0c7e0f53c3743fdf1d2ee76829c7e085053a795a3950b57c7cd7cd1aaa47a84a4c2943bb4a40377ef70900b0fffd4b226ad5ef6e85402600ca
7
+ data.tar.gz: fa43ebdc705f91361e7e6964ca0a1315d0d42cffff876e9389d573997f3835b321ba339e0f266bd9a646ded011db32d5feeed7e29aa1d48127ebe36dec17f583
data/config/default.yml CHANGED
@@ -164,6 +164,8 @@ PreCommit:
164
164
 
165
165
  TrailingWhitespace:
166
166
  description: 'Checking for trailing whitespace'
167
+ exclude:
168
+ - '**/db/structure.sql'
167
169
 
168
170
  TravisLint:
169
171
  description: 'Checking Travis CI configuration'
data/lib/overcommit.rb CHANGED
@@ -1,16 +1,19 @@
1
1
  require 'overcommit/constants'
2
2
  require 'overcommit/exceptions'
3
+ require 'overcommit/configuration_validator'
3
4
  require 'overcommit/configuration'
4
5
  require 'overcommit/configuration_loader'
5
6
  require 'overcommit/hook/base'
6
7
  require 'overcommit/hook_context/base'
7
8
  require 'overcommit/hook_context'
8
9
  require 'overcommit/user_input'
10
+ require 'overcommit/git_repo'
9
11
  require 'overcommit/hook_signer'
10
12
  require 'overcommit/hook_loader/base'
11
13
  require 'overcommit/hook_loader/built_in_hook_loader'
12
14
  require 'overcommit/hook_loader/plugin_hook_loader'
13
15
  require 'overcommit/interrupt_handler'
16
+ require 'overcommit/printer'
14
17
  require 'overcommit/hook_runner'
15
18
  require 'overcommit/installer'
16
19
  require 'overcommit/logger'
@@ -26,33 +26,7 @@ module Overcommit
26
26
  attr_reader :log
27
27
 
28
28
  def parse_arguments
29
- @parser = OptionParser.new do |opts|
30
- opts.banner = "Usage: #{opts.program_name} [options] [target-repo]"
31
-
32
- opts.on_tail('-h', '--help', 'Show this message') do
33
- print_help opts.help
34
- end
35
-
36
- opts.on_tail('-v', '--version', 'Show version') do
37
- print_version(opts.program_name)
38
- end
39
-
40
- opts.on('-u', '--uninstall', 'Remove Overcommit hooks from a repository') do
41
- @options[:action] = :uninstall
42
- end
43
-
44
- opts.on('-i', '--install', 'Install Overcommit hooks in a repository') do
45
- @options[:action] = :install
46
- end
47
-
48
- opts.on('-f', '--force', 'Overwrite any previously installed hooks') do
49
- @options[:force] = true
50
- end
51
-
52
- opts.on('-t', '--template-dir', 'Print location of template directory') do
53
- @options[:action] = :template_dir
54
- end
55
- end
29
+ @parser = create_option_parser
56
30
 
57
31
  begin
58
32
  @parser.parse!(@arguments)
@@ -67,6 +41,46 @@ module Overcommit
67
41
  end
68
42
  end
69
43
 
44
+ def create_option_parser
45
+ OptionParser.new do |opts|
46
+ opts.banner = "Usage: #{opts.program_name} [options] [target-repo]"
47
+
48
+ add_information_options(opts)
49
+ add_installation_options(opts)
50
+ add_other_options(opts)
51
+ end
52
+ end
53
+
54
+ def add_information_options(opts)
55
+ opts.on_tail('-h', '--help', 'Show this message') do
56
+ print_help opts.help
57
+ end
58
+
59
+ opts.on_tail('-v', '--version', 'Show version') do
60
+ print_version(opts.program_name)
61
+ end
62
+ end
63
+
64
+ def add_installation_options(opts)
65
+ opts.on('-u', '--uninstall', 'Remove Overcommit hooks from a repository') do
66
+ @options[:action] = :uninstall
67
+ end
68
+
69
+ opts.on('-i', '--install', 'Install Overcommit hooks in a repository') do
70
+ @options[:action] = :install
71
+ end
72
+
73
+ opts.on('-f', '--force', 'Overwrite any previously installed hooks') do
74
+ @options[:force] = true
75
+ end
76
+ end
77
+
78
+ def add_other_options(opts)
79
+ opts.on('-t', '--template-dir', 'Print location of template directory') do
80
+ @options[:action] = :template_dir
81
+ end
82
+ end
83
+
70
84
  def install_or_uninstall
71
85
  if Array(@options[:targets]).empty?
72
86
  @options[:targets] = [Overcommit::Utils.repo_root].compact
@@ -3,8 +3,7 @@ module Overcommit
3
3
  class Configuration
4
4
  # Creates a configuration from the given hash.
5
5
  def initialize(hash)
6
- @hash = hash
7
- validate
6
+ @hash = ConfigurationValidator.new.validate(hash)
8
7
  end
9
8
 
10
9
  def ==(other)
@@ -104,13 +103,6 @@ module Overcommit
104
103
  true
105
104
  end
106
105
 
107
- # Validates the configuration for any invalid options, normalizing it where
108
- # possible.
109
- def validate
110
- @hash = convert_nils_to_empty_hashes(@hash)
111
- ensure_hook_type_sections_exist(@hash)
112
- end
113
-
114
106
  def smart_merge(parent, child)
115
107
  parent.merge(child) do |_key, old, new|
116
108
  case old
@@ -123,25 +115,5 @@ module Overcommit
123
115
  end
124
116
  end
125
117
  end
126
-
127
- def ensure_hook_type_sections_exist(hash)
128
- Overcommit::Utils.supported_hook_type_classes.each do |hook_type|
129
- hash[hook_type] ||= {}
130
- hash[hook_type]['ALL'] ||= {}
131
- end
132
- end
133
-
134
- def convert_nils_to_empty_hashes(hash)
135
- hash.inject({}) do |h, (key, value)|
136
- h[key] =
137
- case value
138
- when nil then {}
139
- when Hash then convert_nils_to_empty_hashes(value)
140
- else
141
- value
142
- end
143
- h
144
- end
145
- end
146
118
  end
147
119
  end
@@ -0,0 +1,41 @@
1
+ module Overcommit
2
+ # Validates and normalizes a configuration.
3
+ class ConfigurationValidator
4
+ # Validates hash for any invalid options, normalizing where possible.
5
+ def validate(hash)
6
+ hash = convert_nils_to_empty_hashes(hash)
7
+ ensure_hook_type_sections_exist(hash)
8
+
9
+ hash
10
+ end
11
+
12
+ private
13
+
14
+ # Ensures that keys for all supported hook types exist (PreCommit,
15
+ # CommitMsg, etc.)
16
+ def ensure_hook_type_sections_exist(hash)
17
+ Overcommit::Utils.supported_hook_type_classes.each do |hook_type|
18
+ hash[hook_type] ||= {}
19
+ hash[hook_type]['ALL'] ||= {}
20
+ end
21
+ end
22
+
23
+ # Normalizes `nil` values to empty hashes.
24
+ #
25
+ # This is useful for when we want to merge two configuration hashes
26
+ # together, since it's easier to merge two hashes than to have to check if
27
+ # one of the values is nil.
28
+ def convert_nils_to_empty_hashes(hash)
29
+ hash.inject({}) do |h, (key, value)|
30
+ h[key] =
31
+ case value
32
+ when nil then {}
33
+ when Hash then convert_nils_to_empty_hashes(value)
34
+ else
35
+ value
36
+ end
37
+ h
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,121 @@
1
+ module Overcommit
2
+ # Provide a set of utilities for certain interactions with `git`.
3
+ module GitRepo
4
+ module_function
5
+
6
+ # Regular expression used to extract diff ranges from hunks of diff output.
7
+ DIFF_HUNK_REGEX = /
8
+ ^@@\s
9
+ [^\s]+\s # Ignore old file range
10
+ \+(\d+)(?:,(\d+))? # Extract range of hunk containing start line and number of lines
11
+ \s@@.*$
12
+ /x
13
+
14
+ # Extract the set of modified lines from a given file.
15
+ #
16
+ # @param file_path [String]
17
+ # @param options [Hash]
18
+ # @return [Set] line numbers that have been modified in file
19
+ def extract_modified_lines(file_path, options)
20
+ lines = Set.new
21
+
22
+ flags = '--cached' if options[:staged]
23
+
24
+ `git diff --no-ext-diff -U0 #{flags} -- #{file_path}`.
25
+ scan(DIFF_HUNK_REGEX) do |start_line, lines_added|
26
+
27
+ lines_added = (lines_added || 1).to_i # When blank, one line was added
28
+ cur_line = start_line.to_i
29
+
30
+ lines_added.times do
31
+ lines.add cur_line
32
+ cur_line += 1
33
+ end
34
+ end
35
+
36
+ lines
37
+ end
38
+
39
+ # Returns the names of all files that have been modified from compared to
40
+ # HEAD.
41
+ #
42
+ # @param options [Hash]
43
+ # @return [Array<String>] list of absolute file paths
44
+ def modified_files(options)
45
+ flags = '--cached' if options[:staged]
46
+
47
+ `git diff --name-only -z --diff-filter=ACM --ignore-submodules=all #{flags}`.
48
+ split("\0").
49
+ map { |relative_file| File.expand_path(relative_file) }
50
+ end
51
+
52
+ # Returns whether the current git branch is empty (has no commits).
53
+ # @return [true,false]
54
+ def initial_commit?
55
+ !Overcommit::Utils.execute(%w[git rev-parse HEAD]).success?
56
+ end
57
+
58
+ # Store any relevant files that are present when repo is in the middle of a
59
+ # merge.
60
+ #
61
+ # Restored via [#restore_merge_state].
62
+ def store_merge_state
63
+ merge_head = `git rev-parse MERGE_HEAD 2> /dev/null`.chomp
64
+
65
+ # Store the merge state if we're in the middle of resolving a merge
66
+ # conflict. This is necessary since stashing removes the merge state.
67
+ if merge_head != 'MERGE_HEAD'
68
+ @merge_head = merge_head
69
+
70
+ merge_msg_file = File.expand_path('.git/MERGE_MSG', Overcommit::Utils.repo_root)
71
+ @merge_msg = File.open(merge_msg_file).read if File.exist?(merge_msg_file)
72
+ end
73
+ end
74
+
75
+ # Store any relevant files that are present when repo is in the middle of a
76
+ # cherry-pick.
77
+ #
78
+ # Restored via [#restore_cherry_pick_state].
79
+ def store_cherry_pick_state
80
+ cherry_head = `git rev-parse CHERRY_PICK_HEAD 2> /dev/null`.chomp
81
+
82
+ # Store the merge state if we're in the middle of resolving a merge
83
+ # conflict. This is necessary since stashing removes the merge state.
84
+ if cherry_head != 'CHERRY_PICK_HEAD'
85
+ @cherry_head = cherry_head
86
+ end
87
+ end
88
+
89
+ # Restore any relevant files that were present when repo was in the middle
90
+ # of a merge.
91
+ def restore_merge_state
92
+ if @merge_head
93
+ FileUtils.touch(File.expand_path('.git/MERGE_MODE', Overcommit::Utils.repo_root))
94
+
95
+ File.open(File.expand_path('.git/MERGE_HEAD', Overcommit::Utils.repo_root), 'w') do |f|
96
+ f.write("#{@merge_head}\n")
97
+ end
98
+ @merge_head = nil
99
+ end
100
+
101
+ if @merge_msg
102
+ File.open(File.expand_path('.git/MERGE_MSG', Overcommit::Utils.repo_root), 'w') do |f|
103
+ f.write("#{@merge_msg}\n")
104
+ end
105
+ @merge_msg = nil
106
+ end
107
+ end
108
+
109
+ # Restore any relevant files that were present when repo was in the middle
110
+ # of a cherry-pick.
111
+ def restore_cherry_pick_state
112
+ if @cherry_head
113
+ File.open(File.expand_path('.git/CHERRY_PICK_HEAD',
114
+ Overcommit::Utils.repo_root), 'w') do |f|
115
+ f.write("#{@cherry_head}\n")
116
+ end
117
+ @cherry_head = nil
118
+ end
119
+ end
120
+ end
121
+ end
@@ -70,10 +70,10 @@ module Overcommit::Hook
70
70
  def applicable_file?(file)
71
71
  includes = Array(@config['include']).map { |glob| convert_glob_to_absolute(glob) }
72
72
  included = includes.empty? ||
73
- includes.any? { |glob| Dir[glob].include?(file) }
73
+ includes.any? { |glob| matches_path?(glob, file) }
74
74
 
75
75
  excludes = Array(@config['exclude']).map { |glob| convert_glob_to_absolute(glob) }
76
- excluded = excludes.any? { |glob| Dir[glob].include?(file) }
76
+ excluded = excludes.any? { |glob| matches_path?(glob, file) }
77
77
 
78
78
  included && !excluded
79
79
  end
@@ -82,5 +82,16 @@ module Overcommit::Hook
82
82
  repo_root = Overcommit::Utils.repo_root
83
83
  File.join(repo_root, glob)
84
84
  end
85
+
86
+ # Return whether a pattern matches the given path.
87
+ #
88
+ # @param pattern [String]
89
+ # @param path [String]
90
+ def matches_path?(pattern, path)
91
+ File.fnmatch?(pattern, path,
92
+ File::FNM_PATHNAME | # Wildcard doesn't match separator
93
+ File::FNM_DOTMATCH # Wildcards match dotfiles
94
+ )
95
+ end
85
96
  end
86
97
  end
@@ -17,9 +17,9 @@ module Overcommit::Hook::PreCommit
17
17
 
18
18
  if optimized_images.any?
19
19
  return :bad,
20
- "The following images were optimized:\n" <<
21
- optimized_images.join("\n") <<
22
- "\nPlease add them to your commit."
20
+ "The following images are optimizable:\n#{optimized_images.join("\n")}" \
21
+ "\n\nOptimize them by running:\n" \
22
+ " image_optim #{optimized_images.join(' ')}"
23
23
  end
24
24
 
25
25
  :good
@@ -10,7 +10,7 @@ module Overcommit::Hook::PreCommit
10
10
  result = execute(%w[jscs --reporter=inline] + applicable_files)
11
11
  return :good if result.success?
12
12
 
13
- if /Config.*not found/i =~ result.stderr
13
+ if result.status == 1
14
14
  return :warn, result.stderr.chomp
15
15
  end
16
16
 
@@ -1,7 +1,7 @@
1
1
  module Overcommit::Hook::PreCommit
2
2
  # Check to see whether the schema file is in line with the migrations
3
3
  class RailsSchemaUpToDate < Base
4
- def run
4
+ def run # rubocop:disable CyclomaticComplexity
5
5
  if migration_files.any? && schema_files.none?
6
6
  return :bad, "It looks like you're adding a migration, but did not update the schema file"
7
7
  elsif migration_files.none? && schema_files.any?
@@ -5,14 +5,15 @@ module Overcommit::HookContext
5
5
  # Contains helpers related to contextual information used by pre-commit hooks.
6
6
  #
7
7
  # This includes staged files, which lines of those files have been modified,
8
- # etc.
8
+ # etc. It is also responsible for saving/restoring the state of the repo so
9
+ # hooks only inspect staged changes.
9
10
  class PreCommit < Base
10
11
  # Stash unstaged contents of files so hooks don't see changes that aren't
11
12
  # about to be committed.
12
13
  def setup_environment
13
14
  store_modified_times
14
- store_merge_state
15
- store_cherry_pick_state
15
+ Overcommit::GitRepo.store_merge_state
16
+ Overcommit::GitRepo.store_cherry_pick_state
16
17
 
17
18
  if !initial_commit? && any_changes?
18
19
  @changes_stashed = true
@@ -33,28 +34,25 @@ module Overcommit::HookContext
33
34
  end
34
35
 
35
36
  if @changes_stashed
36
- `git stash apply --index --quiet`
37
+ `git stash pop --index --quiet`
37
38
  end
38
39
 
39
- restore_merge_state
40
- restore_cherry_pick_state
40
+ Overcommit::GitRepo.restore_merge_state
41
+ Overcommit::GitRepo.restore_cherry_pick_state
41
42
  restore_modified_times
42
43
  end
43
44
 
44
45
  # Get a list of added, copied, or modified files that have been staged.
45
46
  # Renames and deletions are ignored, since there should be nothing to check.
46
47
  def modified_files
47
- @modified_files ||=
48
- `git diff --cached --name-only -z --diff-filter=ACM --ignore-submodules=all`.
49
- split("\0").
50
- map { |relative_file| File.expand_path(relative_file) }
48
+ @modified_files ||= Overcommit::GitRepo.modified_files(:staged => true)
51
49
  end
52
50
 
53
51
  # Returns the set of line numbers corresponding to the lines that were
54
52
  # changed in a specified file.
55
53
  def modified_lines(file)
56
54
  @modified_lines ||= {}
57
- @modified_lines[file] ||= extract_modified_lines(file)
55
+ @modified_lines[file] ||= Overcommit::GitRepo.extract_modified_lines(file, :staged => true)
58
56
  end
59
57
 
60
58
  private
@@ -72,85 +70,14 @@ module Overcommit::HookContext
72
70
  # Returns whether the current git branch is empty (has no commits).
73
71
  def initial_commit?
74
72
  return @initial_commit unless @initial_commit.nil?
75
- @initial_commit = !Overcommit::Utils.execute(%w[git rev-parse HEAD]).success?
76
- end
77
-
78
- DIFF_HUNK_REGEX = /
79
- ^@@\s
80
- [^\s]+\s # Ignore old file range
81
- \+(\d+)(?:,(\d+))? # Extract range of hunk containing start line and number of lines
82
- \s@@.*$
83
- /x
84
-
85
- def extract_modified_lines(staged_file)
86
- lines = Set.new
87
-
88
- `git diff --no-ext-diff --cached -U0 -- #{staged_file}`.
89
- scan(DIFF_HUNK_REGEX) do |start_line, lines_added|
90
-
91
- lines_added = (lines_added || 1).to_i # When blank, one line was added
92
- cur_line = start_line.to_i
93
-
94
- lines_added.times do
95
- lines.add cur_line
96
- cur_line += 1
97
- end
98
- end
99
-
100
- lines
101
- end
102
-
103
- def store_merge_state
104
- merge_head = `git rev-parse MERGE_HEAD 2> /dev/null`.chomp
105
-
106
- # Store the merge state if we're in the middle of resolving a merge
107
- # conflict. This is necessary since stashing removes the merge state.
108
- if merge_head != 'MERGE_HEAD'
109
- @merge_head = merge_head
110
-
111
- merge_msg_file = File.expand_path('.git/MERGE_MSG', Overcommit::Utils.repo_root)
112
- @merge_msg = File.open(merge_msg_file).read if File.exist?(merge_msg_file)
113
- end
114
- end
115
-
116
- def store_cherry_pick_state
117
- cherry_head = `git rev-parse CHERRY_PICK_HEAD 2> /dev/null`.chomp
118
-
119
- # Store the merge state if we're in the middle of resolving a merge
120
- # conflict. This is necessary since stashing removes the merge state.
121
- if cherry_head != 'CHERRY_PICK_HEAD'
122
- @cherry_head = cherry_head
123
- end
124
- end
125
-
126
- def restore_merge_state
127
- if @merge_head
128
- FileUtils.touch(File.expand_path('.git/MERGE_MODE', Overcommit::Utils.repo_root))
129
-
130
- File.open(File.expand_path('.git/MERGE_HEAD', Overcommit::Utils.repo_root), 'w') do |f|
131
- f.write("#{@merge_head}\n")
132
- end
133
- @merge_head = nil
134
- end
135
-
136
- if @merge_msg
137
- File.open(File.expand_path('.git/MERGE_MSG', Overcommit::Utils.repo_root), 'w') do |f|
138
- f.write("#{@merge_msg}\n")
139
- end
140
- @merge_msg = nil
141
- end
142
- end
143
-
144
- def restore_cherry_pick_state
145
- if @cherry_head
146
- File.open(File.expand_path('.git/CHERRY_PICK_HEAD',
147
- Overcommit::Utils.repo_root), 'w') do |f|
148
- f.write("#{@cherry_head}\n")
149
- end
150
- @cherry_head = nil
151
- end
73
+ @initial_commit = Overcommit::GitRepo.initial_commit?
152
74
  end
153
75
 
76
+ # Stores the modification times for all modified files to make it appear like
77
+ # they never changed.
78
+ #
79
+ # This prevents (some) editors from complaining about files changing when we
80
+ # stash changes before running the hooks.
154
81
  def store_modified_times
155
82
  @modified_times = {}
156
83
 
@@ -159,11 +86,8 @@ module Overcommit::HookContext
159
86
  end
160
87
  end
161
88
 
162
- # Stores the modification times for all modified files to make it appear like
163
- # they never changed.
164
- #
165
- # This prevents editors from complaining about files changing when we stash
166
- # changes before running the hooks.
89
+ # Restores the file modification times for all modified files to make it
90
+ # appear like they never changed.
167
91
  def restore_modified_times
168
92
  modified_files.each do |file|
169
93
  time = @modified_times[file]
@@ -1,5 +1,3 @@
1
- # encoding: utf-8
2
-
3
1
  module Overcommit
4
2
  # Responsible for loading the hooks the repository has configured and running
5
3
  # them, collecting and displaying the results.
@@ -8,11 +6,12 @@ module Overcommit
8
6
  # @param logger [Overcommit::Logger]
9
7
  # @param context [Overcommit::HookContext]
10
8
  # @param input [Overcommit::UserInput]
11
- def initialize(config, logger, context, input)
9
+ def initialize(config, logger, context, input, printer)
12
10
  @config = config
13
11
  @log = logger
14
12
  @context = context
15
13
  @input = input
14
+ @printer = printer
16
15
  @hooks = []
17
16
  end
18
17
 
@@ -33,39 +32,28 @@ module Overcommit
33
32
 
34
33
  def run_hooks
35
34
  if @hooks.any? { |hook| hook.run? || hook.skip? }
36
- log.bold "Running #{hook_script_name} hooks"
35
+ @printer.start_run
37
36
 
38
37
  interrupted = false
38
+ run_failed = false
39
39
 
40
- statuses = @hooks.map do |hook|
40
+ @hooks.each do |hook|
41
41
  hook_status = run_hook(hook)
42
42
 
43
+ run_failed = true if hook_status == :bad
44
+
43
45
  if hook_status == :interrupted
44
46
  # Stop running any more hooks and assume a bad result
45
47
  interrupted = true
46
- break [:bad]
48
+ break
47
49
  end
48
-
49
- hook_status
50
- end.compact
51
-
52
- log.log # Newline
53
-
54
- run_failed = statuses.include?(:bad)
55
-
56
- if interrupted
57
- log.warning '⚠ Hook run interrupted by user'
58
- elsif run_failed
59
- log.error "✗ One or more #{hook_script_name} hooks failed"
60
- else
61
- log.success "✓ All #{hook_script_name} hooks passed"
62
50
  end
63
51
 
64
- log.log # Newline
52
+ @printer.end_run(interrupted, run_failed)
65
53
 
66
- !run_failed
54
+ !(run_failed || interrupted)
67
55
  else
68
- log.success "✓ No applicable #{hook_script_name} hooks to run"
56
+ @printer.nothing_to_run
69
57
  true # Run was successful
70
58
  end
71
59
  end
@@ -73,9 +61,7 @@ module Overcommit
73
61
  def run_hook(hook)
74
62
  return if should_skip?(hook)
75
63
 
76
- unless hook.quiet?
77
- print_header(hook)
78
- end
64
+ @printer.start_hook(hook)
79
65
 
80
66
  begin
81
67
  # Disable the interrupt handler during individual hook run so that
@@ -93,30 +79,19 @@ module Overcommit
93
79
  InterruptHandler.enable!
94
80
  end
95
81
 
96
- # Want to print the header in the event the result wasn't good so that the
97
- # user knows what failed
98
- if hook.quiet? && status != :good
99
- print_header(hook)
100
- end
101
-
102
- print_result(hook, status, output)
82
+ @printer.end_hook(hook, status, output)
103
83
 
104
84
  status
105
85
  end
106
86
 
107
- def print_header(hook)
108
- log.partial hook.description
109
- log.partial '.' * (70 - hook.description.length)
110
- end
111
-
112
87
  def should_skip?(hook)
113
88
  return true unless hook.enabled?
114
89
 
115
90
  if hook.skip?
116
91
  if hook.required?
117
- log.warning "Cannot skip #{hook.name} since it is required"
92
+ @printer.required_hook_not_skipped
118
93
  else
119
- log.warning "Skipping #{hook.name}"
94
+ @printer.hook_skipped
120
95
  return true
121
96
  end
122
97
  end
@@ -124,26 +99,6 @@ module Overcommit
124
99
  !hook.run?
125
100
  end
126
101
 
127
- def print_result(hook, status, output)
128
- case status
129
- when :good
130
- log.success 'OK' unless hook.quiet?
131
- when :warn
132
- log.warning 'WARNING'
133
- print_report(output, :bold_warning)
134
- when :bad
135
- log.error 'FAILED'
136
- print_report(output, :bold_error)
137
- when :interrupted
138
- log.error 'INTERRUPTED'
139
- print_report(output, :bold_error)
140
- end
141
- end
142
-
143
- def print_report(output, format = :log)
144
- log.send(format, output) unless output.nil? || output.empty?
145
- end
146
-
147
102
  def load_hooks
148
103
  require "overcommit/hook/#{@context.hook_type_name}/base"
149
104
 
@@ -152,9 +107,5 @@ module Overcommit
152
107
  # Load plugin hooks after so they can subclass existing hooks
153
108
  @hooks += HookLoader::PluginHookLoader.new(@config, @context, @log, @input).load_hooks
154
109
  end
155
-
156
- def hook_script_name
157
- @context.hook_script_name
158
- end
159
110
  end
160
111
  end
@@ -0,0 +1,105 @@
1
+ # encoding: utf-8
2
+
3
+ module Overcommit
4
+ # Provide a set of callbacks which can be executed as events occur during the
5
+ # course of {HookRunner#run}.
6
+ class Printer
7
+ attr_reader :log
8
+
9
+ def initialize(logger, context)
10
+ @log = logger
11
+ @context = context
12
+ end
13
+
14
+ # Executed at the very beginning of running the collection of hooks.
15
+ def start_run
16
+ log.bold "Running #{hook_script_name} hooks"
17
+ end
18
+
19
+ def nothing_to_run
20
+ log.success "✓ No applicable #{hook_script_name} hooks to run"
21
+ end
22
+
23
+ # Executed at the very end of running the collection of hooks.
24
+ def end_run(run_failed, interrupted)
25
+ log.log # Newline
26
+
27
+ if interrupted
28
+ log.warning '⚠ Hook run interrupted by user'
29
+ elsif run_failed
30
+ log.error "✗ One or more #{hook_script_name} hooks failed"
31
+ else
32
+ log.success "✓ All #{hook_script_name} hooks passed"
33
+ end
34
+
35
+ log.log # Newline
36
+ end
37
+
38
+ # Executed at the start of an individual hook run.
39
+ def start_hook(hook)
40
+ unless hook.quiet?
41
+ print_header(hook)
42
+ end
43
+ end
44
+
45
+ def hook_skipped(hook)
46
+ log.warning "Skipping #{hook.name}"
47
+ end
48
+
49
+ def required_hook_not_skipped(hook)
50
+ log.warning "Cannot skip #{hook.name} since it is required"
51
+ end
52
+
53
+ # Executed at the end of an individual hook run.
54
+ def end_hook(hook, status, output)
55
+ # Want to print the header for quiet hooks only if the result wasn't good
56
+ # so that the user knows what failed
57
+ print_header(hook) if hook.quiet? && status != :good
58
+
59
+ print_result(hook, status, output)
60
+ end
61
+
62
+ private
63
+
64
+ def print_header(hook)
65
+ log.partial hook.description
66
+ log.partial '.' * (70 - hook.description.length)
67
+ end
68
+
69
+ def print_result(hook, status, output)
70
+ case status
71
+ when :good
72
+ log.success 'OK' unless hook.quiet?
73
+ when :warn
74
+ log.warning 'WARNING'
75
+ print_report(output, :bold_warning)
76
+ when :bad
77
+ log.error 'FAILED'
78
+ print_report(output, :bold_error)
79
+ when :interrupted
80
+ log.error 'INTERRUPTED'
81
+ print_report(output, :bold_error)
82
+ end
83
+ end
84
+
85
+ def print_report(output, format = :log)
86
+ log.send(format, output) unless output.nil? || output.empty?
87
+ end
88
+
89
+ def run_interrupted
90
+ log.warning '⚠ Hook run interrupted by user'
91
+ end
92
+
93
+ def run_failed
94
+ log.error "✗ One or more #{hook_script_name} hooks failed"
95
+ end
96
+
97
+ def run_succeeded
98
+ log.success "✓ All #{hook_script_name} hooks passed"
99
+ end
100
+
101
+ def hook_script_name
102
+ @context.hook_script_name
103
+ end
104
+ end
105
+ end
@@ -1,4 +1,4 @@
1
1
  # Defines the gem version.
2
2
  module Overcommit
3
- VERSION = '0.13.0'
3
+ VERSION = '0.14.0'
4
4
  end
@@ -65,7 +65,8 @@ begin
65
65
 
66
66
  input = Overcommit::UserInput.new(STDIN)
67
67
 
68
- runner = Overcommit::HookRunner.new(config, logger, context, input)
68
+ printer = Overcommit::Printer.new(logger, context)
69
+ runner = Overcommit::HookRunner.new(config, logger, context, input, printer)
69
70
 
70
71
  status = runner.run
71
72
 
@@ -65,7 +65,8 @@ begin
65
65
 
66
66
  input = Overcommit::UserInput.new(STDIN)
67
67
 
68
- runner = Overcommit::HookRunner.new(config, logger, context, input)
68
+ printer = Overcommit::Printer.new(logger, context)
69
+ runner = Overcommit::HookRunner.new(config, logger, context, input, printer)
69
70
 
70
71
  status = runner.run
71
72
 
@@ -65,7 +65,8 @@ begin
65
65
 
66
66
  input = Overcommit::UserInput.new(STDIN)
67
67
 
68
- runner = Overcommit::HookRunner.new(config, logger, context, input)
68
+ printer = Overcommit::Printer.new(logger, context)
69
+ runner = Overcommit::HookRunner.new(config, logger, context, input, printer)
69
70
 
70
71
  status = runner.run
71
72
 
@@ -65,7 +65,8 @@ begin
65
65
 
66
66
  input = Overcommit::UserInput.new(STDIN)
67
67
 
68
- runner = Overcommit::HookRunner.new(config, logger, context, input)
68
+ printer = Overcommit::Printer.new(logger, context)
69
+ runner = Overcommit::HookRunner.new(config, logger, context, input, printer)
69
70
 
70
71
  status = runner.run
71
72
 
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.13.0
4
+ version: 0.14.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-07-09 00:00:00.000000000 Z
12
+ date: 2014-07-14 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: childprocess
@@ -26,19 +26,19 @@ dependencies:
26
26
  - !ruby/object:Gem::Version
27
27
  version: 0.5.1
28
28
  - !ruby/object:Gem::Dependency
29
- name: json
29
+ name: image_optim
30
30
  requirement: !ruby/object:Gem::Requirement
31
31
  requirements:
32
- - - '>='
32
+ - - ~>
33
33
  - !ruby/object:Gem::Version
34
- version: '1.8'
35
- type: :runtime
34
+ version: 0.13.0
35
+ type: :development
36
36
  prerelease: false
37
37
  version_requirements: !ruby/object:Gem::Requirement
38
38
  requirements:
39
- - - '>='
39
+ - - ~>
40
40
  - !ruby/object:Gem::Version
41
- version: '1.8'
41
+ version: 0.13.0
42
42
  - !ruby/object:Gem::Dependency
43
43
  name: rspec
44
44
  requirement: !ruby/object:Gem::Requirement
@@ -54,19 +54,19 @@ dependencies:
54
54
  - !ruby/object:Gem::Version
55
55
  version: '3.0'
56
56
  - !ruby/object:Gem::Dependency
57
- name: image_optim
57
+ name: rubocop
58
58
  requirement: !ruby/object:Gem::Requirement
59
59
  requirements:
60
- - - ~>
60
+ - - '='
61
61
  - !ruby/object:Gem::Version
62
- version: 0.13.0
62
+ version: 0.24.1
63
63
  type: :development
64
64
  prerelease: false
65
65
  version_requirements: !ruby/object:Gem::Requirement
66
66
  requirements:
67
- - - ~>
67
+ - - '='
68
68
  - !ruby/object:Gem::Version
69
- version: 0.13.0
69
+ version: 0.24.1
70
70
  description: Utility to install, configure, and extend Git hooks
71
71
  email:
72
72
  - eng@causes.com
@@ -126,6 +126,8 @@ files:
126
126
  - lib/overcommit/hook/pre_commit/base.rb
127
127
  - lib/overcommit/hook/pre_commit/json_syntax.rb
128
128
  - lib/overcommit/hook_signer.rb
129
+ - lib/overcommit/git_repo.rb
130
+ - lib/overcommit/configuration_validator.rb
129
131
  - lib/overcommit/hook_context/pre_commit.rb
130
132
  - lib/overcommit/hook_context/commit_msg.rb
131
133
  - lib/overcommit/hook_context/base.rb
@@ -138,6 +140,7 @@ files:
138
140
  - lib/overcommit/hook_loader/base.rb
139
141
  - lib/overcommit/exceptions.rb
140
142
  - lib/overcommit/configuration.rb
143
+ - lib/overcommit/printer.rb
141
144
  - lib/overcommit/logger.rb
142
145
  - lib/overcommit/cli.rb
143
146
  - libexec/index-tags
@@ -159,7 +162,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
159
162
  requirements:
160
163
  - - '>='
161
164
  - !ruby/object:Gem::Version
162
- version: 1.8.7
165
+ version: 1.9.3
163
166
  required_rubygems_version: !ruby/object:Gem::Requirement
164
167
  requirements:
165
168
  - - '>='