overcommit 0.30.0 → 0.32.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 +123 -93
- data/lib/overcommit/configuration.rb +24 -2
- data/lib/overcommit/configuration_validator.rb +28 -1
- data/lib/overcommit/constants.rb +7 -5
- data/lib/overcommit/exceptions.rb +6 -0
- data/lib/overcommit/git_repo.rb +6 -0
- data/lib/overcommit/hook/base.rb +22 -4
- data/lib/overcommit/hook/commit_msg/capitalized_subject.rb +1 -1
- data/lib/overcommit/hook/commit_msg/message_format.rb +27 -0
- data/lib/overcommit/hook/pre_commit/base.rb +17 -8
- data/lib/overcommit/hook/pre_commit/berksfile_check.rb +3 -1
- data/lib/overcommit/hook/pre_commit/bundle_check.rb +3 -1
- data/lib/overcommit/hook/pre_commit/es_lint.rb +10 -0
- data/lib/overcommit/hook/pre_commit/execute_permissions.rb +10 -0
- data/lib/overcommit/hook/pre_commit/forbidden_branches.rb +24 -0
- data/lib/overcommit/hook/pre_commit/mdl.rb +23 -0
- data/lib/overcommit/hook/pre_commit/rubo_cop.rb +15 -4
- data/lib/overcommit/hook/pre_commit/scss_lint.rb +23 -10
- data/lib/overcommit/hook/pre_push/minitest.rb +4 -0
- data/lib/overcommit/hook/pre_push/protected_branches.rb +13 -6
- data/lib/overcommit/hook_context/base.rb +7 -0
- data/lib/overcommit/hook_context/pre_commit.rb +7 -0
- data/lib/overcommit/hook_context/pre_push.rb +12 -1
- data/lib/overcommit/hook_context/run_all.rb +1 -1
- data/lib/overcommit/hook_runner.rb +90 -41
- data/lib/overcommit/hook_signer.rb +1 -1
- data/lib/overcommit/message_processor.rb +20 -7
- data/lib/overcommit/os.rb +2 -2
- data/lib/overcommit/printer.rb +32 -8
- data/lib/overcommit/utils.rb +36 -0
- data/lib/overcommit/version.rb +3 -1
- data/template-dir/hooks/commit-msg +9 -1
- data/template-dir/hooks/overcommit-hook +9 -1
- data/template-dir/hooks/post-checkout +9 -1
- data/template-dir/hooks/post-commit +9 -1
- data/template-dir/hooks/post-merge +9 -1
- data/template-dir/hooks/post-rewrite +9 -1
- data/template-dir/hooks/pre-commit +9 -1
- data/template-dir/hooks/pre-push +9 -1
- data/template-dir/hooks/pre-rebase +9 -1
- metadata +21 -4
|
@@ -13,13 +13,15 @@ module Overcommit
|
|
|
13
13
|
def initialize(hash, options = {})
|
|
14
14
|
@options = options.dup
|
|
15
15
|
@options[:logger] ||= Overcommit::Logger.silent
|
|
16
|
-
@hash =
|
|
16
|
+
@hash = hash # Assign so validator can read original values
|
|
17
|
+
unless options[:validate] == false
|
|
18
|
+
@hash = Overcommit::ConfigurationValidator.new.validate(self, hash, options)
|
|
19
|
+
end
|
|
17
20
|
end
|
|
18
21
|
|
|
19
22
|
def ==(other)
|
|
20
23
|
super || @hash == other.hash
|
|
21
24
|
end
|
|
22
|
-
alias_method :eql?, :==
|
|
23
25
|
|
|
24
26
|
# Access the configuration as if it were a hash.
|
|
25
27
|
#
|
|
@@ -35,6 +37,26 @@ module Overcommit
|
|
|
35
37
|
File.join(Overcommit::Utils.repo_root, @hash['plugin_directory'] || '.git-hooks')
|
|
36
38
|
end
|
|
37
39
|
|
|
40
|
+
def concurrency
|
|
41
|
+
@concurrency ||=
|
|
42
|
+
begin
|
|
43
|
+
cores = Overcommit::Utils.processor_count
|
|
44
|
+
content = @hash.fetch('concurrency', '%{processors}')
|
|
45
|
+
if content.is_a?(String)
|
|
46
|
+
concurrency_expr = content % { processors: cores }
|
|
47
|
+
|
|
48
|
+
a, op, b = concurrency_expr.scan(%r{(\d+)\s*([+\-*\/])\s*(\d+)})[0]
|
|
49
|
+
if a
|
|
50
|
+
a.to_i.send(op, b.to_i)
|
|
51
|
+
else
|
|
52
|
+
concurrency_expr.to_i
|
|
53
|
+
end
|
|
54
|
+
else
|
|
55
|
+
content.to_i
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
38
60
|
# Returns configuration for all hooks in each hook type.
|
|
39
61
|
#
|
|
40
62
|
# @return [Hash]
|
|
@@ -3,12 +3,13 @@ module Overcommit
|
|
|
3
3
|
class ConfigurationValidator
|
|
4
4
|
# Validates hash for any invalid options, normalizing where possible.
|
|
5
5
|
#
|
|
6
|
+
# @param config [Overcommit::Configuration]
|
|
6
7
|
# @param hash [Hash] hash representation of YAML config
|
|
7
8
|
# @param options[Hash]
|
|
8
9
|
# @option default [Boolean] whether hash represents the default built-in config
|
|
9
10
|
# @option logger [Overcommit::Logger] logger to output warnings to
|
|
10
11
|
# @return [Hash] validated hash (potentially modified)
|
|
11
|
-
def validate(hash, options)
|
|
12
|
+
def validate(config, hash, options)
|
|
12
13
|
@options = options.dup
|
|
13
14
|
@log = options[:logger]
|
|
14
15
|
|
|
@@ -16,6 +17,7 @@ module Overcommit
|
|
|
16
17
|
ensure_hook_type_sections_exist(hash)
|
|
17
18
|
check_hook_name_format(hash)
|
|
18
19
|
check_for_missing_enabled_option(hash) unless @options[:default]
|
|
20
|
+
check_for_too_many_processors(config, hash)
|
|
19
21
|
check_for_verify_plugin_signatures_option(hash)
|
|
20
22
|
|
|
21
23
|
hash
|
|
@@ -96,6 +98,31 @@ module Overcommit
|
|
|
96
98
|
@log.newline if any_warnings
|
|
97
99
|
end
|
|
98
100
|
|
|
101
|
+
# Prints a warning if any hook has a number of processors larger than the
|
|
102
|
+
# global `concurrency` setting.
|
|
103
|
+
def check_for_too_many_processors(config, hash)
|
|
104
|
+
concurrency = config.concurrency
|
|
105
|
+
|
|
106
|
+
errors = []
|
|
107
|
+
Overcommit::Utils.supported_hook_type_classes.each do |hook_type|
|
|
108
|
+
hash.fetch(hook_type, {}).each do |hook_name, hook_config|
|
|
109
|
+
processors = hook_config.fetch('processors', 1)
|
|
110
|
+
if processors > concurrency
|
|
111
|
+
errors << "#{hook_type}::#{hook_name} `processors` value " \
|
|
112
|
+
"(#{processors}) is larger than the global `concurrency` " \
|
|
113
|
+
"option (#{concurrency})"
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
if errors.any?
|
|
119
|
+
@log.error errors.join("\n") if @log
|
|
120
|
+
@log.newline if @log
|
|
121
|
+
raise Overcommit::Exceptions::ConfigurationError,
|
|
122
|
+
'One or more hooks had invalid `processor` value configured'
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
|
|
99
126
|
# Prints a warning if the `verify_plugin_signatures` option is used instead
|
|
100
127
|
# of the new `verify_signatures` option.
|
|
101
128
|
def check_for_verify_plugin_signatures_option(hash)
|
data/lib/overcommit/constants.rb
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
# Global application constants.
|
|
2
4
|
module Overcommit
|
|
3
|
-
HOME = File.expand_path(File.join(File.dirname(__FILE__), '..', '..'))
|
|
4
|
-
CONFIG_FILE_NAME = '.overcommit.yml'
|
|
5
|
+
HOME = File.expand_path(File.join(File.dirname(__FILE__), '..', '..')).freeze
|
|
6
|
+
CONFIG_FILE_NAME = '.overcommit.yml'.freeze
|
|
5
7
|
|
|
6
|
-
HOOK_DIRECTORY = File.join(HOME, 'lib', 'overcommit', 'hook')
|
|
8
|
+
HOOK_DIRECTORY = File.join(HOME, 'lib', 'overcommit', 'hook').freeze
|
|
7
9
|
|
|
8
|
-
REPO_URL = 'https://github.com/brigade/overcommit'
|
|
9
|
-
BUG_REPORT_URL = "#{REPO_URL}/issues"
|
|
10
|
+
REPO_URL = 'https://github.com/brigade/overcommit'.freeze
|
|
11
|
+
BUG_REPORT_URL = "#{REPO_URL}/issues".freeze
|
|
10
12
|
end
|
|
@@ -11,6 +11,9 @@ module Overcommit::Exceptions
|
|
|
11
11
|
# Raised when there was a problem reading submodule information for a repo.
|
|
12
12
|
class GitSubmoduleError < StandardError; end
|
|
13
13
|
|
|
14
|
+
# Raised when there was a problem reading git revision information with `rev-list`.
|
|
15
|
+
class GitRevListError < StandardError; end
|
|
16
|
+
|
|
14
17
|
# Raised when a {HookContext} is unable to setup the environment before a run.
|
|
15
18
|
class HookSetupFailed < StandardError; end
|
|
16
19
|
|
|
@@ -39,6 +42,9 @@ module Overcommit::Exceptions
|
|
|
39
42
|
# Raised when one or more hook plugin signatures have changed.
|
|
40
43
|
class InvalidHookSignature < StandardError; end
|
|
41
44
|
|
|
45
|
+
# Raised when there is a problem processing output into {Hook::Messages}s.
|
|
46
|
+
class MessageProcessingError < StandardError; end
|
|
47
|
+
|
|
42
48
|
# Raised when an installation target already contains non-Overcommit hooks.
|
|
43
49
|
class PreExistingHooks < StandardError; end
|
|
44
50
|
end
|
data/lib/overcommit/git_repo.rb
CHANGED
|
@@ -266,5 +266,11 @@ module Overcommit
|
|
|
266
266
|
split(/\s+/).
|
|
267
267
|
reject { |s| s.empty? || s == '*' }
|
|
268
268
|
end
|
|
269
|
+
|
|
270
|
+
# Returns the name of the currently checked out branch.
|
|
271
|
+
# @return [String]
|
|
272
|
+
def current_branch
|
|
273
|
+
`git symbolic-ref --short -q HEAD`.chomp
|
|
274
|
+
end
|
|
269
275
|
end
|
|
270
276
|
end
|
data/lib/overcommit/hook/base.rb
CHANGED
|
@@ -11,13 +11,13 @@ module Overcommit::Hook
|
|
|
11
11
|
end
|
|
12
12
|
|
|
13
13
|
# Possible types of messages.
|
|
14
|
-
MESSAGE_TYPES = [:error, :warning]
|
|
14
|
+
MESSAGE_TYPES = [:error, :warning].freeze
|
|
15
15
|
|
|
16
16
|
# Functionality common to all hooks.
|
|
17
17
|
class Base # rubocop:disable Metrics/ClassLength
|
|
18
18
|
extend Forwardable
|
|
19
19
|
|
|
20
|
-
def_delegators :@context, :modified_files
|
|
20
|
+
def_delegators :@context, :all_files, :modified_files
|
|
21
21
|
attr_reader :config
|
|
22
22
|
|
|
23
23
|
# @param config [Overcommit::Configuration]
|
|
@@ -54,13 +54,21 @@ module Overcommit::Hook
|
|
|
54
54
|
end
|
|
55
55
|
|
|
56
56
|
def description
|
|
57
|
-
@config['description'] || "
|
|
57
|
+
@config['description'] || "Run #{name}"
|
|
58
58
|
end
|
|
59
59
|
|
|
60
60
|
def required?
|
|
61
61
|
@config['required']
|
|
62
62
|
end
|
|
63
63
|
|
|
64
|
+
def parallelize?
|
|
65
|
+
@config['parallelize'] != false
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def processors
|
|
69
|
+
@config.fetch('processors', 1)
|
|
70
|
+
end
|
|
71
|
+
|
|
64
72
|
def quiet?
|
|
65
73
|
@config['quiet']
|
|
66
74
|
end
|
|
@@ -147,11 +155,21 @@ module Overcommit::Hook
|
|
|
147
155
|
# Gets a list of staged files that apply to this hook based on its
|
|
148
156
|
# configured `include` and `exclude` lists.
|
|
149
157
|
def applicable_files
|
|
150
|
-
@applicable_files ||= modified_files
|
|
158
|
+
@applicable_files ||= select_applicable(modified_files)
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
# Gets a list of all files that apply to this hook based on its
|
|
162
|
+
# configured `include` and `exclude` lists.
|
|
163
|
+
def included_files
|
|
164
|
+
@included_files ||= select_applicable(all_files)
|
|
151
165
|
end
|
|
152
166
|
|
|
153
167
|
private
|
|
154
168
|
|
|
169
|
+
def select_applicable(list)
|
|
170
|
+
list.select { |file| applicable_file?(file) }.sort
|
|
171
|
+
end
|
|
172
|
+
|
|
155
173
|
def applicable_file?(file)
|
|
156
174
|
includes = Array(@config['include']).flatten.map do |glob|
|
|
157
175
|
Overcommit::Utils.convert_glob_to_absolute(glob)
|
|
@@ -5,7 +5,7 @@ module Overcommit::Hook::CommitMsg
|
|
|
5
5
|
return :pass if empty_message?
|
|
6
6
|
|
|
7
7
|
first_letter = commit_message_lines[0].to_s.match(/^[[:punct:]]*(.)/)[1]
|
|
8
|
-
unless first_letter
|
|
8
|
+
unless first_letter =~ /[[:upper:]]/
|
|
9
9
|
return :warn, 'Subject should start with a capital letter'
|
|
10
10
|
end
|
|
11
11
|
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
module Overcommit::Hook::CommitMsg
|
|
2
|
+
# Ensures the commit message follows a specific format.
|
|
3
|
+
class MessageFormat < Base
|
|
4
|
+
def run
|
|
5
|
+
error_msg = validate_pattern(commit_message_lines.join("\n"))
|
|
6
|
+
return :fail, error_msg if error_msg
|
|
7
|
+
|
|
8
|
+
:pass
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
private
|
|
12
|
+
|
|
13
|
+
def validate_pattern(message)
|
|
14
|
+
pattern = config['pattern']
|
|
15
|
+
return if pattern.empty?
|
|
16
|
+
|
|
17
|
+
expected_pattern_message = config['expected_pattern_message']
|
|
18
|
+
sample_message = config['sample_message']
|
|
19
|
+
|
|
20
|
+
[
|
|
21
|
+
'Commit message pattern mismatch.',
|
|
22
|
+
"Expected : #{expected_pattern_message}",
|
|
23
|
+
"Sample : #{sample_message}"
|
|
24
|
+
].join("\n") unless message =~ /#{pattern}/
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -22,13 +22,16 @@ module Overcommit::Hook::PreCommit
|
|
|
22
22
|
# @param type_categorizer [Proc] function executed against the `type`
|
|
23
23
|
# capture group to convert it to a `:warning` or `:error` symbol. Assumes
|
|
24
24
|
# `:error` if `nil`.
|
|
25
|
-
# @raise [
|
|
25
|
+
# @raise [Overcommit::Exceptions::MessageProcessingError] line of output did
|
|
26
|
+
# not match regex
|
|
26
27
|
# @return [Array<Message>]
|
|
27
28
|
def extract_messages(output_messages, regex, type_categorizer = nil)
|
|
28
|
-
output_messages.map do |message|
|
|
29
|
+
output_messages.map.with_index do |message, index|
|
|
29
30
|
unless match = message.match(regex)
|
|
30
|
-
raise
|
|
31
|
-
|
|
31
|
+
raise Overcommit::Exceptions::MessageProcessingError,
|
|
32
|
+
'Unexpected output: unable to determine line number or type ' \
|
|
33
|
+
"of error/warning for output:\n" \
|
|
34
|
+
"#{output_messages[index..-1].join("\n")}"
|
|
32
35
|
end
|
|
33
36
|
|
|
34
37
|
file = extract_file(match, message)
|
|
@@ -40,17 +43,22 @@ module Overcommit::Hook::PreCommit
|
|
|
40
43
|
end
|
|
41
44
|
|
|
42
45
|
def extract_file(match, message)
|
|
43
|
-
|
|
44
|
-
|
|
46
|
+
return unless match.names.include?('file')
|
|
47
|
+
|
|
48
|
+
if match[:file].to_s.empty?
|
|
49
|
+
raise Overcommit::Exceptions::MessageProcessingError,
|
|
50
|
+
"Unexpected output: no file found in '#{message}'"
|
|
45
51
|
end
|
|
46
52
|
|
|
47
53
|
match[:file]
|
|
48
54
|
end
|
|
49
55
|
|
|
50
56
|
def extract_line(match, message)
|
|
57
|
+
return unless match.names.include?('line')
|
|
51
58
|
Integer(match[:line])
|
|
52
59
|
rescue ArgumentError, TypeError
|
|
53
|
-
raise
|
|
60
|
+
raise Overcommit::Exceptions::MessageProcessingError,
|
|
61
|
+
"Unexpected output: invalid line number found in '#{message}'"
|
|
54
62
|
end
|
|
55
63
|
|
|
56
64
|
def extract_type(match, message, type_categorizer)
|
|
@@ -58,7 +66,8 @@ module Overcommit::Hook::PreCommit
|
|
|
58
66
|
type_match = match.names.include?('type') ? match[:type] : nil
|
|
59
67
|
type = type_categorizer.call(type_match)
|
|
60
68
|
unless Overcommit::Hook::MESSAGE_TYPES.include?(type)
|
|
61
|
-
raise
|
|
69
|
+
raise Overcommit::Exceptions::MessageProcessingError,
|
|
70
|
+
"Invalid message type '#{type}' for '#{message}': must " \
|
|
62
71
|
"be one of #{Overcommit::Hook::MESSAGE_TYPES.inspect}"
|
|
63
72
|
end
|
|
64
73
|
type
|
|
@@ -1,10 +1,12 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module Overcommit::Hook::PreCommit
|
|
2
4
|
# Check if local Berksfile.lock matches Berksfile when either changes, unless
|
|
3
5
|
# Berksfile.lock is ignored by git.
|
|
4
6
|
#
|
|
5
7
|
# @see http://berkshelf.com/
|
|
6
8
|
class BerksfileCheck < Base
|
|
7
|
-
LOCK_FILE = 'Berksfile.lock'
|
|
9
|
+
LOCK_FILE = 'Berksfile.lock'.freeze
|
|
8
10
|
|
|
9
11
|
def run
|
|
10
12
|
# Ignore if Berksfile.lock is not tracked by git
|
|
@@ -1,10 +1,12 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module Overcommit::Hook::PreCommit
|
|
2
4
|
# Check if local Gemfile.lock matches Gemfile when either changes, unless
|
|
3
5
|
# Gemfile.lock is ignored by git.
|
|
4
6
|
#
|
|
5
7
|
# @see http://bundler.io/
|
|
6
8
|
class BundleCheck < Base
|
|
7
|
-
LOCK_FILE = 'Gemfile.lock'
|
|
9
|
+
LOCK_FILE = 'Gemfile.lock'.freeze
|
|
8
10
|
|
|
9
11
|
def run
|
|
10
12
|
# Ignore if Gemfile.lock is not tracked by git
|
|
@@ -1,6 +1,16 @@
|
|
|
1
1
|
module Overcommit::Hook::PreCommit
|
|
2
2
|
# Runs `eslint` against any modified JavaScript files.
|
|
3
3
|
#
|
|
4
|
+
# Protip: if you have an npm script set up to run eslint, you can configure
|
|
5
|
+
# this hook to run eslint via your npm script by using the `command` option in
|
|
6
|
+
# your .overcommit.yml file. This can be useful if you have some eslint
|
|
7
|
+
# configuration built into your npm script that you don't want to repeat
|
|
8
|
+
# somewhere else. Example:
|
|
9
|
+
#
|
|
10
|
+
# EsLint:
|
|
11
|
+
# enabled: true
|
|
12
|
+
# command: ['npm', 'run', 'lint']
|
|
13
|
+
#
|
|
4
14
|
# @see http://eslint.org/
|
|
5
15
|
class EsLint < Base
|
|
6
16
|
def run
|
|
@@ -2,6 +2,16 @@ module Overcommit::Hook::PreCommit
|
|
|
2
2
|
# Checks for files with execute permissions, which are usually not necessary
|
|
3
3
|
# in source code files (and are typically caused by a misconfigured editor
|
|
4
4
|
# assigning incorrect default permissions).
|
|
5
|
+
#
|
|
6
|
+
# Protip: if you have some files that you want to allow execute permissions
|
|
7
|
+
# on, you can disable this hook for those files by using the `exclude` option
|
|
8
|
+
# on your .overcommit.yml file. Example:
|
|
9
|
+
#
|
|
10
|
+
# ExecutePermissions:
|
|
11
|
+
# enabled: true
|
|
12
|
+
# exclude:
|
|
13
|
+
# - 'path/to/my/file/that/should/have/execute/permissions.sh'
|
|
14
|
+
# - 'directory/that/should/have/execute/permissions/**/*'
|
|
5
15
|
class ExecutePermissions < Base
|
|
6
16
|
def run
|
|
7
17
|
file_modes = {}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
module Overcommit::Hook::PreCommit
|
|
2
|
+
# Prevents commits to branches matching one of the configured patterns.
|
|
3
|
+
class ForbiddenBranches < Base
|
|
4
|
+
def run
|
|
5
|
+
return :pass unless forbidden_commit?
|
|
6
|
+
|
|
7
|
+
[:fail, "Committing to #{current_branch} is forbidden"]
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
private
|
|
11
|
+
|
|
12
|
+
def forbidden_commit?
|
|
13
|
+
forbidden_branch_patterns.any? { |p| File.fnmatch(p, current_branch) }
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def forbidden_branch_patterns
|
|
17
|
+
@forbidden_branch_patterns ||= Array(config['branch_patterns'])
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def current_branch
|
|
21
|
+
@current_branch ||= Overcommit::GitRepo.current_branch
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
module Overcommit::Hook::PreCommit
|
|
2
|
+
# Runs `mdl` against any modified Markdown files
|
|
3
|
+
#
|
|
4
|
+
# @see https://github.com/mivok/markdownlint
|
|
5
|
+
class Mdl < Base
|
|
6
|
+
MESSAGE_REGEX = /^(?<file>(?:\w:)?[^:]+):(?<line>\d+)/
|
|
7
|
+
|
|
8
|
+
def run
|
|
9
|
+
result = execute(command, args: applicable_files)
|
|
10
|
+
output = result.stdout.chomp
|
|
11
|
+
|
|
12
|
+
return :pass if result.success?
|
|
13
|
+
return [:fail, result.stderr] unless result.stderr.empty?
|
|
14
|
+
|
|
15
|
+
# example message:
|
|
16
|
+
# path/to/file.md:1: MD001 Error message
|
|
17
|
+
extract_messages(
|
|
18
|
+
output.split("\n"),
|
|
19
|
+
MESSAGE_REGEX
|
|
20
|
+
)
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -3,20 +3,31 @@ module Overcommit::Hook::PreCommit
|
|
|
3
3
|
#
|
|
4
4
|
# @see http://batsov.com/rubocop/
|
|
5
5
|
class RuboCop < Base
|
|
6
|
-
|
|
6
|
+
GENERIC_MESSAGE_TYPE_CATEGORIZER = lambda do |type|
|
|
7
|
+
type =~ /^warn/ ? :warning : :error
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
COP_MESSAGE_TYPE_CATEGORIZER = lambda do |type|
|
|
7
11
|
type.include?('W') ? :warning : :error
|
|
8
12
|
end
|
|
9
13
|
|
|
10
14
|
def run
|
|
11
15
|
result = execute(command, args: applicable_files)
|
|
12
16
|
return :pass if result.success?
|
|
13
|
-
return [:fail, result.stderr] unless result.stderr.empty?
|
|
14
17
|
|
|
15
|
-
extract_messages(
|
|
18
|
+
generic_messages = extract_messages(
|
|
19
|
+
result.stderr.split("\n"),
|
|
20
|
+
/^(?<type>[a-z]+)/i,
|
|
21
|
+
GENERIC_MESSAGE_TYPE_CATEGORIZER,
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
cop_messages = extract_messages(
|
|
16
25
|
result.stdout.split("\n"),
|
|
17
26
|
/^(?<file>(?:\w:)?[^:]+):(?<line>\d+):[^ ]+ (?<type>[^ ]+)/,
|
|
18
|
-
|
|
27
|
+
COP_MESSAGE_TYPE_CATEGORIZER,
|
|
19
28
|
)
|
|
29
|
+
|
|
30
|
+
generic_messages + cop_messages
|
|
20
31
|
end
|
|
21
32
|
end
|
|
22
33
|
end
|
|
@@ -3,10 +3,6 @@ module Overcommit::Hook::PreCommit
|
|
|
3
3
|
#
|
|
4
4
|
# @see https://github.com/brigade/scss-lint
|
|
5
5
|
class ScssLint < Base
|
|
6
|
-
MESSAGE_TYPE_CATEGORIZER = lambda do |type|
|
|
7
|
-
type.include?('W') ? :warning : :error
|
|
8
|
-
end
|
|
9
|
-
|
|
10
6
|
def run
|
|
11
7
|
result = execute(command, args: applicable_files)
|
|
12
8
|
|
|
@@ -16,13 +12,30 @@ module Overcommit::Hook::PreCommit
|
|
|
16
12
|
return :pass if [0, 81].include?(result.status)
|
|
17
13
|
|
|
18
14
|
# Any status that isn't indicating lint warnings or errors indicates failure
|
|
19
|
-
return :fail, result.stdout unless [1, 2].include?(result.status)
|
|
15
|
+
return :fail, (result.stdout + result.stderr) unless [1, 2].include?(result.status)
|
|
16
|
+
|
|
17
|
+
begin
|
|
18
|
+
collect_lint_messages(JSON.parse(result.stdout))
|
|
19
|
+
rescue JSON::ParserError => ex
|
|
20
|
+
return :fail, "Unable to parse JSON returned by SCSS-Lint: #{ex.message}\n" \
|
|
21
|
+
"STDOUT: #{result.stdout}\nSTDERR: #{result.stderr}"
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
private
|
|
26
|
+
|
|
27
|
+
def collect_lint_messages(files_to_lints)
|
|
28
|
+
files_to_lints.flat_map do |path, lints|
|
|
29
|
+
lints.map do |lint|
|
|
30
|
+
severity = lint['severity'] == 'warning' ? :warning : :error
|
|
31
|
+
|
|
32
|
+
message = lint['reason']
|
|
33
|
+
message = "#{lint['linter']}: #{message}" if lint['linter']
|
|
34
|
+
message = "#{path}:#{lint['line']} #{message}"
|
|
20
35
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
MESSAGE_TYPE_CATEGORIZER,
|
|
25
|
-
)
|
|
36
|
+
Overcommit::Hook::Message.new(severity, path, lint['line'], message)
|
|
37
|
+
end
|
|
38
|
+
end
|
|
26
39
|
end
|
|
27
40
|
end
|
|
28
41
|
end
|
|
@@ -13,15 +13,22 @@ module Overcommit::Hook::PrePush
|
|
|
13
13
|
|
|
14
14
|
private
|
|
15
15
|
|
|
16
|
-
def branches
|
|
17
|
-
@branches ||= config['branches']
|
|
18
|
-
end
|
|
19
|
-
|
|
20
16
|
def illegal_pushes
|
|
21
17
|
@illegal_pushes ||= pushed_refs.select do |pushed_ref|
|
|
22
|
-
(pushed_ref.
|
|
23
|
-
branches.any? { |branch| pushed_ref.remote_ref == "refs/heads/#{branch}" }
|
|
18
|
+
protected?(pushed_ref.remote_ref) && pushed_ref.destructive?
|
|
24
19
|
end
|
|
25
20
|
end
|
|
21
|
+
|
|
22
|
+
def protected?(remote_ref)
|
|
23
|
+
ref_name = remote_ref[%r{refs/heads/(.*)}, 1]
|
|
24
|
+
protected_branch_patterns.any? do |pattern|
|
|
25
|
+
File.fnmatch(pattern, ref_name)
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def protected_branch_patterns
|
|
30
|
+
@protected_branch_patterns ||= Array(config['branches']).
|
|
31
|
+
concat(Array(config['branch_patterns']))
|
|
32
|
+
end
|
|
26
33
|
end
|
|
27
34
|
end
|
|
@@ -79,6 +79,13 @@ module Overcommit::HookContext
|
|
|
79
79
|
[]
|
|
80
80
|
end
|
|
81
81
|
|
|
82
|
+
# Returns the full list of files tracked by git
|
|
83
|
+
#
|
|
84
|
+
# @return [Array<String>]
|
|
85
|
+
def all_files
|
|
86
|
+
Overcommit::GitRepo.all_files
|
|
87
|
+
end
|
|
88
|
+
|
|
82
89
|
# Returns the contents of the entire standard input stream that were passed
|
|
83
90
|
# to the hook.
|
|
84
91
|
#
|
|
@@ -15,6 +15,13 @@ module Overcommit::HookContext
|
|
|
15
15
|
cmd = Overcommit::Utils.parent_command
|
|
16
16
|
amend_pattern = 'commit(\s.*)?\s--amend(\s|$)'
|
|
17
17
|
|
|
18
|
+
# Since the ps command can return invalid byte sequences for commands
|
|
19
|
+
# containing unicode characters, we replace the offending characters,
|
|
20
|
+
# since the pattern we're looking for will consist of ASCII characters
|
|
21
|
+
unless cmd.valid_encoding?
|
|
22
|
+
cmd.encode!('UTF-16be', invalid: :replace, replace: '?').encode!('UTF-8')
|
|
23
|
+
end
|
|
24
|
+
|
|
18
25
|
return @amendment if
|
|
19
26
|
# True if the command is a commit with the --amend flag
|
|
20
27
|
@amendment = !(/\s#{amend_pattern}/ =~ cmd).nil?
|
|
@@ -30,6 +30,10 @@ module Overcommit::HookContext
|
|
|
30
30
|
local_sha1 == '0' * 40
|
|
31
31
|
end
|
|
32
32
|
|
|
33
|
+
def destructive?
|
|
34
|
+
deleted? || forced?
|
|
35
|
+
end
|
|
36
|
+
|
|
33
37
|
def to_s
|
|
34
38
|
"#{local_ref} #{local_sha1} #{remote_ref} #{remote_sha1}"
|
|
35
39
|
end
|
|
@@ -37,7 +41,14 @@ module Overcommit::HookContext
|
|
|
37
41
|
private
|
|
38
42
|
|
|
39
43
|
def overwritten_commits
|
|
40
|
-
|
|
44
|
+
return @overwritten_commits if defined? @overwritten_commits
|
|
45
|
+
result = Overcommit::Subprocess.spawn(%W[git rev-list #{remote_sha1} ^#{local_sha1}])
|
|
46
|
+
if result.success?
|
|
47
|
+
result.stdout.split("\n")
|
|
48
|
+
else
|
|
49
|
+
raise Overcommit::Exceptions::GitRevListError,
|
|
50
|
+
"Unable to check if commits on the remote ref will be overwritten: #{result.stderr}"
|
|
51
|
+
end
|
|
41
52
|
end
|
|
42
53
|
end
|
|
43
54
|
end
|
|
@@ -7,7 +7,7 @@ module Overcommit::HookContext
|
|
|
7
7
|
# which is useful for automated CI scripts.
|
|
8
8
|
class RunAll < Base
|
|
9
9
|
def modified_files
|
|
10
|
-
@modified_files ||=
|
|
10
|
+
@modified_files ||= all_files
|
|
11
11
|
end
|
|
12
12
|
|
|
13
13
|
# Returns all lines in the file since in this context the entire repo is
|