overcommit 0.13.0 → 0.14.0

Sign up to get free protection for your applications and to get access to all the features.
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
  - - '>='