rabbitt-githooks 1.2.7
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 +7 -0
- data/.gitignore +34 -0
- data/.rubocop.yml +73 -0
- data/Gemfile +21 -0
- data/Gemfile.lock +45 -0
- data/LICENSE.txt +339 -0
- data/README.md +4 -0
- data/Rakefile +19 -0
- data/bin/githooks +15 -0
- data/bin/githooks-runner +17 -0
- data/hooks/commit-messages.rb +29 -0
- data/hooks/formatting.rb +53 -0
- data/lib/githooks.rb +89 -0
- data/lib/githooks/action.rb +150 -0
- data/lib/githooks/cli.rb +93 -0
- data/lib/githooks/commands/config.rb +107 -0
- data/lib/githooks/core_ext.rb +23 -0
- data/lib/githooks/core_ext/array.rb +3 -0
- data/lib/githooks/core_ext/array/extract_options.rb +5 -0
- data/lib/githooks/core_ext/array/min_max.rb +37 -0
- data/lib/githooks/core_ext/array/select_with_index.rb +13 -0
- data/lib/githooks/core_ext/numbers.rb +1 -0
- data/lib/githooks/core_ext/numbers/infinity.rb +19 -0
- data/lib/githooks/core_ext/pathname.rb +27 -0
- data/lib/githooks/core_ext/process.rb +7 -0
- data/lib/githooks/core_ext/string.rb +3 -0
- data/lib/githooks/core_ext/string/git_option_path_split.rb +6 -0
- data/lib/githooks/core_ext/string/inflections.rb +67 -0
- data/lib/githooks/core_ext/string/strip_empty_lines.rb +9 -0
- data/lib/githooks/error.rb +10 -0
- data/lib/githooks/hook.rb +159 -0
- data/lib/githooks/repository.rb +152 -0
- data/lib/githooks/repository/config.rb +170 -0
- data/lib/githooks/repository/diff_index_entry.rb +80 -0
- data/lib/githooks/repository/file.rb +125 -0
- data/lib/githooks/repository/limiter.rb +55 -0
- data/lib/githooks/runner.rb +317 -0
- data/lib/githooks/section.rb +98 -0
- data/lib/githooks/system_utils.rb +109 -0
- data/lib/githooks/terminal_colors.rb +63 -0
- data/lib/githooks/version.rb +22 -0
- data/rabbitt-githooks.gemspec +49 -0
- data/thoughts.txt +56 -0
- metadata +175 -0
@@ -0,0 +1,55 @@
|
|
1
|
+
=begin
|
2
|
+
Copyright (C) 2013 Carl P. Corliss
|
3
|
+
|
4
|
+
This program is free software; you can redistribute it and/or modify
|
5
|
+
it under the terms of the GNU General Public License as published by
|
6
|
+
the Free Software Foundation; either version 2 of the License, or
|
7
|
+
(at your option) any later version.
|
8
|
+
|
9
|
+
This program is distributed in the hope that it will be useful,
|
10
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
11
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
12
|
+
GNU General Public License for more details.
|
13
|
+
|
14
|
+
You should have received a copy of the GNU General Public License along
|
15
|
+
with this program; if not, write to the Free Software Foundation, Inc.,
|
16
|
+
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
17
|
+
=end
|
18
|
+
|
19
|
+
module GitHooks
|
20
|
+
class Repository::Limiter
|
21
|
+
attr_reader :type, :only
|
22
|
+
|
23
|
+
def initialize(type, options = {})
|
24
|
+
@type = type
|
25
|
+
@only = options.delete(:only) || options.delete(:to)
|
26
|
+
end
|
27
|
+
|
28
|
+
def only(*args)
|
29
|
+
return @only if args.empty?
|
30
|
+
@only = args.flatten
|
31
|
+
end
|
32
|
+
alias_method :to, :only
|
33
|
+
|
34
|
+
def limit(files)
|
35
|
+
files.select! do |file|
|
36
|
+
match_file(file, @only).tap do |result|
|
37
|
+
if GitHooks.debug?
|
38
|
+
result = (result ? 'success' : 'failure')
|
39
|
+
puts " #{file.path.to_s} (#{file.attribute_value(@type).inspect}) was a #{result}"
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
def match_file(file, match_value)
|
48
|
+
if match_value.is_a? Array
|
49
|
+
match_value.any? { |value| file.match(@type, value) }
|
50
|
+
else
|
51
|
+
file.match(@type, match_value)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,317 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
=begin
|
3
|
+
Copyright (C) 2013 Carl P. Corliss
|
4
|
+
|
5
|
+
This program is free software; you can redistribute it and/or modify
|
6
|
+
it under the terms of the GNU General Public License as published by
|
7
|
+
the Free Software Foundation; either version 2 of the License, or
|
8
|
+
(at your option) any later version.
|
9
|
+
|
10
|
+
This program is distributed in the hope that it will be useful,
|
11
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
12
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
13
|
+
GNU General Public License for more details.
|
14
|
+
|
15
|
+
You should have received a copy of the GNU General Public License along
|
16
|
+
with this program; if not, write to the Free Software Foundation, Inc.,
|
17
|
+
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
18
|
+
=end
|
19
|
+
|
20
|
+
require 'fileutils'
|
21
|
+
require 'githooks/terminal_colors'
|
22
|
+
require 'shellwords'
|
23
|
+
require 'thor'
|
24
|
+
|
25
|
+
module GitHooks
|
26
|
+
module Runner
|
27
|
+
extend TerminalColors
|
28
|
+
|
29
|
+
MARK_SUCCESS = '✓'
|
30
|
+
MARK_FAILURE = 'X'
|
31
|
+
MARK_UNKNOWN = '?'
|
32
|
+
|
33
|
+
def run(options = {}) # rubocop:disable CyclomaticComplexity, MethodLength
|
34
|
+
# unfreeze options
|
35
|
+
options = Thor::CoreExt::HashWithIndifferentAccess.new(options)
|
36
|
+
|
37
|
+
repo = options['repo'] ||= Repository.root_path
|
38
|
+
script = options['script'] ||= Repository.instance(repo).config.script
|
39
|
+
libpath = options['path'] ||= Repository.instance(repo).config.path
|
40
|
+
args = options['args'] ||= []
|
41
|
+
|
42
|
+
GitHooks.verbose = !!ENV['GITHOOKS_VERBOSE']
|
43
|
+
GitHooks.debug = !!ENV['GITHOOKS_DEBUG']
|
44
|
+
|
45
|
+
if options['skip-pre']
|
46
|
+
puts 'Skipping PreRun Executables'
|
47
|
+
else
|
48
|
+
run_externals('pre-run-execute', repo, args)
|
49
|
+
end
|
50
|
+
|
51
|
+
if script && !(options['ignore-script'] || GitHooks.ignore_script)
|
52
|
+
command = "#{script} #{Pathname.new($0).to_s} #{Shellwords.join(ARGV)};"
|
53
|
+
puts "Kernel#exec(#{command.inspect})" if GitHooks.verbose
|
54
|
+
exec(command)
|
55
|
+
elsif libpath
|
56
|
+
load_tests(libpath, options['skip-bundler'])
|
57
|
+
start(options)
|
58
|
+
else
|
59
|
+
puts 'I can\'t figure out what to run - specify either path or script to give me a hint...'
|
60
|
+
end
|
61
|
+
|
62
|
+
if options['skip-post']
|
63
|
+
puts 'Skipping PostRun Executables'
|
64
|
+
else
|
65
|
+
run_externals('post-run-execute', repo, args)
|
66
|
+
end
|
67
|
+
rescue GitHooks::Error::NotAGitRepo
|
68
|
+
puts "Unable to find a valid git repo in #{repo}."
|
69
|
+
puts 'Please specify path to repo via --repo <path>' if GitHooks::SCRIPT_NAME == 'githooks'
|
70
|
+
end
|
71
|
+
module_function :run
|
72
|
+
|
73
|
+
def attach(options = {}) # rubocop:disable CyclomaticComplexity, MethodLength
|
74
|
+
repo_path = options[:repo] || Repository.root_path
|
75
|
+
repo_path = Pathname.new(repo_path) unless repo_path.nil?
|
76
|
+
repo_hooks = repo_path + '.git' + 'hooks'
|
77
|
+
|
78
|
+
entry_path = options[:script] || options[:path]
|
79
|
+
|
80
|
+
hook_phases = options[:hooks]
|
81
|
+
hook_phases ||= Hook::VALID_PHASES
|
82
|
+
|
83
|
+
bootstrapper = options[:bootstrap]
|
84
|
+
bootstrapper = Pathname.new(bootstrapper).realpath unless bootstrapper.nil?
|
85
|
+
entry_path = Pathname.new(entry_path).realdirpath
|
86
|
+
|
87
|
+
repo = Repository.instance(repo_path)
|
88
|
+
|
89
|
+
if entry_path.directory?
|
90
|
+
if path = repo.config['path'] # rubocop:disable AssignmentInCondition
|
91
|
+
fail Error::AlreadyAttached, "Repository [#{repo_path}] already attached to path #{path} - Detach to continue."
|
92
|
+
end
|
93
|
+
repo.config.set('path', entry_path)
|
94
|
+
elsif entry_path.executable?
|
95
|
+
if path = repo.config['script'] # rubocop:disable AssignmentInCondition
|
96
|
+
fail Error::AlreadyAttached, "Repository [#{repo_path}] already attached to script #{path}. Detach to continue."
|
97
|
+
end
|
98
|
+
repo.config.set('script', entry_path)
|
99
|
+
else
|
100
|
+
fail ArgumentError, "Provided path '#{entry_path}' is neither a directory nor an executable file."
|
101
|
+
end
|
102
|
+
|
103
|
+
gitrunner = bootstrapper
|
104
|
+
gitrunner ||= SystemUtils.which('githooks-runner')
|
105
|
+
gitrunner ||= (GitHooks::BIN_PATH + 'githooks-runner').realpath
|
106
|
+
|
107
|
+
hook_phases.each do |hook|
|
108
|
+
hook = (repo_hooks + hook).to_s
|
109
|
+
puts "Linking #{gitrunner.to_s} -> #{hook}" if GitHooks.verbose
|
110
|
+
FileUtils.ln_sf gitrunner.to_s, hook
|
111
|
+
end
|
112
|
+
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) + '.git' + 'hooks'
|
118
|
+
hook_phases ||= Hook::VALID_PHASES
|
119
|
+
|
120
|
+
repo = Repository.instance(repo_path)
|
121
|
+
|
122
|
+
hook_phases.each do |hook|
|
123
|
+
if (repo_hook = repo_hooks + hook).symlink?
|
124
|
+
puts "Removing hook '#{hook}' from repository at: #{repo_path}" if GitHooks.verbose
|
125
|
+
FileUtils.rm_f repo_hook
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
active_hooks = Hook::VALID_PHASES.select { |hook| (repo_hooks + hook).exist? }
|
130
|
+
|
131
|
+
if active_hooks.empty?
|
132
|
+
puts 'All hooks detached. Removing configuration section.'
|
133
|
+
repo.config.remove_section(repo_path: repo_path)
|
134
|
+
else
|
135
|
+
puts "Keeping configuration for active hooks: #{active_hooks.join(', ')}"
|
136
|
+
end
|
137
|
+
end
|
138
|
+
module_function :detach
|
139
|
+
|
140
|
+
def list(repo_path)
|
141
|
+
repo_path ||= Pathname.new(Repository.root_path)
|
142
|
+
|
143
|
+
repo = Repository.instance(repo_path)
|
144
|
+
script = repo.config.script
|
145
|
+
libpath = repo.config.path
|
146
|
+
|
147
|
+
unless script || libpath
|
148
|
+
fail Error::NotAttached, 'Repository currently not configured. Usage attach to setup for use with githooks.'
|
149
|
+
end
|
150
|
+
|
151
|
+
if (executables = repo.config.pre_run_execute).size > 0
|
152
|
+
puts 'PreRun Executables (in execution order):'
|
153
|
+
executables.each do |exe|
|
154
|
+
puts " #{exe}"
|
155
|
+
end
|
156
|
+
puts
|
157
|
+
end
|
158
|
+
|
159
|
+
if script
|
160
|
+
puts 'Main Test Script:'
|
161
|
+
puts " #{script}"
|
162
|
+
puts
|
163
|
+
end
|
164
|
+
|
165
|
+
if libpath
|
166
|
+
puts 'Main Testing Library with Tests (in execution order):'
|
167
|
+
puts ' Tests loaded from:'
|
168
|
+
puts " #{libpath}"
|
169
|
+
puts
|
170
|
+
|
171
|
+
SystemUtils.quiet { load_tests(libpath, true) }
|
172
|
+
|
173
|
+
%w{ pre-commit commit-msg }.each do |phase|
|
174
|
+
next unless Hook.phases[phase]
|
175
|
+
|
176
|
+
puts " Phase #{phase.camelize}:"
|
177
|
+
Hook.phases[phase].sections.each_with_index do |section, section_index|
|
178
|
+
printf " %3d: %s\n", section_index + 1, section.title
|
179
|
+
section.all.each_with_index do |action, action_index|
|
180
|
+
printf " %3d: %s\n", action_index + 1, action.title
|
181
|
+
action.limiters.each_with_index do |limiter, limiter_index|
|
182
|
+
type, value = limiter.type.inspect, limiter.only
|
183
|
+
value = value.first if value.size == 1
|
184
|
+
printf " Limiter %d: %s -> %s\n", limiter_index + 1, type, value.inspect
|
185
|
+
end
|
186
|
+
end
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
puts
|
191
|
+
end
|
192
|
+
|
193
|
+
if (executables = repo.config.post_run_execute).size > 0
|
194
|
+
puts 'PostRun Executables (in execution order):'
|
195
|
+
executables.each do |exe|
|
196
|
+
puts " #{exe}"
|
197
|
+
end
|
198
|
+
puts
|
199
|
+
end
|
200
|
+
rescue GitHooks::Error::NotAGitRepo
|
201
|
+
puts "Unable to find a valid git repo in #{repo}."
|
202
|
+
puts 'Please specify path to repo via --repo <path>' if GitHooks::SCRIPT_NAME == 'githooks'
|
203
|
+
end
|
204
|
+
module_function :list
|
205
|
+
|
206
|
+
private
|
207
|
+
|
208
|
+
def run_externals(which, repo_path, args)
|
209
|
+
Repository.instance(repo_path).config[which].all? do |executable|
|
210
|
+
command = SystemUtils::Command.new(File.basename(executable), path: executable)
|
211
|
+
|
212
|
+
puts "#{which.camelize}: #{command.build_command(args)}" if GitHooks.verbose
|
213
|
+
unless (r = command.execute(*args)).status.success?
|
214
|
+
print "#{which.camelize} Executable [#{executable}] failed with error code #{r.status.exitstatus} and "
|
215
|
+
if r.error.empty?
|
216
|
+
puts 'no output'
|
217
|
+
else
|
218
|
+
puts "error message:\n\t#{r.error}"
|
219
|
+
end
|
220
|
+
end
|
221
|
+
r.status.success?
|
222
|
+
end || fail(TestsFailed, "Failed #{which.camelize} executables - giving up")
|
223
|
+
end
|
224
|
+
module_function :run_externals
|
225
|
+
|
226
|
+
def start(options = {}) # rubocop:disable MethodLength
|
227
|
+
phase = options[:hook] || GitHooks.hook_name || 'pre-commit'
|
228
|
+
puts "PHASE: #{phase}" if GitHooks.debug
|
229
|
+
|
230
|
+
if active_hook = Hook.phases[phase]
|
231
|
+
active_hook.args = options.delete(:args)
|
232
|
+
active_hook.unstaged = options.delete(:unstaged)
|
233
|
+
active_hook.untracked = options.delete(:untracked)
|
234
|
+
active_hook.repository_path = options.delete(:repo)
|
235
|
+
else
|
236
|
+
fail Error::InvalidPhase, "Hook '#{phase}' is not defined - have you registered any tests for this hook yet?"
|
237
|
+
end
|
238
|
+
|
239
|
+
success = active_hook.run
|
240
|
+
section_length = active_hook.sections.max { |s| s.title.length }
|
241
|
+
sections = active_hook.sections.select { |section| !section.actions.empty? }
|
242
|
+
|
243
|
+
sections.each do |section|
|
244
|
+
hash_tail_length = (section_length - section.title.length)
|
245
|
+
printf "===== %s %s=====\n", section.colored_name(phase), ('=' * hash_tail_length)
|
246
|
+
|
247
|
+
section.actions.each_with_index do |action, index|
|
248
|
+
printf " %d. [ %s ] %s\n", (index + 1), action.state_symbol, action.colored_title
|
249
|
+
|
250
|
+
action.errors.each do |error|
|
251
|
+
printf " %s %s\n", color_bright_red(MARK_FAILURE), error
|
252
|
+
end
|
253
|
+
|
254
|
+
state_string = ( action.success? ? color_bright_green(MARK_SUCCESS) : color_bright_yellow(MARK_UNKNOWN))
|
255
|
+
action.warnings.each do |warning|
|
256
|
+
printf " %s %s\n", state_string, warning
|
257
|
+
end
|
258
|
+
end
|
259
|
+
puts
|
260
|
+
end
|
261
|
+
|
262
|
+
success = false if ENV['GITHOOKS_FORCE_FAIL']
|
263
|
+
|
264
|
+
unless success
|
265
|
+
$stderr.puts 'Commit failed due to errors listed above.'
|
266
|
+
$stderr.puts 'Please fix and attempt your commit again.'
|
267
|
+
end
|
268
|
+
|
269
|
+
exit(success ? 0 : 1)
|
270
|
+
end
|
271
|
+
module_function :start
|
272
|
+
|
273
|
+
def load_tests(path, skip_bundler = false) # rubocop:disable MethodLength
|
274
|
+
hooks_root = Pathname.new(path).realpath
|
275
|
+
hooks_path = hooks_root + 'hooks'
|
276
|
+
hooks_libs = hooks_root + 'libs'
|
277
|
+
gemfile = hooks_root + 'Gemfile'
|
278
|
+
|
279
|
+
if gemfile.exist? && !skip_bundler
|
280
|
+
puts "loading Gemfile from: #{gemfile}" if GitHooks.verbose
|
281
|
+
|
282
|
+
begin
|
283
|
+
ENV['BUNDLE_GEMFILE'] = (hooks_root + 'Gemfile').to_s
|
284
|
+
|
285
|
+
# stupid RVM polluting my environment without asking via it's
|
286
|
+
# executable-hooks gem preloading bundler. hence the following ...
|
287
|
+
if defined? Bundler
|
288
|
+
[:@bundle_path, :@configured, :@definition, :@load].each do |var|
|
289
|
+
Bundler.instance_variable_set(var, nil)
|
290
|
+
end
|
291
|
+
# bundler tests for @settings using defined? - which means we need
|
292
|
+
# to forcibly remove it.
|
293
|
+
Bundler.send(:remove_instance_variable, :@settings)
|
294
|
+
else
|
295
|
+
require 'bundler'
|
296
|
+
end
|
297
|
+
Bundler.require(:default)
|
298
|
+
rescue LoadError
|
299
|
+
puts 'Unable to load bundler - please make sure it\'s installed.'
|
300
|
+
raise # rubocop:disable SignalException
|
301
|
+
rescue Bundler::GemNotFound => e
|
302
|
+
puts "Error: #{e.message}"
|
303
|
+
puts 'Did you bundle install your Gemfile?'
|
304
|
+
raise # rubocop:disable SignalException
|
305
|
+
end
|
306
|
+
end
|
307
|
+
|
308
|
+
$LOAD_PATH.unshift hooks_libs.to_s
|
309
|
+
Dir["#{hooks_path}/**/*.rb"].each do |lib|
|
310
|
+
lib.gsub!('.rb', '')
|
311
|
+
puts "Loading: #{lib}" if GitHooks.verbose
|
312
|
+
require lib
|
313
|
+
end
|
314
|
+
end
|
315
|
+
module_function :load_tests
|
316
|
+
end
|
317
|
+
end
|
@@ -0,0 +1,98 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
=begin
|
3
|
+
Copyright (C) 2013 Carl P. Corliss
|
4
|
+
|
5
|
+
This program is free software; you can redistribute it and/or modify
|
6
|
+
it under the terms of the GNU General Public License as published by
|
7
|
+
the Free Software Foundation; either version 2 of the License, or
|
8
|
+
(at your option) any later version.
|
9
|
+
|
10
|
+
This program is distributed in the hope that it will be useful,
|
11
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
12
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
13
|
+
GNU General Public License for more details.
|
14
|
+
|
15
|
+
You should have received a copy of the GNU General Public License along
|
16
|
+
with this program; if not, write to the Free Software Foundation, Inc.,
|
17
|
+
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
18
|
+
=end
|
19
|
+
|
20
|
+
require 'delegate'
|
21
|
+
|
22
|
+
module GitHooks
|
23
|
+
class Section < DelegateClass(Array)
|
24
|
+
include TerminalColors
|
25
|
+
|
26
|
+
attr_reader :name, :hook, :success, :actions
|
27
|
+
alias_method :title, :name
|
28
|
+
alias_method :success?, :success
|
29
|
+
alias_method :all, :actions
|
30
|
+
|
31
|
+
def initialize(name, hook, &block)
|
32
|
+
@name = name.to_s.titleize
|
33
|
+
@success = true
|
34
|
+
@actions = []
|
35
|
+
@hook = hook
|
36
|
+
|
37
|
+
instance_eval(&block)
|
38
|
+
|
39
|
+
waiting!
|
40
|
+
end
|
41
|
+
|
42
|
+
# overrides previous action method to only return
|
43
|
+
# actions that have a non-empty manifest
|
44
|
+
def actions
|
45
|
+
@actions.select { |action| !action.manifest.empty? }
|
46
|
+
end
|
47
|
+
alias_method :__getobj__, :actions
|
48
|
+
|
49
|
+
def <<(action)
|
50
|
+
@actions << action
|
51
|
+
end
|
52
|
+
|
53
|
+
%w(finished running waiting).each do |method|
|
54
|
+
define_method(:"#{method}?") { @status == method.to_sym }
|
55
|
+
define_method(:"#{method}!") { @status = method.to_sym }
|
56
|
+
end
|
57
|
+
|
58
|
+
def completed?
|
59
|
+
@actions.all? { |action| action.finished? }
|
60
|
+
end
|
61
|
+
|
62
|
+
def wait_count
|
63
|
+
@actions.select { |action| action.waiting? }.size
|
64
|
+
end
|
65
|
+
|
66
|
+
def name(phase = GitHooks::HOOK_NAME)
|
67
|
+
phase = (phase || GitHooks::HOOK_NAME).to_s.gsub('-', '_').camelize
|
68
|
+
"#{phase} :: #{@name}"
|
69
|
+
end
|
70
|
+
|
71
|
+
def colored_name(phase = GitHooks::HOOK_NAME)
|
72
|
+
status_colorize name(phase)
|
73
|
+
end
|
74
|
+
|
75
|
+
def action(title, options = {}, &block)
|
76
|
+
fail ArgumentError, 'Missing required block to #perform' unless block_given?
|
77
|
+
@actions << Action.new(title, self, &block)
|
78
|
+
self
|
79
|
+
end
|
80
|
+
|
81
|
+
def status_colorize(text)
|
82
|
+
if finished? && completed?
|
83
|
+
success? ? color_bright_green(text) : color_bright_red(text)
|
84
|
+
else
|
85
|
+
color_dark_cyan(text)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
def run
|
90
|
+
running!
|
91
|
+
begin
|
92
|
+
actions.collect { |action| @success &= action.run }.all?
|
93
|
+
ensure
|
94
|
+
finished!
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|