overcommit 0.19.0 → 0.20.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'set'
|
2
|
+
|
3
|
+
module Overcommit::HookContext
|
4
|
+
# Simulates a pre-commit context pretending that all files have been changed.
|
5
|
+
#
|
6
|
+
# This results in pre-commit hooks running against the entire repository,
|
7
|
+
# which is useful for automated CI scripts.
|
8
|
+
class RunAll < Base
|
9
|
+
EMPTY_SET = Set.new
|
10
|
+
|
11
|
+
def modified_files
|
12
|
+
all_files
|
13
|
+
end
|
14
|
+
|
15
|
+
# Return an empty set since in this context the user didn't actually touch
|
16
|
+
# any lines.
|
17
|
+
def modified_lines_in_file(_file)
|
18
|
+
EMPTY_SET
|
19
|
+
end
|
20
|
+
|
21
|
+
def hook_class_name
|
22
|
+
'PreCommit'
|
23
|
+
end
|
24
|
+
|
25
|
+
def hook_type_name
|
26
|
+
'pre_commit'
|
27
|
+
end
|
28
|
+
|
29
|
+
def hook_script_name
|
30
|
+
'pre-commit'
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def all_files
|
36
|
+
@all_files ||= Overcommit::GitRepo.all_files
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -1,12 +1,12 @@
|
|
1
1
|
# Utility module which manages the creation of {HookContext}s.
|
2
2
|
module Overcommit::HookContext
|
3
|
-
def self.create(hook_type, config, args
|
3
|
+
def self.create(hook_type, config, args)
|
4
4
|
hook_type_class = Overcommit::Utils.camel_case(hook_type)
|
5
5
|
underscored_hook_type = Overcommit::Utils.snake_case(hook_type)
|
6
6
|
|
7
7
|
require "overcommit/hook_context/#{underscored_hook_type}"
|
8
8
|
|
9
|
-
Overcommit::HookContext.const_get(hook_type_class).new(config, args
|
9
|
+
Overcommit::HookContext.const_get(hook_type_class).new(config, args)
|
10
10
|
rescue LoadError, NameError => error
|
11
11
|
# Could happen when a symlink was created for a hook type Overcommit does
|
12
12
|
# not yet support.
|
@@ -4,12 +4,10 @@ module Overcommit::HookLoader
|
|
4
4
|
# @param config [Overcommit::Configuration]
|
5
5
|
# @param context [Overcommit::HookContext]
|
6
6
|
# @param logger [Overcommit::Logger]
|
7
|
-
|
8
|
-
def initialize(config, context, logger, input)
|
7
|
+
def initialize(config, context, logger)
|
9
8
|
@config = config
|
10
9
|
@context = context
|
11
10
|
@log = logger
|
12
|
-
@input = input
|
13
11
|
end
|
14
12
|
|
15
13
|
# When implemented in subclasses, loads the hooks for which that subclass is
|
@@ -5,10 +5,7 @@ module Overcommit::HookLoader
|
|
5
5
|
# is running in.
|
6
6
|
class PluginHookLoader < Base
|
7
7
|
def load_hooks
|
8
|
-
|
9
|
-
plugin_paths = Dir[File.join(directory, '*.rb')].sort
|
10
|
-
|
11
|
-
check_for_modified_plugins(plugin_paths) if @config.verify_plugin_signatures?
|
8
|
+
check_for_modified_plugins if @config.verify_plugin_signatures?
|
12
9
|
|
13
10
|
plugin_paths.map do |plugin_path|
|
14
11
|
require plugin_path
|
@@ -18,34 +15,47 @@ module Overcommit::HookLoader
|
|
18
15
|
end
|
19
16
|
end
|
20
17
|
|
18
|
+
def update_signatures
|
19
|
+
log.success('No plugin signatures have changed') if modified_plugins.empty?
|
20
|
+
|
21
|
+
modified_plugins.each do |plugin|
|
22
|
+
plugin.update_signature!
|
23
|
+
log.warning "Updated signature of plugin #{plugin.hook_name}"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
21
27
|
private
|
22
28
|
|
23
|
-
def
|
24
|
-
|
29
|
+
def plugin_paths
|
30
|
+
directory = File.join(@config.plugin_directory, @context.hook_type_name)
|
31
|
+
Dir[File.join(directory, '*.rb')].sort
|
32
|
+
end
|
33
|
+
|
34
|
+
def modified_plugins
|
35
|
+
plugin_paths.
|
25
36
|
map { |path| Overcommit::HookSigner.new(path, @config, @context) }.
|
26
37
|
select(&:signature_changed?)
|
38
|
+
end
|
27
39
|
|
40
|
+
def check_for_modified_plugins
|
28
41
|
return if modified_plugins.empty?
|
29
42
|
|
30
43
|
log.bold_warning "The following #{@context.hook_script_name} plugins " \
|
31
44
|
'have been added, changed, or had their configuration modified:'
|
32
|
-
log.
|
45
|
+
log.newline
|
33
46
|
|
34
47
|
modified_plugins.each do |signer|
|
35
48
|
log.warning " * #{signer.hook_name} in #{signer.hook_path}"
|
36
49
|
end
|
37
50
|
|
38
|
-
log.
|
39
|
-
log.bold_warning 'You should verify the changes
|
51
|
+
log.newline
|
52
|
+
log.bold_warning 'You should verify the changes and then run:'
|
53
|
+
log.newline
|
54
|
+
log.warning "overcommit --sign #{@context.hook_script_name}"
|
55
|
+
log.newline
|
40
56
|
log.log "For more information, see #{Overcommit::REPO_URL}#security"
|
41
|
-
log.log
|
42
|
-
log.partial 'Continue? (y/n) '
|
43
|
-
|
44
|
-
unless (answer = @input.get) && answer.strip.downcase.start_with?('y')
|
45
|
-
raise Overcommit::Exceptions::HookCancelled
|
46
|
-
end
|
47
57
|
|
48
|
-
|
58
|
+
raise Overcommit::Exceptions::InvalidHookSignature
|
49
59
|
end
|
50
60
|
end
|
51
61
|
end
|
@@ -5,12 +5,11 @@ module Overcommit
|
|
5
5
|
# @param config [Overcommit::Configuration]
|
6
6
|
# @param logger [Overcommit::Logger]
|
7
7
|
# @param context [Overcommit::HookContext]
|
8
|
-
# @param
|
9
|
-
def initialize(config, logger, context,
|
8
|
+
# @param printer [Overcommit::Printer]
|
9
|
+
def initialize(config, logger, context, printer)
|
10
10
|
@config = config
|
11
11
|
@log = logger
|
12
12
|
@context = context
|
13
|
-
@input = input
|
14
13
|
@printer = printer
|
15
14
|
@hooks = []
|
16
15
|
end
|
@@ -36,7 +35,7 @@ module Overcommit
|
|
36
35
|
attr_reader :log
|
37
36
|
|
38
37
|
def run_hooks
|
39
|
-
if @hooks.any?
|
38
|
+
if @hooks.any?(&:enabled?)
|
40
39
|
@printer.start_run
|
41
40
|
|
42
41
|
interrupted = false
|
@@ -54,7 +53,7 @@ module Overcommit
|
|
54
53
|
end
|
55
54
|
end
|
56
55
|
|
57
|
-
|
56
|
+
print_results(run_failed, interrupted)
|
58
57
|
|
59
58
|
!(run_failed || interrupted)
|
60
59
|
else
|
@@ -63,6 +62,16 @@ module Overcommit
|
|
63
62
|
end
|
64
63
|
end
|
65
64
|
|
65
|
+
def print_results(failed, interrupted)
|
66
|
+
if interrupted
|
67
|
+
@printer.run_interrupted
|
68
|
+
elsif failed
|
69
|
+
@printer.run_failed
|
70
|
+
else
|
71
|
+
@printer.run_succeeded
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
66
75
|
def run_hook(hook)
|
67
76
|
return if should_skip?(hook)
|
68
77
|
|
@@ -79,7 +88,7 @@ module Overcommit
|
|
79
88
|
end
|
80
89
|
rescue => ex
|
81
90
|
status = :fail
|
82
|
-
output = "Hook raised unexpected error\n#{ex.message}"
|
91
|
+
output = "Hook raised unexpected error\n#{ex.message}\n#{ex.backtrace.join("\n")}"
|
83
92
|
rescue Interrupt
|
84
93
|
# At this point, interrupt has been handled and protection is back in
|
85
94
|
# effect thanks to the InterruptHandler.
|
@@ -99,7 +108,8 @@ module Overcommit
|
|
99
108
|
if hook.required?
|
100
109
|
@printer.required_hook_not_skipped(hook)
|
101
110
|
else
|
102
|
-
|
111
|
+
# Tell user if hook was skipped only if it actually would have run
|
112
|
+
@printer.hook_skipped(hook) if hook.run?
|
103
113
|
return true
|
104
114
|
end
|
105
115
|
end
|
@@ -110,10 +120,10 @@ module Overcommit
|
|
110
120
|
def load_hooks
|
111
121
|
require "overcommit/hook/#{@context.hook_type_name}/base"
|
112
122
|
|
113
|
-
@hooks += HookLoader::BuiltInHookLoader.new(@config, @context, @log
|
123
|
+
@hooks += HookLoader::BuiltInHookLoader.new(@config, @context, @log).load_hooks
|
114
124
|
|
115
125
|
# Load plugin hooks after so they can subclass existing hooks
|
116
|
-
@hooks += HookLoader::PluginHookLoader.new(@config, @context, @log
|
126
|
+
@hooks += HookLoader::PluginHookLoader.new(@config, @context, @log).load_hooks
|
117
127
|
end
|
118
128
|
end
|
119
129
|
end
|
data/lib/overcommit/installer.rb
CHANGED
@@ -3,8 +3,8 @@ require 'fileutils'
|
|
3
3
|
module Overcommit
|
4
4
|
# Manages the installation of Overcommit hooks in a git repository.
|
5
5
|
class Installer # rubocop:disable ClassLength
|
6
|
-
|
7
|
-
|
6
|
+
TEMPLATE_DIRECTORY = File.join(OVERCOMMIT_HOME, 'template-dir')
|
7
|
+
MASTER_HOOK = File.join(TEMPLATE_DIRECTORY, 'hooks', 'overcommit-hook')
|
8
8
|
|
9
9
|
def initialize(logger)
|
10
10
|
@log = logger
|
@@ -115,13 +115,15 @@ module Overcommit
|
|
115
115
|
def can_replace_file?(file)
|
116
116
|
@options[:force] ||
|
117
117
|
!File.exist?(file) ||
|
118
|
-
|
118
|
+
overcommit_hook?(file)
|
119
119
|
end
|
120
120
|
|
121
121
|
def uninstall_hook_symlinks
|
122
|
+
return unless File.directory?(hooks_path)
|
123
|
+
|
122
124
|
Dir.chdir(hooks_path) do
|
123
125
|
Overcommit::Utils.supported_hook_types.each do |hook_type|
|
124
|
-
FileUtils.rm_rf(hook_type) if
|
126
|
+
FileUtils.rm_rf(hook_type) if overcommit_hook?(hook_type)
|
125
127
|
end
|
126
128
|
end
|
127
129
|
end
|
@@ -133,7 +135,9 @@ module Overcommit
|
|
133
135
|
FileUtils.cp(File.join(OVERCOMMIT_HOME, 'config', 'starter.yml'), repo_config_file)
|
134
136
|
end
|
135
137
|
|
136
|
-
def
|
138
|
+
def overcommit_hook?(file)
|
139
|
+
return true if File.read(file) =~ /OVERCOMMIT_DISABLE/
|
140
|
+
# TODO: Remove these checks once we hit version 1.0
|
137
141
|
File.symlink?(file) && File.readlink(file) == 'overcommit-hook'
|
138
142
|
rescue Errno::ENOENT
|
139
143
|
# Some Ruby implementations (e.g. JRuby) raise an error when the file
|
data/lib/overcommit/logger.rb
CHANGED
@@ -6,44 +6,71 @@ module Overcommit
|
|
6
6
|
new(File.open('/dev/null', 'w'))
|
7
7
|
end
|
8
8
|
|
9
|
+
# Creates a logger that will write to the given output stream.
|
10
|
+
#
|
11
|
+
# @param out [IO]
|
9
12
|
def initialize(out)
|
10
13
|
@out = out
|
11
14
|
end
|
12
15
|
|
16
|
+
# Write output without a trailing newline.
|
13
17
|
def partial(*args)
|
14
18
|
@out.print(*args)
|
15
19
|
end
|
16
20
|
|
21
|
+
# Prints a newline character (alias for readability).
|
22
|
+
def newline
|
23
|
+
log
|
24
|
+
end
|
25
|
+
|
26
|
+
# Write a line of output.
|
27
|
+
#
|
28
|
+
# A newline character will always be appended.
|
17
29
|
def log(*args)
|
18
30
|
@out.puts(*args)
|
19
31
|
end
|
20
32
|
|
33
|
+
# Write a line of output that is intended to be emphasized.
|
21
34
|
def bold(*args)
|
22
35
|
color('1', *args)
|
23
36
|
end
|
24
37
|
|
38
|
+
# Write a line of output indicating a problem or error.
|
25
39
|
def error(*args)
|
26
40
|
color(31, *args)
|
27
41
|
end
|
28
42
|
|
43
|
+
# Write a line of output indicating a problem or error which is emphasized
|
44
|
+
# over a regular problem or error.
|
29
45
|
def bold_error(*args)
|
30
46
|
color('1;31', *args)
|
31
47
|
end
|
32
48
|
|
49
|
+
# Write a line of output indicating a successful or noteworthy event.
|
33
50
|
def success(*args)
|
34
51
|
color(32, *args)
|
35
52
|
end
|
36
53
|
|
54
|
+
# Write a line of output indicating a potential cause for concern, but not
|
55
|
+
# an actual error.
|
37
56
|
def warning(*args)
|
38
57
|
color(33, *args)
|
39
58
|
end
|
40
59
|
|
60
|
+
# Write a line of output indicating a potential cause for concern, but with
|
61
|
+
# greater emphasize compared to other warnings.
|
41
62
|
def bold_warning(*args)
|
42
63
|
color('1;33', *args)
|
43
64
|
end
|
44
65
|
|
45
66
|
private
|
46
67
|
|
68
|
+
# Outputs text wrapped in ANSI escape code necessary to produce a given
|
69
|
+
# color/text display.
|
70
|
+
#
|
71
|
+
# @param code [String] ANSI escape code, e.g. '1;33' for "bold yellow"
|
72
|
+
# @param str [String] string to wrap
|
73
|
+
# @param partial [true,false] whether to omit a newline
|
47
74
|
def color(code, str, partial = false)
|
48
75
|
send(partial ? :partial : :log,
|
49
76
|
@out.tty? ? "\033[#{code}m#{str}\033[0m" : str)
|
@@ -0,0 +1,132 @@
|
|
1
|
+
module Overcommit
|
2
|
+
# Utility class that encapsulates the handling of hook messages and whether
|
3
|
+
# they affect lines the user has modified or not.
|
4
|
+
#
|
5
|
+
# This class exposes an endpoint that extracts an appropriate hook/status
|
6
|
+
# output tuple from an array of {Overcommit::Hook::Message}s, respecting the
|
7
|
+
# configuration settings for the given hook.
|
8
|
+
class MessageProcessor
|
9
|
+
ERRORS_MODIFIED_HEADER = 'Errors on modified lines:'
|
10
|
+
WARNINGS_MODIFIED_HEADER = 'Warnings on modified lines:'
|
11
|
+
ERRORS_UNMODIFIED_HEADER = "Errors on lines you didn't modify:"
|
12
|
+
WARNINGS_UNMODIFIED_HEADER = "Warnings on lines you didn't modify:"
|
13
|
+
|
14
|
+
# @param hook [Overcommit::Hook::Base]
|
15
|
+
# @param unmodified_lines_setting [String] how to treat messages on
|
16
|
+
# unmodified lines
|
17
|
+
def initialize(hook, unmodified_lines_setting)
|
18
|
+
@hook = hook
|
19
|
+
@setting = unmodified_lines_setting
|
20
|
+
end
|
21
|
+
|
22
|
+
# Returns a hook status/output tuple from the messages this processor was
|
23
|
+
# initialized with.
|
24
|
+
#
|
25
|
+
# @return [Array<Symbol,String>]
|
26
|
+
def hook_result(messages)
|
27
|
+
status, output = basic_status_and_output(messages)
|
28
|
+
|
29
|
+
# Nothing to do if there are no problems to begin with
|
30
|
+
return [status, output] if status == :pass
|
31
|
+
|
32
|
+
# Return as-is if this type of hook doesn't have the concept of modified lines
|
33
|
+
return [status, output] unless @hook.respond_to?(:modified_lines_in_file)
|
34
|
+
|
35
|
+
handle_modified_lines(messages, status)
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
def handle_modified_lines(messages, status)
|
41
|
+
messages = remove_ignored_messages(messages)
|
42
|
+
|
43
|
+
messages_on_modified_lines, messages_on_unmodified_lines =
|
44
|
+
messages.partition { |message| message_on_modified_line?(message) }
|
45
|
+
|
46
|
+
output = print_messages(
|
47
|
+
messages_on_modified_lines,
|
48
|
+
ERRORS_MODIFIED_HEADER,
|
49
|
+
WARNINGS_MODIFIED_HEADER
|
50
|
+
)
|
51
|
+
output += print_messages(
|
52
|
+
messages_on_unmodified_lines,
|
53
|
+
ERRORS_UNMODIFIED_HEADER,
|
54
|
+
WARNINGS_UNMODIFIED_HEADER
|
55
|
+
)
|
56
|
+
|
57
|
+
[transform_status(status, messages_on_modified_lines), output]
|
58
|
+
end
|
59
|
+
|
60
|
+
def transform_status(status, messages_on_modified_lines)
|
61
|
+
# `report` indicates user wants the original status
|
62
|
+
return status if @setting == 'report'
|
63
|
+
|
64
|
+
error_messages, warning_messages =
|
65
|
+
messages_on_modified_lines.partition { |msg| msg.type == :error }
|
66
|
+
|
67
|
+
if can_upgrade_to_warning?(status, error_messages)
|
68
|
+
status = :warn
|
69
|
+
end
|
70
|
+
|
71
|
+
if can_upgrade_to_passing?(status, warning_messages)
|
72
|
+
status = :pass
|
73
|
+
end
|
74
|
+
|
75
|
+
status
|
76
|
+
end
|
77
|
+
|
78
|
+
def can_upgrade_to_warning?(status, error_messages)
|
79
|
+
status == :fail && error_messages.empty?
|
80
|
+
end
|
81
|
+
|
82
|
+
def can_upgrade_to_passing?(status, warning_messages)
|
83
|
+
status == :warn && @setting == 'ignore' && warning_messages.empty?
|
84
|
+
end
|
85
|
+
|
86
|
+
# Returns status and output for messages assuming no special treatment of
|
87
|
+
# messages occurring on unmodified lines.
|
88
|
+
def basic_status_and_output(messages)
|
89
|
+
status =
|
90
|
+
if messages.any? { |message| message.type == :error }
|
91
|
+
:fail
|
92
|
+
elsif messages.any? { |message| message.type == :warning }
|
93
|
+
:warn
|
94
|
+
else
|
95
|
+
:pass
|
96
|
+
end
|
97
|
+
|
98
|
+
output = ''
|
99
|
+
if messages.any?
|
100
|
+
output += messages.join("\n") + "\n"
|
101
|
+
end
|
102
|
+
|
103
|
+
[status, output]
|
104
|
+
end
|
105
|
+
|
106
|
+
def print_messages(messages, error_heading, warning_heading)
|
107
|
+
output = ''
|
108
|
+
errors, warnings = messages.partition { |msg| msg.type == :error }
|
109
|
+
|
110
|
+
if errors.any?
|
111
|
+
output += "#{error_heading}\n#{errors.join("\n")}\n"
|
112
|
+
end
|
113
|
+
|
114
|
+
if warnings.any?
|
115
|
+
output += "#{warning_heading}\n#{warnings.join("\n")}\n"
|
116
|
+
end
|
117
|
+
|
118
|
+
output
|
119
|
+
end
|
120
|
+
|
121
|
+
def remove_ignored_messages(messages)
|
122
|
+
# If user wants to ignore messages on unmodified lines, simply remove them
|
123
|
+
return messages unless @setting == 'ignore'
|
124
|
+
|
125
|
+
messages.select { |message| message_on_modified_line?(message) }
|
126
|
+
end
|
127
|
+
|
128
|
+
def message_on_modified_line?(message)
|
129
|
+
@hook.modified_lines_in_file(message.file).include?(message.line)
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
data/lib/overcommit/printer.rb
CHANGED
@@ -20,21 +20,6 @@ module Overcommit
|
|
20
20
|
log.success "✓ No applicable #{hook_script_name} hooks to run"
|
21
21
|
end
|
22
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
23
|
# Executed at the start of an individual hook run.
|
39
24
|
def start_hook(hook)
|
40
25
|
unless hook.quiet?
|
@@ -59,6 +44,27 @@ module Overcommit
|
|
59
44
|
print_result(hook, status, output)
|
60
45
|
end
|
61
46
|
|
47
|
+
# Executed when a hook run was interrupted/cancelled by user.
|
48
|
+
def run_interrupted
|
49
|
+
log.newline
|
50
|
+
log.warning '⚠ Hook run interrupted by user'
|
51
|
+
log.newline
|
52
|
+
end
|
53
|
+
|
54
|
+
# Executed when one or more hooks by the end of the run.
|
55
|
+
def run_failed
|
56
|
+
log.newline
|
57
|
+
log.error "✗ One or more #{hook_script_name} hooks failed"
|
58
|
+
log.newline
|
59
|
+
end
|
60
|
+
|
61
|
+
# Executed when no hooks failed by the end of the run.
|
62
|
+
def run_succeeded
|
63
|
+
log.newline
|
64
|
+
log.success "✓ All #{hook_script_name} hooks passed"
|
65
|
+
log.newline
|
66
|
+
end
|
67
|
+
|
62
68
|
private
|
63
69
|
|
64
70
|
def print_header(hook)
|
@@ -103,18 +109,6 @@ module Overcommit
|
|
103
109
|
log.send(format, output) unless output.nil? || output.empty?
|
104
110
|
end
|
105
111
|
|
106
|
-
def run_interrupted
|
107
|
-
log.warning '⚠ Hook run interrupted by user'
|
108
|
-
end
|
109
|
-
|
110
|
-
def run_failed
|
111
|
-
log.error "✗ One or more #{hook_script_name} hooks failed"
|
112
|
-
end
|
113
|
-
|
114
|
-
def run_succeeded
|
115
|
-
log.success "✓ All #{hook_script_name} hooks passed"
|
116
|
-
end
|
117
|
-
|
118
112
|
def hook_script_name
|
119
113
|
@context.hook_script_name
|
120
114
|
end
|
@@ -6,32 +6,41 @@ module Overcommit
|
|
6
6
|
# standard out/error output.
|
7
7
|
class Subprocess
|
8
8
|
# Encapsulates the result of a process.
|
9
|
-
Result = Struct.new(:status, :
|
9
|
+
Result = Struct.new(:status, :stdout, :stderr) do
|
10
10
|
def success?
|
11
11
|
status == 0
|
12
12
|
end
|
13
13
|
end
|
14
14
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
15
|
+
class << self
|
16
|
+
# Spawns a new process using the given array of arguments (the first
|
17
|
+
# element is the command).
|
18
|
+
def spawn(args)
|
19
|
+
process = ChildProcess.build(*args)
|
19
20
|
|
20
|
-
|
21
|
-
err.sync = true
|
22
|
-
out = ::Tempfile.new('out')
|
23
|
-
out.sync = true
|
21
|
+
out, err = assign_output_streams(process)
|
24
22
|
|
25
|
-
|
26
|
-
|
23
|
+
process.start
|
24
|
+
process.wait
|
27
25
|
|
28
|
-
|
29
|
-
|
26
|
+
err.rewind
|
27
|
+
out.rewind
|
30
28
|
|
31
|
-
|
32
|
-
|
29
|
+
Result.new(process.exit_code, out.read, err.read)
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
33
|
|
34
|
-
|
34
|
+
# @param process [ChildProcess]
|
35
|
+
# @return [Array<IO>]
|
36
|
+
def assign_output_streams(process)
|
37
|
+
%w[out err].map do |stream_name|
|
38
|
+
::Tempfile.new(stream_name).tap do |stream|
|
39
|
+
stream.sync = true
|
40
|
+
process.io.send("std#{stream_name}=", stream)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
35
44
|
end
|
36
45
|
end
|
37
46
|
end
|
data/lib/overcommit/utils.rb
CHANGED
@@ -132,6 +132,26 @@ module Overcommit
|
|
132
132
|
# symlinks, so we need use File.size?
|
133
133
|
File.symlink?(file) && File.size?(file).nil?
|
134
134
|
end
|
135
|
+
|
136
|
+
# Convert a glob pattern to an absolute path glob pattern rooted from the
|
137
|
+
# repository root directory.
|
138
|
+
#
|
139
|
+
# @param glob [String]
|
140
|
+
# @return [String]
|
141
|
+
def convert_glob_to_absolute(glob)
|
142
|
+
File.join(repo_root, glob)
|
143
|
+
end
|
144
|
+
|
145
|
+
# Return whether a pattern matches the given path.
|
146
|
+
#
|
147
|
+
# @param pattern [String]
|
148
|
+
# @param path [String]
|
149
|
+
def matches_path?(pattern, path)
|
150
|
+
File.fnmatch?(pattern, path,
|
151
|
+
File::FNM_PATHNAME | # Wildcard doesn't match separator
|
152
|
+
File::FNM_DOTMATCH # Wildcards match dotfiles
|
153
|
+
)
|
154
|
+
end
|
135
155
|
end
|
136
156
|
end
|
137
157
|
end
|
data/lib/overcommit/version.rb
CHANGED
data/lib/overcommit.rb
CHANGED
@@ -6,7 +6,6 @@ require 'overcommit/configuration_loader'
|
|
6
6
|
require 'overcommit/hook/base'
|
7
7
|
require 'overcommit/hook_context/base'
|
8
8
|
require 'overcommit/hook_context'
|
9
|
-
require 'overcommit/user_input'
|
10
9
|
require 'overcommit/git_repo'
|
11
10
|
require 'overcommit/hook_signer'
|
12
11
|
require 'overcommit/hook_loader/base'
|