rundoc 5.0.0 → 6.0.0
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/.github/workflows/ci.yml +1 -0
- data/CHANGELOG.md +5 -0
- data/README.md +62 -1
- data/lib/rundoc/cli.rb +14 -1
- data/lib/rundoc/code_command/bash/cd.rb +5 -11
- data/lib/rundoc/code_command/empty_binding.rb +18 -0
- data/lib/rundoc/code_command/print/erb.rb +1 -14
- data/lib/rundoc/code_command/rundoc/ensure_later.rb +59 -0
- data/lib/rundoc/code_command/rundoc_command.rb +5 -1
- data/lib/rundoc/code_command.rb +1 -0
- data/lib/rundoc/peg_parser.rb +8 -0
- data/lib/rundoc/version.rb +1 -1
- data/lib/rundoc.rb +37 -0
- data/rundoc.gemspec +1 -0
- data/test/integration/ensure_later_test.rb +335 -0
- data/test/integration/print_test.rb +51 -0
- data/test/rundoc/peg_parser_test.rb +25 -0
- metadata +19 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 498d5109daa7abb733fc5c27cf583bb1c84cc7b92bbccaaf9e005a51a6ec0555
|
|
4
|
+
data.tar.gz: fc72016241033a945486b5fa893b3f2cad0c8b3c7a2c44eab3f964adb7308f9e
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 5af654672de3e6051ec46377052c55b55207ce13eb29cf977d1cf793291e953d28e842fd79b0f0972f8eb83a98c6671c1834a5ac75f20da795eb686a99a02c52
|
|
7
|
+
data.tar.gz: b2acdf08759aa0c6f73410a00a4ad387da198f1f4497228c69d27dd799799e12107cc421c8f3fd5242f9517dbfd2565e71b56e2b3a6ffd77ffd879906c902d65
|
data/.github/workflows/ci.yml
CHANGED
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
## HEAD
|
|
2
2
|
|
|
3
|
+
## 6.0.0
|
|
4
|
+
|
|
5
|
+
- Added: `rundoc.ensure_later(dir: :cwd)` command to register cleanup blocks that run on every build (success and failure). Useful for guaranteed resource teardown (e.g., destroying Heroku apps). Multiple blocks execute in order; failures in one block do not stop the rest.
|
|
6
|
+
- Changed: The ruby context in `rundoc` and `rundoc.configure` commands is now the same binding as the default ERB evaluation. This means that methods can be defined in one and used in both.
|
|
7
|
+
|
|
3
8
|
## 5.0.0
|
|
4
9
|
|
|
5
10
|
- Added comment syntax. Use an octothorpe (`#`) after the visibility markers to comment out any commands and make them a no-op.
|
data/README.md
CHANGED
|
@@ -98,6 +98,8 @@ This will generate a project folder with your project in it, and a markdown `REA
|
|
|
98
98
|
- [website.screenshot](#screenshots)
|
|
99
99
|
- Configure RunDOC
|
|
100
100
|
- [rundoc.configure](#configure)
|
|
101
|
+
- [rundoc.ensure_later](#ensure_later)
|
|
102
|
+
- [rundoc](#configure) an alias for `rundoc.configure`
|
|
101
103
|
- Import and compose documents
|
|
102
104
|
- [rundoc.require](#compose-multiple-rundoc-documents)
|
|
103
105
|
|
|
@@ -616,7 +618,7 @@ If you need to specify project specific environment variables create a file call
|
|
|
616
618
|
|
|
617
619
|
## Configure
|
|
618
620
|
|
|
619
|
-
You can configure your docs in your docs use the `RunDOC` command
|
|
621
|
+
You can configure your docs in your docs use the `RunDOC` command via `rundoc.configure` (or alias `rundoc`):
|
|
620
622
|
|
|
621
623
|
```
|
|
622
624
|
:::-- rundoc.configure
|
|
@@ -624,6 +626,30 @@ You can configure your docs in your docs use the `RunDOC` command
|
|
|
624
626
|
|
|
625
627
|
Note: Make sure you run this as a hidden command (with `-`).
|
|
626
628
|
|
|
629
|
+
This will give you a Ruby codeblock that executes and gives you access to `Rundoc.configure do |config|` to configure things about your build (such as modifying your markdown document after successful builds).
|
|
630
|
+
|
|
631
|
+
**Define and Re-use logic**
|
|
632
|
+
|
|
633
|
+
Since it's **just ruby** :tm: you can also use it to define shared logic that can be re-used in ERB templates. For example:
|
|
634
|
+
|
|
635
|
+
```
|
|
636
|
+
:::-- rundoc
|
|
637
|
+
def run!(command, quiet: false, error_on_fail: true)
|
|
638
|
+
puts "Running `#{command}`" unless quiet
|
|
639
|
+
output = `#{command}`
|
|
640
|
+
puts "Command `#{command}` output:\n#{output}" unless quiet
|
|
641
|
+
if error_on_fail && !$?.success?
|
|
642
|
+
raise "Error running #{command}. Output:\n#{output}"
|
|
643
|
+
end
|
|
644
|
+
output
|
|
645
|
+
end
|
|
646
|
+
```
|
|
647
|
+
|
|
648
|
+
```
|
|
649
|
+
:::-> print.erb
|
|
650
|
+
Hello <%= run!("heroku whoami") %>!
|
|
651
|
+
```
|
|
652
|
+
|
|
627
653
|
**After Build**
|
|
628
654
|
|
|
629
655
|
This will eval any code you put under that line (in Ruby) when the build was successful but before the contents are finalized on disk. If you want to run some code after you're done building your docs you could use `Rundoc.configure` block and call the `after_build` method like this:
|
|
@@ -658,6 +684,41 @@ Sometimes sensitive info like usernames, email addresses, or passwords may be in
|
|
|
658
684
|
|
|
659
685
|
This command `filter_sensitive` can be called multiple times with different values. Since the config is in Ruby you could iterate over an array of sensitive data
|
|
660
686
|
|
|
687
|
+
## Ensure Later
|
|
688
|
+
|
|
689
|
+
Run a script on EVERY build (success and failure). Used to guarantee resources are cleaned up.
|
|
690
|
+
|
|
691
|
+
- Arguments
|
|
692
|
+
- `dir:` The directory where the script will be run. Must be one of these values:
|
|
693
|
+
- `:cwd` The directory where the command is first invoked. If this directory does not exist when the `rundoc.ensure_later` is invoked, it will raise an error.
|
|
694
|
+
- `:rundoc_root` The tmp directory where the script is being executed. Useful if the directory where the `rundoc.ensure_later` is defined, is deleted by the rundoc script.
|
|
695
|
+
|
|
696
|
+
For example:
|
|
697
|
+
|
|
698
|
+
```
|
|
699
|
+
:::>> $ heroku create
|
|
700
|
+
:::-- rundoc
|
|
701
|
+
@app_name = run!("heroku info --json | jq -r '.app.name'").strip
|
|
702
|
+
|
|
703
|
+
def app_name
|
|
704
|
+
@app_name
|
|
705
|
+
end
|
|
706
|
+
```
|
|
707
|
+
|
|
708
|
+
```ruby
|
|
709
|
+
:::-- rundoc.ensure_later(dir: :cwd)
|
|
710
|
+
if run!("heroku apps").include?(app_name)
|
|
711
|
+
puts "Cleaning up web app #{app_name}"
|
|
712
|
+
run!("heroku apps:destroy #{app_name} --confirm #{app_name}")
|
|
713
|
+
else
|
|
714
|
+
puts "App `#{app_name}` already cleaned, nothing to do"
|
|
715
|
+
end
|
|
716
|
+
```
|
|
717
|
+
|
|
718
|
+
The output of this will not be included in the document. Multiple ensure blocks can be defined and will execute in the order of their definition. Since they'll be executed EVERY time, logic must handle both success and failure cases. This execution occurs before the temp directory is removed, and before any background task shutdown ensure blocks are triggered.
|
|
719
|
+
|
|
720
|
+
If a build is successful, but an `ensure_later` block fails, the build will be considered a failure. A failure in one block will not stop the rest from executing.
|
|
721
|
+
|
|
661
722
|
## Writing a new command
|
|
662
723
|
|
|
663
724
|
> Note: This is an advanced topic and this interface is unstable.
|
data/lib/rundoc/cli.rb
CHANGED
|
@@ -134,6 +134,9 @@ module Rundoc
|
|
|
134
134
|
end
|
|
135
135
|
|
|
136
136
|
def call
|
|
137
|
+
build_success = false
|
|
138
|
+
ensure_later_errors = []
|
|
139
|
+
|
|
137
140
|
io.puts "## Running your docs"
|
|
138
141
|
load_dotenv
|
|
139
142
|
check_directories_empty!
|
|
@@ -165,7 +168,11 @@ module Rundoc
|
|
|
165
168
|
io: io
|
|
166
169
|
)
|
|
167
170
|
output = begin
|
|
168
|
-
|
|
171
|
+
begin
|
|
172
|
+
parser.to_md
|
|
173
|
+
ensure
|
|
174
|
+
ensure_later_errors = Rundoc.run_ensure_later(io: io)
|
|
175
|
+
end
|
|
169
176
|
rescue StandardError, SignalException => e
|
|
170
177
|
io.puts "Received exception: #{e.inspect}, cleaning up before re-raise"
|
|
171
178
|
on_fail
|
|
@@ -174,6 +181,8 @@ module Rundoc
|
|
|
174
181
|
|
|
175
182
|
on_success(output)
|
|
176
183
|
end
|
|
184
|
+
|
|
185
|
+
build_success = true
|
|
177
186
|
ensure
|
|
178
187
|
# Stop any hanging background tasks
|
|
179
188
|
Rundoc::CodeCommand::Background::ProcessSpawn.tasks.each do |name, task|
|
|
@@ -189,6 +198,10 @@ module Rundoc
|
|
|
189
198
|
description: "tmp working directory"
|
|
190
199
|
)
|
|
191
200
|
end
|
|
201
|
+
|
|
202
|
+
if ensure_later_errors.any? && build_success
|
|
203
|
+
raise ensure_later_errors.first
|
|
204
|
+
end
|
|
192
205
|
end
|
|
193
206
|
|
|
194
207
|
private def clean_dir(dir:, description:)
|
|
@@ -7,25 +7,19 @@ class Rundoc::CodeCommand::BashRunner
|
|
|
7
7
|
@line = line
|
|
8
8
|
end
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
capture_stderr = StringIO.new
|
|
14
|
-
$stderr = capture_stderr
|
|
10
|
+
def suppress_chdir_warning
|
|
11
|
+
old_verbose = $VERBOSE
|
|
12
|
+
$VERBOSE = nil
|
|
15
13
|
yield
|
|
16
14
|
ensure
|
|
17
|
-
|
|
18
|
-
$stderr = old_stderr
|
|
19
|
-
capture_string = capture_stderr.string
|
|
20
|
-
warn capture_string if capture_string.each_line.count > 1 || !capture_string.include?("conflicting chdir")
|
|
21
|
-
end
|
|
15
|
+
$VERBOSE = old_verbose
|
|
22
16
|
end
|
|
23
17
|
|
|
24
18
|
def call(env)
|
|
25
19
|
line = @line.sub("cd", "").strip
|
|
26
20
|
@io.puts "running $ cd #{line}"
|
|
27
21
|
|
|
28
|
-
|
|
22
|
+
suppress_chdir_warning do
|
|
29
23
|
Dir.chdir(line)
|
|
30
24
|
end
|
|
31
25
|
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "erb"
|
|
4
|
+
|
|
5
|
+
class EmptyBinding
|
|
6
|
+
def self.create
|
|
7
|
+
new.empty_binding
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def empty_binding
|
|
11
|
+
binding
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
module Rundoc::CodeCommand
|
|
16
|
+
RUNDOC_ERB_BINDINGS = Hash.new { |h, k| h[k] = EmptyBinding.create }
|
|
17
|
+
RUNDOC_DEFAULT_ERB_BINDING = "default"
|
|
18
|
+
end
|
|
@@ -1,21 +1,8 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
class EmptyBinding
|
|
6
|
-
def self.create
|
|
7
|
-
new.empty_binding
|
|
8
|
-
end
|
|
9
|
-
|
|
10
|
-
def empty_binding
|
|
11
|
-
binding
|
|
12
|
-
end
|
|
13
|
-
end
|
|
3
|
+
require_relative "../empty_binding"
|
|
14
4
|
|
|
15
5
|
module Rundoc::CodeCommand
|
|
16
|
-
RUNDOC_ERB_BINDINGS = Hash.new { |h, k| h[k] = EmptyBinding.create }
|
|
17
|
-
RUNDOC_DEFAULT_ERB_BINDING = "default"
|
|
18
|
-
|
|
19
6
|
class PrintERBArgs
|
|
20
7
|
attr_reader :line, :binding_name
|
|
21
8
|
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ::Rundoc::CodeCommand
|
|
4
|
+
class RundocCommand
|
|
5
|
+
class EnsureLaterArgs
|
|
6
|
+
MAPPING = {
|
|
7
|
+
cwd: ->(context:) {
|
|
8
|
+
Dir.pwd
|
|
9
|
+
},
|
|
10
|
+
rundoc_root: ->(context:) {
|
|
11
|
+
context.output_dir.to_s
|
|
12
|
+
}
|
|
13
|
+
}.freeze
|
|
14
|
+
|
|
15
|
+
def initialize(dir:)
|
|
16
|
+
@dir = dir
|
|
17
|
+
@logic = MAPPING[dir] or raise ArgumentError, "Invalid argument dir: #{dir} must be one of #{MAPPING.keys}"
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def call(context:)
|
|
21
|
+
@logic.call(context: context)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def to_s
|
|
25
|
+
@dir
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
class EnsureLaterRunner
|
|
30
|
+
attr_reader :io, :contents
|
|
31
|
+
|
|
32
|
+
def initialize(user_args:, render_command:, render_result:, io:, contents: nil)
|
|
33
|
+
@io = io
|
|
34
|
+
@contents = contents.dup if contents && !contents.empty?
|
|
35
|
+
@dir = user_args
|
|
36
|
+
@binding = RUNDOC_ERB_BINDINGS[RUNDOC_DEFAULT_ERB_BINDING]
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def to_md(env = {})
|
|
40
|
+
""
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def call(env = {})
|
|
44
|
+
resolved_dir = @dir.call(context: env[:context])
|
|
45
|
+
|
|
46
|
+
io.puts "Registering ensure_later block (dir: #{@dir} => #{resolved_dir})"
|
|
47
|
+
Rundoc.add_ensure_later(dir: resolved_dir, code: @contents, binding: @binding)
|
|
48
|
+
""
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
Rundoc.register_code_command(
|
|
55
|
+
keyword: :"rundoc.ensure_later",
|
|
56
|
+
args_klass: Rundoc::CodeCommand::RundocCommand::EnsureLaterArgs,
|
|
57
|
+
runner_klass: Rundoc::CodeCommand::RundocCommand::EnsureLaterRunner,
|
|
58
|
+
always_hidden: true
|
|
59
|
+
)
|
|
@@ -17,6 +17,7 @@ module ::Rundoc
|
|
|
17
17
|
@io = io
|
|
18
18
|
@contents = contents.dup if contents && !contents.empty?
|
|
19
19
|
@contents = user_args.code + (@contents || +"")
|
|
20
|
+
@binding = RUNDOC_ERB_BINDINGS[RUNDOC_DEFAULT_ERB_BINDING]
|
|
20
21
|
end
|
|
21
22
|
|
|
22
23
|
def to_md(env = {})
|
|
@@ -25,7 +26,9 @@ module ::Rundoc
|
|
|
25
26
|
|
|
26
27
|
def call(env = {})
|
|
27
28
|
io.puts "Running: #{contents}"
|
|
28
|
-
|
|
29
|
+
Rundoc.capture_stdout_stderr(io) do
|
|
30
|
+
eval(contents, @binding) # rubocop:disable Security/Eval
|
|
31
|
+
end
|
|
29
32
|
""
|
|
30
33
|
end
|
|
31
34
|
end
|
|
@@ -36,3 +39,4 @@ Rundoc.register_code_command(keyword: :rundoc, args_klass: Rundoc::CodeCommand::
|
|
|
36
39
|
Rundoc.register_code_command(keyword: :"rundoc.configure", args_klass: Rundoc::CodeCommand::RundocCommandArgs, runner_klass: Rundoc::CodeCommand::RundocCommandRunner)
|
|
37
40
|
|
|
38
41
|
require "rundoc/code_command/rundoc/require"
|
|
42
|
+
require "rundoc/code_command/rundoc/ensure_later"
|
data/lib/rundoc/code_command.rb
CHANGED
data/lib/rundoc/peg_parser.rb
CHANGED
|
@@ -39,9 +39,16 @@ module Rundoc
|
|
|
39
39
|
).as(:number)
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
+
rule(:symbol) {
|
|
43
|
+
str(":") >> (
|
|
44
|
+
match("[a-zA-Z_]") >> match("[a-zA-Z0-9_]").repeat
|
|
45
|
+
).as(:symbol)
|
|
46
|
+
}
|
|
47
|
+
|
|
42
48
|
rule(:value) {
|
|
43
49
|
string |
|
|
44
50
|
number |
|
|
51
|
+
symbol |
|
|
45
52
|
str("true").as(true) |
|
|
46
53
|
str("false").as(false) |
|
|
47
54
|
str("nil").as(:nil)
|
|
@@ -175,6 +182,7 @@ module Rundoc
|
|
|
175
182
|
rule(true => simple(:tr)) { true }
|
|
176
183
|
rule(false => simple(:fa)) { false }
|
|
177
184
|
rule(string: simple(:st)) { st.to_s }
|
|
185
|
+
rule(symbol: simple(:sy)) { sy.to_s.to_sym }
|
|
178
186
|
|
|
179
187
|
rule(number: simple(:nb)) {
|
|
180
188
|
/[eE.]/.match?(nb) ? Float(nb) : Integer(nb)
|
data/lib/rundoc/version.rb
CHANGED
data/lib/rundoc.rb
CHANGED
|
@@ -97,6 +97,43 @@ module Rundoc
|
|
|
97
97
|
yield self
|
|
98
98
|
end
|
|
99
99
|
|
|
100
|
+
def ensure_later_blocks
|
|
101
|
+
@ensure_later_blocks ||= []
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def add_ensure_later(dir:, code:, binding:)
|
|
105
|
+
ensure_later_blocks << {dir: dir, code: code, binding: binding}
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def run_ensure_later(io:)
|
|
109
|
+
errors = []
|
|
110
|
+
ensure_later_blocks.each do |block|
|
|
111
|
+
io.puts "Running ensure_later block in #{block[:dir]}:\n#{block[:code]}"
|
|
112
|
+
Dir.chdir(block[:dir]) do
|
|
113
|
+
capture_stdout_stderr(io) do
|
|
114
|
+
eval(block[:code], block[:binding]) # rubocop:disable Security/Eval
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
rescue => e
|
|
118
|
+
io.puts "ensure_later block failed in #{block[:dir]}: #{e.message}"
|
|
119
|
+
io.puts e.backtrace.join("\n")
|
|
120
|
+
errors << e
|
|
121
|
+
end
|
|
122
|
+
ensure_later_blocks.clear
|
|
123
|
+
errors
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
def capture_stdout_stderr(io)
|
|
127
|
+
old_stdout = $stdout
|
|
128
|
+
old_stderr = $stderr
|
|
129
|
+
$stdout = io
|
|
130
|
+
$stderr = io
|
|
131
|
+
yield
|
|
132
|
+
ensure
|
|
133
|
+
$stdout = old_stdout
|
|
134
|
+
$stderr = old_stderr
|
|
135
|
+
end
|
|
136
|
+
|
|
100
137
|
def filter_sensitive(sensitive)
|
|
101
138
|
raise "Expecting #{sensitive} to be a hash" unless sensitive.is_a?(Hash)
|
|
102
139
|
@sensitive ||= {}
|
data/rundoc.gemspec
CHANGED
|
@@ -0,0 +1,335 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "test_helper"
|
|
4
|
+
|
|
5
|
+
class IntegrationEnsureLaterTest < Minitest::Test
|
|
6
|
+
def test_runs_on_success
|
|
7
|
+
Dir.mktmpdir do |dir|
|
|
8
|
+
Dir.chdir(dir) do
|
|
9
|
+
dir = Pathname(dir)
|
|
10
|
+
marker = dir.join("ensure_ran.txt")
|
|
11
|
+
|
|
12
|
+
source_path = dir.join("RUNDOC.md")
|
|
13
|
+
source_path.write <<~EOF
|
|
14
|
+
```
|
|
15
|
+
:::-- rundoc.ensure_later(dir: :cwd)
|
|
16
|
+
File.write("#{marker}", "yes")
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
```
|
|
20
|
+
:::>> $ echo "hello"
|
|
21
|
+
```
|
|
22
|
+
EOF
|
|
23
|
+
|
|
24
|
+
Rundoc::CLI.new(
|
|
25
|
+
io: StringIO.new,
|
|
26
|
+
source_path: source_path,
|
|
27
|
+
on_success_dir: dir.join(SUCCESS_DIRNAME)
|
|
28
|
+
).call
|
|
29
|
+
|
|
30
|
+
assert marker.exist?, "ensure_later block should have run on success"
|
|
31
|
+
assert_equal "yes", marker.read
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def test_runs_on_failure
|
|
37
|
+
Dir.mktmpdir do |dir|
|
|
38
|
+
Dir.chdir(dir) do
|
|
39
|
+
dir = Pathname(dir)
|
|
40
|
+
marker = dir.join("ensure_ran.txt")
|
|
41
|
+
|
|
42
|
+
source_path = dir.join("RUNDOC.md")
|
|
43
|
+
source_path.write <<~EOF
|
|
44
|
+
```
|
|
45
|
+
:::-- rundoc.ensure_later(dir: :cwd)
|
|
46
|
+
File.write("#{marker}", "cleaned")
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
```
|
|
50
|
+
:::>> $ exit 1
|
|
51
|
+
```
|
|
52
|
+
EOF
|
|
53
|
+
|
|
54
|
+
assert_raises do
|
|
55
|
+
Rundoc::CLI.new(
|
|
56
|
+
io: StringIO.new,
|
|
57
|
+
source_path: source_path,
|
|
58
|
+
on_success_dir: dir.join(SUCCESS_DIRNAME),
|
|
59
|
+
on_failure_dir: dir.join(FAILURE_DIRNAME)
|
|
60
|
+
).call
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
assert marker.exist?, "ensure_later block should have run on failure"
|
|
64
|
+
assert_equal "cleaned", marker.read
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def test_multiple_blocks_run_in_order
|
|
70
|
+
Dir.mktmpdir do |dir|
|
|
71
|
+
Dir.chdir(dir) do
|
|
72
|
+
dir = Pathname(dir)
|
|
73
|
+
marker = dir.join("order.txt")
|
|
74
|
+
|
|
75
|
+
source_path = dir.join("RUNDOC.md")
|
|
76
|
+
source_path.write <<~EOF
|
|
77
|
+
```
|
|
78
|
+
:::-- rundoc.ensure_later(dir: :cwd)
|
|
79
|
+
File.write("#{marker}", "first")
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
```
|
|
83
|
+
:::-- rundoc.ensure_later(dir: :cwd)
|
|
84
|
+
File.write("#{marker}", File.read("#{marker}") + ",second")
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
```
|
|
88
|
+
:::>> $ echo "hello"
|
|
89
|
+
```
|
|
90
|
+
EOF
|
|
91
|
+
|
|
92
|
+
Rundoc::CLI.new(
|
|
93
|
+
io: StringIO.new,
|
|
94
|
+
source_path: source_path,
|
|
95
|
+
on_success_dir: dir.join(SUCCESS_DIRNAME)
|
|
96
|
+
).call
|
|
97
|
+
|
|
98
|
+
assert_equal "first,second", marker.read
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def test_one_failure_does_not_stop_others
|
|
104
|
+
Dir.mktmpdir do |dir|
|
|
105
|
+
Dir.chdir(dir) do
|
|
106
|
+
dir = Pathname(dir)
|
|
107
|
+
marker = dir.join("second_ran.txt")
|
|
108
|
+
|
|
109
|
+
source_path = dir.join("RUNDOC.md")
|
|
110
|
+
source_path.write <<~EOF
|
|
111
|
+
```
|
|
112
|
+
:::-- rundoc.ensure_later(dir: :cwd)
|
|
113
|
+
raise "intentional failure"
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
```
|
|
117
|
+
:::-- rundoc.ensure_later(dir: :cwd)
|
|
118
|
+
File.write("#{marker}", "yes")
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
```
|
|
122
|
+
:::>> $ echo "hello"
|
|
123
|
+
```
|
|
124
|
+
EOF
|
|
125
|
+
|
|
126
|
+
error = assert_raises(RuntimeError) do
|
|
127
|
+
Rundoc::CLI.new(
|
|
128
|
+
io: StringIO.new,
|
|
129
|
+
source_path: source_path,
|
|
130
|
+
on_success_dir: dir.join(SUCCESS_DIRNAME)
|
|
131
|
+
).call
|
|
132
|
+
end
|
|
133
|
+
assert_match(/intentional failure/, error.message)
|
|
134
|
+
|
|
135
|
+
assert marker.exist?, "second ensure_later should still run after first fails"
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
def test_success_plus_ensure_failure_is_overall_failure
|
|
141
|
+
Dir.mktmpdir do |dir|
|
|
142
|
+
Dir.chdir(dir) do
|
|
143
|
+
dir = Pathname(dir)
|
|
144
|
+
|
|
145
|
+
source_path = dir.join("RUNDOC.md")
|
|
146
|
+
source_path.write <<~EOF
|
|
147
|
+
```
|
|
148
|
+
:::-- rundoc.ensure_later(dir: :cwd)
|
|
149
|
+
raise "cleanup failed"
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
```
|
|
153
|
+
:::>> $ echo "hello"
|
|
154
|
+
```
|
|
155
|
+
EOF
|
|
156
|
+
|
|
157
|
+
error = assert_raises(RuntimeError) do
|
|
158
|
+
Rundoc::CLI.new(
|
|
159
|
+
io: StringIO.new,
|
|
160
|
+
source_path: source_path,
|
|
161
|
+
on_success_dir: dir.join(SUCCESS_DIRNAME)
|
|
162
|
+
).call
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
assert_match(/cleanup failed/, error.message)
|
|
166
|
+
end
|
|
167
|
+
end
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
def test_dir_rundoc_root
|
|
171
|
+
Dir.mktmpdir do |dir|
|
|
172
|
+
Dir.chdir(dir) do
|
|
173
|
+
dir = Pathname(dir)
|
|
174
|
+
marker = dir.join("root_marker.txt")
|
|
175
|
+
|
|
176
|
+
source_path = dir.join("RUNDOC.md")
|
|
177
|
+
source_path.write <<~EOF
|
|
178
|
+
```
|
|
179
|
+
:::>> $ mkdir subdir
|
|
180
|
+
:::>> $ cd subdir
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
```
|
|
184
|
+
:::-- rundoc.ensure_later(dir: :rundoc_root)
|
|
185
|
+
File.write("#{marker}", Dir.pwd)
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
```
|
|
189
|
+
:::>> $ echo "hello"
|
|
190
|
+
```
|
|
191
|
+
EOF
|
|
192
|
+
|
|
193
|
+
cli = Rundoc::CLI.new(
|
|
194
|
+
io: StringIO.new,
|
|
195
|
+
source_path: source_path,
|
|
196
|
+
on_success_dir: dir.join(SUCCESS_DIRNAME)
|
|
197
|
+
)
|
|
198
|
+
output_dir = cli.execution_context.output_dir.realpath.to_s
|
|
199
|
+
|
|
200
|
+
cli.call
|
|
201
|
+
|
|
202
|
+
assert marker.exist?, "ensure_later with dir: :rundoc_root should run"
|
|
203
|
+
assert_equal output_dir, marker.read
|
|
204
|
+
end
|
|
205
|
+
end
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
def test_output_not_in_document
|
|
209
|
+
Dir.mktmpdir do |dir|
|
|
210
|
+
Dir.chdir(dir) do
|
|
211
|
+
dir = Pathname(dir)
|
|
212
|
+
|
|
213
|
+
source_path = dir.join("RUNDOC.md")
|
|
214
|
+
source_path.write <<~EOF
|
|
215
|
+
```
|
|
216
|
+
:::-- rundoc.ensure_later(dir: :cwd)
|
|
217
|
+
puts "THIS SHOULD NOT APPEAR"
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
```
|
|
221
|
+
:::>> $ echo "visible"
|
|
222
|
+
```
|
|
223
|
+
EOF
|
|
224
|
+
|
|
225
|
+
Rundoc::CLI.new(
|
|
226
|
+
io: StringIO.new,
|
|
227
|
+
source_path: source_path,
|
|
228
|
+
on_success_dir: dir.join(SUCCESS_DIRNAME)
|
|
229
|
+
).call
|
|
230
|
+
|
|
231
|
+
readme = dir.join(SUCCESS_DIRNAME).join("README.md").read
|
|
232
|
+
refute_match(/THIS SHOULD NOT APPEAR/, readme)
|
|
233
|
+
assert_match(/visible/, readme)
|
|
234
|
+
end
|
|
235
|
+
end
|
|
236
|
+
end
|
|
237
|
+
|
|
238
|
+
def test_invalid_dir_raises
|
|
239
|
+
Dir.mktmpdir do |dir|
|
|
240
|
+
Dir.chdir(dir) do
|
|
241
|
+
dir = Pathname(dir)
|
|
242
|
+
|
|
243
|
+
source_path = dir.join("RUNDOC.md")
|
|
244
|
+
source_path.write <<~EOF
|
|
245
|
+
```
|
|
246
|
+
:::-- rundoc.ensure_later(dir: :invalid)
|
|
247
|
+
puts "should not run"
|
|
248
|
+
```
|
|
249
|
+
EOF
|
|
250
|
+
|
|
251
|
+
assert_raises(ArgumentError) do
|
|
252
|
+
Rundoc::CLI.new(
|
|
253
|
+
io: StringIO.new,
|
|
254
|
+
source_path: source_path,
|
|
255
|
+
on_success_dir: dir.join(SUCCESS_DIRNAME)
|
|
256
|
+
).call
|
|
257
|
+
end
|
|
258
|
+
end
|
|
259
|
+
end
|
|
260
|
+
end
|
|
261
|
+
|
|
262
|
+
def test_shared_binding_with_rundoc
|
|
263
|
+
Dir.mktmpdir do |dir|
|
|
264
|
+
Dir.chdir(dir) do
|
|
265
|
+
dir = Pathname(dir)
|
|
266
|
+
marker = dir.join("binding_test.txt")
|
|
267
|
+
|
|
268
|
+
source_path = dir.join("RUNDOC.md")
|
|
269
|
+
source_path.write <<~EOF
|
|
270
|
+
```
|
|
271
|
+
:::-- rundoc
|
|
272
|
+
def my_helper
|
|
273
|
+
"from_rundoc"
|
|
274
|
+
end
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
```
|
|
278
|
+
:::-- rundoc.ensure_later(dir: :cwd)
|
|
279
|
+
File.write("#{marker}", my_helper)
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
```
|
|
283
|
+
:::>> $ echo "hello"
|
|
284
|
+
```
|
|
285
|
+
EOF
|
|
286
|
+
|
|
287
|
+
Rundoc::CLI.new(
|
|
288
|
+
io: StringIO.new,
|
|
289
|
+
source_path: source_path,
|
|
290
|
+
on_success_dir: dir.join(SUCCESS_DIRNAME)
|
|
291
|
+
).call
|
|
292
|
+
|
|
293
|
+
assert_equal "from_rundoc", marker.read
|
|
294
|
+
end
|
|
295
|
+
end
|
|
296
|
+
end
|
|
297
|
+
|
|
298
|
+
def test_runs_on_failure_from_subdirectory
|
|
299
|
+
Dir.mktmpdir do |dir|
|
|
300
|
+
Dir.chdir(dir) do
|
|
301
|
+
dir = Pathname(dir)
|
|
302
|
+
marker = dir.join("ensure_ran.txt")
|
|
303
|
+
|
|
304
|
+
source_path = dir.join("RUNDOC.md")
|
|
305
|
+
source_path.write <<~EOF
|
|
306
|
+
```
|
|
307
|
+
:::>> $ mkdir myapp
|
|
308
|
+
:::>> $ cd myapp
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
```
|
|
312
|
+
:::-- rundoc.ensure_later(dir: :cwd)
|
|
313
|
+
File.write("#{marker}", "cleaned")
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
```
|
|
317
|
+
:::>> $ exit 1
|
|
318
|
+
```
|
|
319
|
+
EOF
|
|
320
|
+
|
|
321
|
+
assert_raises do
|
|
322
|
+
Rundoc::CLI.new(
|
|
323
|
+
io: StringIO.new,
|
|
324
|
+
source_path: source_path,
|
|
325
|
+
on_success_dir: dir.join(SUCCESS_DIRNAME),
|
|
326
|
+
on_failure_dir: dir.join(FAILURE_DIRNAME)
|
|
327
|
+
).call
|
|
328
|
+
end
|
|
329
|
+
|
|
330
|
+
assert marker.exist?, "ensure_later from subdirectory should run even on failure"
|
|
331
|
+
assert_equal "cleaned", marker.read
|
|
332
|
+
end
|
|
333
|
+
end
|
|
334
|
+
end
|
|
335
|
+
end
|
|
@@ -50,6 +50,57 @@ class IntegrationPrintTest < Minitest::Test
|
|
|
50
50
|
end
|
|
51
51
|
end
|
|
52
52
|
|
|
53
|
+
def test_rundoc_configure_defines_variable_accessible_from_erb
|
|
54
|
+
key = SecureRandom.hex
|
|
55
|
+
contents = <<~RUBY
|
|
56
|
+
```
|
|
57
|
+
:::-- rundoc.configure
|
|
58
|
+
@shared_value = "#{key}"
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
```
|
|
62
|
+
:::-> print.erb
|
|
63
|
+
<%= @shared_value %>
|
|
64
|
+
```
|
|
65
|
+
RUBY
|
|
66
|
+
|
|
67
|
+
Dir.mktmpdir do |dir|
|
|
68
|
+
Dir.chdir(dir) do
|
|
69
|
+
parsed = parse_contents(contents)
|
|
70
|
+
actual = parsed.to_md.gsub(Rundoc::FencedCodeBlock::AUTOGEN_WARNING, "")
|
|
71
|
+
assert_includes actual, key
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def test_erb_defines_variable_accessible_from_rundoc_configure
|
|
77
|
+
key = SecureRandom.hex
|
|
78
|
+
contents = <<~RUBY
|
|
79
|
+
```
|
|
80
|
+
:::-> print.erb
|
|
81
|
+
<% @from_erb = "#{key}" %>
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
```
|
|
85
|
+
:::-- rundoc.configure
|
|
86
|
+
@roundtripped = @from_erb + "_via_configure"
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
```
|
|
90
|
+
:::-> print.erb
|
|
91
|
+
<%= @roundtripped %>
|
|
92
|
+
```
|
|
93
|
+
RUBY
|
|
94
|
+
|
|
95
|
+
Dir.mktmpdir do |dir|
|
|
96
|
+
Dir.chdir(dir) do
|
|
97
|
+
parsed = parse_contents(contents)
|
|
98
|
+
actual = parsed.to_md.gsub(Rundoc::FencedCodeBlock::AUTOGEN_WARNING, "")
|
|
99
|
+
assert_includes actual, "#{key}_via_configure"
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
|
|
53
104
|
def test_erb_in_block
|
|
54
105
|
contents = <<~RUBY
|
|
55
106
|
```
|
|
@@ -367,4 +367,29 @@ class PegParserTest < Minitest::Test
|
|
|
367
367
|
assert_equal :rundoc, actual.keyword
|
|
368
368
|
assert_equal "first = 1 # comment\nsecond = 2".strip, actual.contents.strip
|
|
369
369
|
end
|
|
370
|
+
|
|
371
|
+
def test_symbol_value
|
|
372
|
+
input = %(:cwd)
|
|
373
|
+
parser = Rundoc::PegParser.new.symbol
|
|
374
|
+
tree = parser.parse_with_debug(input)
|
|
375
|
+
actual = @transformer.apply(tree)
|
|
376
|
+
assert_equal :cwd, actual
|
|
377
|
+
end
|
|
378
|
+
|
|
379
|
+
def test_symbol_in_named_args
|
|
380
|
+
input = %(dir: :cwd)
|
|
381
|
+
parser = Rundoc::PegParser.new.named_args
|
|
382
|
+
tree = parser.parse_with_debug(input)
|
|
383
|
+
actual = @transformer.apply(tree)
|
|
384
|
+
assert_equal({dir: :cwd}, actual)
|
|
385
|
+
end
|
|
386
|
+
|
|
387
|
+
def test_symbol_in_method_call
|
|
388
|
+
input = %(rundoc.ensure_later(dir: :cwd))
|
|
389
|
+
parser = Rundoc::PegParser.new.method_call
|
|
390
|
+
tree = parser.parse_with_debug(input)
|
|
391
|
+
actual = @transformer.apply(tree)
|
|
392
|
+
assert_equal :"rundoc.ensure_later", actual.keyword
|
|
393
|
+
assert_equal({dir: :cwd}, actual.original_args)
|
|
394
|
+
end
|
|
370
395
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: rundoc
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version:
|
|
4
|
+
version: 6.0.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Richard Schneeman
|
|
@@ -107,6 +107,20 @@ dependencies:
|
|
|
107
107
|
- - ">="
|
|
108
108
|
- !ruby/object:Gem::Version
|
|
109
109
|
version: '0'
|
|
110
|
+
- !ruby/object:Gem::Dependency
|
|
111
|
+
name: cgi
|
|
112
|
+
requirement: !ruby/object:Gem::Requirement
|
|
113
|
+
requirements:
|
|
114
|
+
- - ">="
|
|
115
|
+
- !ruby/object:Gem::Version
|
|
116
|
+
version: 0.3.6
|
|
117
|
+
type: :runtime
|
|
118
|
+
prerelease: false
|
|
119
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
120
|
+
requirements:
|
|
121
|
+
- - ">="
|
|
122
|
+
- !ruby/object:Gem::Version
|
|
123
|
+
version: 0.3.6
|
|
110
124
|
- !ruby/object:Gem::Dependency
|
|
111
125
|
name: rake
|
|
112
126
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -212,6 +226,7 @@ files:
|
|
|
212
226
|
- lib/rundoc/code_command/bash/cd.rb
|
|
213
227
|
- lib/rundoc/code_command/comment.rb
|
|
214
228
|
- lib/rundoc/code_command/deferred.rb
|
|
229
|
+
- lib/rundoc/code_command/empty_binding.rb
|
|
215
230
|
- lib/rundoc/code_command/file_command/append.rb
|
|
216
231
|
- lib/rundoc/code_command/file_command/remove.rb
|
|
217
232
|
- lib/rundoc/code_command/no_such_command.rb
|
|
@@ -220,6 +235,7 @@ files:
|
|
|
220
235
|
- lib/rundoc/code_command/print/erb.rb
|
|
221
236
|
- lib/rundoc/code_command/print/text.rb
|
|
222
237
|
- lib/rundoc/code_command/raw.rb
|
|
238
|
+
- lib/rundoc/code_command/rundoc/ensure_later.rb
|
|
223
239
|
- lib/rundoc/code_command/rundoc/require.rb
|
|
224
240
|
- lib/rundoc/code_command/rundoc_command.rb
|
|
225
241
|
- lib/rundoc/code_command/website.rb
|
|
@@ -262,6 +278,7 @@ files:
|
|
|
262
278
|
- test/fixtures/simple_git/rundoc.md
|
|
263
279
|
- test/integration/after_build_test.rb
|
|
264
280
|
- test/integration/background_stdin_test.rb
|
|
281
|
+
- test/integration/ensure_later_test.rb
|
|
265
282
|
- test/integration/failure_test.rb
|
|
266
283
|
- test/integration/pre_erb_test.rb
|
|
267
284
|
- test/integration/print_test.rb
|
|
@@ -301,7 +318,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
301
318
|
- !ruby/object:Gem::Version
|
|
302
319
|
version: '0'
|
|
303
320
|
requirements: []
|
|
304
|
-
rubygems_version:
|
|
321
|
+
rubygems_version: 4.0.10
|
|
305
322
|
specification_version: 4
|
|
306
323
|
summary: RunDOC generates runable code from docs
|
|
307
324
|
test_files: []
|