polytrix 0.1.2 → 0.1.3
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/.rubocop-todo.yml +14 -5
- data/Gemfile +2 -1
- data/README.md +139 -177
- data/Rakefile +5 -12
- data/bin/polytrix +0 -1
- data/features/bootstrapping.feature +0 -3
- data/features/cloning.feature +0 -3
- data/features/show.feature +38 -0
- data/features/states.feature +12 -13
- data/features/step_definitions/sdk_steps.rb +0 -4
- data/lib/polytrix/challenge.rb +135 -53
- data/lib/polytrix/challenge_result.rb +0 -2
- data/lib/polytrix/challenge_runner.rb +28 -18
- data/lib/polytrix/cli.rb +53 -69
- data/lib/polytrix/color.rb +2 -2
- data/lib/polytrix/command/action.rb +4 -3
- data/lib/polytrix/command/list.rb +39 -28
- data/lib/polytrix/command/report.rb +9 -86
- data/lib/polytrix/command/reports/code2doc.rb +72 -0
- data/lib/polytrix/command/reports/dashboard.rb +125 -0
- data/lib/polytrix/command/show.rb +148 -0
- data/lib/polytrix/command.rb +37 -104
- data/lib/polytrix/configuration.rb +14 -18
- data/lib/polytrix/{core/hashie.rb → dash.rb} +4 -3
- data/lib/polytrix/documentation/code_segmenter.rb +8 -8
- data/lib/polytrix/documentation/comment_styles.rb +1 -1
- data/lib/polytrix/documentation/helpers/code_helper.rb +9 -0
- data/lib/polytrix/documentation_generator.rb +11 -14
- data/lib/polytrix/error.rb +104 -97
- data/lib/polytrix/executor.rb +33 -0
- data/lib/polytrix/{runners → executors}/buff_shellout_executor.rb +1 -1
- data/lib/polytrix/executors/linux_challenge_executor.rb +29 -0
- data/lib/polytrix/executors/mixlib_shellout_executor.rb +55 -0
- data/lib/polytrix/{runners/windows_challenge_runner.rb → executors/windows_challenge_executor.rb} +4 -11
- data/lib/polytrix/{core/implementor.rb → implementor.rb} +10 -6
- data/lib/polytrix/manifest.rb +2 -31
- data/lib/polytrix/{reports → reporters}/hash_reporter.rb +6 -2
- data/lib/polytrix/{reports → reporters}/json_reporter.rb +2 -2
- data/lib/polytrix/{reports → reporters}/markdown_reporter.rb +7 -2
- data/lib/polytrix/{reports → reporters}/yaml_reporter.rb +2 -2
- data/lib/polytrix/reporters.rb +27 -0
- data/lib/polytrix/result.rb +6 -5
- data/lib/polytrix/spies/file_system_spy.rb +15 -0
- data/lib/polytrix/spies.rb +61 -0
- data/lib/polytrix/state_file.rb +1 -20
- data/lib/polytrix/util.rb +157 -62
- data/lib/polytrix/validation.rb +41 -2
- data/lib/polytrix/validator.rb +9 -4
- data/lib/polytrix/version.rb +1 -1
- data/lib/polytrix.rb +110 -105
- data/polytrix.gemspec +7 -2
- data/polytrix.yml +16 -13
- data/resources/assets/pygments/autumn.css +58 -0
- data/resources/assets/pygments/borland.css +46 -0
- data/resources/assets/pygments/bw.css +34 -0
- data/resources/assets/pygments/colorful.css +61 -0
- data/resources/assets/pygments/default.css +62 -0
- data/resources/assets/pygments/emacs.css +61 -0
- data/resources/assets/pygments/friendly.css +61 -0
- data/resources/assets/pygments/fruity.css +69 -0
- data/resources/assets/pygments/github.css +61 -0
- data/resources/assets/pygments/manni.css +61 -0
- data/resources/assets/pygments/monokai.css +64 -0
- data/resources/assets/pygments/murphy.css +61 -0
- data/resources/assets/pygments/native.css +69 -0
- data/resources/assets/pygments/pastie.css +60 -0
- data/resources/assets/pygments/perldoc.css +58 -0
- data/resources/assets/pygments/tango.css +69 -0
- data/resources/assets/pygments/trac.css +59 -0
- data/resources/assets/pygments/vim.css +69 -0
- data/resources/assets/pygments/vs.css +33 -0
- data/resources/assets/pygments/zenburn.css +1 -0
- data/resources/assets/style.css +41 -0
- data/resources/templates/dashboard/files/dashboard.html.tt +82 -0
- data/resources/templates/dashboard/templates/_test_report.html.tt +87 -0
- data/samples/bootstrap.sh +2 -0
- data/samples/clone.sh +2 -0
- data/samples/code2doc.sh +4 -0
- data/samples/docs/samples/code2doc/java/katas-hello_world-java.md +17 -0
- data/samples/docs/samples/code2doc/java/katas-quine-java.md +35 -0
- data/samples/docs/samples/code2doc/python/katas-hello_world-python.md +5 -0
- data/samples/docs/samples/code2doc/python/katas-quine-python.md +6 -0
- data/samples/docs/samples/code2doc/ruby/katas-hello_world-ruby.md +11 -0
- data/samples/exec.sh +2 -0
- data/samples/polytrix.rb +2 -2
- data/samples/polytrix.yml +5 -2
- data/samples/show.sh +4 -0
- data/samples/test.sh +2 -0
- data/samples/tests/polytrix/validators.rb +2 -2
- data/samples/verify.sh +3 -0
- data/scripts/wrapper +4 -7
- data/spec/fabricators/challenge_fabricator.rb +2 -9
- data/spec/fabricators/implementor_fabricator.rb +0 -8
- data/spec/fabricators/manifest_fabricator.rb +2 -9
- data/spec/fabricators/validator_fabricator.rb +2 -4
- data/spec/polytrix/challenge_runner_spec.rb +20 -0
- data/spec/polytrix/documentation/helpers/code_helper_spec.rb +7 -7
- data/spec/polytrix/file_finder_spec.rb +5 -5
- data/spec/polytrix/manifest_spec.rb +0 -21
- data/spec/polytrix/result_spec.rb +14 -14
- data/spec/polytrix/validator_registry_spec.rb +4 -4
- data/spec/polytrix/validator_spec.rb +9 -9
- data/spec/polytrix_spec.rb +1 -25
- data/spec/spec_helper.rb +8 -1
- metadata +130 -38
- data/features/execution.feature +0 -53
- data/features/fixtures/spec/polytrix_spec.rb +0 -7
- data/lib/polytrix/cli/report.rb +0 -84
- data/lib/polytrix/command/rundoc.rb +0 -27
- data/lib/polytrix/core/file_system_helper.rb +0 -75
- data/lib/polytrix/core/manifest_section.rb +0 -4
- data/lib/polytrix/core/string_helpers.rb +0 -15
- data/lib/polytrix/documentation/view_helper.rb +0 -21
- data/lib/polytrix/rspec/documentation_formatter.rb +0 -66
- data/lib/polytrix/rspec/yaml_report.rb +0 -51
- data/lib/polytrix/rspec.rb +0 -56
- data/lib/polytrix/runners/executor.rb +0 -34
- data/lib/polytrix/runners/linux_challenge_runner.rb +0 -23
- data/lib/polytrix/runners/middleware/change_directory.rb +0 -20
- data/lib/polytrix/runners/middleware/feature_executor.rb +0 -24
- data/lib/polytrix/runners/middleware/setup_env_vars.rb +0 -42
- data/lib/polytrix/runners/mixlib_shellout_executor.rb +0 -83
- data/lib/polytrix/validations.rb +0 -23
- data/samples/scripts/wrapper +0 -7
- data/spec/polytrix/middleware/feature_executor_spec.rb +0 -48
- data/spec/polytrix/validations_spec.rb +0 -16
data/lib/polytrix/challenge.rb
CHANGED
|
@@ -1,14 +1,11 @@
|
|
|
1
1
|
require 'benchmark'
|
|
2
|
-
require 'hashie/dash'
|
|
3
|
-
require 'hashie/extensions/coercion'
|
|
4
|
-
require 'hashie/extensions/indifferent_access'
|
|
5
2
|
require 'polytrix/documentation/helpers/code_helper'
|
|
6
3
|
|
|
7
4
|
module Polytrix
|
|
8
5
|
class Challenge < Polytrix::Dash # rubocop:disable ClassLength
|
|
9
|
-
include Polytrix::
|
|
6
|
+
include Polytrix::Util::FileSystem
|
|
10
7
|
include Polytrix::Logging
|
|
11
|
-
include Polytrix::
|
|
8
|
+
include Polytrix::Util::String
|
|
12
9
|
# View helpers
|
|
13
10
|
include Polytrix::Documentation::Helpers::CodeHelper
|
|
14
11
|
|
|
@@ -17,28 +14,45 @@ module Polytrix
|
|
|
17
14
|
coerce_key :implementor, Polytrix::Implementor
|
|
18
15
|
property :suite, required: true
|
|
19
16
|
property :vars, default: {}
|
|
17
|
+
# coerce_key :vars, Polytrix::Manifest::Environment
|
|
20
18
|
property :source_file
|
|
21
19
|
coerce_key :source_file, Pathname
|
|
22
20
|
property :basedir
|
|
23
21
|
coerce_key :basedir, Pathname
|
|
24
22
|
property :challenge_runner, default: ChallengeRunner.create_runner
|
|
25
23
|
property :result
|
|
26
|
-
|
|
27
|
-
property :
|
|
28
|
-
# coerce_key :vars, Polytrix::Manifest::Environment
|
|
29
|
-
property :plugin_data, default: {}
|
|
24
|
+
coerce_key :results, ChallengeResult
|
|
25
|
+
property :spy_data, default: {}
|
|
30
26
|
property :verification_level, default: 0
|
|
31
27
|
|
|
28
|
+
KEYS_TO_PERSIST = [:result, :spy_data]
|
|
29
|
+
|
|
30
|
+
def initialize(hash)
|
|
31
|
+
super
|
|
32
|
+
refresh
|
|
33
|
+
end
|
|
34
|
+
|
|
32
35
|
def state_file
|
|
33
36
|
@state_file ||= StateFile.new(Dir.pwd, slug)
|
|
34
37
|
end
|
|
35
38
|
|
|
39
|
+
def refresh
|
|
40
|
+
@state = state_file.read
|
|
41
|
+
KEYS_TO_PERSIST.each do |key|
|
|
42
|
+
public_send("#{key}=".to_sym, @state[key]) if @state[key]
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def validators
|
|
47
|
+
Polytrix::ValidatorRegistry.validators_for self
|
|
48
|
+
end
|
|
49
|
+
|
|
36
50
|
def logger
|
|
37
51
|
implementor.logger
|
|
38
52
|
end
|
|
39
53
|
|
|
40
54
|
def slug
|
|
41
|
-
slugify(
|
|
55
|
+
slugify(suite, name, implementor.name)
|
|
42
56
|
end
|
|
43
57
|
|
|
44
58
|
def absolute_source_file
|
|
@@ -47,6 +61,18 @@ module Polytrix
|
|
|
47
61
|
File.expand_path source_file, basedir
|
|
48
62
|
end
|
|
49
63
|
|
|
64
|
+
def detect
|
|
65
|
+
transition_to :detect
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def detect_action
|
|
69
|
+
perform_action(:detect, 'Detecting code sample') do
|
|
70
|
+
fail FeatureNotImplementedError, "Implementor #{name} has not been cloned" unless implementor.cloned?
|
|
71
|
+
fail FeatureNotImplementedError, name if source_file.nil?
|
|
72
|
+
fail FeatureNotImplementedError, name unless File.exist?(absolute_source_file)
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
|
|
50
76
|
def exec
|
|
51
77
|
transition_to :exec
|
|
52
78
|
end
|
|
@@ -55,7 +81,7 @@ module Polytrix
|
|
|
55
81
|
perform_action(:exec, 'Executing') do
|
|
56
82
|
fail FeatureNotImplementedError, "Implementor #{name} has not been cloned" unless implementor.cloned?
|
|
57
83
|
fail FeatureNotImplementedError, name if source_file.nil?
|
|
58
|
-
fail FeatureNotImplementedError, name unless File.
|
|
84
|
+
fail FeatureNotImplementedError, name unless File.exist?(absolute_source_file)
|
|
59
85
|
self.result = challenge_runner.run_challenge self
|
|
60
86
|
end
|
|
61
87
|
end
|
|
@@ -68,7 +94,7 @@ module Polytrix
|
|
|
68
94
|
transition_to :destroy
|
|
69
95
|
end
|
|
70
96
|
|
|
71
|
-
def test(
|
|
97
|
+
def test(_destroy_mode = :passing)
|
|
72
98
|
elapsed = Benchmark.measure do
|
|
73
99
|
banner "Cleaning up any prior instances of #{slug}"
|
|
74
100
|
destroy
|
|
@@ -78,47 +104,34 @@ module Polytrix
|
|
|
78
104
|
end
|
|
79
105
|
info "Finished testing #{slug} #{Util.duration(elapsed.real)}."
|
|
80
106
|
self
|
|
81
|
-
|
|
107
|
+
# ensure
|
|
82
108
|
# destroy if destroy_mode == :always
|
|
83
109
|
end
|
|
84
110
|
|
|
85
|
-
def code2doc
|
|
86
|
-
if source_file.nil?
|
|
87
|
-
warn "No code sample available for #{slug}, no documentation will be generated."
|
|
88
|
-
return
|
|
89
|
-
end
|
|
90
|
-
|
|
91
|
-
display_file = relativize(absolute_source_file, Dir.pwd)
|
|
92
|
-
banner "Generating documentation for #{slug} from #{display_file}"
|
|
93
|
-
target_dir = Polytrix.configuration.documentation_dir
|
|
94
|
-
format = Polytrix.configuration.documentation_format
|
|
95
|
-
target_file_name = File.basename(source_file, File.extname(source_file)) + ".#{format}"
|
|
96
|
-
target_file = File.join(target_dir, target_file_name)
|
|
97
|
-
doc = Polytrix::DocumentationGenerator.new.code2doc(absolute_source_file)
|
|
98
|
-
FileUtils.mkdir_p File.dirname(target_file)
|
|
99
|
-
File.write(target_file, doc)
|
|
100
|
-
info "Documentated saved to #{target_file}"
|
|
101
|
-
rescue Polytrix::Documentation::CommentStyles::UnknownStyleError => e
|
|
102
|
-
abort "Unknown file extension: #{e.extension}, please use --lang to set the language manually"
|
|
103
|
-
end
|
|
104
|
-
|
|
105
111
|
def destroy_action
|
|
106
112
|
perform_action(:destroy, 'Destroying') do
|
|
107
113
|
@state_file.destroy
|
|
108
114
|
@state_file = nil
|
|
109
|
-
@validations = nil
|
|
110
115
|
@state = {}
|
|
116
|
+
refresh
|
|
111
117
|
end
|
|
112
118
|
end
|
|
113
119
|
|
|
114
120
|
def verify_action
|
|
115
121
|
perform_action(:verify, 'Verifying') do
|
|
116
|
-
validators = Polytrix::ValidatorRegistry.validators_for self
|
|
117
122
|
validators.each do |validator|
|
|
118
|
-
validator.validate(self)
|
|
119
|
-
|
|
123
|
+
validation = validator.validate(self)
|
|
124
|
+
status = case validation.result
|
|
125
|
+
when :passed
|
|
126
|
+
Polytrix::Color.colorize('✓ Passed', :green)
|
|
127
|
+
when :failed
|
|
128
|
+
Polytrix::Color.colorize('x Failed', :red)
|
|
129
|
+
Polytrix.handle_validation_failure(validation.error)
|
|
130
|
+
else
|
|
131
|
+
Polytrix::Color.colorize(validation.result, :yellow)
|
|
132
|
+
end
|
|
133
|
+
info format('%-50s %s', validator.description, status)
|
|
120
134
|
end
|
|
121
|
-
@state['validations'] = validations
|
|
122
135
|
end
|
|
123
136
|
end
|
|
124
137
|
|
|
@@ -133,55 +146,124 @@ module Polytrix
|
|
|
133
146
|
end
|
|
134
147
|
|
|
135
148
|
def action(what, &block)
|
|
136
|
-
@state
|
|
149
|
+
@state ||= state_file.read
|
|
150
|
+
@state['last_attempted_action'] = what.to_s
|
|
137
151
|
elapsed = Benchmark.measure do
|
|
138
152
|
# synchronize_or_call(what, @state, &block)
|
|
139
153
|
block.call(@state)
|
|
140
154
|
end
|
|
141
|
-
@state['
|
|
155
|
+
@state['last_completed_action'] = what.to_s
|
|
142
156
|
elapsed
|
|
143
157
|
rescue Polytrix::FeatureNotImplementedError => e
|
|
144
158
|
raise e
|
|
145
159
|
rescue ActionFailed => e
|
|
146
160
|
log_failure(what, e)
|
|
147
|
-
|
|
161
|
+
raise(ChallengeFailure, failure_message(what) +
|
|
148
162
|
" Please see .polytrix/logs/#{name}.log for more details",
|
|
149
|
-
|
|
163
|
+
e.backtrace)
|
|
150
164
|
rescue Exception => e # rubocop:disable RescueException
|
|
151
165
|
log_failure(what, e)
|
|
152
|
-
|
|
153
|
-
|
|
166
|
+
raise ActionFailed,
|
|
167
|
+
"Failed to complete ##{what} action: [#{e.message}]", e.backtrace
|
|
154
168
|
ensure
|
|
169
|
+
KEYS_TO_PERSIST.each do |key|
|
|
170
|
+
@state[key] = public_send(key)
|
|
171
|
+
end
|
|
155
172
|
state_file.write(@state) unless what == :destroy
|
|
156
173
|
end
|
|
157
174
|
|
|
175
|
+
def failed?
|
|
176
|
+
last_attempted_action != last_completed_action
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
def skipped?
|
|
180
|
+
result.nil?
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
def sample?
|
|
184
|
+
!source_file.nil?
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
def status
|
|
188
|
+
status = last_attempted_action
|
|
189
|
+
failed? ? "#{status}_failed" : status
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
def status_description
|
|
193
|
+
case status
|
|
194
|
+
when 'clone' then 'Cloned'
|
|
195
|
+
when 'clone_failed' then 'Clone Failed'
|
|
196
|
+
when 'detect' then 'Sample Found'
|
|
197
|
+
when 'detect_failed', nil then '<Not Found>'
|
|
198
|
+
when 'bootstrap' then 'Bootstrapped'
|
|
199
|
+
when 'bootstrap_failed' then 'Bootstrap Failed'
|
|
200
|
+
when 'detect' then 'Detected'
|
|
201
|
+
when 'exec' then 'Executed'
|
|
202
|
+
when 'exec_failed' then 'Execution Failed'
|
|
203
|
+
when 'verify', 'verify_failed'
|
|
204
|
+
validator_count = validators.count
|
|
205
|
+
validation_count = validations.values.select { |v| v['result'] == :passed }.count
|
|
206
|
+
if validator_count == validation_count
|
|
207
|
+
"Fully Verified (#{validation_count} of #{validator_count})"
|
|
208
|
+
else
|
|
209
|
+
"Partially Verified (#{validation_count} of #{validator_count})"
|
|
210
|
+
end
|
|
211
|
+
# when 'verify_failed' then 'Verification Failed'
|
|
212
|
+
else "<Unknown (#{status})>"
|
|
213
|
+
end
|
|
214
|
+
end
|
|
215
|
+
|
|
216
|
+
def status_color
|
|
217
|
+
case status_description
|
|
218
|
+
when '<Not Found>' then :white
|
|
219
|
+
when 'Cloned' then :magenta
|
|
220
|
+
when 'Bootstrapped' then :magenta
|
|
221
|
+
when 'Sample Found' then :cyan
|
|
222
|
+
when 'Executed' then :blue
|
|
223
|
+
when /Verified/
|
|
224
|
+
if status_description =~ /Fully/
|
|
225
|
+
:green
|
|
226
|
+
else
|
|
227
|
+
:yellow
|
|
228
|
+
end
|
|
229
|
+
else :red
|
|
230
|
+
end
|
|
231
|
+
end
|
|
232
|
+
|
|
158
233
|
# Returns the last successfully completed action state of the instance.
|
|
159
234
|
#
|
|
160
235
|
# @return [String] a named action which was last successfully completed
|
|
161
|
-
def
|
|
162
|
-
state_file.read['
|
|
236
|
+
def last_attempted_action
|
|
237
|
+
state_file.read['last_attempted_action']
|
|
238
|
+
end
|
|
239
|
+
|
|
240
|
+
def last_completed_action
|
|
241
|
+
state_file.read['last_completed_action']
|
|
163
242
|
end
|
|
164
243
|
|
|
165
244
|
def validations
|
|
166
|
-
|
|
245
|
+
return nil if result.nil?
|
|
246
|
+
result.validations
|
|
167
247
|
end
|
|
168
248
|
|
|
169
249
|
def transition_to(desired)
|
|
170
250
|
transition_result = nil
|
|
171
251
|
begin
|
|
172
|
-
FSM.actions(
|
|
252
|
+
FSM.actions(last_completed_action, desired).each do |transition|
|
|
173
253
|
transition_result = send("#{transition}_action")
|
|
174
254
|
end
|
|
175
255
|
rescue Polytrix::FeatureNotImplementedError
|
|
176
256
|
warn("#{slug} is not implemented")
|
|
177
257
|
rescue ActionFailed => e
|
|
178
|
-
|
|
179
|
-
|
|
258
|
+
# Need to use with_friendly_errors again somewhere, since errors don't bubble up
|
|
259
|
+
# without fast-fail?
|
|
260
|
+
Polytrix.handle_error(e)
|
|
261
|
+
raise(ChallengeFailure, e.message, e.backtrace)
|
|
180
262
|
end
|
|
181
263
|
transition_result
|
|
182
264
|
end
|
|
183
265
|
|
|
184
|
-
def log_failure(what,
|
|
266
|
+
def log_failure(what, _e)
|
|
185
267
|
return if logger.logdev.nil?
|
|
186
268
|
|
|
187
269
|
logger.logdev.error(failure_message(what))
|
|
@@ -195,7 +277,7 @@ module Polytrix
|
|
|
195
277
|
# @return [String] a failure message
|
|
196
278
|
# @api private
|
|
197
279
|
def failure_message(what)
|
|
198
|
-
"#{what.capitalize} failed
|
|
280
|
+
"#{what.capitalize} failed for test #{slug}."
|
|
199
281
|
end
|
|
200
282
|
|
|
201
283
|
# The simplest finite state machine pseudo-implementation needed to manage
|
|
@@ -223,7 +305,7 @@ module Polytrix
|
|
|
223
305
|
end
|
|
224
306
|
end
|
|
225
307
|
|
|
226
|
-
TRANSITIONS = [:destroy, :exec, :verify]
|
|
308
|
+
TRANSITIONS = [:destroy, :detect, :exec, :verify]
|
|
227
309
|
|
|
228
310
|
# Determines the index of a state in the state lifecycle vector. Woah.
|
|
229
311
|
#
|
|
@@ -2,44 +2,54 @@ require 'polytrix'
|
|
|
2
2
|
require 'rbconfig'
|
|
3
3
|
|
|
4
4
|
module Polytrix
|
|
5
|
-
module
|
|
6
|
-
autoload :LinuxChallengeRunner, 'polytrix/
|
|
7
|
-
autoload :WindowsChallengeRunner, 'polytrix/
|
|
5
|
+
module Executors
|
|
6
|
+
autoload :LinuxChallengeRunner, 'polytrix/executors/linux_challenge_executor'
|
|
7
|
+
autoload :WindowsChallengeRunner, 'polytrix/executors/windows_challenge_executor'
|
|
8
8
|
end
|
|
9
9
|
|
|
10
10
|
class ChallengeRunner < Thor::Shell::Color
|
|
11
|
-
include Polytrix::
|
|
12
|
-
include
|
|
13
|
-
|
|
14
|
-
attr_accessor :env
|
|
11
|
+
include Polytrix::Util::FileSystem
|
|
12
|
+
include Executor
|
|
15
13
|
|
|
16
14
|
def self.create_runner
|
|
17
15
|
case RbConfig::CONFIG['host_os']
|
|
18
16
|
when /mswin(\d+)|mingw/i
|
|
19
|
-
|
|
17
|
+
# TODO: Display warning that Windows support is experimental
|
|
18
|
+
Executors::WindowsChallengeRunner.new
|
|
20
19
|
else
|
|
21
|
-
|
|
20
|
+
Executors::LinuxChallengeRunner.new
|
|
22
21
|
end
|
|
23
22
|
end
|
|
24
23
|
|
|
25
|
-
def run_command(command)
|
|
24
|
+
def run_command(command, opts = { cwd: Dir.pwd })
|
|
26
25
|
if Polytrix.configuration.dry_run
|
|
27
|
-
puts "Would have run #{command}"
|
|
26
|
+
puts "Would have run #{command} with #{opts.inspect}"
|
|
28
27
|
else
|
|
29
28
|
say_status 'polytrix:execute', command
|
|
30
|
-
execute
|
|
29
|
+
execute(command, opts)
|
|
31
30
|
end
|
|
32
31
|
end
|
|
33
32
|
|
|
34
|
-
def run_challenge(challenge)
|
|
35
|
-
|
|
36
|
-
challenge.
|
|
33
|
+
def run_challenge(challenge, spies = Polytrix::Spies)
|
|
34
|
+
source_file = challenge[:source_file].to_s
|
|
35
|
+
basedir = challenge[:basedir].to_s
|
|
36
|
+
command = challenge_command(source_file, basedir)
|
|
37
|
+
spies.observe(challenge) do
|
|
38
|
+
execution_result = run_command(command, cwd: basedir, env: environment_variables(challenge[:vars]))
|
|
39
|
+
challenge[:result] = Result.new(execution_result: execution_result, source_file: source_file)
|
|
40
|
+
end
|
|
41
|
+
challenge[:result]
|
|
37
42
|
end
|
|
38
43
|
|
|
39
|
-
|
|
44
|
+
protected
|
|
40
45
|
|
|
41
|
-
def
|
|
42
|
-
|
|
46
|
+
def environment_variables(test_vars)
|
|
47
|
+
global_vars = begin
|
|
48
|
+
Polytrix.manifest[:global_env].dup
|
|
49
|
+
rescue
|
|
50
|
+
{}
|
|
51
|
+
end
|
|
52
|
+
global_vars.merge(test_vars.dup)
|
|
43
53
|
end
|
|
44
54
|
end
|
|
45
55
|
end
|
data/lib/polytrix/cli.rb
CHANGED
|
@@ -2,6 +2,7 @@ require 'thor'
|
|
|
2
2
|
|
|
3
3
|
require 'polytrix'
|
|
4
4
|
require 'polytrix/command'
|
|
5
|
+
require 'polytrix/command/report'
|
|
5
6
|
|
|
6
7
|
module Polytrix
|
|
7
8
|
class CLI < Thor # rubocop:disable ClassLength
|
|
@@ -29,8 +30,6 @@ module Polytrix
|
|
|
29
30
|
str_const = Thor::Util.camel_case(command)
|
|
30
31
|
klass = ::Polytrix::Command.const_get(str_const)
|
|
31
32
|
klass.new(args, options, command_options).call
|
|
32
|
-
rescue ArgumentError => e
|
|
33
|
-
abort e.message
|
|
34
33
|
end
|
|
35
34
|
end
|
|
36
35
|
|
|
@@ -44,17 +43,30 @@ module Polytrix
|
|
|
44
43
|
# Constructs a new instance.
|
|
45
44
|
def initialize(*args)
|
|
46
45
|
super
|
|
46
|
+
Polytrix.logger = Polytrix.default_file_logger
|
|
47
47
|
$stdout.sync = true
|
|
48
48
|
end
|
|
49
49
|
|
|
50
|
+
def self.filter_options
|
|
51
|
+
method_option :failed,
|
|
52
|
+
type: :boolean,
|
|
53
|
+
desc: 'Only list tests that failed / passed'
|
|
54
|
+
method_option :skipped,
|
|
55
|
+
type: :boolean,
|
|
56
|
+
desc: 'Only list tests that were skipped / executed'
|
|
57
|
+
method_option :samples,
|
|
58
|
+
type: :boolean,
|
|
59
|
+
desc: 'Only list tests that have sample code / do not have sample code'
|
|
60
|
+
end
|
|
61
|
+
|
|
50
62
|
desc 'list [INSTANCE|REGEXP|all]', 'Lists one or more scenarios'
|
|
51
|
-
method_option :bare,
|
|
52
|
-
aliases: '-b',
|
|
53
|
-
type: :boolean,
|
|
54
|
-
desc: 'List the name of each scenario only, one per line'
|
|
55
63
|
method_option :log_level,
|
|
56
64
|
aliases: '-l',
|
|
57
65
|
desc: 'Set the log level (debug, info, warn, error, fatal)'
|
|
66
|
+
method_option :format,
|
|
67
|
+
desc: 'List output format',
|
|
68
|
+
enum: %w(text markdown json yaml),
|
|
69
|
+
default: 'text'
|
|
58
70
|
method_option :manifest,
|
|
59
71
|
aliases: '-m',
|
|
60
72
|
desc: 'The Polytrix test manifest file location',
|
|
@@ -65,22 +77,26 @@ module Polytrix
|
|
|
65
77
|
default: 'tests/polytrix'
|
|
66
78
|
method_option :solo,
|
|
67
79
|
desc: 'Enable solo mode - Polytrix will auto-configure a single implementor and its scenarios'
|
|
68
|
-
|
|
80
|
+
# , default: 'polytrix.yml'
|
|
69
81
|
method_option :solo_glob,
|
|
70
82
|
desc: 'The globbing pattern to find code samples in solo mode'
|
|
83
|
+
method_option :source,
|
|
84
|
+
type: :boolean,
|
|
85
|
+
desc: 'Include source file in listing'
|
|
86
|
+
filter_options
|
|
71
87
|
def list(*args)
|
|
72
88
|
update_config!
|
|
73
89
|
perform('list', 'list', args, options)
|
|
74
90
|
end
|
|
75
91
|
|
|
76
|
-
desc '
|
|
77
|
-
method_option :bare,
|
|
78
|
-
aliases: '-b',
|
|
79
|
-
type: :boolean,
|
|
80
|
-
desc: 'List the name of each scenario only, one per line'
|
|
92
|
+
desc 'show [INSTANCE|REGEXP|all]', 'Show detailed status for one or more scenarios'
|
|
81
93
|
method_option :log_level,
|
|
82
94
|
aliases: '-l',
|
|
83
95
|
desc: 'Set the log level (debug, info, warn, error, fatal)'
|
|
96
|
+
method_option :format,
|
|
97
|
+
desc: 'List output format',
|
|
98
|
+
enum: %w(text markdown json yaml),
|
|
99
|
+
default: 'text'
|
|
84
100
|
method_option :manifest,
|
|
85
101
|
aliases: '-m',
|
|
86
102
|
desc: 'The Polytrix test manifest file location',
|
|
@@ -91,25 +107,28 @@ module Polytrix
|
|
|
91
107
|
default: 'tests/polytrix'
|
|
92
108
|
method_option :solo,
|
|
93
109
|
desc: 'Enable solo mode - Polytrix will auto-configure a single implementor and its scenarios'
|
|
94
|
-
|
|
110
|
+
# , default: 'polytrix.yml'
|
|
95
111
|
method_option :solo_glob,
|
|
96
112
|
desc: 'The globbing pattern to find code samples in solo mode'
|
|
97
|
-
|
|
113
|
+
filter_options
|
|
114
|
+
def show(*args)
|
|
98
115
|
update_config!
|
|
99
|
-
perform('
|
|
116
|
+
perform('show', 'show', args, options)
|
|
100
117
|
end
|
|
101
118
|
|
|
102
119
|
{
|
|
103
|
-
clone:
|
|
104
|
-
|
|
105
|
-
bootstrap:
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
120
|
+
clone: 'Change scenario state to cloned. ' \
|
|
121
|
+
'Clone the code sample from git',
|
|
122
|
+
bootstrap: 'Change scenario state to bootstraped. ' \
|
|
123
|
+
'Running bootstrap scripts for the implementor',
|
|
124
|
+
detect: 'Find sample code that matches a test scenario. ' \
|
|
125
|
+
'Attempts to locate a code sample with a filename that the test scenario name.',
|
|
126
|
+
exec: 'Change instance state to executed. ' \
|
|
127
|
+
'Execute the code sample and capture the results.',
|
|
128
|
+
verify: 'Change instance state to verified. ' \
|
|
129
|
+
'Assert that the captured results match the expectations for the scenario.',
|
|
130
|
+
destroy: 'Change scenario state to destroyed. ' \
|
|
131
|
+
'Delete all information for one or more scenarios'
|
|
113
132
|
}.each do |action, short_desc|
|
|
114
133
|
desc(
|
|
115
134
|
"#{action} [INSTANCE|REGEXP|all]",
|
|
@@ -146,7 +165,6 @@ module Polytrix
|
|
|
146
165
|
define_method(action) do |*args|
|
|
147
166
|
update_config!
|
|
148
167
|
action_options = options.dup
|
|
149
|
-
action_options['on'] = :implementor if [:clone, :bootstrap].include? action
|
|
150
168
|
perform(action, 'action', args, action_options)
|
|
151
169
|
end
|
|
152
170
|
end
|
|
@@ -179,7 +197,7 @@ module Polytrix
|
|
|
179
197
|
default: 'tests/polytrix'
|
|
180
198
|
method_option :solo,
|
|
181
199
|
desc: 'Enable solo mode - Polytrix will auto-configure a single implementor and its scenarios'
|
|
182
|
-
|
|
200
|
+
# , default: 'polytrix.yml'
|
|
183
201
|
method_option :solo_glob,
|
|
184
202
|
desc: 'The globbing pattern to find code samples in solo mode'
|
|
185
203
|
def test(*args)
|
|
@@ -188,54 +206,20 @@ module Polytrix
|
|
|
188
206
|
perform('test', 'test', args, action_options)
|
|
189
207
|
end
|
|
190
208
|
|
|
191
|
-
desc 'code2doc [INSTANCE|REGEXP|all]',
|
|
192
|
-
'Generates documenation from sample code for one or more scenarios'
|
|
193
|
-
long_desc <<-DESC
|
|
194
|
-
This task will convert annotated sample code to documentation. Markdown or
|
|
195
|
-
reStructureText are supported.
|
|
196
|
-
DESC
|
|
197
|
-
method_option :log_level,
|
|
198
|
-
aliases: '-l',
|
|
199
|
-
desc: 'Set the log level (debug, info, warn, error, fatal)'
|
|
200
|
-
method_option :manifest,
|
|
201
|
-
aliases: '-m',
|
|
202
|
-
desc: 'The Polytrix test manifest file location',
|
|
203
|
-
default: 'polytrix.yml'
|
|
204
|
-
method_option :solo,
|
|
205
|
-
desc: 'Enable solo mode - Polytrix will auto-configure a single implementor and its scenarios'
|
|
206
|
-
# , default: 'polytrix.yml'
|
|
207
|
-
method_option :solo_glob,
|
|
208
|
-
desc: 'The globbing pattern to find code samples in solo mode'
|
|
209
|
-
method_option :format,
|
|
210
|
-
aliases: '-f',
|
|
211
|
-
enum: %w(md rst),
|
|
212
|
-
default: 'md',
|
|
213
|
-
desc: 'Target documentation format'
|
|
214
|
-
method_option :target_dir,
|
|
215
|
-
aliases: '-d',
|
|
216
|
-
default: 'docs/',
|
|
217
|
-
desc: 'The target directory where documentation for generated documentation.'
|
|
218
|
-
def code2doc(*args)
|
|
219
|
-
update_config!
|
|
220
|
-
action_options = options.dup
|
|
221
|
-
perform('code2doc', 'action', args, action_options)
|
|
222
|
-
end
|
|
223
|
-
|
|
224
209
|
desc 'version', "Print Polytrix's version information"
|
|
225
210
|
def version
|
|
226
211
|
puts "Polytrix version #{Polytrix::VERSION}"
|
|
227
212
|
end
|
|
228
|
-
map %w
|
|
213
|
+
map %w(-v --version) => :version
|
|
229
214
|
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
#
|
|
233
|
-
#
|
|
234
|
-
#
|
|
235
|
-
#
|
|
236
|
-
# and one or more gems will be added to the project's Gemfile.
|
|
215
|
+
desc 'report', 'Generate reports'
|
|
216
|
+
subcommand 'report', Polytrix::Command::Report
|
|
217
|
+
# register Polytrix::Command::Report, 'report',
|
|
218
|
+
# 'report', 'Generates a report'
|
|
219
|
+
# long_desc <<-D, for: 'report'
|
|
220
|
+
# Polytrix will generate an HTML report.
|
|
237
221
|
# D
|
|
238
|
-
# tasks[
|
|
222
|
+
# tasks['report'].options = Polytrix::Command::Report.class_options
|
|
239
223
|
|
|
240
224
|
private
|
|
241
225
|
|
data/lib/polytrix/color.rb
CHANGED
|
@@ -8,10 +8,10 @@ module Polytrix
|
|
|
8
8
|
bright_cyan: 96, bright_white: 97
|
|
9
9
|
}.freeze
|
|
10
10
|
|
|
11
|
-
COLORS = %w
|
|
11
|
+
COLORS = %w(
|
|
12
12
|
cyan yellow green magenta blue bright_cyan bright_yellow
|
|
13
13
|
bright_green bright_magenta bright_blue
|
|
14
|
-
|
|
14
|
+
).freeze
|
|
15
15
|
|
|
16
16
|
# Returns an ansi escaped string representing a color control sequence.
|
|
17
17
|
#
|
|
@@ -5,15 +5,16 @@ module Polytrix
|
|
|
5
5
|
class Action < Polytrix::Command::Base
|
|
6
6
|
include RunAction
|
|
7
7
|
|
|
8
|
+
IMPLEMENTOR_ACTIONS = [:clone, :bootstrap] # These are run once per implementor, not per test
|
|
9
|
+
|
|
8
10
|
# Invoke the command.
|
|
9
11
|
def call
|
|
10
12
|
banner "Starting Polytrix (v#{Polytrix::VERSION})"
|
|
11
13
|
elapsed = Benchmark.measure do
|
|
12
14
|
setup
|
|
13
|
-
tests = parse_subcommand(args.
|
|
15
|
+
tests = parse_subcommand(args.pop)
|
|
14
16
|
implementors = tests.map(&:implementor).uniq
|
|
15
|
-
|
|
16
|
-
if [:clone, :bootstrap].include? action # actions on implementors
|
|
17
|
+
if IMPLEMENTOR_ACTIONS.include? action # actions on implementors
|
|
17
18
|
run_action(action, implementors)
|
|
18
19
|
else # actions on tests
|
|
19
20
|
run_action(action, tests)
|