howzit 2.1.25 → 2.1.27
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 +20 -0
- data/lib/howzit/colors.rb +2 -2
- data/lib/howzit/run_report.rb +10 -10
- data/lib/howzit/stringutils.rb +8 -1
- data/lib/howzit/topic.rb +9 -2
- data/lib/howzit/version.rb +1 -1
- data/spec/run_report_spec.rb +20 -0
- data/spec/stringutils_spec.rb +82 -0
- data/spec/topic_spec.rb +29 -0
- metadata +3 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: cfddcd9969d36eaa46a5441a912b60a0d4622c7536ffd34c6aebe83cc3c840a3
|
|
4
|
+
data.tar.gz: 9e5d7fee17c7931fc03b455eebe411f1490e1c27d70545f5e5a3d62f492a2f50
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: '019b3813e1f3ed8a79f70711a0f2dae38a83f0cfca205a32d9ab14794ba9815ce8d971d26f6bed0afbb90ce9d4ffd5d0d926cf50ef965cf806ffa45565203611'
|
|
7
|
+
data.tar.gz: c77fdeea70957604027d8152517498e8fe6df7043f36e139f8a81b23daca958d701a2dda786385921a6d9bf5c01acaca068375e7d3b9bd680091a3e988275069
|
data/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,23 @@
|
|
|
1
|
+
### 2.1.27
|
|
2
|
+
|
|
3
|
+
2025-12-26 08:59
|
|
4
|
+
|
|
5
|
+
#### IMPROVED
|
|
6
|
+
|
|
7
|
+
- Task titles now support variable substitution using ${VAR} syntax, so titles like "@run(echo test) Title with ${var}" will replace ${var} with its value from topic metadata. This applies to all task types (run, copy, open, include) and code block titles.
|
|
8
|
+
|
|
9
|
+
#### FIXED
|
|
10
|
+
|
|
11
|
+
- Task and topic names containing dollar signs (like $text$ or ${VAR}) now display correctly in run report output without causing color code interpretation issues. Dollar signs are properly escaped during formatting and unescaped in the final output.
|
|
12
|
+
|
|
13
|
+
### 2.1.26
|
|
14
|
+
|
|
15
|
+
2025-12-26 04:53
|
|
16
|
+
|
|
17
|
+
#### FIXED
|
|
18
|
+
|
|
19
|
+
- Bash script variables in run blocks now preserve ${VAR} syntax when the variable is not defined by howzit, allowing bash to handle them normally instead of being replaced with empty strings.
|
|
20
|
+
|
|
1
21
|
### 2.1.25
|
|
2
22
|
|
|
3
23
|
2025-12-19 07:41
|
data/lib/howzit/colors.rb
CHANGED
|
@@ -288,8 +288,8 @@ module Howzit
|
|
|
288
288
|
d: dark, b: bold, u: underline, i: italic, x: reset }
|
|
289
289
|
|
|
290
290
|
result = fmt.empty? ? input : format(fmt, colors)
|
|
291
|
-
# Unescape braces that were escaped to prevent color code interpretation
|
|
292
|
-
result.gsub(/\\\{/, '{').gsub(/\\\}/, '}')
|
|
291
|
+
# Unescape braces and dollar signs that were escaped to prevent color code interpretation
|
|
292
|
+
result.gsub(/\\\{/, '{').gsub(/\\\}/, '}').gsub(/\\\$/, '$')
|
|
293
293
|
end
|
|
294
294
|
end
|
|
295
295
|
|
data/lib/howzit/run_report.rb
CHANGED
|
@@ -30,13 +30,13 @@ module Howzit
|
|
|
30
30
|
symbol = entry[:success] ? '✅' : '❌'
|
|
31
31
|
parts = ["#{symbol} "]
|
|
32
32
|
if prefix_topic && entry[:topic] && !entry[:topic].empty?
|
|
33
|
-
# Escape braces in topic name to prevent color code interpretation
|
|
34
|
-
topic_escaped = entry[:topic].gsub(/\{/, '\\{').gsub(/\}/, '\\}')
|
|
33
|
+
# Escape braces and dollar signs in topic name to prevent color code interpretation
|
|
34
|
+
topic_escaped = entry[:topic].gsub(/\{/, '\\{').gsub(/\}/, '\\}').gsub(/\$/, '\\$')
|
|
35
35
|
parts << "{bw}#{topic_escaped}{x}: "
|
|
36
36
|
end
|
|
37
|
-
# Escape braces in task name to prevent color code interpretation
|
|
38
|
-
task_escaped = entry[:task].gsub(/\{/, '\\{').gsub(/\}/, '\\}')
|
|
39
|
-
parts << "{by}#{task_escaped}{x}"
|
|
37
|
+
# Escape braces and dollar signs in task name to prevent color code interpretation
|
|
38
|
+
task_escaped = entry[:task].gsub(/\{/, '\\{').gsub(/\}/, '\\}').gsub(/\$/, '\\$')
|
|
39
|
+
parts << "{by}#{task_escaped} {x}"
|
|
40
40
|
unless entry[:success]
|
|
41
41
|
reason = entry[:exit_status] ? "exit code #{entry[:exit_status]}" : 'failed'
|
|
42
42
|
parts << " {br}(#{reason}){x}"
|
|
@@ -82,15 +82,15 @@ module Howzit
|
|
|
82
82
|
task_parts_plain = []
|
|
83
83
|
|
|
84
84
|
if prefix_topic && entry[:topic] && !entry[:topic].empty?
|
|
85
|
-
# Escape braces in topic name to prevent color code interpretation
|
|
86
|
-
topic_escaped = entry[:topic].gsub(/\{/, '\\{').gsub(/\}/, '\\}')
|
|
85
|
+
# Escape braces and dollar signs in topic name to prevent color code interpretation
|
|
86
|
+
topic_escaped = entry[:topic].gsub(/\{/, '\\{').gsub(/\}/, '\\}').gsub(/\$/, '\\$')
|
|
87
87
|
task_parts << "{bw}#{topic_escaped}{x}: "
|
|
88
88
|
task_parts_plain << "#{entry[:topic]}: "
|
|
89
89
|
end
|
|
90
90
|
|
|
91
|
-
# Escape braces in task name to prevent color code interpretation
|
|
92
|
-
task_escaped = entry[:task].gsub(/\{/, '\\{').gsub(/\}/, '\\}')
|
|
93
|
-
task_parts << "{by}#{task_escaped}{x}"
|
|
91
|
+
# Escape braces and dollar signs in task name to prevent color code interpretation
|
|
92
|
+
task_escaped = entry[:task].gsub(/\{/, '\\{').gsub(/\}/, '\\}').gsub(/\$/, '\\$')
|
|
93
|
+
task_parts << "{by}#{task_escaped} {x}"
|
|
94
94
|
task_parts_plain << entry[:task]
|
|
95
95
|
|
|
96
96
|
unless entry[:success]
|
data/lib/howzit/stringutils.rb
CHANGED
|
@@ -337,7 +337,14 @@ module Howzit
|
|
|
337
337
|
gsub!(/\$\{(?<name>[A-Z0-9_]+(?::.*?)?)\}/i) do
|
|
338
338
|
m = Regexp.last_match
|
|
339
339
|
arg, default = m['name'].split(/:/).map(&:strip)
|
|
340
|
-
Howzit.named_arguments.key?(arg) && !Howzit.named_arguments[arg].nil?
|
|
340
|
+
if Howzit.named_arguments && Howzit.named_arguments.key?(arg) && !Howzit.named_arguments[arg].nil?
|
|
341
|
+
Howzit.named_arguments[arg]
|
|
342
|
+
elsif default
|
|
343
|
+
default
|
|
344
|
+
else
|
|
345
|
+
# Preserve the original ${VAR} syntax if variable is not defined and no default provided
|
|
346
|
+
m[0]
|
|
347
|
+
end
|
|
341
348
|
end
|
|
342
349
|
end
|
|
343
350
|
|
data/lib/howzit/topic.rb
CHANGED
|
@@ -302,26 +302,31 @@ module Howzit
|
|
|
302
302
|
title: title.dup, # Make a copy to avoid reference issues
|
|
303
303
|
action: obj,
|
|
304
304
|
parent: self }
|
|
305
|
+
# Set named_arguments before processing titles for variable substitution
|
|
306
|
+
Howzit.named_arguments = @named_args
|
|
305
307
|
case cmd
|
|
306
308
|
when /include/i
|
|
307
309
|
if title =~ /\[(.*?)\] *$/
|
|
308
|
-
Howzit.named_arguments = @named_args
|
|
309
310
|
args = Regexp.last_match(1).split(/ *, */).map(&:render_arguments)
|
|
310
311
|
Howzit.arguments = args
|
|
311
312
|
arguments
|
|
312
313
|
title.sub!(/ *\[.*?\] *$/, '')
|
|
313
|
-
task_args[:title] = title
|
|
314
314
|
end
|
|
315
|
+
# Apply variable substitution to title after bracket processing
|
|
316
|
+
task_args[:title] = title.render_arguments
|
|
315
317
|
|
|
316
318
|
task_args[:type] = :include
|
|
317
319
|
task_args[:arguments] = Howzit.named_arguments
|
|
318
320
|
when /run/i
|
|
319
321
|
task_args[:type] = :run
|
|
322
|
+
task_args[:title] = title.render_arguments
|
|
320
323
|
when /copy/i
|
|
321
324
|
task_args[:type] = :copy
|
|
322
325
|
task_args[:action] = Shellwords.escape(obj)
|
|
326
|
+
task_args[:title] = title.render_arguments
|
|
323
327
|
when /open|url/i
|
|
324
328
|
task_args[:type] = :open
|
|
329
|
+
task_args[:title] = title.render_arguments
|
|
325
330
|
end
|
|
326
331
|
|
|
327
332
|
task_args
|
|
@@ -373,6 +378,8 @@ module Howzit
|
|
|
373
378
|
if c[:cmd].nil?
|
|
374
379
|
optional, default = define_optional(c[:optional2])
|
|
375
380
|
title = c[:title2].nil? ? '' : c[:title2].strip
|
|
381
|
+
# Apply variable substitution to block title
|
|
382
|
+
title = title.render_arguments if title && !title.empty?
|
|
376
383
|
block = c[:block]&.strip
|
|
377
384
|
runnable << Howzit::Task.new({ type: :block,
|
|
378
385
|
title: title,
|
data/lib/howzit/version.rb
CHANGED
data/spec/run_report_spec.rb
CHANGED
|
@@ -47,5 +47,25 @@ describe Howzit::RunReport do
|
|
|
47
47
|
# Second line should be separator
|
|
48
48
|
expect(lines[1]).to match(/^\|[\s:-]+\|[\s:-]+\|$/)
|
|
49
49
|
end
|
|
50
|
+
|
|
51
|
+
it 'preserves dollar signs in task names without interfering with color codes' do
|
|
52
|
+
Howzit::RunReport.log({ topic: 'Test Topic', task: '$text$', success: true, exit_status: 0 })
|
|
53
|
+
Howzit::RunReport.log({ topic: 'Test', task: 'echo ${VAR}', success: true, exit_status: 0 })
|
|
54
|
+
plain = Howzit::RunReport.format.uncolor
|
|
55
|
+
expect(plain).to include('$text$')
|
|
56
|
+
expect(plain).to include('${VAR}')
|
|
57
|
+
# Verify dollar signs are preserved and not causing color code issues
|
|
58
|
+
expect(plain).not_to include('{x}')
|
|
59
|
+
expect(plain.scan(/\$\{x\}/).length).to eq(0)
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
it 'preserves dollar signs in topic names without interfering with color codes' do
|
|
63
|
+
Howzit.multi_topic_run = true
|
|
64
|
+
Howzit::RunReport.log({ topic: '$dollar$ Topic', task: 'Some Task', success: true, exit_status: 0 })
|
|
65
|
+
plain = Howzit::RunReport.format.uncolor
|
|
66
|
+
expect(plain).to include('$dollar$ Topic')
|
|
67
|
+
expect(plain).not_to include('{x}')
|
|
68
|
+
expect(plain.scan(/\$\{x\}/).length).to eq(0)
|
|
69
|
+
end
|
|
50
70
|
end
|
|
51
71
|
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'spec_helper'
|
|
4
|
+
|
|
5
|
+
describe 'StringUtils' do
|
|
6
|
+
describe '#render_named_placeholders' do
|
|
7
|
+
before do
|
|
8
|
+
Howzit.named_arguments = {}
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
it 'preserves ${VAR} syntax when variable is not defined' do
|
|
12
|
+
str = 'echo ${MY_VAR}'.dup
|
|
13
|
+
str.render_named_placeholders
|
|
14
|
+
expect(str).to eq('echo ${MY_VAR}')
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
it 'preserves ${VAR} syntax for multiple undefined variables' do
|
|
18
|
+
str = 'echo ${VAR1} and ${VAR2}'.dup
|
|
19
|
+
str.render_named_placeholders
|
|
20
|
+
expect(str).to eq('echo ${VAR1} and ${VAR2}')
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
it 'replaces ${VAR} with value when variable is defined' do
|
|
24
|
+
Howzit.named_arguments = { 'MY_VAR' => 'hello' }
|
|
25
|
+
str = 'echo ${MY_VAR}'.dup
|
|
26
|
+
str.render_named_placeholders
|
|
27
|
+
expect(str).to eq('echo hello')
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
it 'uses default value when variable is not defined but default is provided' do
|
|
31
|
+
str = 'echo ${MY_VAR:default_value}'.dup
|
|
32
|
+
str.render_named_placeholders
|
|
33
|
+
expect(str).to eq('echo default_value')
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
it 'replaces variable when defined even if default is provided' do
|
|
37
|
+
Howzit.named_arguments = { 'MY_VAR' => 'actual_value' }
|
|
38
|
+
str = 'echo ${MY_VAR:default_value}'.dup
|
|
39
|
+
str.render_named_placeholders
|
|
40
|
+
expect(str).to eq('echo actual_value')
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
it 'preserves ${VAR} in bash script blocks' do
|
|
44
|
+
script = <<~SCRIPT
|
|
45
|
+
#!/bin/bash
|
|
46
|
+
echo "The value is ${ENV_VAR}"
|
|
47
|
+
echo "Another ${OTHER_VAR}"
|
|
48
|
+
SCRIPT
|
|
49
|
+
str = script.dup
|
|
50
|
+
str.render_named_placeholders
|
|
51
|
+
expect(str).to eq(script)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
it 'handles mixed defined and undefined variables' do
|
|
55
|
+
Howzit.named_arguments = { 'DEFINED_VAR' => 'value1' }
|
|
56
|
+
str = 'echo ${DEFINED_VAR} and ${UNDEFINED_VAR}'.dup
|
|
57
|
+
str.render_named_placeholders
|
|
58
|
+
expect(str).to eq('echo value1 and ${UNDEFINED_VAR}')
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
it 'handles nil named_arguments gracefully' do
|
|
62
|
+
Howzit.named_arguments = nil
|
|
63
|
+
str = 'echo ${MY_VAR}'.dup
|
|
64
|
+
expect { str.render_named_placeholders }.not_to raise_error
|
|
65
|
+
expect(str).to eq('echo ${MY_VAR}')
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
describe '#render_arguments' do
|
|
70
|
+
before do
|
|
71
|
+
Howzit.named_arguments = {}
|
|
72
|
+
Howzit.arguments = nil
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
it 'preserves ${VAR} syntax through render_arguments' do
|
|
76
|
+
str = 'echo ${BASH_VAR}'.dup
|
|
77
|
+
result = str.render_arguments
|
|
78
|
+
expect(result).to eq('echo ${BASH_VAR}')
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
|
data/spec/topic_spec.rb
CHANGED
|
@@ -101,4 +101,33 @@ describe Howzit::Topic do
|
|
|
101
101
|
expect(topic.print_out({ single: true, header: true }).join("\n").uncolor).to match(/▶ ls -1/)
|
|
102
102
|
end
|
|
103
103
|
end
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
describe '.arguments' do
|
|
107
|
+
before do
|
|
108
|
+
Howzit.arguments = []
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
it 'extracts named arguments from topic title with defaults' do
|
|
112
|
+
topic = Howzit::Topic.new('Test Topic (var1:default1, var2:default2)', 'Content')
|
|
113
|
+
expect(topic.named_args['var1']).to eq('default1')
|
|
114
|
+
expect(topic.named_args['var2']).to eq('default2')
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
it 'does nothing when title has no arguments' do
|
|
118
|
+
topic = Howzit::Topic.new('Test Topic', 'Content')
|
|
119
|
+
expect(topic.named_args).to eq({})
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
it 'cleans title after extracting arguments' do
|
|
123
|
+
topic = Howzit::Topic.new('Test Topic (var:val)', 'Content')
|
|
124
|
+
expect(topic.title).to eq('Test Topic')
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
it 'uses provided arguments over defaults' do
|
|
128
|
+
Howzit.arguments = ['provided_value']
|
|
129
|
+
topic = Howzit::Topic.new('Test Topic (var:default_value)', 'Content')
|
|
130
|
+
expect(topic.named_args['var']).to eq('provided_value')
|
|
131
|
+
end
|
|
132
|
+
end
|
|
104
133
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: howzit
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 2.1.
|
|
4
|
+
version: 2.1.27
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Brett Terpstra
|
|
@@ -315,6 +315,7 @@ files:
|
|
|
315
315
|
- spec/ruby_gem_spec.rb
|
|
316
316
|
- spec/run_report_spec.rb
|
|
317
317
|
- spec/spec_helper.rb
|
|
318
|
+
- spec/stringutils_spec.rb
|
|
318
319
|
- spec/task_spec.rb
|
|
319
320
|
- spec/topic_spec.rb
|
|
320
321
|
- spec/util_spec.rb
|
|
@@ -349,6 +350,7 @@ test_files:
|
|
|
349
350
|
- spec/ruby_gem_spec.rb
|
|
350
351
|
- spec/run_report_spec.rb
|
|
351
352
|
- spec/spec_helper.rb
|
|
353
|
+
- spec/stringutils_spec.rb
|
|
352
354
|
- spec/task_spec.rb
|
|
353
355
|
- spec/topic_spec.rb
|
|
354
356
|
- spec/util_spec.rb
|