howzit 2.1.28 → 2.1.30
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/CHANGELOG.md +121 -0
- data/README.md +5 -1
- data/Rakefile +11 -4
- data/bin/howzit +65 -65
- data/howzit.gemspec +1 -1
- data/lib/howzit/buildnote.rb +4 -8
- data/lib/howzit/colors.rb +50 -22
- data/lib/howzit/condition_evaluator.rb +307 -0
- data/lib/howzit/conditional_content.rb +96 -0
- data/lib/howzit/config.rb +28 -3
- data/lib/howzit/console_logger.rb +74 -2
- data/lib/howzit/directive.rb +137 -0
- data/lib/howzit/prompt.rb +20 -12
- data/lib/howzit/run_report.rb +1 -1
- data/lib/howzit/script_comm.rb +105 -0
- data/lib/howzit/script_support.rb +479 -0
- data/lib/howzit/stringutils.rb +4 -4
- data/lib/howzit/task.rb +68 -6
- data/lib/howzit/topic.rb +576 -13
- data/lib/howzit/util.rb +11 -3
- data/lib/howzit/version.rb +1 -1
- data/lib/howzit.rb +5 -0
- data/spec/condition_evaluator_spec.rb +261 -0
- data/spec/conditional_blocks_integration_spec.rb +159 -0
- data/spec/conditional_content_spec.rb +296 -0
- data/spec/log_level_spec.rb +247 -0
- data/spec/script_comm_spec.rb +303 -0
- data/spec/sequential_conditional_spec.rb +319 -0
- data/spec/set_var_spec.rb +603 -0
- data/spec/spec_helper.rb +3 -1
- data/spec/topic_spec.rb +8 -6
- data/src/_README.md +5 -1
- metadata +23 -4
|
@@ -0,0 +1,303 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'spec_helper'
|
|
4
|
+
|
|
5
|
+
describe Howzit::ScriptComm do
|
|
6
|
+
before do
|
|
7
|
+
Howzit.named_arguments = {}
|
|
8
|
+
Howzit.options[:log_level] = 0
|
|
9
|
+
# Clear any existing HOWZIT_COMM_FILE
|
|
10
|
+
ENV.delete('HOWZIT_COMM_FILE')
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
after do
|
|
14
|
+
# Clean up any leftover communication files
|
|
15
|
+
if ENV['HOWZIT_COMM_FILE'] && File.exist?(ENV['HOWZIT_COMM_FILE']) && File.file?(ENV['HOWZIT_COMM_FILE'])
|
|
16
|
+
begin
|
|
17
|
+
File.unlink(ENV['HOWZIT_COMM_FILE'])
|
|
18
|
+
rescue Errno::EPERM, Errno::ENOENT
|
|
19
|
+
# Ignore permission errors or missing files
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
ENV.delete('HOWZIT_COMM_FILE')
|
|
23
|
+
Howzit.named_arguments = {}
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
describe '.setup' do
|
|
27
|
+
it 'creates a communication file' do
|
|
28
|
+
comm_file = Howzit::ScriptComm.setup
|
|
29
|
+
expect(comm_file).to be_a(String)
|
|
30
|
+
expect(File.exist?(comm_file)).to be true
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
it 'sets HOWZIT_COMM_FILE environment variable' do
|
|
34
|
+
comm_file = Howzit::ScriptComm.setup
|
|
35
|
+
expect(ENV['HOWZIT_COMM_FILE']).to eq(comm_file)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
it 'creates a writable file' do
|
|
39
|
+
comm_file = Howzit::ScriptComm.setup
|
|
40
|
+
expect { File.write(comm_file, 'test') }.not_to raise_error
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
describe '.process' do
|
|
45
|
+
it 'returns empty hash for non-existent file' do
|
|
46
|
+
result = Howzit::ScriptComm.process('/nonexistent/path')
|
|
47
|
+
expect(result).to eq({ logs: [], vars: {} })
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
it 'processes log messages' do
|
|
51
|
+
comm_file = Howzit::ScriptComm.setup
|
|
52
|
+
File.write(comm_file, "LOG:info:Test message\nLOG:warn:Warning message\n")
|
|
53
|
+
result = Howzit::ScriptComm.process(comm_file)
|
|
54
|
+
expect(result[:logs].length).to eq(2)
|
|
55
|
+
expect(result[:logs][0][:level]).to eq(:info)
|
|
56
|
+
expect(result[:logs][0][:message]).to eq('Test message')
|
|
57
|
+
expect(result[:logs][1][:level]).to eq(:warn)
|
|
58
|
+
expect(result[:logs][1][:message]).to eq('Warning message')
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
it 'processes variables' do
|
|
62
|
+
comm_file = Howzit::ScriptComm.setup
|
|
63
|
+
File.write(comm_file, "VAR:TEST_VAR=test_value\nVAR:ANOTHER_VAR=another_value\n")
|
|
64
|
+
result = Howzit::ScriptComm.process(comm_file)
|
|
65
|
+
expect(result[:vars]).to eq({ 'TEST_VAR' => 'test_value', 'ANOTHER_VAR' => 'another_value' })
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
it 'processes mixed logs and variables' do
|
|
69
|
+
comm_file = Howzit::ScriptComm.setup
|
|
70
|
+
File.write(comm_file, "LOG:info:Starting\nVAR:STATUS=running\nLOG:info:Done\nVAR:STATUS=complete\n")
|
|
71
|
+
result = Howzit::ScriptComm.process(comm_file)
|
|
72
|
+
expect(result[:logs].length).to eq(2)
|
|
73
|
+
expect(result[:vars]).to eq({ 'STATUS' => 'complete' })
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
it 'handles all log levels' do
|
|
77
|
+
comm_file = Howzit::ScriptComm.setup
|
|
78
|
+
File.write(comm_file, "LOG:info:Info message\nLOG:warn:Warn message\nLOG:error:Error message\nLOG:debug:Debug message\n")
|
|
79
|
+
result = Howzit::ScriptComm.process(comm_file)
|
|
80
|
+
expect(result[:logs].map { |l| l[:level] }).to contain_exactly(:info, :warn, :error, :debug)
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
it 'ignores empty lines' do
|
|
84
|
+
comm_file = Howzit::ScriptComm.setup
|
|
85
|
+
File.write(comm_file, "\nLOG:info:Message\n\nVAR:TEST=value\n\n")
|
|
86
|
+
result = Howzit::ScriptComm.process(comm_file)
|
|
87
|
+
expect(result[:logs].length).to eq(1)
|
|
88
|
+
expect(result[:vars]).to eq({ 'TEST' => 'value' })
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
it 'handles case-insensitive log levels' do
|
|
92
|
+
comm_file = Howzit::ScriptComm.setup
|
|
93
|
+
File.write(comm_file, "LOG:INFO:Uppercase\nLOG:Warn:Mixed\nLOG:error:lowercase\n")
|
|
94
|
+
result = Howzit::ScriptComm.process(comm_file)
|
|
95
|
+
expect(result[:logs].map { |l| l[:level] }).to contain_exactly(:info, :warn, :error)
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
it 'handles case-insensitive variable names' do
|
|
99
|
+
comm_file = Howzit::ScriptComm.setup
|
|
100
|
+
File.write(comm_file, "VAR:test_var=lowercase\nVAR:TEST_VAR=uppercase\n")
|
|
101
|
+
result = Howzit::ScriptComm.process(comm_file)
|
|
102
|
+
# Variable names match case-insensitively, but both are stored (last one wins)
|
|
103
|
+
# The regex captures the original case, so both keys are present
|
|
104
|
+
expect(result[:vars].keys).to include('TEST_VAR')
|
|
105
|
+
expect(result[:vars].keys).to include('test_var')
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
it 'removes the communication file after processing' do
|
|
109
|
+
comm_file = Howzit::ScriptComm.setup
|
|
110
|
+
File.write(comm_file, "VAR:TEST=value\n")
|
|
111
|
+
Howzit::ScriptComm.process(comm_file)
|
|
112
|
+
expect(File.exist?(comm_file)).to be false
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
it 'handles malformed lines gracefully' do
|
|
116
|
+
comm_file = Howzit::ScriptComm.setup
|
|
117
|
+
File.write(comm_file, "INVALID:line\nLOG:info:Valid message\nVAR:TEST=value\nBOGUS\n")
|
|
118
|
+
result = Howzit::ScriptComm.process(comm_file)
|
|
119
|
+
expect(result[:logs].length).to eq(1)
|
|
120
|
+
expect(result[:vars]).to eq({ 'TEST' => 'value' })
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
it 'handles file read errors gracefully' do
|
|
124
|
+
# Create a file that will cause a read error
|
|
125
|
+
comm_file = Howzit::ScriptComm.setup
|
|
126
|
+
# Make it unreadable (but this is platform-dependent, so just test that it doesn't crash)
|
|
127
|
+
# Instead, test with a file that doesn't exist after setup
|
|
128
|
+
File.unlink(comm_file) if File.exist?(comm_file)
|
|
129
|
+
result = Howzit::ScriptComm.process(comm_file)
|
|
130
|
+
expect(result).to eq({ logs: [], vars: {} })
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
describe '.apply' do
|
|
135
|
+
it 'applies log messages to console' do
|
|
136
|
+
comm_file = Howzit::ScriptComm.setup
|
|
137
|
+
File.write(comm_file, "LOG:info:Test info message\n")
|
|
138
|
+
expect(Howzit.console).to receive(:info).with('Test info message')
|
|
139
|
+
Howzit::ScriptComm.apply(comm_file)
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
it 'applies variables to named_arguments' do
|
|
143
|
+
comm_file = Howzit::ScriptComm.setup
|
|
144
|
+
File.write(comm_file, "VAR:TEST_VAR=test_value\n")
|
|
145
|
+
Howzit::ScriptComm.apply(comm_file)
|
|
146
|
+
expect(Howzit.named_arguments['TEST_VAR']).to eq('test_value')
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
it 'merges variables with existing named_arguments' do
|
|
150
|
+
Howzit.named_arguments = { 'EXISTING' => 'old_value' }
|
|
151
|
+
comm_file = Howzit::ScriptComm.setup
|
|
152
|
+
File.write(comm_file, "VAR:NEW_VAR=new_value\n")
|
|
153
|
+
Howzit::ScriptComm.apply(comm_file)
|
|
154
|
+
expect(Howzit.named_arguments).to eq({ 'EXISTING' => 'old_value', 'NEW_VAR' => 'new_value' })
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
it 'overwrites existing variables' do
|
|
158
|
+
Howzit.named_arguments = { 'TEST_VAR' => 'old_value' }
|
|
159
|
+
comm_file = Howzit::ScriptComm.setup
|
|
160
|
+
File.write(comm_file, "VAR:TEST_VAR=new_value\n")
|
|
161
|
+
Howzit::ScriptComm.apply(comm_file)
|
|
162
|
+
expect(Howzit.named_arguments['TEST_VAR']).to eq('new_value')
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
it 'handles multiple log levels' do
|
|
166
|
+
comm_file = Howzit::ScriptComm.setup
|
|
167
|
+
File.write(comm_file, "LOG:info:Info\nLOG:warn:Warn\nLOG:error:Error\nLOG:debug:Debug\n")
|
|
168
|
+
expect(Howzit.console).to receive(:info).with('Info')
|
|
169
|
+
expect(Howzit.console).to receive(:warn).with('Warn')
|
|
170
|
+
expect(Howzit.console).to receive(:error).with('Error')
|
|
171
|
+
expect(Howzit.console).to receive(:debug).with('Debug')
|
|
172
|
+
Howzit::ScriptComm.apply(comm_file)
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
it 'does nothing if file is empty' do
|
|
176
|
+
comm_file = Howzit::ScriptComm.setup
|
|
177
|
+
File.write(comm_file, "\n")
|
|
178
|
+
Howzit::ScriptComm.apply(comm_file)
|
|
179
|
+
expect(Howzit.named_arguments).to be_empty
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
it 'initializes named_arguments if nil' do
|
|
183
|
+
Howzit.named_arguments = nil
|
|
184
|
+
comm_file = Howzit::ScriptComm.setup
|
|
185
|
+
File.write(comm_file, "VAR:TEST=value\n")
|
|
186
|
+
Howzit::ScriptComm.apply(comm_file)
|
|
187
|
+
expect(Howzit.named_arguments).to eq({ 'TEST' => 'value' })
|
|
188
|
+
end
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
describe 'integration with Task#run_run' do
|
|
192
|
+
it 'processes communication file after script execution' do
|
|
193
|
+
# Create a temporary script that writes to communication file
|
|
194
|
+
script_file = Tempfile.new('test_script')
|
|
195
|
+
script_file.write(<<~SCRIPT)
|
|
196
|
+
#!/bin/bash
|
|
197
|
+
echo "VAR:TEST_VAR=script_value" >> "$HOWZIT_COMM_FILE"
|
|
198
|
+
echo "LOG:info:Script message" >> "$HOWZIT_COMM_FILE"
|
|
199
|
+
SCRIPT
|
|
200
|
+
script_file.close
|
|
201
|
+
File.chmod(0o755, script_file.path)
|
|
202
|
+
|
|
203
|
+
task = Howzit::Task.new({ type: :run,
|
|
204
|
+
title: 'Test Script',
|
|
205
|
+
action: script_file.path })
|
|
206
|
+
|
|
207
|
+
allow(Howzit.console).to receive(:info)
|
|
208
|
+
expect(Howzit.console).to receive(:info).with('Script message')
|
|
209
|
+
|
|
210
|
+
task.run
|
|
211
|
+
|
|
212
|
+
expect(Howzit.named_arguments['TEST_VAR']).to eq('script_value')
|
|
213
|
+
|
|
214
|
+
script_file.unlink
|
|
215
|
+
end
|
|
216
|
+
|
|
217
|
+
it 'makes variables available for subsequent tasks' do
|
|
218
|
+
# Create first script that sets a variable
|
|
219
|
+
script1 = Tempfile.new('script1')
|
|
220
|
+
script1.write(<<~SCRIPT)
|
|
221
|
+
#!/bin/bash
|
|
222
|
+
echo "VAR:BUILD_VERSION=1.2.3" >> "$HOWZIT_COMM_FILE"
|
|
223
|
+
SCRIPT
|
|
224
|
+
script1.close
|
|
225
|
+
File.chmod(0o755, script1.path)
|
|
226
|
+
|
|
227
|
+
# Create second script that uses the variable (simulated via echo)
|
|
228
|
+
script2 = Tempfile.new('script2')
|
|
229
|
+
script2.write(<<~SCRIPT)
|
|
230
|
+
#!/bin/bash
|
|
231
|
+
echo "Version would be: ${BUILD_VERSION}"
|
|
232
|
+
SCRIPT
|
|
233
|
+
script2.close
|
|
234
|
+
File.chmod(0o755, script2.path)
|
|
235
|
+
|
|
236
|
+
# Run first task
|
|
237
|
+
task1 = Howzit::Task.new({ type: :run,
|
|
238
|
+
title: 'Set Version',
|
|
239
|
+
action: script1.path })
|
|
240
|
+
allow(Howzit.console).to receive(:info)
|
|
241
|
+
task1.run
|
|
242
|
+
|
|
243
|
+
# Verify variable is set
|
|
244
|
+
expect(Howzit.named_arguments['BUILD_VERSION']).to eq('1.2.3')
|
|
245
|
+
|
|
246
|
+
# Create a task with variable substitution in the action
|
|
247
|
+
# Note: Variable substitution happens when Task is created,
|
|
248
|
+
# so we need to create task2 AFTER task1 runs
|
|
249
|
+
action_with_var = "echo Version: ${BUILD_VERSION}"
|
|
250
|
+
action_rendered = action_with_var.dup
|
|
251
|
+
action_rendered.render_named_placeholders
|
|
252
|
+
expect(action_rendered).to include('1.2.3')
|
|
253
|
+
|
|
254
|
+
script1.unlink
|
|
255
|
+
script2.unlink
|
|
256
|
+
end
|
|
257
|
+
end
|
|
258
|
+
|
|
259
|
+
describe 'integration with Task#run_block' do
|
|
260
|
+
it 'processes communication file after block execution' do
|
|
261
|
+
block_content = <<~BLOCK
|
|
262
|
+
#!/bin/bash
|
|
263
|
+
echo "VAR:BLOCK_VAR=block_value" >> "$HOWZIT_COMM_FILE"
|
|
264
|
+
echo "LOG:info:Block message" >> "$HOWZIT_COMM_FILE"
|
|
265
|
+
BLOCK
|
|
266
|
+
|
|
267
|
+
task = Howzit::Task.new({ type: :block,
|
|
268
|
+
title: 'Test Block',
|
|
269
|
+
action: block_content })
|
|
270
|
+
|
|
271
|
+
allow(Howzit.console).to receive(:info)
|
|
272
|
+
expect(Howzit.console).to receive(:info).with('Block message')
|
|
273
|
+
|
|
274
|
+
task.run
|
|
275
|
+
|
|
276
|
+
expect(Howzit.named_arguments['BLOCK_VAR']).to eq('block_value')
|
|
277
|
+
end
|
|
278
|
+
|
|
279
|
+
it 'cleans up communication file after block execution' do
|
|
280
|
+
comm_file_path = nil
|
|
281
|
+
allow(Howzit::ScriptComm).to receive(:setup).and_wrap_original do |m|
|
|
282
|
+
comm_file_path = m.call
|
|
283
|
+
comm_file_path
|
|
284
|
+
end
|
|
285
|
+
|
|
286
|
+
block_content = <<~BLOCK
|
|
287
|
+
#!/bin/bash
|
|
288
|
+
echo "VAR:TEST=value" >> "$HOWZIT_COMM_FILE"
|
|
289
|
+
BLOCK
|
|
290
|
+
|
|
291
|
+
task = Howzit::Task.new({ type: :block,
|
|
292
|
+
title: 'Test Block',
|
|
293
|
+
action: block_content })
|
|
294
|
+
|
|
295
|
+
allow(Howzit.console).to receive(:info)
|
|
296
|
+
task.run
|
|
297
|
+
|
|
298
|
+
# Communication file should be cleaned up
|
|
299
|
+
expect(File.exist?(comm_file_path)).to be false if comm_file_path
|
|
300
|
+
end
|
|
301
|
+
end
|
|
302
|
+
end
|
|
303
|
+
|
|
@@ -0,0 +1,319 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'spec_helper'
|
|
4
|
+
|
|
5
|
+
describe 'Sequential Conditional Evaluation' do
|
|
6
|
+
before do
|
|
7
|
+
Howzit.options[:include_upstream] = false
|
|
8
|
+
Howzit.options[:default] = true
|
|
9
|
+
Howzit.options[:matching] = 'partial'
|
|
10
|
+
Howzit.options[:multiple_matches] = 'choose'
|
|
11
|
+
Howzit.options[:log_level] = 1
|
|
12
|
+
Howzit.named_arguments = {}
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
after do
|
|
16
|
+
FileUtils.rm_f('builda.md')
|
|
17
|
+
Howzit.named_arguments = {}
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
describe 'variables set in run blocks affecting conditionals' do
|
|
21
|
+
it 'allows @if blocks to use variables set in preceding run blocks' do
|
|
22
|
+
note = <<~EONOTE
|
|
23
|
+
# Test
|
|
24
|
+
|
|
25
|
+
## Test Topic
|
|
26
|
+
|
|
27
|
+
```run Set Variable
|
|
28
|
+
#!/bin/bash
|
|
29
|
+
echo "VAR:TEST_VAR=success" >> "$HOWZIT_COMM_FILE"
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
@if ${TEST_VAR} == "success"
|
|
33
|
+
@run(echo "Conditional task executed") Conditional Task
|
|
34
|
+
@end
|
|
35
|
+
EONOTE
|
|
36
|
+
File.open('builda.md', 'w') { |f| f.puts note }
|
|
37
|
+
Howzit.instance_variable_set(:@buildnote, nil)
|
|
38
|
+
topic = Howzit.buildnote.find_topic('Test Topic')[0]
|
|
39
|
+
expect(topic).not_to be_nil
|
|
40
|
+
|
|
41
|
+
# Verify the conditional task is present
|
|
42
|
+
expect(topic.directives).not_to be_nil
|
|
43
|
+
expect(topic.directives.any?(&:conditional?)).to be true
|
|
44
|
+
|
|
45
|
+
# Run the topic and verify the conditional task executes
|
|
46
|
+
allow(Howzit::Prompt).to receive(:yn).and_return(true)
|
|
47
|
+
|
|
48
|
+
# Track which tasks actually run
|
|
49
|
+
task_titles = []
|
|
50
|
+
allow_any_instance_of(Howzit::Task).to receive(:run).and_wrap_original do |method|
|
|
51
|
+
task = method.receiver
|
|
52
|
+
task_titles << task.title if task.respond_to?(:title) && task.title
|
|
53
|
+
method.call
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
topic.run
|
|
57
|
+
|
|
58
|
+
# The conditional task should have been executed
|
|
59
|
+
expect(task_titles).to include('Conditional Task')
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
it 'does not execute @if blocks when variable condition is false' do
|
|
63
|
+
note = <<~EONOTE
|
|
64
|
+
# Test
|
|
65
|
+
|
|
66
|
+
## Test Topic
|
|
67
|
+
|
|
68
|
+
```run Set Variable
|
|
69
|
+
#!/bin/bash
|
|
70
|
+
echo "VAR:TEST_VAR=failure" >> "$HOWZIT_COMM_FILE"
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
@if ${TEST_VAR} == "success"
|
|
74
|
+
@run(echo "This should not run") Hidden Task
|
|
75
|
+
@end
|
|
76
|
+
EONOTE
|
|
77
|
+
File.open('builda.md', 'w') { |f| f.puts note }
|
|
78
|
+
Howzit.instance_variable_set(:@buildnote, nil)
|
|
79
|
+
topic = Howzit.buildnote.find_topic('Test Topic')[0]
|
|
80
|
+
|
|
81
|
+
task_titles = []
|
|
82
|
+
allow(Howzit::Prompt).to receive(:yn).and_return(true)
|
|
83
|
+
|
|
84
|
+
# Track which tasks actually run
|
|
85
|
+
allow_any_instance_of(Howzit::Task).to receive(:run).and_wrap_original do |method|
|
|
86
|
+
task = method.receiver
|
|
87
|
+
task_titles << task.title if task.respond_to?(:title) && task.title
|
|
88
|
+
method.call
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
topic.run
|
|
92
|
+
|
|
93
|
+
# The conditional task should NOT have been executed
|
|
94
|
+
expect(task_titles).not_to include('Hidden Task')
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
it 're-evaluates conditionals after each task execution' do
|
|
98
|
+
note = <<~EONOTE
|
|
99
|
+
# Test
|
|
100
|
+
|
|
101
|
+
## Test Topic
|
|
102
|
+
|
|
103
|
+
```run Set First Variable
|
|
104
|
+
#!/bin/bash
|
|
105
|
+
echo "VAR:STEP=1" >> "$HOWZIT_COMM_FILE"
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
@if ${STEP} == "1"
|
|
109
|
+
@run(echo "VAR:STEP=2" >> "$HOWZIT_COMM_FILE") Update Step
|
|
110
|
+
@end
|
|
111
|
+
|
|
112
|
+
@if ${STEP} == "2"
|
|
113
|
+
@run(echo "Final step") Final Task
|
|
114
|
+
@end
|
|
115
|
+
EONOTE
|
|
116
|
+
File.open('builda.md', 'w') { |f| f.puts note }
|
|
117
|
+
Howzit.instance_variable_set(:@buildnote, nil)
|
|
118
|
+
topic = Howzit.buildnote.find_topic('Test Topic')[0]
|
|
119
|
+
|
|
120
|
+
task_titles = []
|
|
121
|
+
allow(Howzit::Prompt).to receive(:yn).and_return(true)
|
|
122
|
+
|
|
123
|
+
# Track which tasks actually run
|
|
124
|
+
allow_any_instance_of(Howzit::Task).to receive(:run).and_wrap_original do |method|
|
|
125
|
+
task = method.receiver
|
|
126
|
+
task_titles << task.title if task.respond_to?(:title) && task.title
|
|
127
|
+
method.call
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
topic.run
|
|
131
|
+
|
|
132
|
+
# Both conditional tasks should execute
|
|
133
|
+
expect(task_titles).to include('Update Step')
|
|
134
|
+
expect(task_titles).to include('Final Task')
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
it 'handles @unless blocks with variables from run blocks' do
|
|
138
|
+
note = <<~EONOTE
|
|
139
|
+
# Test
|
|
140
|
+
|
|
141
|
+
## Test Topic
|
|
142
|
+
|
|
143
|
+
```run Set Variable
|
|
144
|
+
#!/bin/bash
|
|
145
|
+
echo "VAR:STATUS=ready" >> "$HOWZIT_COMM_FILE"
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
@unless ${STATUS} == "not_ready"
|
|
149
|
+
@run(echo "Status is ready") Ready Task
|
|
150
|
+
@end
|
|
151
|
+
EONOTE
|
|
152
|
+
File.open('builda.md', 'w') { |f| f.puts note }
|
|
153
|
+
Howzit.instance_variable_set(:@buildnote, nil)
|
|
154
|
+
topic = Howzit.buildnote.find_topic('Test Topic')[0]
|
|
155
|
+
|
|
156
|
+
task_titles = []
|
|
157
|
+
allow(Howzit::Prompt).to receive(:yn).and_return(true)
|
|
158
|
+
|
|
159
|
+
# Track which tasks actually run
|
|
160
|
+
allow_any_instance_of(Howzit::Task).to receive(:run).and_wrap_original do |method|
|
|
161
|
+
task = method.receiver
|
|
162
|
+
task_titles << task.title if task.respond_to?(:title) && task.title
|
|
163
|
+
method.call
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
topic.run
|
|
167
|
+
|
|
168
|
+
expect(task_titles).to include('Ready Task')
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
it 'handles @elsif blocks with variables from run blocks' do
|
|
172
|
+
note = <<~EONOTE
|
|
173
|
+
# Test
|
|
174
|
+
|
|
175
|
+
## Test Topic
|
|
176
|
+
|
|
177
|
+
```run Set Variable
|
|
178
|
+
#!/bin/bash
|
|
179
|
+
echo "VAR:VALUE=two" >> "$HOWZIT_COMM_FILE"
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
@if ${VALUE} == "one"
|
|
183
|
+
@run(echo "Value is one") One Task
|
|
184
|
+
@elsif ${VALUE} == "two"
|
|
185
|
+
@run(echo "Value is two") Two Task
|
|
186
|
+
@else
|
|
187
|
+
@run(echo "Value is other") Other Task
|
|
188
|
+
@end
|
|
189
|
+
EONOTE
|
|
190
|
+
File.open('builda.md', 'w') { |f| f.puts note }
|
|
191
|
+
Howzit.instance_variable_set(:@buildnote, nil)
|
|
192
|
+
topic = Howzit.buildnote.find_topic('Test Topic')[0]
|
|
193
|
+
|
|
194
|
+
task_titles = []
|
|
195
|
+
allow(Howzit::Prompt).to receive(:yn).and_return(true)
|
|
196
|
+
|
|
197
|
+
# Track which tasks actually run
|
|
198
|
+
allow_any_instance_of(Howzit::Task).to receive(:run).and_wrap_original do |method|
|
|
199
|
+
task = method.receiver
|
|
200
|
+
task_titles << task.title if task.respond_to?(:title) && task.title
|
|
201
|
+
method.call
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
topic.run
|
|
205
|
+
|
|
206
|
+
expect(task_titles).to include('Two Task')
|
|
207
|
+
expect(task_titles).not_to include('One Task')
|
|
208
|
+
expect(task_titles).not_to include('Other Task')
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
it 'handles @else blocks with variables from run blocks' do
|
|
212
|
+
note = <<~EONOTE
|
|
213
|
+
# Test
|
|
214
|
+
|
|
215
|
+
## Test Topic
|
|
216
|
+
|
|
217
|
+
```run Set Variable
|
|
218
|
+
#!/bin/bash
|
|
219
|
+
echo "VAR:VALUE=other" >> "$HOWZIT_COMM_FILE"
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
@if ${VALUE} == "one"
|
|
223
|
+
@run(echo "Value is one") One Task
|
|
224
|
+
@else
|
|
225
|
+
@run(echo "Value is other") Other Task
|
|
226
|
+
@end
|
|
227
|
+
EONOTE
|
|
228
|
+
File.open('builda.md', 'w') { |f| f.puts note }
|
|
229
|
+
Howzit.instance_variable_set(:@buildnote, nil)
|
|
230
|
+
topic = Howzit.buildnote.find_topic('Test Topic')[0]
|
|
231
|
+
|
|
232
|
+
task_titles = []
|
|
233
|
+
allow(Howzit::Prompt).to receive(:yn).and_return(true)
|
|
234
|
+
|
|
235
|
+
# Track which tasks actually run
|
|
236
|
+
allow_any_instance_of(Howzit::Task).to receive(:run).and_wrap_original do |method|
|
|
237
|
+
task = method.receiver
|
|
238
|
+
task_titles << task.title if task.respond_to?(:title) && task.title
|
|
239
|
+
method.call
|
|
240
|
+
end
|
|
241
|
+
|
|
242
|
+
topic.run
|
|
243
|
+
|
|
244
|
+
expect(task_titles).to include('Other Task')
|
|
245
|
+
expect(task_titles).not_to include('One Task')
|
|
246
|
+
end
|
|
247
|
+
end
|
|
248
|
+
|
|
249
|
+
describe 'variables set in run blocks available in subsequent run blocks' do
|
|
250
|
+
it 'makes variables set in one run block available to subsequent run blocks' do
|
|
251
|
+
note = <<~EONOTE
|
|
252
|
+
# Test
|
|
253
|
+
|
|
254
|
+
## Test Topic
|
|
255
|
+
|
|
256
|
+
```run Set Variable
|
|
257
|
+
#!/bin/bash
|
|
258
|
+
echo "VAR:SHARED_VAR=test_value" >> "$HOWZIT_COMM_FILE"
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
```run Use Variable
|
|
262
|
+
#!/bin/bash
|
|
263
|
+
set_var VERIFIED "true"
|
|
264
|
+
```
|
|
265
|
+
EONOTE
|
|
266
|
+
File.open('builda.md', 'w') { |f| f.puts note }
|
|
267
|
+
Howzit.instance_variable_set(:@buildnote, nil)
|
|
268
|
+
topic = Howzit.buildnote.find_topic('Test Topic')[0]
|
|
269
|
+
|
|
270
|
+
allow(Howzit::Prompt).to receive(:yn).and_return(true)
|
|
271
|
+
|
|
272
|
+
# Actually run the tasks to set variables
|
|
273
|
+
topic.run
|
|
274
|
+
|
|
275
|
+
# Verify the variables were set and available
|
|
276
|
+
expect(Howzit.named_arguments['SHARED_VAR']).to eq('test_value')
|
|
277
|
+
expect(Howzit.named_arguments['VERIFIED']).to eq('true')
|
|
278
|
+
end
|
|
279
|
+
|
|
280
|
+
it 'allows multiple run blocks to set and use variables sequentially' do
|
|
281
|
+
note = <<~EONOTE
|
|
282
|
+
# Test
|
|
283
|
+
|
|
284
|
+
## Test Topic
|
|
285
|
+
|
|
286
|
+
```run First Block
|
|
287
|
+
#!/bin/bash
|
|
288
|
+
echo "VAR:FIRST=1" >> "$HOWZIT_COMM_FILE"
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
```run Second Block
|
|
292
|
+
#!/bin/bash
|
|
293
|
+
set_var SECOND "2"
|
|
294
|
+
set_var COMBINED "12"
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
```run Third Block
|
|
298
|
+
#!/bin/bash
|
|
299
|
+
set_var THIRD "3"
|
|
300
|
+
set_var ALL "123"
|
|
301
|
+
```
|
|
302
|
+
EONOTE
|
|
303
|
+
File.open('builda.md', 'w') { |f| f.puts note }
|
|
304
|
+
Howzit.instance_variable_set(:@buildnote, nil)
|
|
305
|
+
topic = Howzit.buildnote.find_topic('Test Topic')[0]
|
|
306
|
+
|
|
307
|
+
allow(Howzit::Prompt).to receive(:yn).and_return(true)
|
|
308
|
+
|
|
309
|
+
# Actually run the tasks to set variables sequentially
|
|
310
|
+
topic.run
|
|
311
|
+
|
|
312
|
+
expect(Howzit.named_arguments['FIRST']).to eq('1')
|
|
313
|
+
expect(Howzit.named_arguments['SECOND']).to eq('2')
|
|
314
|
+
expect(Howzit.named_arguments['COMBINED']).to eq('12')
|
|
315
|
+
expect(Howzit.named_arguments['THIRD']).to eq('3')
|
|
316
|
+
expect(Howzit.named_arguments['ALL']).to eq('123')
|
|
317
|
+
end
|
|
318
|
+
end
|
|
319
|
+
end
|