rabbitt-githooks 1.3.2 → 1.4.1
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/CONTRIBUTORS.txt +2 -0
- data/Gemfile.lock +3 -3
- data/bin/githooks +2 -4
- data/bin/githooks-runner +9 -13
- data/lib/githooks/action.rb +21 -10
- data/lib/githooks/{commands → cli}/config.rb +4 -4
- data/lib/githooks/cli.rb +18 -9
- data/lib/githooks/core_ext/array/extract_options.rb +18 -0
- data/lib/githooks/core_ext/array/select_with_index.rb +18 -0
- data/lib/githooks/core_ext/array.rb +18 -0
- data/lib/githooks/core_ext/numbers.rb +18 -0
- data/lib/githooks/core_ext/object.rb +18 -0
- data/lib/githooks/core_ext/ostruct.rb +44 -0
- data/lib/githooks/core_ext/pathname.rb +28 -0
- data/lib/githooks/core_ext/rainbow.rb +40 -0
- data/lib/githooks/core_ext/string/git_option_path_split.rb +18 -0
- data/lib/githooks/core_ext/string/inflections.rb +18 -0
- data/lib/githooks/core_ext/string/sanitize.rb +18 -0
- data/lib/githooks/core_ext/string.rb +18 -0
- data/lib/githooks/core_ext.rb +2 -1
- data/lib/githooks/hook.rb +36 -13
- data/lib/githooks/repository/config.rb +1 -1
- data/lib/githooks/repository/diff_index_entry.rb +2 -2
- data/lib/githooks/repository.rb +10 -5
- data/lib/githooks/runner.rb +100 -94
- data/lib/githooks/section.rb +34 -8
- data/lib/githooks/system_utils.rb +36 -19
- data/lib/githooks/version.rb +1 -1
- data/lib/githooks.rb +5 -6
- data/rabbitt-githooks.gemspec +34 -33
- metadata +10 -8
- data/lib/githooks/core_ext/colorize.rb +0 -30
data/lib/githooks/hook.rb
CHANGED
@@ -22,7 +22,7 @@ require_relative 'system_utils'
|
|
22
22
|
|
23
23
|
module GitHooks
|
24
24
|
class Hook
|
25
|
-
VALID_PHASES = %w{ pre-commit commit-msg }.freeze
|
25
|
+
VALID_PHASES = %w{ pre-commit commit-msg }.freeze unless defined? VALID_PHASES
|
26
26
|
|
27
27
|
@__phases__ = {}
|
28
28
|
@__mutex__ = Mutex.new
|
@@ -61,19 +61,19 @@ module GitHooks
|
|
61
61
|
end
|
62
62
|
end
|
63
63
|
|
64
|
-
attr_reader :sections, :phase, :repository, :repository_path
|
64
|
+
attr_reader :sections, :phase, :repository, :repository_path, :limiters
|
65
65
|
attr_accessor :args, :staged, :untracked, :tracked
|
66
66
|
|
67
67
|
def initialize(phase)
|
68
|
-
@phase
|
69
|
-
@sections
|
70
|
-
@
|
71
|
-
@
|
72
|
-
@
|
73
|
-
@
|
74
|
-
@
|
75
|
-
|
76
|
-
|
68
|
+
@phase = phase.to_s
|
69
|
+
@sections = {}
|
70
|
+
@limiters = {}
|
71
|
+
@commands = []
|
72
|
+
@args = []
|
73
|
+
@staged = true
|
74
|
+
@tracked = false
|
75
|
+
@untracked = false
|
76
|
+
@repository = Repository.new(Dir.getwd)
|
77
77
|
end
|
78
78
|
|
79
79
|
def [](name)
|
@@ -117,6 +117,29 @@ module GitHooks
|
|
117
117
|
|
118
118
|
# DSL methods
|
119
119
|
|
120
|
+
def config_path
|
121
|
+
GitHooks.hooks_root.join('configs')
|
122
|
+
end
|
123
|
+
|
124
|
+
def config_file(*path_components)
|
125
|
+
config_path.join(*path_components)
|
126
|
+
end
|
127
|
+
|
128
|
+
def lib_path
|
129
|
+
GitHooks.hooks_root.join('lib')
|
130
|
+
end
|
131
|
+
|
132
|
+
def lib_file(*path_components)
|
133
|
+
lib_path.join(*path_components)
|
134
|
+
end
|
135
|
+
|
136
|
+
def limit(type)
|
137
|
+
unless @limiters.include? type
|
138
|
+
@limiters[type] ||= Repository::Limiter.new(type)
|
139
|
+
end
|
140
|
+
@limiters[type]
|
141
|
+
end
|
142
|
+
|
120
143
|
def command(name, options = {})
|
121
144
|
setup_command name, options
|
122
145
|
end
|
@@ -160,8 +183,8 @@ module GitHooks
|
|
160
183
|
|
161
184
|
def filter(limiters)
|
162
185
|
manifest.dup.tap do |files|
|
163
|
-
limiters.each do |limiter|
|
164
|
-
puts "Limiter [#{
|
186
|
+
limiters.each do |type, limiter|
|
187
|
+
puts "Limiter [#{type}] -> (#{limiter.only.inspect}) match against: " if GitHooks.debug?
|
165
188
|
limiter.limit(files)
|
166
189
|
end
|
167
190
|
end
|
@@ -18,8 +18,8 @@ module GitHooks
|
|
18
18
|
|
19
19
|
def self.from_file_path(path, tracked = false)
|
20
20
|
path = Pathname.new(path)
|
21
|
-
entry_line =
|
22
|
-
|
21
|
+
entry_line = format(":%06o %06o %040x %040x %s\t%s",
|
22
|
+
0, path.stat.mode, 0, 0, (tracked ? '^' : '?'), path.to_s)
|
23
23
|
new(entry_line)
|
24
24
|
end
|
25
25
|
|
data/lib/githooks/repository.rb
CHANGED
@@ -59,15 +59,17 @@ module GitHooks
|
|
59
59
|
instance.public_send(method, *args, &block)
|
60
60
|
end
|
61
61
|
|
62
|
-
attr_reader :
|
62
|
+
attr_reader :path, :hooks
|
63
|
+
alias_method :path, :path
|
63
64
|
|
64
65
|
def initialize(path = Dir.getwd)
|
65
|
-
@
|
66
|
+
@path = get_root_path(path)
|
67
|
+
@hooks = Pathname.new(@path).join('.git', 'hooks')
|
66
68
|
end
|
67
69
|
protected :initialize
|
68
70
|
|
69
71
|
def config
|
70
|
-
@config ||= Repository::Config.new(
|
72
|
+
@config ||= Repository::Config.new(path)
|
71
73
|
end
|
72
74
|
|
73
75
|
def get_root_path(path)
|
@@ -140,10 +142,13 @@ module GitHooks
|
|
140
142
|
cmd << (options.delete(:ref) || 'HEAD')
|
141
143
|
end
|
142
144
|
|
143
|
-
git(*cmd.
|
145
|
+
git(*cmd.flatten.compact).output_lines.collect do |diff_data|
|
144
146
|
DiffIndexEntry.new(diff_data).to_repo_file
|
145
147
|
end
|
146
|
-
rescue
|
148
|
+
rescue StandardError => e
|
149
|
+
puts 'Error Encountered while acquiring manifest'
|
150
|
+
puts "Command: git #{cmd.flatten.compact.join(' ')}"
|
151
|
+
puts "Error: #{e.class.name}: #{e.message}: #{e.backtrace[0..5].join("\n\t")}"
|
147
152
|
exit! 1
|
148
153
|
end
|
149
154
|
|
data/lib/githooks/runner.rb
CHANGED
@@ -27,75 +27,68 @@ require_relative 'repository'
|
|
27
27
|
require_relative 'system_utils'
|
28
28
|
|
29
29
|
module GitHooks
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
options = Thor::CoreExt::HashWithIndifferentAccess.new(options)
|
34
|
-
|
35
|
-
options['staged'] = options['staged'].nil? ? true : options['staged']
|
30
|
+
class Runner # rubocop:disable Metrics/ClassLength
|
31
|
+
attr_reader :repository, :script, :hook_path, :repo_path, :options
|
32
|
+
private :repository, :script, :hook_path, :repo_path, :options
|
36
33
|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
34
|
+
def initialize(options = {}) # rubocop:disable Metrics/AbcSize
|
35
|
+
@repo_path = Pathname.new(options.delete('repo') || Repository.path)
|
36
|
+
@repository = Repository.instance(@repo_path)
|
37
|
+
@hook_path = acquire_hooks_path(options.delete('path') || @repository.config.path || @repository.path)
|
38
|
+
@script = options.delete('script') || @repository.config.script
|
39
|
+
@options = IndifferentAccessOpenStruct.new(options)
|
41
40
|
|
42
41
|
GitHooks.verbose = !!ENV['GITHOOKS_VERBOSE']
|
43
42
|
GitHooks.debug = !!ENV['GITHOOKS_DEBUG']
|
43
|
+
end
|
44
44
|
|
45
|
-
|
45
|
+
# rubocop:disable CyclomaticComplexity, MethodLength, AbcSize, PerceivedComplexity
|
46
|
+
def run
|
47
|
+
options.staged = options.staged.nil? ? true : options.staged
|
48
|
+
|
49
|
+
if options.skip_pre
|
46
50
|
puts 'Skipping PreRun Executables'
|
47
51
|
else
|
48
|
-
run_externals('pre-run-execute'
|
52
|
+
run_externals('pre-run-execute')
|
49
53
|
end
|
50
54
|
|
51
|
-
if script && !(options
|
55
|
+
if script && !(options.ignore_script || GitHooks.ignore_script)
|
52
56
|
command = "#{script} #{Pathname.new($0)} #{Shellwords.join(ARGV)};"
|
53
57
|
puts "Kernel#exec(#{command.inspect})" if GitHooks.verbose
|
54
58
|
exec(command)
|
55
|
-
elsif
|
56
|
-
load_tests(
|
57
|
-
start
|
59
|
+
elsif hook_path
|
60
|
+
load_tests(hook_path, options.skip_bundler)
|
61
|
+
start
|
58
62
|
else
|
59
|
-
puts %q"I can't figure out what to run
|
63
|
+
puts %q"I can't figure out what to run! Specify either path or script to give me a hint..."
|
60
64
|
end
|
61
65
|
|
62
|
-
if options
|
66
|
+
if options.skip_post
|
63
67
|
puts 'Skipping PostRun Executables'
|
64
68
|
else
|
65
|
-
run_externals('post-run-execute'
|
69
|
+
run_externals('post-run-execute')
|
66
70
|
end
|
67
71
|
rescue GitHooks::Error::NotAGitRepo => e
|
68
72
|
puts "Unable to find a valid git repo in #{repo}."
|
69
73
|
puts 'Please specify path to repo via --repo <path>' if GitHooks::SCRIPT_NAME == 'githooks'
|
70
74
|
raise e
|
71
75
|
end
|
72
|
-
module_function :run
|
73
|
-
|
74
|
-
def attach(options = {})
|
75
|
-
repo_path = options[:repo] || Repository.root_path
|
76
|
-
repo_path = Pathname.new(repo_path) unless repo_path.nil?
|
77
|
-
repo_hooks = repo_path.join('.git', 'hooks')
|
78
|
-
entry_path = options[:script] || options[:path]
|
79
76
|
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
bootstrapper = options
|
84
|
-
bootstrapper = Pathname.new(bootstrapper).realpath unless bootstrapper.nil?
|
85
|
-
entry_path = Pathname.new(entry_path).realdirpath
|
86
|
-
|
87
|
-
repo = Repository.instance(repo_path)
|
77
|
+
def attach
|
78
|
+
entry_path = Pathname.new(options.script || options.path).realdirpath
|
79
|
+
hook_phases = options.hooks || Hook::VALID_PHASES
|
80
|
+
bootstrapper = Pathname.new(options.bootstrap).realpath if options.bootstrap
|
88
81
|
|
89
82
|
if entry_path.directory?
|
90
|
-
if path =
|
83
|
+
if path = repository.config['path'] # rubocop:disable AssignmentInCondition
|
91
84
|
fail Error::AlreadyAttached, "Repository [#{repo_path}] already attached to path #{path} - Detach to continue."
|
92
85
|
end
|
93
|
-
|
86
|
+
repository.config.set('path', entry_path)
|
94
87
|
elsif entry_path.executable?
|
95
|
-
if path =
|
88
|
+
if path = repository.config['script'] # rubocop:disable AssignmentInCondition
|
96
89
|
fail Error::AlreadyAttached, "Repository [#{repo_path}] already attached to script #{path}. Detach to continue."
|
97
90
|
end
|
98
|
-
|
91
|
+
repository.config.set('script', entry_path)
|
99
92
|
else
|
100
93
|
fail ArgumentError, "Provided path '#{entry_path}' is neither a directory nor an executable file."
|
101
94
|
end
|
@@ -105,49 +98,35 @@ module GitHooks
|
|
105
98
|
gitrunner ||= (GitHooks::BIN_PATH + 'githooks-runner').realpath
|
106
99
|
|
107
100
|
hook_phases.each do |hook|
|
108
|
-
hook = (
|
101
|
+
hook = (@repository.hooks + hook).to_s
|
109
102
|
puts "Linking #{gitrunner} -> #{hook}" if GitHooks.verbose
|
110
103
|
FileUtils.ln_sf gitrunner.to_s, hook
|
111
104
|
end
|
112
105
|
end
|
113
|
-
module_function :attach
|
114
|
-
|
115
|
-
def detach(repo_path, hook_phases)
|
116
|
-
repo_path ||= Repository.root_path
|
117
|
-
repo_hooks = Pathname.new(repo_path).join('.git', 'hooks')
|
118
|
-
hook_phases ||= Hook::VALID_PHASES
|
119
106
|
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
puts "Removing hook '#{hook}' from repository at: #{repo_path}" if GitHooks.verbose
|
107
|
+
def detach(hook_phases = nil)
|
108
|
+
(hook_phases || Hook::VALID_PHASES).each do |hook|
|
109
|
+
next unless (repo_hook = (@repository.hooks + hook)).symlink?
|
110
|
+
puts "Removing hook '#{hook}' from repository at: #{repository.path}" if GitHooks.verbose
|
125
111
|
FileUtils.rm_f repo_hook
|
126
112
|
end
|
127
113
|
|
128
|
-
active_hooks = Hook::VALID_PHASES.select { |hook| (
|
114
|
+
active_hooks = Hook::VALID_PHASES.select { |hook| (@repository.hooks + hook).exist? }
|
129
115
|
|
130
116
|
if active_hooks.empty?
|
131
117
|
puts 'All hooks detached. Removing configuration section.'
|
132
|
-
repo.config.remove_section(repo_path:
|
118
|
+
repo.config.remove_section(repo_path: repository.path)
|
133
119
|
else
|
134
120
|
puts "Keeping configuration for active hooks: #{active_hooks.join(', ')}"
|
135
121
|
end
|
136
122
|
end
|
137
|
-
module_function :detach
|
138
|
-
|
139
|
-
def list(repo_path)
|
140
|
-
repo_path ||= Pathname.new(Repository.root_path)
|
141
123
|
|
142
|
-
|
143
|
-
script
|
144
|
-
libpath = repo.config.path
|
145
|
-
|
146
|
-
unless script || libpath
|
124
|
+
def list
|
125
|
+
unless script || hook_path
|
147
126
|
fail Error::NotAttached, 'Repository currently not configured. Usage attach to setup for use with githooks.'
|
148
127
|
end
|
149
128
|
|
150
|
-
if (executables =
|
129
|
+
if (executables = repository.config.pre_run_execute).size > 0
|
151
130
|
puts 'PreRun Executables (in execution order):'
|
152
131
|
puts executables.collect { |exe| " #{exe}" }.join("\n")
|
153
132
|
puts
|
@@ -159,13 +138,13 @@ module GitHooks
|
|
159
138
|
puts
|
160
139
|
end
|
161
140
|
|
162
|
-
if
|
141
|
+
if hook_path
|
163
142
|
puts 'Main Testing Library with Tests (in execution order):'
|
164
143
|
puts ' Tests loaded from:'
|
165
|
-
puts " #{
|
144
|
+
puts " #{hook_path}"
|
166
145
|
puts
|
167
146
|
|
168
|
-
SystemUtils.quiet { load_tests(
|
147
|
+
SystemUtils.quiet { load_tests(hook_path, true) }
|
169
148
|
|
170
149
|
%w{ pre-commit commit-msg }.each do |phase|
|
171
150
|
next unless Hook.phases[phase]
|
@@ -173,7 +152,7 @@ module GitHooks
|
|
173
152
|
puts " Phase #{phase.camelize}:"
|
174
153
|
Hook.phases[phase].sections.each_with_index do |section, section_index|
|
175
154
|
printf " %3d: %s\n", section_index + 1, section.title
|
176
|
-
section.
|
155
|
+
section.actions.each_with_index do |action, action_index|
|
177
156
|
printf " %3d: %s\n", action_index + 1, action.title
|
178
157
|
action.limiters.each_with_index do |limiter, limiter_index|
|
179
158
|
type, value = limiter.type.inspect, limiter.only
|
@@ -187,7 +166,7 @@ module GitHooks
|
|
187
166
|
puts
|
188
167
|
end
|
189
168
|
|
190
|
-
if (executables =
|
169
|
+
if (executables = repository.config.post_run_execute).size > 0
|
191
170
|
puts 'PostRun Executables (in execution order):'
|
192
171
|
executables.each do |exe|
|
193
172
|
puts " #{exe}"
|
@@ -195,16 +174,26 @@ module GitHooks
|
|
195
174
|
puts
|
196
175
|
end
|
197
176
|
rescue Error::NotAGitRepo
|
198
|
-
puts "Unable to find a valid git repo in #{
|
177
|
+
puts "Unable to find a valid git repo in #{repository}."
|
199
178
|
puts 'Please specify path to repo via --repo <path>' if GitHooks::SCRIPT_NAME == 'githooks'
|
200
179
|
raise
|
201
180
|
end
|
202
|
-
module_function :list
|
203
181
|
|
204
182
|
private
|
205
183
|
|
206
|
-
def
|
207
|
-
|
184
|
+
def acquire_hooks_path(path)
|
185
|
+
path = Pathname.new(path) unless path.is_a? Pathname
|
186
|
+
path.tap do # return input path by default
|
187
|
+
return path if path.include? 'hooks'
|
188
|
+
return path if path.include? '.hooks'
|
189
|
+
return p if (p = path.join('hooks')).exist? # rubocop:disable Lint/UselessAssignment
|
190
|
+
return p if (p = path.join('.hooks')).exist? # rubocop:disable Lint/UselessAssignment
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
def run_externals(which)
|
195
|
+
args = options.args || []
|
196
|
+
repository.config[which].all? { |executable|
|
208
197
|
command = SystemUtils::Command.new(File.basename(executable), bin_path: executable)
|
209
198
|
|
210
199
|
puts "#{which.camelize}: #{command.build_command(args)}" if GitHooks.verbose
|
@@ -217,20 +206,19 @@ module GitHooks
|
|
217
206
|
end
|
218
207
|
end
|
219
208
|
r.status.success?
|
220
|
-
|
209
|
+
} || fail(TestsFailed, "Failed #{which.camelize} executables - giving up")
|
221
210
|
end
|
222
|
-
module_function :run_externals
|
223
211
|
|
224
|
-
def start
|
225
|
-
phase = options
|
212
|
+
def start # rubocop:disable CyclomaticComplexity, MethodLength
|
213
|
+
phase = options.hook || GitHooks.hook_name || 'pre-commit'
|
226
214
|
puts "PHASE: #{phase}" if GitHooks.debug
|
227
215
|
|
228
216
|
if (active_hook = Hook.phases[phase])
|
229
|
-
active_hook.args = options.
|
230
|
-
active_hook.staged = options.
|
231
|
-
active_hook.untracked = options.
|
232
|
-
active_hook.tracked = options.
|
233
|
-
active_hook.repository_path =
|
217
|
+
active_hook.args = options.args
|
218
|
+
active_hook.staged = options.staged
|
219
|
+
active_hook.untracked = options.untracked
|
220
|
+
active_hook.tracked = options.tracked
|
221
|
+
active_hook.repository_path = repository.path
|
234
222
|
else
|
235
223
|
fail Error::InvalidPhase, "Hook '#{phase}' is not defined - have you registered any tests for this hook yet?"
|
236
224
|
end
|
@@ -268,26 +256,39 @@ module GitHooks
|
|
268
256
|
|
269
257
|
exit(success ? 0 : 1)
|
270
258
|
end
|
271
|
-
module_function :start
|
272
259
|
|
273
|
-
def load_tests(
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
260
|
+
def load_tests(hooks_path, skip_bundler = false)
|
261
|
+
# hooks stored locally in the repo_root should have their libs, init and
|
262
|
+
# gemfile stored in the hooks directory itself, whereas hooks stored
|
263
|
+
# in a separate repository should have have them all stored relative
|
264
|
+
# to the separate hooks directory.
|
265
|
+
if hook_path.to_s.start_with? repository.path
|
266
|
+
hook_data_path = acquire_hooks_path(repository.path)
|
267
|
+
else
|
268
|
+
hook_data_path = acquire_hooks_path(hook_path)
|
269
|
+
end
|
270
|
+
|
271
|
+
hooks_libs = hook_data_path.join('lib')
|
272
|
+
hooks_init = hook_data_path.join('hooks_init.rb')
|
273
|
+
gemfile = hook_data_path.join('Gemfile')
|
274
|
+
|
275
|
+
GitHooks.hooks_root = hook_data_path
|
278
276
|
|
279
|
-
if gemfile.exist? && !skip_bundler
|
277
|
+
if gemfile.exist? && !(skip_bundler.nil? ? ENV.include?('GITHOOKS_SKIP_BUNDLER') : skip_bundler)
|
280
278
|
puts "loading Gemfile from: #{gemfile}" if GitHooks.verbose
|
281
279
|
|
282
280
|
begin
|
283
|
-
ENV['BUNDLE_GEMFILE'] =
|
281
|
+
ENV['BUNDLE_GEMFILE'] = gemfile.to_s
|
284
282
|
|
285
283
|
# stupid RVM polluting my environment without asking via it's
|
286
284
|
# executable-hooks gem preloading bundler. hence the following ...
|
287
285
|
if defined? Bundler
|
288
|
-
[:@
|
286
|
+
[:@bundle_path, :@configured, :@definition, :@load].each do |var|
|
289
287
|
::Bundler.instance_variable_set(var, nil)
|
290
288
|
end
|
289
|
+
# bundler tests for @settings using defined? - which means we need
|
290
|
+
# to forcibly remove it.
|
291
|
+
Bundler.send(:remove_instance_variable, :@settings)
|
291
292
|
else
|
292
293
|
require 'bundler'
|
293
294
|
end
|
@@ -304,13 +305,18 @@ module GitHooks
|
|
304
305
|
|
305
306
|
$LOAD_PATH.unshift hooks_libs.to_s
|
306
307
|
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
308
|
+
if hooks_init.exist?
|
309
|
+
puts "Loading hooks from #{hooks_init} ..." if GitHooks.verbose?
|
310
|
+
require hooks_init.sub_ext('').to_s
|
311
|
+
else
|
312
|
+
puts 'Loading hooks brute-force style ...' if GitHooks.verbose?
|
313
|
+
Dir["#{hooks_path}/**/*.rb"].each do |lib|
|
314
|
+
lib.gsub!('.rb', '')
|
315
|
+
puts " -> #{lib}" if GitHooks.verbose
|
316
|
+
require lib
|
317
|
+
end
|
311
318
|
end
|
312
319
|
end
|
313
|
-
module_function :load_tests
|
314
320
|
|
315
321
|
# rubocop:enable CyclomaticComplexity, MethodLength, AbcSize, PerceivedComplexity
|
316
322
|
end
|
data/lib/githooks/section.rb
CHANGED
@@ -21,10 +21,10 @@ require 'delegate'
|
|
21
21
|
|
22
22
|
module GitHooks
|
23
23
|
class Section < DelegateClass(Array)
|
24
|
-
attr_reader :name, :hook, :success, :actions, :benchmark
|
24
|
+
attr_reader :name, :hook, :success, :actions, :benchmark, :limiters
|
25
|
+
|
25
26
|
alias_method :title, :name
|
26
27
|
alias_method :success?, :success
|
27
|
-
alias_method :all, :actions
|
28
28
|
|
29
29
|
class << self
|
30
30
|
def key_from_name(name)
|
@@ -36,6 +36,7 @@ module GitHooks
|
|
36
36
|
@name = name.to_s.titleize
|
37
37
|
@success = true
|
38
38
|
@actions = []
|
39
|
+
@limiters = hook.limiters
|
39
40
|
@hook = hook
|
40
41
|
@benchmark = 0
|
41
42
|
|
@@ -85,12 +86,6 @@ module GitHooks
|
|
85
86
|
success? ? text.success! : text.failure!
|
86
87
|
end
|
87
88
|
|
88
|
-
def action(title, &block)
|
89
|
-
fail ArgumentError, 'expected block, received none' unless block_given?
|
90
|
-
@actions << Action.new(title, self, &block)
|
91
|
-
self
|
92
|
-
end
|
93
|
-
|
94
89
|
def run
|
95
90
|
running!
|
96
91
|
begin
|
@@ -101,5 +96,36 @@ module GitHooks
|
|
101
96
|
finished!
|
102
97
|
end
|
103
98
|
end
|
99
|
+
|
100
|
+
## DSL
|
101
|
+
|
102
|
+
def config_path
|
103
|
+
GitHooks.hooks_root.join('configs')
|
104
|
+
end
|
105
|
+
|
106
|
+
def config_file(*path_components)
|
107
|
+
config_path.join(*path_components)
|
108
|
+
end
|
109
|
+
|
110
|
+
def lib_path
|
111
|
+
GitHooks.hooks_root.join('lib')
|
112
|
+
end
|
113
|
+
|
114
|
+
def lib_file(*path_components)
|
115
|
+
lib_path.join(*path_components)
|
116
|
+
end
|
117
|
+
|
118
|
+
def limit(type)
|
119
|
+
unless @limiters.include? type
|
120
|
+
@limiters[type] ||= Repository::Limiter.new(type)
|
121
|
+
end
|
122
|
+
@limiters[type]
|
123
|
+
end
|
124
|
+
|
125
|
+
def action(title, &block)
|
126
|
+
fail ArgumentError, 'expected block, received none' unless block_given?
|
127
|
+
@actions << Action.new(title, self, &block)
|
128
|
+
self
|
129
|
+
end
|
104
130
|
end
|
105
131
|
end
|
@@ -14,8 +14,8 @@ module GitHooks
|
|
14
14
|
|
15
15
|
def find_bin(name)
|
16
16
|
# rubocop:disable MultilineBlockChain, Blocks
|
17
|
-
ENV['PATH'].split(/:/).collect {
|
18
|
-
|
17
|
+
ENV['PATH'].split(/:/).collect { |path|
|
18
|
+
Pathname.new(path) + name.to_s
|
19
19
|
}.select { |path|
|
20
20
|
path.exist? && path.executable?
|
21
21
|
}.collect(&:to_s)
|
@@ -67,10 +67,12 @@ module GitHooks
|
|
67
67
|
LANG LC_ALL SHELL SHLVL TERM TMPDIR USER
|
68
68
|
SSH_USER SSH_AUTH_SOCK
|
69
69
|
GEM_HOME GEM_PATH MY_RUBY_HOME
|
70
|
-
|
70
|
+
GIT_DIR GIT_AUTHOR_DATE GIT_INDEX_FILE GIT_AUTHOR_NAME GIT_PREFIX GIT_AUTHOR_EMAIL
|
71
|
+
) unless defined? ENV_WHITELIST
|
71
72
|
|
72
73
|
class Result
|
73
|
-
|
74
|
+
attr_accessor :output, :error
|
75
|
+
attr_reader :status
|
74
76
|
def initialize(output, error, status)
|
75
77
|
@output = output.strip
|
76
78
|
@error = error.strip
|
@@ -135,7 +137,7 @@ module GitHooks
|
|
135
137
|
def prep_env(env = {})
|
136
138
|
Hash[env].each_with_object([]) do |(k, v), array|
|
137
139
|
array << %Q|#{k}="#{v}"| if ENV_WHITELIST.include? k
|
138
|
-
end
|
140
|
+
end
|
139
141
|
end
|
140
142
|
|
141
143
|
def execute(*args, &_block) # rubocop:disable MethodLength, CyclomaticComplexity, AbcSize, PerceivedComplexity
|
@@ -154,27 +156,39 @@ module GitHooks
|
|
154
156
|
command.push options.delete(:post_run) if options[:post_run]
|
155
157
|
command = shellwords(command.flatten.join(';'))
|
156
158
|
|
157
|
-
environment = prep_env(options.delete(:env) || ENV)
|
159
|
+
environment = prep_env(options.delete(:env) || ENV).join(' ')
|
158
160
|
|
159
161
|
error_file = Tempfile.new('ghstderr')
|
162
|
+
|
163
|
+
script_file = Tempfile.new('ghscript')
|
164
|
+
script_file.puts "exec 2>#{error_file.path}"
|
165
|
+
script_file.puts command.join(' ')
|
166
|
+
|
167
|
+
script_file.rewind
|
168
|
+
|
160
169
|
begin
|
161
|
-
real_command =
|
162
|
-
/usr/bin/env -i #{environment} bash -c '
|
163
|
-
( #{command.join(' ').gsub("'", %q|'"'"'|)}) 2>#{error_file.path}
|
164
|
-
'
|
165
|
-
}
|
170
|
+
real_command = "/usr/bin/env -i #{environment} bash #{script_file.path}"
|
166
171
|
|
167
|
-
|
172
|
+
if GitHooks.verbose?
|
173
|
+
$stderr.puts "Command Line :\n----\n#{real_command}\n----\n"
|
174
|
+
$stderr.puts "Command Script:\n----\n#{script_file.read}\n----\n"
|
175
|
+
end
|
168
176
|
|
169
177
|
output = %x{ #{real_command} }
|
170
178
|
result = Result.new(output, error_file.read, $?)
|
171
179
|
|
172
|
-
if GitHooks.verbose?
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
180
|
+
if GitHooks.verbose?
|
181
|
+
if result.failure?
|
182
|
+
STDERR.puts "Command failed with exit code [#{result.status.exitstatus}]",
|
183
|
+
"ENVIRONMENT:\n\t#{environment}\n\n",
|
184
|
+
"COMMAND:\n\t#{command.join(' ')}\n\n",
|
185
|
+
"OUTPUT:\n-----\n#{result.output}\n-----\n\n",
|
186
|
+
"ERROR:\n-----\n#{result.error}\n-----\n\n"
|
187
|
+
else
|
188
|
+
STDERR.puts "Command succeeded with exit code [#{result.status.exitstatus}]",
|
189
|
+
"OUTPUT:\n-----\n#{result.output}\n-----\n\n",
|
190
|
+
"ERROR:\n-----\n#{result.error}\n-----\n\n"
|
191
|
+
end
|
178
192
|
end
|
179
193
|
|
180
194
|
sanitize = [ :strip, :non_printable ]
|
@@ -182,8 +196,11 @@ module GitHooks
|
|
182
196
|
sanitize << :empty_lines if options.delete(:strip_empty_lines)
|
183
197
|
result.sanitize!(*sanitize)
|
184
198
|
|
185
|
-
|
199
|
+
result.tap { yield(result) if block_given? }
|
186
200
|
ensure
|
201
|
+
script_file.close
|
202
|
+
script_file.unlink
|
203
|
+
|
187
204
|
error_file.close
|
188
205
|
error_file.unlink
|
189
206
|
end
|
data/lib/githooks/version.rb
CHANGED