overcommit 0.19.0 → 0.20.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 +4 -4
- data/config/default.yml +2 -1
- data/lib/overcommit/cli.rb +41 -1
- data/lib/overcommit/configuration_validator.rb +1 -2
- data/lib/overcommit/exceptions.rb +3 -0
- data/lib/overcommit/git_repo.rb +9 -1
- data/lib/overcommit/hook/base.rb +54 -32
- data/lib/overcommit/hook/commit_msg/text_width.rb +23 -16
- data/lib/overcommit/hook/pre_commit/base.rb +61 -1
- data/lib/overcommit/hook/pre_commit/haml_lint.rb +9 -13
- data/lib/overcommit/hook/pre_commit/image_optim.rb +3 -3
- data/lib/overcommit/hook/pre_commit/jscs.rb +5 -13
- data/lib/overcommit/hook/pre_commit/jsxcs.rb +5 -13
- data/lib/overcommit/hook/pre_commit/reek.rb +8 -15
- data/lib/overcommit/hook/pre_commit/rubocop.rb +9 -15
- data/lib/overcommit/hook/pre_commit/scss_lint.rb +9 -13
- data/lib/overcommit/hook_context/base.rb +3 -2
- data/lib/overcommit/hook_context/pre_commit.rb +11 -3
- data/lib/overcommit/hook_context/run_all.rb +39 -0
- data/lib/overcommit/hook_context.rb +2 -2
- data/lib/overcommit/hook_loader/base.rb +1 -3
- data/lib/overcommit/hook_loader/plugin_hook_loader.rb +26 -16
- data/lib/overcommit/hook_runner.rb +19 -9
- data/lib/overcommit/installer.rb +9 -5
- data/lib/overcommit/logger.rb +27 -0
- data/lib/overcommit/message_processor.rb +132 -0
- data/lib/overcommit/printer.rb +21 -27
- data/lib/overcommit/subprocess.rb +25 -16
- data/lib/overcommit/utils.rb +20 -0
- data/lib/overcommit/version.rb +1 -1
- data/lib/overcommit.rb +0 -1
- data/template-dir/hooks/commit-msg +9 -38
- data/template-dir/hooks/overcommit-hook +9 -38
- data/template-dir/hooks/post-checkout +9 -38
- data/template-dir/hooks/pre-commit +9 -38
- metadata +63 -76
- data/lib/overcommit/user_input.rb +0 -26
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: dcf7ae4335496b2ce26f507167d772d304a7afd2
|
4
|
+
data.tar.gz: 25ef2ce0e6350399b0814b94b7ac78929923b2bc
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ab8e8e06501b756741038cc6ea651d215ffd47201390dbff2351fdc0fc668d51378402cf9f08d13ba887c50fa74cfbca7cafa954d908f5ca9f6f1405adc25eed
|
7
|
+
data.tar.gz: 9043450a453504dc2a41110bd184ef5d08ec4580cac9f78f29bfa5eb8cea715f84b660e1e9e024b7cad42049d564e771f2a475c93b0f33bb5c6882b2f6a9fb9c
|
data/config/default.yml
CHANGED
@@ -31,6 +31,7 @@ PostCheckout:
|
|
31
31
|
# created.
|
32
32
|
PreCommit:
|
33
33
|
ALL:
|
34
|
+
problem_on_unmodified_line: warn
|
34
35
|
requires_files: true
|
35
36
|
required: false
|
36
37
|
quiet: false
|
@@ -154,7 +155,7 @@ PreCommit:
|
|
154
155
|
include: '**/*.jsx'
|
155
156
|
|
156
157
|
LocalPathsInGemfile:
|
157
|
-
description: 'Checking for
|
158
|
+
description: 'Checking for local paths in Gemfile'
|
158
159
|
include: '**/Gemfile'
|
159
160
|
|
160
161
|
MergeConflicts:
|
data/lib/overcommit/cli.rb
CHANGED
@@ -18,7 +18,14 @@ module Overcommit
|
|
18
18
|
install_or_uninstall
|
19
19
|
when :template_dir
|
20
20
|
print_template_directory_path
|
21
|
+
when :sign_plugins
|
22
|
+
sign_plugins
|
23
|
+
when :run_all
|
24
|
+
run_all
|
21
25
|
end
|
26
|
+
rescue Overcommit::Exceptions::HookContextLoadError => ex
|
27
|
+
puts ex
|
28
|
+
exit 64 # EX_USAGE
|
22
29
|
end
|
23
30
|
|
24
31
|
private
|
@@ -77,9 +84,18 @@ module Overcommit
|
|
77
84
|
opts.on('-f', '--force', 'Overwrite any previously installed hooks') do
|
78
85
|
@options[:force] = true
|
79
86
|
end
|
87
|
+
|
88
|
+
opts.on('-r', '--run', 'Run pre-commit hook against all git tracked files') do
|
89
|
+
@options[:action] = :run_all
|
90
|
+
end
|
80
91
|
end
|
81
92
|
|
82
93
|
def add_other_options(opts)
|
94
|
+
opts.on('-s', '--sign hook', 'Update plugin signatures for hook', String) do |hook|
|
95
|
+
@options[:action] = :sign_plugins
|
96
|
+
@options[:hook_to_sign] = hook
|
97
|
+
end
|
98
|
+
|
83
99
|
opts.on('-t', '--template-dir', 'Print location of template directory') do
|
84
100
|
@options[:action] = :template_dir
|
85
101
|
end
|
@@ -152,11 +168,35 @@ module Overcommit
|
|
152
168
|
if repo_config.plugin_hook?(hook_type, hook_name)
|
153
169
|
log.warning(' (plugin)')
|
154
170
|
else
|
155
|
-
log.
|
171
|
+
log.newline
|
156
172
|
end
|
157
173
|
end
|
158
174
|
end
|
159
175
|
|
176
|
+
def sign_plugins
|
177
|
+
config = Overcommit::ConfigurationLoader.load_repo_config
|
178
|
+
context = Overcommit::HookContext.create(@options[:hook_to_sign],
|
179
|
+
config,
|
180
|
+
@arguments)
|
181
|
+
Overcommit::HookLoader::PluginHookLoader.new(config,
|
182
|
+
context,
|
183
|
+
log).update_signatures
|
184
|
+
halt
|
185
|
+
end
|
186
|
+
|
187
|
+
def run_all
|
188
|
+
config = Overcommit::ConfigurationLoader.load_repo_config
|
189
|
+
context = Overcommit::HookContext.create('run-all', config, @arguments)
|
190
|
+
config.apply_environment!(context, ENV)
|
191
|
+
|
192
|
+
printer = Overcommit::Printer.new(log, context)
|
193
|
+
runner = Overcommit::HookRunner.new(config, log, context, printer)
|
194
|
+
|
195
|
+
status = runner.run
|
196
|
+
|
197
|
+
halt(status ? 0 : 65)
|
198
|
+
end
|
199
|
+
|
160
200
|
# Used for ease of stubbing in tests
|
161
201
|
def halt(status = 0)
|
162
202
|
exit status
|
@@ -26,7 +26,7 @@ module Overcommit
|
|
26
26
|
# together, since it's easier to merge two hashes than to have to check if
|
27
27
|
# one of the values is nil.
|
28
28
|
def convert_nils_to_empty_hashes(hash)
|
29
|
-
hash.
|
29
|
+
hash.each_with_object({}) do |(key, value), h|
|
30
30
|
h[key] =
|
31
31
|
case value
|
32
32
|
when nil then {}
|
@@ -34,7 +34,6 @@ module Overcommit
|
|
34
34
|
else
|
35
35
|
value
|
36
36
|
end
|
37
|
-
h
|
38
37
|
end
|
39
38
|
end
|
40
39
|
end
|
@@ -27,6 +27,9 @@ module Overcommit::Exceptions
|
|
27
27
|
# Raised when an installation target is not a valid git repository.
|
28
28
|
class InvalidGitRepo < StandardError; end
|
29
29
|
|
30
|
+
# Raised when one or more hook plugin signatures have changed.
|
31
|
+
class InvalidHookSignature < StandardError; end
|
32
|
+
|
30
33
|
# Raised when an installation target already contains non-Overcommit hooks.
|
31
34
|
class PreExistingHooks < StandardError; end
|
32
35
|
end
|
data/lib/overcommit/git_repo.rb
CHANGED
@@ -23,7 +23,6 @@ module Overcommit
|
|
23
23
|
|
24
24
|
`git diff --no-ext-diff -U0 #{flags} -- #{file_path}`.
|
25
25
|
scan(DIFF_HUNK_REGEX) do |start_line, lines_added|
|
26
|
-
|
27
26
|
lines_added = (lines_added || 1).to_i # When blank, one line was added
|
28
27
|
cur_line = start_line.to_i
|
29
28
|
|
@@ -49,6 +48,15 @@ module Overcommit
|
|
49
48
|
map { |relative_file| File.expand_path(relative_file) }
|
50
49
|
end
|
51
50
|
|
51
|
+
# Returns the names of all files that are tracked by git.
|
52
|
+
#
|
53
|
+
# @return [Array<String>] list of absolute file paths
|
54
|
+
def all_files
|
55
|
+
`git ls-files`.
|
56
|
+
split(/\n/).
|
57
|
+
map { |relative_file| File.expand_path(relative_file) }
|
58
|
+
end
|
59
|
+
|
52
60
|
# Returns whether the current git branch is empty (has no commits).
|
53
61
|
# @return [true,false]
|
54
62
|
def initial_commit?
|
data/lib/overcommit/hook/base.rb
CHANGED
@@ -1,6 +1,18 @@
|
|
1
1
|
require 'forwardable'
|
2
|
+
require 'overcommit/message_processor'
|
2
3
|
|
4
|
+
# Container for top-level hook-related classes and constants.
|
3
5
|
module Overcommit::Hook
|
6
|
+
# Helper containing metadata about error/warning messages returned by hooks.
|
7
|
+
Message = Struct.new(:type, :file, :line, :content) do
|
8
|
+
def to_s
|
9
|
+
content
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
# Possible types of messages.
|
14
|
+
MESSAGE_TYPES = [:error, :warning]
|
15
|
+
|
4
16
|
# Functionality common to all hooks.
|
5
17
|
class Base
|
6
18
|
extend Forwardable
|
@@ -30,12 +42,38 @@ module Overcommit::Hook
|
|
30
42
|
if output = check_for_executable
|
31
43
|
status = :fail
|
32
44
|
else
|
33
|
-
status, output = run
|
45
|
+
status, output = process_hook_return_value(run)
|
34
46
|
end
|
35
47
|
|
36
48
|
[transform_status(status), output]
|
37
49
|
end
|
38
50
|
|
51
|
+
# Converts the hook's return value into a canonical form of a tuple
|
52
|
+
# containing status (pass/warn/fail) and output.
|
53
|
+
#
|
54
|
+
# This is intended to support various shortcuts for writing hooks so that
|
55
|
+
# hook authors don't need to work with {Overcommit::Hook::Message} objects
|
56
|
+
# for simple pass/fail hooks. It also saves you from needing to manually
|
57
|
+
# encode logic like "if there are errors, fail; if there are warnings, warn,
|
58
|
+
# otherwise pass." by simply returning an array of
|
59
|
+
# {Overcommit::Hook::Message} objects.
|
60
|
+
#
|
61
|
+
# @param hook_return_value [Symbol, Array<Symbol,String>, Array<Message>]
|
62
|
+
# @return [Array<Symbol,String>] tuple of status and output
|
63
|
+
def process_hook_return_value(hook_return_value)
|
64
|
+
if hook_return_value.is_a?(Array) &&
|
65
|
+
hook_return_value.first.is_a?(Message)
|
66
|
+
# Process messages into a status and output
|
67
|
+
Overcommit::MessageProcessor.new(
|
68
|
+
self,
|
69
|
+
@config['problem_on_unmodified_line'],
|
70
|
+
).hook_result(hook_return_value)
|
71
|
+
else
|
72
|
+
# Otherwise return as-is
|
73
|
+
hook_return_value
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
39
77
|
def name
|
40
78
|
self.class.name.split('::').last
|
41
79
|
end
|
@@ -62,8 +100,7 @@ module Overcommit::Hook
|
|
62
100
|
|
63
101
|
def run?
|
64
102
|
enabled? &&
|
65
|
-
(
|
66
|
-
!(requires_modified_files? && applicable_files.empty?)
|
103
|
+
!(@config['requires_files'] && applicable_files.empty?)
|
67
104
|
end
|
68
105
|
|
69
106
|
def in_path?(cmd)
|
@@ -78,10 +115,6 @@ module Overcommit::Hook
|
|
78
115
|
@config['required_executable']
|
79
116
|
end
|
80
117
|
|
81
|
-
def install_command
|
82
|
-
@config['install_command']
|
83
|
-
end
|
84
|
-
|
85
118
|
# Gets a list of staged files that apply to this hook based on its
|
86
119
|
# configured `include` and `exclude` lists.
|
87
120
|
def applicable_files
|
@@ -90,35 +123,24 @@ module Overcommit::Hook
|
|
90
123
|
|
91
124
|
private
|
92
125
|
|
93
|
-
def requires_modified_files?
|
94
|
-
@config['requires_files']
|
95
|
-
end
|
96
|
-
|
97
126
|
def applicable_file?(file)
|
98
|
-
includes = Array(@config['include']).map
|
99
|
-
|
100
|
-
|
127
|
+
includes = Array(@config['include']).map do |glob|
|
128
|
+
Overcommit::Utils.convert_glob_to_absolute(glob)
|
129
|
+
end
|
101
130
|
|
102
|
-
|
103
|
-
|
131
|
+
included = includes.empty? || includes.any? do |glob|
|
132
|
+
Overcommit::Utils.matches_path?(glob, file)
|
133
|
+
end
|
104
134
|
|
105
|
-
|
106
|
-
|
135
|
+
excludes = Array(@config['exclude']).map do |glob|
|
136
|
+
Overcommit::Utils.convert_glob_to_absolute(glob)
|
137
|
+
end
|
107
138
|
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
end
|
139
|
+
excluded = excludes.any? do |glob|
|
140
|
+
Overcommit::Utils.matches_path?(glob, file)
|
141
|
+
end
|
112
142
|
|
113
|
-
|
114
|
-
#
|
115
|
-
# @param pattern [String]
|
116
|
-
# @param path [String]
|
117
|
-
def matches_path?(pattern, path)
|
118
|
-
File.fnmatch?(pattern, path,
|
119
|
-
File::FNM_PATHNAME | # Wildcard doesn't match separator
|
120
|
-
File::FNM_DOTMATCH # Wildcards match dotfiles
|
121
|
-
)
|
143
|
+
included && !excluded
|
122
144
|
end
|
123
145
|
|
124
146
|
# If the hook defines a required executable, check if it's in the path and
|
@@ -128,7 +150,7 @@ module Overcommit::Hook
|
|
128
150
|
|
129
151
|
output = "'#{executable}' is not installed (or is not in your PATH)"
|
130
152
|
|
131
|
-
if install_command
|
153
|
+
if install_command = @config['install_command']
|
132
154
|
output += "\nInstall it by running: #{install_command}"
|
133
155
|
end
|
134
156
|
|
@@ -3,29 +3,36 @@ module Overcommit::Hook::CommitMsg
|
|
3
3
|
# under the preferred limits.
|
4
4
|
class TextWidth < Base
|
5
5
|
def run
|
6
|
-
errors = []
|
6
|
+
@errors = []
|
7
7
|
|
8
|
+
find_errors_in_subject(commit_message_lines.first)
|
9
|
+
find_errors_in_body(commit_message_lines)
|
10
|
+
|
11
|
+
return :warn, @errors.join("\n") if @errors.any?
|
12
|
+
|
13
|
+
:pass
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def find_errors_in_subject(subject)
|
8
19
|
max_subject_width = config['max_subject_width']
|
9
|
-
|
20
|
+
return unless subject.length > max_subject_width
|
10
21
|
|
11
|
-
|
12
|
-
|
13
|
-
|
22
|
+
@errors << "Please keep the subject <= #{max_subject_width} characters"
|
23
|
+
end
|
24
|
+
|
25
|
+
def find_errors_in_body(lines)
|
26
|
+
return unless lines.count > 2
|
27
|
+
|
28
|
+
max_body_width = config['max_body_width']
|
14
29
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
if chomped.size > max_body_width
|
19
|
-
error = "Line #{index + 3} of commit message has > " \
|
30
|
+
lines[2..-1].each_with_index do |line, index|
|
31
|
+
if line.chomp.size > max_body_width
|
32
|
+
@errors << "Line #{index + 3} of commit message has > " \
|
20
33
|
"#{max_body_width} characters"
|
21
|
-
errors << error
|
22
|
-
end
|
23
34
|
end
|
24
35
|
end
|
25
|
-
|
26
|
-
return :warn, errors.join("\n") if errors.any?
|
27
|
-
|
28
|
-
:pass
|
29
36
|
end
|
30
37
|
end
|
31
38
|
end
|
@@ -5,6 +5,66 @@ module Overcommit::Hook::PreCommit
|
|
5
5
|
class Base < Overcommit::Hook::Base
|
6
6
|
extend Forwardable
|
7
7
|
|
8
|
-
def_delegators :@context, :
|
8
|
+
def_delegators :@context, :modified_lines_in_file
|
9
|
+
|
10
|
+
private
|
11
|
+
|
12
|
+
# Extract file, line number, and type of message from an error/warning
|
13
|
+
# messages in output.
|
14
|
+
#
|
15
|
+
# Assumes each element of `output` is a separate error/warning with all
|
16
|
+
# information necessary to identify it.
|
17
|
+
#
|
18
|
+
# @param output_messages [Array<String>] unprocessed error/warning messages
|
19
|
+
# @param regex [Regexp] regular expression defining `file`, `line` and
|
20
|
+
# `type` capture groups used to extract file locations and error/warning
|
21
|
+
# type from each line of output
|
22
|
+
# @param type_categorizer [Proc] function executed against the `type`
|
23
|
+
# capture group to convert it to a `:warning` or `:error` symbol. Assumes
|
24
|
+
# `:error` if `nil`.
|
25
|
+
# @raise [RuntimeError] line of output did not match regex
|
26
|
+
# @return [Array<Message>]
|
27
|
+
def extract_messages(output_messages, regex, type_categorizer = nil)
|
28
|
+
output_messages.map do |message|
|
29
|
+
unless match = message.match(regex)
|
30
|
+
raise 'Unexpected output: unable to determine line number or type ' \
|
31
|
+
"of error/warning for message '#{message}'"
|
32
|
+
end
|
33
|
+
|
34
|
+
file = extract_file(match, message)
|
35
|
+
line = extract_line(match, message)
|
36
|
+
type = extract_type(match, message, type_categorizer)
|
37
|
+
|
38
|
+
Overcommit::Hook::Message.new(type, file, line, message)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def extract_file(match, message)
|
43
|
+
if match[:file].nil? || match[:file].empty?
|
44
|
+
raise "Unexpected output: no file found in '#{message}'"
|
45
|
+
end
|
46
|
+
|
47
|
+
match[:file]
|
48
|
+
end
|
49
|
+
|
50
|
+
def extract_line(match, message)
|
51
|
+
Integer(match[:line])
|
52
|
+
rescue ArgumentError, TypeError
|
53
|
+
raise "Unexpected output: invalid line number found in '#{message}'"
|
54
|
+
end
|
55
|
+
|
56
|
+
def extract_type(match, message, type_categorizer)
|
57
|
+
if type_categorizer
|
58
|
+
type_match = match.names.include?('type') ? match[:type] : nil
|
59
|
+
type = type_categorizer.call(type_match)
|
60
|
+
unless Overcommit::Hook::MESSAGE_TYPES.include?(type)
|
61
|
+
raise "Invalid message type '#{type}' for '#{message}': must " \
|
62
|
+
"be one of #{Overcommit::Hook::MESSAGE_TYPES.inspect}"
|
63
|
+
end
|
64
|
+
type
|
65
|
+
else
|
66
|
+
:error # Assume error since no categorizer was defined
|
67
|
+
end
|
68
|
+
end
|
9
69
|
end
|
10
70
|
end
|
@@ -1,23 +1,19 @@
|
|
1
1
|
module Overcommit::Hook::PreCommit
|
2
2
|
# Runs `haml-lint` against any modified HAML files.
|
3
3
|
class HamlLint < Base
|
4
|
+
MESSAGE_TYPE_CATEGORIZER = lambda do |type|
|
5
|
+
type.include?('W') ? :warning : :error
|
6
|
+
end
|
7
|
+
|
4
8
|
def run
|
5
9
|
result = execute([executable] + applicable_files)
|
6
10
|
return :pass if result.success?
|
7
11
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
end
|
14
|
-
modified_lines(file).include?(line.to_i)
|
15
|
-
end
|
16
|
-
|
17
|
-
return :fail, error_lines.join("\n") unless error_lines.empty?
|
18
|
-
|
19
|
-
[:warn, "Modified files have lints (on lines you didn't modify)\n" <<
|
20
|
-
warning_lines.join("\n")]
|
12
|
+
extract_messages(
|
13
|
+
result.stdout.split("\n"),
|
14
|
+
/^(?<file>[^:]+):(?<line>\d+)[^ ]* (?<type>[^ ]+)/,
|
15
|
+
MESSAGE_TYPE_CATEGORIZER,
|
16
|
+
)
|
21
17
|
end
|
22
18
|
end
|
23
19
|
end
|
@@ -19,7 +19,7 @@ module Overcommit::Hook::PreCommit
|
|
19
19
|
return :fail,
|
20
20
|
"The following images are optimizable:\n#{optimized_images.join("\n")}" \
|
21
21
|
"\n\nOptimize them by running:\n" \
|
22
|
-
" image_optim --
|
22
|
+
" image_optim --skip-missing-workers #{optimized_images.join(' ')}"
|
23
23
|
end
|
24
24
|
|
25
25
|
:pass
|
@@ -28,10 +28,10 @@ module Overcommit::Hook::PreCommit
|
|
28
28
|
private
|
29
29
|
|
30
30
|
def optimize_images(image_paths)
|
31
|
-
image_optim = ::ImageOptim.new(:
|
31
|
+
image_optim = ::ImageOptim.new(skip_missing_workers: true)
|
32
32
|
|
33
33
|
optimized_images =
|
34
|
-
image_optim.optimize_images
|
34
|
+
image_optim.optimize_images(image_paths) do |path, optimized|
|
35
35
|
path if optimized
|
36
36
|
end
|
37
37
|
|
@@ -7,22 +7,14 @@ module Overcommit::Hook::PreCommit
|
|
7
7
|
return :pass if result.success?
|
8
8
|
|
9
9
|
if result.status == 1
|
10
|
+
# No configuration was found
|
10
11
|
return :warn, result.stderr.chomp
|
11
12
|
end
|
12
13
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
line = match[2]
|
18
|
-
end
|
19
|
-
modified_lines(file).include?(line.to_i)
|
20
|
-
end
|
21
|
-
|
22
|
-
return :fail, error_lines.join("\n") unless error_lines.empty?
|
23
|
-
|
24
|
-
[:warn, "Modified files have lints (on lines you didn't modify)\n" <<
|
25
|
-
warning_lines.join("\n")]
|
14
|
+
extract_messages(
|
15
|
+
result.stdout.split("\n"),
|
16
|
+
/^(?<file>[^:]+):[^\d]+(?<line>\d+)/,
|
17
|
+
)
|
26
18
|
end
|
27
19
|
end
|
28
20
|
end
|
@@ -7,22 +7,14 @@ module Overcommit::Hook::PreCommit
|
|
7
7
|
return :pass if result.success?
|
8
8
|
|
9
9
|
if result.status == 1
|
10
|
+
# No configuration found
|
10
11
|
return :warn, result.stderr.chomp
|
11
12
|
end
|
12
13
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
line = match[2]
|
18
|
-
end
|
19
|
-
modified_lines(file).include?(line.to_i)
|
20
|
-
end
|
21
|
-
|
22
|
-
return :fail, error_lines.join("\n") unless error_lines.empty?
|
23
|
-
|
24
|
-
[:warn, "Modified files have lints (on lines you didn't modify)\n" <<
|
25
|
-
warning_lines.join("\n")]
|
14
|
+
extract_messages(
|
15
|
+
result.stdout.split("\n"),
|
16
|
+
/^(?<file>[^:]+):[^\d]+(?<line>\d+)/,
|
17
|
+
)
|
26
18
|
end
|
27
19
|
end
|
28
20
|
end
|
@@ -5,24 +5,17 @@ module Overcommit::Hook::PreCommit
|
|
5
5
|
result = execute(%W[#{executable} --single-line --no-color] + applicable_files)
|
6
6
|
return :pass if result.success?
|
7
7
|
|
8
|
-
output =
|
8
|
+
output = scrub_output(result.stdout + result.stderr)
|
9
9
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
line = match[2]
|
15
|
-
end
|
16
|
-
modified_lines(file).include?(line.to_i)
|
17
|
-
end
|
18
|
-
|
19
|
-
return :fail, error_lines.join("\n") unless error_lines.empty?
|
20
|
-
|
21
|
-
[:warn, "Modified files have lints (on lines you didn't modify)\n" <<
|
22
|
-
warning_lines.join("\n")]
|
10
|
+
extract_messages(
|
11
|
+
output,
|
12
|
+
/^(?<file>[^:]+):(?<line>\d+):/,
|
13
|
+
)
|
23
14
|
end
|
24
15
|
|
25
|
-
|
16
|
+
private
|
17
|
+
|
18
|
+
def scrub_output(raw_output)
|
26
19
|
raw_output.split("\n").grep(/^(.(?!warning))*$/)
|
27
20
|
end
|
28
21
|
end
|
@@ -1,25 +1,19 @@
|
|
1
1
|
module Overcommit::Hook::PreCommit
|
2
2
|
# Runs `rubocop` against any modified Ruby files.
|
3
3
|
class Rubocop < Base
|
4
|
+
MESSAGE_TYPE_CATEGORIZER = lambda do |type|
|
5
|
+
type.include?('W') ? :warning : :error
|
6
|
+
end
|
7
|
+
|
4
8
|
def run
|
5
9
|
result = execute(%W[#{executable} --format=emacs --force-exclusion] + applicable_files)
|
6
10
|
return :pass if result.success?
|
7
11
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
file = match[1]
|
14
|
-
line = match[2]
|
15
|
-
end
|
16
|
-
modified_lines(file).include?(line.to_i)
|
17
|
-
end
|
18
|
-
|
19
|
-
return :fail, error_lines.join("\n") unless error_lines.empty?
|
20
|
-
|
21
|
-
[:warn, "Modified files have lints (on lines you didn't modify)\n" <<
|
22
|
-
warning_lines.join("\n")]
|
12
|
+
extract_messages(
|
13
|
+
result.stdout.split("\n"),
|
14
|
+
/^(?<file>[^:]+):(?<line>\d+):[^ ]+ (?<type>[^ ]+)/,
|
15
|
+
MESSAGE_TYPE_CATEGORIZER,
|
16
|
+
)
|
23
17
|
end
|
24
18
|
end
|
25
19
|
end
|
@@ -1,23 +1,19 @@
|
|
1
1
|
module Overcommit::Hook::PreCommit
|
2
2
|
# Runs `scss-lint` against any modified SCSS files.
|
3
3
|
class ScssLint < Base
|
4
|
+
MESSAGE_TYPE_CATEGORIZER = lambda do |type|
|
5
|
+
type.include?('W') ? :warning : :error
|
6
|
+
end
|
7
|
+
|
4
8
|
def run
|
5
9
|
result = execute([executable] + applicable_files)
|
6
10
|
return :pass if result.success?
|
7
11
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
end
|
14
|
-
modified_lines(file).include?(line.to_i)
|
15
|
-
end
|
16
|
-
|
17
|
-
return :fail, error_lines.join("\n") unless error_lines.empty?
|
18
|
-
|
19
|
-
[:warn, "Modified files have lints (on lines you didn't modify)\n" <<
|
20
|
-
warning_lines.join("\n")]
|
12
|
+
extract_messages(
|
13
|
+
result.stdout.split("\n"),
|
14
|
+
/^(?<file>[^:]+):(?<line>\d+)[^ ]* (?<type>[^ ]+)/,
|
15
|
+
MESSAGE_TYPE_CATEGORIZER,
|
16
|
+
)
|
21
17
|
end
|
22
18
|
end
|
23
19
|
end
|
@@ -11,10 +11,11 @@ module Overcommit::HookContext
|
|
11
11
|
# calculations can be memoized across all hooks in a single object, which
|
12
12
|
# helps with performance.
|
13
13
|
class Base
|
14
|
-
|
14
|
+
# @param config [Overcommit::Configuration]
|
15
|
+
# @param args [Array<String>]
|
16
|
+
def initialize(config, args)
|
15
17
|
@config = config
|
16
18
|
@args = args
|
17
|
-
@input = input
|
18
19
|
end
|
19
20
|
|
20
21
|
# Returns the camel-cased type of this hook (e.g. PreCommit)
|
@@ -64,14 +64,22 @@ module Overcommit::HookContext
|
|
64
64
|
# Get a list of added, copied, or modified files that have been staged.
|
65
65
|
# Renames and deletions are ignored, since there should be nothing to check.
|
66
66
|
def modified_files
|
67
|
-
@modified_files ||= Overcommit::GitRepo.modified_files(:
|
67
|
+
@modified_files ||= Overcommit::GitRepo.modified_files(staged: true)
|
68
|
+
end
|
69
|
+
|
70
|
+
# @deprecated
|
71
|
+
# TODO: Remove this once we've moved all existing hooks to stop using this
|
72
|
+
# endpoint
|
73
|
+
def modified_lines(file)
|
74
|
+
modified_lines_in_file(file)
|
68
75
|
end
|
69
76
|
|
70
77
|
# Returns the set of line numbers corresponding to the lines that were
|
71
78
|
# changed in a specified file.
|
72
|
-
def
|
79
|
+
def modified_lines_in_file(file)
|
73
80
|
@modified_lines ||= {}
|
74
|
-
@modified_lines[file] ||=
|
81
|
+
@modified_lines[file] ||=
|
82
|
+
Overcommit::GitRepo.extract_modified_lines(file, staged: true)
|
75
83
|
end
|
76
84
|
|
77
85
|
private
|