backspin 0.3.0 → 0.4.1
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/.circleci/config.yml +3 -1
- data/CHANGELOG.md +4 -0
- data/CLAUDE.md +6 -6
- data/CONTRIBUTING.md +3 -5
- data/Gemfile +1 -1
- data/Gemfile.lock +2 -2
- data/README.md +113 -34
- data/backspin.gemspec +2 -2
- data/bin/rake +27 -0
- data/bin/rspec +27 -0
- data/fixtures/backspin/all_mode_filter.yml +14 -0
- data/fixtures/backspin/credential_filter.yml +18 -0
- data/fixtures/backspin/echo_hello.yml +14 -0
- data/fixtures/backspin/echo_verify.yml +14 -0
- data/fixtures/backspin/episodes_filter.yml +26 -0
- data/fixtures/backspin/failure_test.yml +14 -0
- data/fixtures/backspin/full_data_filter.yml +17 -0
- data/fixtures/backspin/mixed_calls.yml +24 -0
- data/fixtures/backspin/multi_command.yml +34 -0
- data/fixtures/backspin/multi_command_filter.yml +26 -0
- data/fixtures/backspin/multi_field_filter.yml +13 -0
- data/fixtures/backspin/multi_system.yml +20 -0
- data/fixtures/backspin/nil_filter.yml +14 -0
- data/fixtures/backspin/none_mode_test.yml +14 -0
- data/fixtures/backspin/path_test.yml +17 -0
- data/fixtures/backspin/playback_system.yml +12 -0
- data/fixtures/backspin/playback_test.yml +14 -0
- data/fixtures/backspin/stderr_test.yml +19 -0
- data/fixtures/backspin/system_echo.yml +12 -0
- data/fixtures/backspin/system_false.yml +18 -0
- data/fixtures/backspin/timestamp_test.yml +18 -0
- data/fixtures/backspin/use_record_filter.yml +15 -0
- data/fixtures/backspin/verify_system.yml +12 -0
- data/fixtures/backspin/verify_system_diff.yml +11 -0
- data/fixtures/backspin/version_test.yml +14 -0
- data/lib/backspin/command.rb +33 -14
- data/lib/backspin/command_diff.rb +88 -0
- data/lib/backspin/command_result.rb +60 -0
- data/lib/backspin/record.rb +2 -2
- data/lib/backspin/record_result.rb +153 -0
- data/lib/backspin/recorder.rb +4 -23
- data/lib/backspin/version.rb +1 -1
- data/lib/backspin.rb +169 -287
- metadata +33 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f44a53c1983fd41c2660bc9652c158b2193e880e0e1339fa49c882d26fdd0852
|
4
|
+
data.tar.gz: 3b53d9ba92db35ad66c128bc049762e06c307472827fe2d4b795427c7e668bdf
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 28909c63f9befbe8a0ae208328b9c527b3f1ca28417a66e96afad6ee9be41c2fa157ede63e4c5073f049ac59ab9c336a5fde7b97e109b7efc61480942ddc1a58
|
7
|
+
data.tar.gz: e63c8c4fff6ac690575ffadfe48efd6b4d0bc2267680e1c99637a888edcf3034bb315d96efedc400bfabdf5f8a9aa7912dfef03771b86a6a69769efe1bdcaac6
|
data/.circleci/config.yml
CHANGED
@@ -7,6 +7,7 @@ orbs:
|
|
7
7
|
|
8
8
|
jobs:
|
9
9
|
build:
|
10
|
+
resource_class: medium
|
10
11
|
parameters:
|
11
12
|
ruby-version:
|
12
13
|
type: string
|
@@ -15,7 +16,8 @@ jobs:
|
|
15
16
|
|
16
17
|
steps:
|
17
18
|
- checkout
|
18
|
-
- ruby/install-deps
|
19
|
+
- ruby/install-deps:
|
20
|
+
key: gems-v1-ruby<< parameters.ruby-version >>
|
19
21
|
- run:
|
20
22
|
name: Run specs and lint
|
21
23
|
command: bundle exec rake
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,9 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
## [0.4.0] - 2025-06-06
|
4
|
+
|
5
|
+
Simpler, unified API: `Backspin.run` and `Backspin run!` methods that automatically record on first use and verify on subsequent runs. `run!` will raise an error if results differ, whereas `run` will return the result for the caller to decide what to do with
|
6
|
+
|
3
7
|
## [0.3.0] - 2025-06-05
|
4
8
|
- Scrub credentials from command arguments
|
5
9
|
|
data/CLAUDE.md
CHANGED
@@ -17,14 +17,14 @@ bin/setup
|
|
17
17
|
### Testing
|
18
18
|
```bash
|
19
19
|
bin/rake spec # Run all tests
|
20
|
-
rspec spec/[file] # Run specific test file
|
21
|
-
rspec spec/[file]:[line] # Run specific test
|
20
|
+
bin/rspec spec/[file] # Run specific test file
|
21
|
+
bin/rspec spec/[file]:[line] # Run specific test
|
22
22
|
```
|
23
23
|
|
24
24
|
### Building and Releasing
|
25
25
|
```bash
|
26
|
-
|
27
|
-
|
26
|
+
bin/rake install # Install gem locally for testing
|
27
|
+
bin/rake release # Release to RubyGems (updates version, tags, pushes)
|
28
28
|
```
|
29
29
|
|
30
30
|
### Code Quality
|
@@ -62,7 +62,7 @@ bin/rake standard # Run Standard Ruby linter
|
|
62
62
|
### Testing Approach
|
63
63
|
|
64
64
|
- Integration-focused tests that exercise the full stack
|
65
|
-
- Default record directory is `
|
65
|
+
- Default record directory is `fixtures/backspin` (can be configured)
|
66
66
|
- Tests use real shell commands (`echo`, `date`, etc.)
|
67
67
|
- Configuration is reset between tests to avoid side effects
|
68
68
|
- **Important**: Backspin specs MUST be as local and un-DRY as possible. Each spec should be self-contained with its own setup, expectations, and cleanup if needed. Avoid shared contexts or helpers that hide important test details.
|
@@ -76,7 +76,7 @@ bin/rake standard # Run Standard Ruby linter
|
|
76
76
|
4. Run tests with `rake spec`
|
77
77
|
|
78
78
|
### Debugging Tests
|
79
|
-
- Records are saved to `
|
79
|
+
- Records are saved to `fixtures/backspin/` by default
|
80
80
|
- Check YAML files to see recorded command outputs
|
81
81
|
|
82
82
|
### Updating Credential Patterns
|
data/CONTRIBUTING.md
CHANGED
@@ -99,7 +99,7 @@ Backspin is a Ruby gem for characterization testing of command-line interfaces.
|
|
99
99
|
|
100
100
|
#### Debugging Tests
|
101
101
|
|
102
|
-
- Records are saved to `
|
102
|
+
- Records are saved to `fixtures/backspin/` by default
|
103
103
|
- Check YAML files to see recorded command outputs
|
104
104
|
|
105
105
|
## Testing
|
@@ -125,7 +125,7 @@ Backspin uses integration-focused tests that exercise the full stack. When writi
|
|
125
125
|
- Avoid shared contexts or helpers that hide important test details
|
126
126
|
- Use real shell commands (`echo`, `date`, etc.) for testing
|
127
127
|
- Ensure configuration is reset between tests to avoid side effects
|
128
|
-
- Verify new or updated test records in `
|
128
|
+
- Verify new or updated test records in `fixtures/backspin/`
|
129
129
|
|
130
130
|
Example test structure:
|
131
131
|
|
@@ -161,7 +161,6 @@ end
|
|
161
161
|
|
162
162
|
- Keep changes focused and atomic
|
163
163
|
- Include tests for new functionality
|
164
|
-
- Maintain backward compatibility when possible
|
165
164
|
- Update examples in README.md if changing public APIs
|
166
165
|
- Ensure CI passes (tests against Ruby 3.2, 3.3, and 3.4)
|
167
166
|
|
@@ -203,8 +202,7 @@ We welcome feature requests! When proposing new features:
|
|
203
202
|
1. Check existing issues to avoid duplicates
|
204
203
|
2. Describe the use case and motivation
|
205
204
|
3. Provide code examples of how the feature would work
|
206
|
-
4.
|
207
|
-
5. Be open to discussion and alternative approaches
|
205
|
+
4. Be open to discussion and alternative approaches
|
208
206
|
|
209
207
|
## Additional Resources
|
210
208
|
|
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
backspin (0.
|
4
|
+
backspin (0.4.1)
|
5
5
|
ostruct (~> 0.5.0)
|
6
6
|
rspec-mocks (~> 3.0)
|
7
7
|
|
@@ -80,7 +80,7 @@ DEPENDENCIES
|
|
80
80
|
backspin!
|
81
81
|
rake (~> 13.0)
|
82
82
|
rspec (~> 3.0)
|
83
|
-
standard
|
83
|
+
standard
|
84
84
|
timecop (~> 0.9)
|
85
85
|
|
86
86
|
BUNDLED WITH
|
data/README.md
CHANGED
@@ -1,8 +1,13 @@
|
|
1
|
-
# Backspin
|
1
|
+
# Backspin
|
2
2
|
|
3
|
-
|
3
|
+
[](https://www.ruby-lang.org/)
|
4
|
+
[](https://rubygems.org/gems/backspin)
|
5
|
+
[](https://circleci.com/gh/rsanheim/backspin)
|
6
|
+
[](https://github.com/rsanheim/backspin/commits/main)
|
4
7
|
|
5
|
-
|
8
|
+
Backspin records and replays CLI interactions in Ruby for easy snapshot testing of command-line interfaces. Currently supports `Open3.capture3` and `system` and requires `rspec-mocks`. More system calls and test integrations are welcome - send a PR!
|
9
|
+
|
10
|
+
**NOTE:** Backspin should be considered alpha quality software while pre v1.0. It is in heavy development, and you can expect the API to change. It is being developed in conjunction with production CLI apps, so the API will be refined and improved as we get to 1.0.
|
6
11
|
|
7
12
|
Inspired by [VCR](https://github.com/vcr/vcr) and other [golden master](https://en.wikipedia.org/wiki/Golden_master_(software_development)) libraries.
|
8
13
|
|
@@ -24,73 +29,147 @@ And then run `bundle install`.
|
|
24
29
|
|
25
30
|
## Usage
|
26
31
|
|
27
|
-
###
|
32
|
+
### Quick Start
|
33
|
+
|
34
|
+
The simplest way to use Backspin is with the `run` method, which automatically records on the first execution and verifies on subsequent runs:
|
28
35
|
|
29
36
|
```ruby
|
30
|
-
require "backspin"
|
37
|
+
require "backspin"
|
38
|
+
|
39
|
+
# First run: records the output
|
40
|
+
result = Backspin.run("my_command") do
|
41
|
+
Open3.capture3("echo hello world")
|
42
|
+
end
|
31
43
|
|
32
|
-
#
|
33
|
-
result = Backspin.
|
34
|
-
|
35
|
-
# This will save the output to `spec/backspin_data/echo_hello.yaml`.
|
44
|
+
# Subsequent runs: verifies the output matches
|
45
|
+
result = Backspin.run("my_command") do
|
46
|
+
Open3.capture3("echo hello world")
|
36
47
|
end
|
37
48
|
|
49
|
+
# Use run! to automatically fail tests on mismatch
|
50
|
+
Backspin.run!("my_command") do
|
51
|
+
Open3.capture3("echo hello mars")
|
52
|
+
end
|
53
|
+
# Raises an error because stdout will not match the recorded output
|
38
54
|
```
|
39
55
|
|
40
|
-
###
|
56
|
+
### Recording Modes
|
57
|
+
|
58
|
+
Backspin supports different modes for controlling how commands are recorded and verified:
|
41
59
|
|
42
60
|
```ruby
|
43
|
-
#
|
44
|
-
result = Backspin.
|
61
|
+
# Auto mode (default): Record on first run, verify on subsequent runs
|
62
|
+
result = Backspin.run("my_command") do
|
63
|
+
Open3.capture3("echo hello")
|
64
|
+
end
|
65
|
+
|
66
|
+
# Explicit record mode: Always record, overwriting existing recordings
|
67
|
+
result = Backspin.run("echo_test", mode: :record) do
|
45
68
|
Open3.capture3("echo hello")
|
46
69
|
end
|
70
|
+
# This will save the output to `fixtures/backspin/echo_test.yml`.
|
47
71
|
|
72
|
+
# Explicit verify mode: Always verify against existing recording
|
73
|
+
result = Backspin.run("echo_test", mode: :verify) do
|
74
|
+
Open3.capture3("echo hello")
|
75
|
+
end
|
48
76
|
expect(result.verified?).to be true
|
77
|
+
|
78
|
+
# Playback mode: Return recorded output without running the command
|
79
|
+
result = Backspin.run("slow_command", mode: :playback) do
|
80
|
+
Open3.capture3("slow_command") # Not executed - returns recorded output
|
81
|
+
end
|
49
82
|
```
|
50
83
|
|
51
|
-
### Using
|
84
|
+
### Using run! for automatic test failures
|
85
|
+
|
86
|
+
The `run!` method works exactly like `run` but automatically fails the test if verification fails:
|
52
87
|
|
53
88
|
```ruby
|
54
89
|
# Automatically fail the test if output doesn't match
|
55
|
-
Backspin.
|
90
|
+
Backspin.run!("echo_test") do
|
56
91
|
Open3.capture3("echo hello")
|
57
92
|
end
|
93
|
+
# Raises an error with detailed diff if verification fails from recorded data in "echo_test.yml"
|
58
94
|
```
|
59
95
|
|
60
|
-
###
|
96
|
+
### Custom matchers
|
97
|
+
|
98
|
+
For cases where exact matching isn't suitable, you can provide custom verification logic:
|
61
99
|
|
62
100
|
```ruby
|
63
|
-
#
|
64
|
-
result = Backspin.
|
65
|
-
|
101
|
+
# Use custom logic to verify output
|
102
|
+
result = Backspin.run("version_check",
|
103
|
+
matcher: ->(recorded, actual) {
|
104
|
+
# Just check that both start with "ruby"
|
105
|
+
recorded["stdout"].start_with?("ruby") &&
|
106
|
+
actual["stdout"].start_with?("ruby")
|
107
|
+
}) do
|
108
|
+
Open3.capture3("ruby --version")
|
66
109
|
end
|
67
110
|
```
|
68
111
|
|
69
|
-
###
|
112
|
+
### Working with the Result Object
|
113
|
+
|
114
|
+
The API returns a `RecordResult` object with helpful methods:
|
70
115
|
|
71
116
|
```ruby
|
72
|
-
|
73
|
-
|
74
|
-
matcher: ->(recorded, actual) {
|
75
|
-
# Just check that both start with "ruby"
|
76
|
-
recorded["stdout"].start_with?("ruby") &&
|
77
|
-
actual["stdout"].start_with?("ruby")
|
78
|
-
}) do
|
79
|
-
Open3.capture3("ruby --version")
|
117
|
+
result = Backspin.run("my_test") do
|
118
|
+
Open3.capture3("echo out; echo err >&2; exit 42")
|
80
119
|
end
|
120
|
+
|
121
|
+
# Check the mode
|
122
|
+
result.recorded? # true on first run
|
123
|
+
result.verified? # true/false on subsequent runs, nil when recording
|
124
|
+
result.playback? # true in playback mode
|
125
|
+
|
126
|
+
# Access output (first command for single commands)
|
127
|
+
result.stdout # "out\n"
|
128
|
+
result.stderr # "err\n"
|
129
|
+
result.status # 42
|
130
|
+
result.success? # false (non-zero exit)
|
131
|
+
result.output # The raw return value from the block
|
132
|
+
|
133
|
+
# Debug information
|
134
|
+
result.record_path # Path to the YAML file
|
135
|
+
result.error_message # Human-readable error if verification failed
|
136
|
+
result.diff # Diff between expected and actual output
|
81
137
|
```
|
82
138
|
|
83
|
-
###
|
139
|
+
### Multiple Commands
|
84
140
|
|
85
|
-
|
141
|
+
Backspin automatically records and verifies all commands executed in a block:
|
86
142
|
|
87
143
|
```ruby
|
88
|
-
|
89
|
-
|
90
|
-
Open3.capture3("
|
144
|
+
result = Backspin.run("multi_command_test") do
|
145
|
+
# All of these commands will be recorded
|
146
|
+
version, = Open3.capture3("ruby --version")
|
147
|
+
files, = Open3.capture3("ls -la")
|
148
|
+
system("echo 'Processing...'") # Note: system doesn't capture output
|
149
|
+
data, stderr, = Open3.capture3("curl https://api.example.com/data")
|
150
|
+
|
151
|
+
# Return whatever you need
|
152
|
+
{ version: version.strip, file_count: files.lines.count, data: data }
|
91
153
|
end
|
154
|
+
|
155
|
+
# Access individual command results
|
156
|
+
result.commands.size # 4
|
157
|
+
result.multiple_commands? # true
|
158
|
+
|
159
|
+
# For multiple commands, use these accessors
|
160
|
+
result.all_stdout # Array of stdout from each command
|
161
|
+
result.all_stderr # Array of stderr from each command
|
162
|
+
result.all_status # Array of exit statuses
|
163
|
+
|
164
|
+
# Or access specific commands
|
165
|
+
result.commands[0].stdout # Ruby version output
|
166
|
+
result.commands[1].stdout # ls output
|
167
|
+
result.commands[2].status # system call exit status (stdout is empty)
|
168
|
+
result.commands[3].stderr # curl errors if any
|
92
169
|
```
|
93
170
|
|
171
|
+
When verifying multiple commands, Backspin ensures all commands match in the exact order they were recorded. If any command differs, you'll get a detailed error showing which commands failed.
|
172
|
+
|
94
173
|
### Credential Scrubbing
|
95
174
|
|
96
175
|
If the CLI interaction you are recording contains sensitive data in stdout or stderr, you should be careful to make sure it is not recorded to yaml!
|
@@ -102,7 +181,7 @@ A tool like [trufflehog](https://github.com/trufflesecurity/trufflehog) or [gitl
|
|
102
181
|
|
103
182
|
```ruby
|
104
183
|
# This will automatically scrub AWS keys, API tokens, passwords, etc.
|
105
|
-
Backspin.
|
184
|
+
Backspin.run("aws_command") do
|
106
185
|
Open3.capture3("aws s3 ls")
|
107
186
|
end
|
108
187
|
|
@@ -146,4 +225,4 @@ Bug reports and pull requests are welcome on GitHub at https://github.com/rsanhe
|
|
146
225
|
|
147
226
|
## License
|
148
227
|
|
149
|
-
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
228
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
data/backspin.gemspec
CHANGED
@@ -20,8 +20,8 @@ Gem::Specification.new do |spec|
|
|
20
20
|
spec.files = Dir.chdir(File.expand_path("..", __FILE__)) do
|
21
21
|
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
22
22
|
end
|
23
|
-
spec.bindir = "
|
24
|
-
spec.executables = spec.files.grep(%r{
|
23
|
+
spec.bindir = "exe"
|
24
|
+
spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
|
25
25
|
spec.require_paths = ["lib"]
|
26
26
|
|
27
27
|
spec.add_dependency "rspec-mocks", "~> 3.0"
|
data/bin/rake
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
#
|
5
|
+
# This file was generated by Bundler.
|
6
|
+
#
|
7
|
+
# The application 'rake' is installed as part of a gem, and
|
8
|
+
# this file is here to facilitate running it.
|
9
|
+
#
|
10
|
+
|
11
|
+
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__)
|
12
|
+
|
13
|
+
bundle_binstub = File.expand_path("bundle", __dir__)
|
14
|
+
|
15
|
+
if File.file?(bundle_binstub)
|
16
|
+
if File.read(bundle_binstub, 300).include?("This file was generated by Bundler")
|
17
|
+
load(bundle_binstub)
|
18
|
+
else
|
19
|
+
abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
|
20
|
+
Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
require "rubygems"
|
25
|
+
require "bundler/setup"
|
26
|
+
|
27
|
+
load Gem.bin_path("rake", "rake")
|
data/bin/rspec
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
#
|
5
|
+
# This file was generated by Bundler.
|
6
|
+
#
|
7
|
+
# The application 'rspec' is installed as part of a gem, and
|
8
|
+
# this file is here to facilitate running it.
|
9
|
+
#
|
10
|
+
|
11
|
+
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__)
|
12
|
+
|
13
|
+
bundle_binstub = File.expand_path("bundle", __dir__)
|
14
|
+
|
15
|
+
if File.file?(bundle_binstub)
|
16
|
+
if File.read(bundle_binstub, 300).include?("This file was generated by Bundler")
|
17
|
+
load(bundle_binstub)
|
18
|
+
else
|
19
|
+
abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
|
20
|
+
Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
require "rubygems"
|
25
|
+
require "bundler/setup"
|
26
|
+
|
27
|
+
load Gem.bin_path("rspec-core", "rspec")
|
@@ -0,0 +1,18 @@
|
|
1
|
+
---
|
2
|
+
first_recorded_at: '2025-05-01T12:00:00Z'
|
3
|
+
format_version: '2.0'
|
4
|
+
commands:
|
5
|
+
- command_type: Open3::Capture3
|
6
|
+
args:
|
7
|
+
- echo
|
8
|
+
- "'My"
|
9
|
+
- API
|
10
|
+
- key
|
11
|
+
- is
|
12
|
+
- "********************'"
|
13
|
+
stdout: 'MY API KEY IS ********************
|
14
|
+
|
15
|
+
'
|
16
|
+
stderr: ''
|
17
|
+
status: 0
|
18
|
+
recorded_at: '2025-05-01T12:00:00Z'
|
@@ -0,0 +1,26 @@
|
|
1
|
+
---
|
2
|
+
first_recorded_at: '2025-05-01T12:00:00Z'
|
3
|
+
format_version: '2.0'
|
4
|
+
commands:
|
5
|
+
- command_type: Open3::Capture3
|
6
|
+
args:
|
7
|
+
- echo
|
8
|
+
- "'episode"
|
9
|
+
- 1'
|
10
|
+
stdout: 'EPISODE 1
|
11
|
+
|
12
|
+
'
|
13
|
+
stderr: ''
|
14
|
+
status: 0
|
15
|
+
recorded_at: '2025-05-01T12:00:00Z'
|
16
|
+
- command_type: Open3::Capture3
|
17
|
+
args:
|
18
|
+
- echo
|
19
|
+
- "'episode"
|
20
|
+
- 2'
|
21
|
+
stdout: 'EPISODE 2
|
22
|
+
|
23
|
+
'
|
24
|
+
stderr: ''
|
25
|
+
status: 0
|
26
|
+
recorded_at: '2025-05-01T12:00:00Z'
|
@@ -0,0 +1,17 @@
|
|
1
|
+
---
|
2
|
+
first_recorded_at: '2025-05-01T12:00:00Z'
|
3
|
+
format_version: '2.0'
|
4
|
+
commands:
|
5
|
+
- command_type: Open3::Capture3
|
6
|
+
args:
|
7
|
+
- bash
|
8
|
+
- "-c"
|
9
|
+
- echo 'stdout message' && echo 'stderr message' >&2 && exit 42
|
10
|
+
stdout: 'stdout message
|
11
|
+
|
12
|
+
'
|
13
|
+
stderr: 'stderr message
|
14
|
+
|
15
|
+
'
|
16
|
+
status: 42
|
17
|
+
recorded_at: '2025-05-01T12:00:00Z'
|
@@ -0,0 +1,24 @@
|
|
1
|
+
---
|
2
|
+
first_recorded_at: '2025-05-01T12:00:00Z'
|
3
|
+
format_version: '2.0'
|
4
|
+
commands:
|
5
|
+
- command_type: Kernel::System
|
6
|
+
args:
|
7
|
+
- echo
|
8
|
+
- from
|
9
|
+
- system
|
10
|
+
stdout: ''
|
11
|
+
stderr: ''
|
12
|
+
status: 0
|
13
|
+
recorded_at: '2025-05-01T12:00:00Z'
|
14
|
+
- command_type: Open3::Capture3
|
15
|
+
args:
|
16
|
+
- echo
|
17
|
+
- from
|
18
|
+
- capture3
|
19
|
+
stdout: 'from capture3
|
20
|
+
|
21
|
+
'
|
22
|
+
stderr: ''
|
23
|
+
status: 0
|
24
|
+
recorded_at: '2025-05-01T12:00:00Z'
|
@@ -0,0 +1,34 @@
|
|
1
|
+
---
|
2
|
+
first_recorded_at: '2025-05-01T12:00:00Z'
|
3
|
+
format_version: '2.0'
|
4
|
+
commands:
|
5
|
+
- command_type: Open3::Capture3
|
6
|
+
args:
|
7
|
+
- echo
|
8
|
+
- first
|
9
|
+
stdout: 'first
|
10
|
+
|
11
|
+
'
|
12
|
+
stderr: ''
|
13
|
+
status: 0
|
14
|
+
recorded_at: '2025-05-01T12:00:00Z'
|
15
|
+
- command_type: Open3::Capture3
|
16
|
+
args:
|
17
|
+
- echo
|
18
|
+
- second
|
19
|
+
stdout: 'second
|
20
|
+
|
21
|
+
'
|
22
|
+
stderr: ''
|
23
|
+
status: 0
|
24
|
+
recorded_at: '2025-05-01T12:00:00Z'
|
25
|
+
- command_type: Open3::Capture3
|
26
|
+
args:
|
27
|
+
- echo
|
28
|
+
- third
|
29
|
+
stdout: 'third
|
30
|
+
|
31
|
+
'
|
32
|
+
stderr: ''
|
33
|
+
status: 0
|
34
|
+
recorded_at: '2025-05-01T12:00:00Z'
|
@@ -0,0 +1,26 @@
|
|
1
|
+
---
|
2
|
+
first_recorded_at: '2025-05-01T12:00:00Z'
|
3
|
+
format_version: '2.0'
|
4
|
+
commands:
|
5
|
+
- command_type: Open3::Capture3
|
6
|
+
args:
|
7
|
+
- echo
|
8
|
+
- "'Count:"
|
9
|
+
- 42'
|
10
|
+
stdout: 'Count: X
|
11
|
+
|
12
|
+
'
|
13
|
+
stderr: ''
|
14
|
+
status: 0
|
15
|
+
recorded_at: '2025-05-01T12:00:00Z'
|
16
|
+
- command_type: Open3::Capture3
|
17
|
+
args:
|
18
|
+
- echo
|
19
|
+
- "'Total:"
|
20
|
+
- 100'
|
21
|
+
stdout: 'Total: X
|
22
|
+
|
23
|
+
'
|
24
|
+
stderr: ''
|
25
|
+
status: 0
|
26
|
+
recorded_at: '2025-05-01T12:00:00Z'
|
@@ -0,0 +1,13 @@
|
|
1
|
+
---
|
2
|
+
first_recorded_at: '2025-05-01T12:00:00Z'
|
3
|
+
format_version: '2.0'
|
4
|
+
commands:
|
5
|
+
- command_type: Open3::Capture3
|
6
|
+
args:
|
7
|
+
- bash
|
8
|
+
- "-c"
|
9
|
+
- echo 'out' && echo 'err' >&2 && exit 1
|
10
|
+
stdout: modified stdout
|
11
|
+
stderr: modified stderr
|
12
|
+
status: 0
|
13
|
+
recorded_at: '2025-05-01T12:00:00Z'
|
@@ -0,0 +1,20 @@
|
|
1
|
+
---
|
2
|
+
first_recorded_at: '2025-05-01T12:00:00Z'
|
3
|
+
format_version: '2.0'
|
4
|
+
commands:
|
5
|
+
- command_type: Kernel::System
|
6
|
+
args:
|
7
|
+
- echo
|
8
|
+
- first
|
9
|
+
stdout: ''
|
10
|
+
stderr: ''
|
11
|
+
status: 0
|
12
|
+
recorded_at: '2025-05-01T12:00:00Z'
|
13
|
+
- command_type: Kernel::System
|
14
|
+
args:
|
15
|
+
- echo
|
16
|
+
- second
|
17
|
+
stdout: ''
|
18
|
+
stderr: ''
|
19
|
+
status: 0
|
20
|
+
recorded_at: '2025-05-01T12:00:00Z'
|