rabbitt-githooks 1.3.2 → 1.4.1
Sign up to get free protection for your applications and to get access to all the features.
- 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