backspin 0.4.1 → 0.4.2
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/.gem_release.yml +13 -0
- data/CHANGELOG.md +5 -7
- data/CLAUDE.md +5 -1
- data/Gemfile +3 -1
- data/Gemfile.lock +3 -1
- data/MATCH_ON_USAGE.md +110 -0
- data/Rakefile +5 -1
- data/backspin.gemspec +6 -3
- data/examples/match_on_example.rb +116 -0
- data/fixtures/backspin/all_and_fields.yml +15 -0
- data/fixtures/backspin/all_bypass_equality.yml +14 -0
- data/fixtures/backspin/all_checks_equality.yml +17 -0
- data/fixtures/backspin/all_for_logging.yml +13 -0
- data/fixtures/backspin/all_matcher_basic.yml +14 -0
- data/fixtures/backspin/all_matcher_custom.yml +17 -0
- data/fixtures/backspin/all_matcher_demo.yml +14 -0
- data/fixtures/backspin/all_matcher_test.yml +14 -0
- data/fixtures/backspin/all_no_short_circuit.yml +14 -0
- data/fixtures/backspin/all_pass_field_fail.yml +14 -0
- data/fixtures/backspin/all_short_circuit.yml +14 -0
- data/fixtures/backspin/all_skips_equality.yml +17 -0
- data/fixtures/backspin/all_with_equality.yml +17 -0
- data/fixtures/backspin/all_with_fields.yml +17 -0
- data/fixtures/backspin/combined_fail_demo.yml +14 -0
- data/fixtures/backspin/combined_matcher_demo.yml +14 -0
- data/fixtures/backspin/field_matcher_demo.yml +17 -0
- data/fixtures/backspin/field_matcher_values.yml +14 -0
- data/fixtures/backspin/key_confusion_test.yml +14 -0
- data/fixtures/backspin/match_on_any_fail.yml +21 -0
- data/fixtures/backspin/match_on_bad_format.yml +14 -0
- data/fixtures/backspin/match_on_fail.yml +15 -0
- data/fixtures/backspin/match_on_invalid.yml +14 -0
- data/fixtures/backspin/match_on_multiple.yml +28 -0
- data/fixtures/backspin/match_on_nil.yml +14 -0
- data/fixtures/backspin/match_on_other_fields.yml +23 -0
- data/fixtures/backspin/match_on_run_bang.yml +16 -0
- data/fixtures/backspin/match_on_run_bang_fail.yml +15 -0
- data/fixtures/backspin/match_on_single.yml +17 -0
- data/fixtures/backspin/string_symbol_test.yml +14 -0
- data/lib/backspin/command.rb +1 -5
- data/lib/backspin/command_diff.rb +98 -16
- data/lib/backspin/command_result.rb +2 -4
- data/lib/backspin/record.rb +31 -10
- data/lib/backspin/record_result.rb +20 -14
- data/lib/backspin/recorder.rb +100 -55
- data/lib/backspin/version.rb +3 -1
- data/lib/backspin.rb +34 -173
- data/release.rake +97 -0
- data/script/lint +6 -0
- metadata +54 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 055d320685da2ca9e280c3aa8bcb15edb101d788c4d8c4df8ff203d4c2c34dac
|
4
|
+
data.tar.gz: cf21c90a588ff5590844ae2a9c50a78707a5c71d44b43ad0d3a571fed0bbe4b5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7c3a0941042e885d5370c4287fdd88323bc1b95d15a7c795afde0d08aa5efe050f7e54838a5774de967d4d633b9e30df82b5700d17c431fa8ea1cce79777bee9
|
7
|
+
data.tar.gz: 86584a95060fda843934065c2d9a3ca59acd12a1e21f70dcf3d9bd648f4cd1cec97ff21a57f98f8aa7a133865ccbb38438bdb05402f19e8292bed02c56d51bfe
|
data/.gem_release.yml
ADDED
data/CHANGELOG.md
CHANGED
@@ -1,21 +1,19 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
-
##
|
3
|
+
## 0.4.0 - 2025-06-06
|
4
4
|
|
5
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
6
|
|
7
|
-
##
|
7
|
+
## 0.3.0 - 2025-06-05
|
8
8
|
- Scrub credentials from command arguments
|
9
9
|
|
10
|
-
##
|
10
|
+
## 0.2.0 - 2025-06-05
|
11
11
|
- First public release of Backspin, extracteed from `name-TBD` CLI tool
|
12
12
|
|
13
|
-
##
|
13
|
+
## 0.2.1 - 2025-06-04
|
14
14
|
- major refactoring, add support for `system` calls
|
15
15
|
|
16
|
-
##
|
17
|
-
|
18
|
-
### Added
|
16
|
+
## 0.1.0 - 2025-06-02
|
19
17
|
- Initial (internal) release of Backspin
|
20
18
|
- `record` method to capture CLI command outputs
|
21
19
|
- `verify` and `verify!` methods for output verification
|
data/CLAUDE.md
CHANGED
@@ -29,9 +29,13 @@ bin/rake release # Release to RubyGems (updates version, tags, pushes)
|
|
29
29
|
|
30
30
|
### Code Quality
|
31
31
|
```bash
|
32
|
-
|
32
|
+
script/lint # Run Standard Ruby linter
|
33
|
+
script/lint --fix # Auto-fix linting issues
|
34
|
+
bin/rake standard # Alternative: Run via Rake task
|
33
35
|
```
|
34
36
|
|
37
|
+
**Important**: Always use `standardrb` for linting, never use `rubocop` directly. The project uses Standard Ruby for consistent code style.
|
38
|
+
|
35
39
|
## Architecture
|
36
40
|
|
37
41
|
### Core Components
|
data/Gemfile
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
source "https://rubygems.org"
|
2
4
|
|
3
5
|
# Specify your gem's dependencies in backspin.gemspec
|
@@ -6,6 +8,6 @@ gemspec
|
|
6
8
|
group :development do
|
7
9
|
gem "rake", "~> 13.0"
|
8
10
|
gem "rspec", "~> 3.0"
|
9
|
-
gem "timecop", "~> 0.9"
|
10
11
|
gem "standard"
|
12
|
+
gem "timecop", "~> 0.9"
|
11
13
|
end
|
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
backspin (0.4.
|
4
|
+
backspin (0.4.2)
|
5
5
|
ostruct (~> 0.5.0)
|
6
6
|
rspec-mocks (~> 3.0)
|
7
7
|
|
@@ -10,6 +10,7 @@ GEM
|
|
10
10
|
specs:
|
11
11
|
ast (2.4.3)
|
12
12
|
diff-lcs (1.6.2)
|
13
|
+
gem-release (2.2.4)
|
13
14
|
json (2.12.2)
|
14
15
|
language_server-protocol (3.17.0.5)
|
15
16
|
lint_roller (1.1.0)
|
@@ -78,6 +79,7 @@ PLATFORMS
|
|
78
79
|
|
79
80
|
DEPENDENCIES
|
80
81
|
backspin!
|
82
|
+
gem-release (~> 2.2)
|
81
83
|
rake (~> 13.0)
|
82
84
|
rspec (~> 3.0)
|
83
85
|
standard
|
data/MATCH_ON_USAGE.md
ADDED
@@ -0,0 +1,110 @@
|
|
1
|
+
# Using match_on for Field-Specific Verification
|
2
|
+
|
3
|
+
The `match_on` option allows you to use custom matchers for specific fields while maintaining exact equality checks for all other fields. This is useful when dealing with dynamic content like timestamps, process IDs, or version numbers.
|
4
|
+
|
5
|
+
## Basic Usage
|
6
|
+
|
7
|
+
### Single Field Matcher
|
8
|
+
|
9
|
+
```ruby
|
10
|
+
# Record a command with a timestamp
|
11
|
+
Backspin.run("timestamp_test") do
|
12
|
+
Open3.capture3("date")
|
13
|
+
end
|
14
|
+
|
15
|
+
# Verify with a custom matcher for stdout
|
16
|
+
result = Backspin.run("timestamp_test",
|
17
|
+
match_on: [:stdout, ->(recorded, actual) {
|
18
|
+
# Both should contain a day of the week
|
19
|
+
recorded.match?(/Mon|Tue|Wed|Thu|Fri|Sat|Sun/) &&
|
20
|
+
actual.match?(/Mon|Tue|Wed|Thu|Fri|Sat|Sun/)
|
21
|
+
}]) do
|
22
|
+
Open3.capture3("date")
|
23
|
+
end
|
24
|
+
```
|
25
|
+
|
26
|
+
### Multiple Field Matchers
|
27
|
+
|
28
|
+
```ruby
|
29
|
+
# Match different fields with different rules
|
30
|
+
result = Backspin.run("multi_field_test",
|
31
|
+
match_on: [
|
32
|
+
[:stdout, ->(recorded, actual) {
|
33
|
+
# Match process ID format
|
34
|
+
recorded.match?(/PID: \d+/) && actual.match?(/PID: \d+/)
|
35
|
+
}],
|
36
|
+
[:stderr, ->(recorded, actual) {
|
37
|
+
# Match error type, ignore details
|
38
|
+
recorded.include?("Error:") && actual.include?("Error:")
|
39
|
+
}]
|
40
|
+
]) do
|
41
|
+
Open3.capture3("./my_script.sh")
|
42
|
+
end
|
43
|
+
```
|
44
|
+
|
45
|
+
## Matcher Format
|
46
|
+
|
47
|
+
The `match_on` option accepts two formats:
|
48
|
+
|
49
|
+
1. **Single field**: `[:field_name, matcher_proc]`
|
50
|
+
2. **Multiple fields**: `[[:field1, matcher1], [:field2, matcher2], ...]`
|
51
|
+
|
52
|
+
Valid field names are:
|
53
|
+
- `:stdout` - Standard output
|
54
|
+
- `:stderr` - Standard error
|
55
|
+
- `:status` - Exit status code
|
56
|
+
|
57
|
+
## Matcher Proc
|
58
|
+
|
59
|
+
The matcher proc receives two arguments:
|
60
|
+
- `recorded_value` - The value from the saved recording
|
61
|
+
- `actual_value` - The value from the current execution
|
62
|
+
|
63
|
+
It should return `true` if the values match according to your criteria, `false` otherwise.
|
64
|
+
|
65
|
+
## Examples
|
66
|
+
|
67
|
+
### Matching Version Numbers
|
68
|
+
|
69
|
+
```ruby
|
70
|
+
# Match major version only
|
71
|
+
match_on: [:stdout, ->(recorded, actual) {
|
72
|
+
recorded.match(/Version: (\d+)\./) &&
|
73
|
+
actual.match(/Version: (\d+)\./) &&
|
74
|
+
$1 == $1 # Major versions match
|
75
|
+
}]
|
76
|
+
```
|
77
|
+
|
78
|
+
### Ignoring Timestamps
|
79
|
+
|
80
|
+
```ruby
|
81
|
+
# Match log format but ignore timestamp
|
82
|
+
match_on: [:stdout, ->(recorded, actual) {
|
83
|
+
# Remove timestamps before comparing
|
84
|
+
recorded.gsub(/\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}/, '') ==
|
85
|
+
actual.gsub(/\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}/, '')
|
86
|
+
}]
|
87
|
+
```
|
88
|
+
|
89
|
+
### Handling Dynamic IDs
|
90
|
+
|
91
|
+
```ruby
|
92
|
+
# Match API response structure, ignore dynamic IDs
|
93
|
+
match_on: [:stdout, ->(recorded, actual) {
|
94
|
+
recorded_json = JSON.parse(recorded)
|
95
|
+
actual_json = JSON.parse(actual)
|
96
|
+
|
97
|
+
# Compare structure, not values
|
98
|
+
recorded_json.keys.sort == actual_json.keys.sort
|
99
|
+
}]
|
100
|
+
```
|
101
|
+
|
102
|
+
## Important Notes
|
103
|
+
|
104
|
+
1. **Other fields must match exactly**: When using `match_on`, all fields not specified in the matcher list must match exactly. If stdout has a custom matcher but stderr doesn't, stderr must be identical to pass verification.
|
105
|
+
|
106
|
+
2. **Precedence**: If both `matcher` and `match_on` options are provided, `matcher` takes precedence (for backward compatibility).
|
107
|
+
|
108
|
+
3. **Error messages**: When verification fails with `match_on`, the error will indicate which fields failed and whether they failed exact matching or custom matching.
|
109
|
+
|
110
|
+
4. **Works with run!**: The `match_on` option works with both `run` and `run!` methods.
|
data/Rakefile
CHANGED
@@ -1,7 +1,11 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "bundler/gem_tasks"
|
2
4
|
require "rspec/core/rake_task"
|
3
5
|
require "standard/rake"
|
4
6
|
|
5
7
|
RSpec::Core::RakeTask.new(:spec)
|
6
8
|
|
7
|
-
task default: [
|
9
|
+
task default: %i[spec standard]
|
10
|
+
|
11
|
+
load "release.rake" if File.exist?("release.rake")
|
data/backspin.gemspec
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require_relative "lib/backspin/version"
|
2
4
|
|
3
5
|
Gem::Specification.new do |spec|
|
@@ -16,14 +18,15 @@ Gem::Specification.new do |spec|
|
|
16
18
|
spec.metadata["source_code_uri"] = spec.homepage
|
17
19
|
spec.metadata["changelog_uri"] = "#{spec.homepage}/blob/main/CHANGELOG.md"
|
18
20
|
|
19
|
-
|
20
|
-
spec.files = Dir.chdir(File.expand_path("..", __FILE__)) do
|
21
|
+
spec.files = Dir.chdir(File.expand_path(__dir__)) do
|
21
22
|
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
22
23
|
end
|
23
24
|
spec.bindir = "exe"
|
24
25
|
spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
|
25
26
|
spec.require_paths = ["lib"]
|
26
27
|
|
27
|
-
spec.add_dependency "rspec-mocks", "~> 3.0"
|
28
28
|
spec.add_dependency "ostruct", "~> 0.5.0"
|
29
|
+
spec.add_dependency "rspec-mocks", "~> 3.0"
|
30
|
+
|
31
|
+
spec.add_development_dependency "gem-release", "~> 2.2"
|
29
32
|
end
|
@@ -0,0 +1,116 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require "bundler/inline"
|
5
|
+
require "open3"
|
6
|
+
|
7
|
+
gemfile do
|
8
|
+
source "https://rubygems.org"
|
9
|
+
gem "backspin", path: ".."
|
10
|
+
end
|
11
|
+
|
12
|
+
# Example 1: Single field matcher
|
13
|
+
puts "Example 1: Matching timestamps with custom matcher"
|
14
|
+
puts "-" * 50
|
15
|
+
|
16
|
+
# First run: Record the output
|
17
|
+
result = Backspin.run("timestamp_example") do
|
18
|
+
Open3.capture3("date '+%Y-%m-%d %H:%M:%S'")
|
19
|
+
end
|
20
|
+
puts "Recorded: #{result.stdout.chomp}"
|
21
|
+
|
22
|
+
# Sleep to ensure different timestamp
|
23
|
+
sleep 1
|
24
|
+
|
25
|
+
# Second run: Verify with custom matcher
|
26
|
+
result = Backspin.run("timestamp_example",
|
27
|
+
match_on: [:stdout, lambda { |recorded, actual|
|
28
|
+
# Both should have the same date format
|
29
|
+
recorded.match?(/\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}/) &&
|
30
|
+
actual.match?(/\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}/)
|
31
|
+
}]) do
|
32
|
+
Open3.capture3("date '+%Y-%m-%d %H:%M:%S'")
|
33
|
+
end
|
34
|
+
|
35
|
+
puts "Current: #{result.stdout.chomp}"
|
36
|
+
puts "Verified: #{result.verified?}"
|
37
|
+
puts
|
38
|
+
|
39
|
+
# Example 2: Multiple field matchers
|
40
|
+
puts "Example 2: Matching multiple fields with different patterns"
|
41
|
+
puts "-" * 50
|
42
|
+
|
43
|
+
# Record a command with dynamic content
|
44
|
+
Backspin.run("multi_field_example") do
|
45
|
+
script = <<~BASH
|
46
|
+
echo "PID: $$"
|
47
|
+
echo "Error: Timeout at $(date '+%H:%M:%S')" >&2
|
48
|
+
exit 1
|
49
|
+
BASH
|
50
|
+
Open3.capture3("bash", "-c", script)
|
51
|
+
end
|
52
|
+
|
53
|
+
# Verify with different PID and timestamp
|
54
|
+
result = Backspin.run("multi_field_example",
|
55
|
+
match_on: [
|
56
|
+
[:stdout, lambda { |recorded, actual|
|
57
|
+
# Both should have PID format
|
58
|
+
recorded.match?(/PID: \d+/) && actual.match?(/PID: \d+/)
|
59
|
+
}],
|
60
|
+
[:stderr, lambda { |recorded, actual|
|
61
|
+
# Both should have timeout error, ignore timestamp
|
62
|
+
recorded.match?(/Error: Timeout at/) && actual.match?(/Error: Timeout at/)
|
63
|
+
}]
|
64
|
+
]) do
|
65
|
+
script = <<~BASH
|
66
|
+
echo "PID: $$"
|
67
|
+
echo "Error: Timeout at $(date '+%H:%M:%S')" >&2
|
68
|
+
exit 1
|
69
|
+
BASH
|
70
|
+
Open3.capture3("bash", "-c", script)
|
71
|
+
end
|
72
|
+
|
73
|
+
puts "Stdout: #{result.stdout.chomp}"
|
74
|
+
puts "Stderr: #{result.stderr.chomp}"
|
75
|
+
puts "Status: #{result.status}"
|
76
|
+
puts "Verified: #{result.verified?}"
|
77
|
+
puts
|
78
|
+
|
79
|
+
# Example 3: Mixed matching - some fields exact, some custom
|
80
|
+
puts "Example 3: Mixed field matching"
|
81
|
+
puts "-" * 50
|
82
|
+
|
83
|
+
# Record with specific values
|
84
|
+
Backspin.run("mixed_matching") do
|
85
|
+
script = <<~BASH
|
86
|
+
echo "Version: 1.2.3"
|
87
|
+
echo "Build: $(date +%s)"
|
88
|
+
echo "Status: OK"
|
89
|
+
BASH
|
90
|
+
Open3.capture3("bash", "-c", script)
|
91
|
+
end
|
92
|
+
|
93
|
+
# Verify - stdout uses custom matcher, stderr must match exactly
|
94
|
+
result = Backspin.run("mixed_matching",
|
95
|
+
match_on: [:stdout, lambda { |recorded, actual|
|
96
|
+
# Version and Status must match, Build can differ
|
97
|
+
recorded_lines = recorded.lines
|
98
|
+
actual_lines = actual.lines
|
99
|
+
|
100
|
+
recorded_lines[0] == actual_lines[0] && # Version line must match
|
101
|
+
recorded_lines[1].start_with?("Build:") && actual_lines[1].start_with?("Build:") && # Build line format
|
102
|
+
recorded_lines[2] == actual_lines[2] # Status line must match
|
103
|
+
}]) do
|
104
|
+
script = <<~BASH
|
105
|
+
echo "Version: 1.2.3"
|
106
|
+
echo "Build: $(date +%s)"
|
107
|
+
echo "Status: OK"
|
108
|
+
BASH
|
109
|
+
Open3.capture3("bash", "-c", script)
|
110
|
+
end
|
111
|
+
|
112
|
+
puts "Output:\n#{result.stdout}"
|
113
|
+
puts "Verified: #{result.verified?}"
|
114
|
+
|
115
|
+
# Cleanup
|
116
|
+
FileUtils.rm_rf("fixtures/backspin")
|
@@ -0,0 +1,15 @@
|
|
1
|
+
---
|
2
|
+
first_recorded_at: '2025-06-10T11:27:40-05:00'
|
3
|
+
format_version: '2.0'
|
4
|
+
commands:
|
5
|
+
- command_type: Open3::Capture3
|
6
|
+
args:
|
7
|
+
- sh
|
8
|
+
- "-c"
|
9
|
+
- echo 'valid'; exit 0
|
10
|
+
stdout: 'valid
|
11
|
+
|
12
|
+
'
|
13
|
+
stderr: ''
|
14
|
+
status: 0
|
15
|
+
recorded_at: '2025-06-10T11:27:40-05:00'
|
@@ -0,0 +1,14 @@
|
|
1
|
+
---
|
2
|
+
first_recorded_at: '2025-06-10T11:02:03-05:00'
|
3
|
+
format_version: '2.0'
|
4
|
+
commands:
|
5
|
+
- command_type: Open3::Capture3
|
6
|
+
args:
|
7
|
+
- echo
|
8
|
+
- first output
|
9
|
+
stdout: 'first output
|
10
|
+
|
11
|
+
'
|
12
|
+
stderr: ''
|
13
|
+
status: 0
|
14
|
+
recorded_at: '2025-06-10T11:02:03-05:00'
|
@@ -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
|
+
- sh
|
8
|
+
- "-c"
|
9
|
+
- echo 'original'; echo 'original error' >&2
|
10
|
+
stdout: 'original
|
11
|
+
|
12
|
+
'
|
13
|
+
stderr: 'original error
|
14
|
+
|
15
|
+
'
|
16
|
+
status: 0
|
17
|
+
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
|
+
- sh
|
8
|
+
- "-c"
|
9
|
+
- 'echo ''PASS: test 1''; echo ''WARNING: minor issue'' >&2'
|
10
|
+
stdout: 'PASS: test 1
|
11
|
+
|
12
|
+
'
|
13
|
+
stderr: 'WARNING: minor issue
|
14
|
+
|
15
|
+
'
|
16
|
+
status: 0
|
17
|
+
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
|
+
- sh
|
8
|
+
- "-c"
|
9
|
+
- echo 'original'; echo 'original error' >&2
|
10
|
+
stdout: 'original
|
11
|
+
|
12
|
+
'
|
13
|
+
stderr: 'original error
|
14
|
+
|
15
|
+
'
|
16
|
+
status: 0
|
17
|
+
recorded_at: '2025-05-01T12:00:00Z'
|
@@ -0,0 +1,17 @@
|
|
1
|
+
---
|
2
|
+
first_recorded_at: '2025-06-10T11:27:40-05:00'
|
3
|
+
format_version: '2.0'
|
4
|
+
commands:
|
5
|
+
- command_type: Open3::Capture3
|
6
|
+
args:
|
7
|
+
- sh
|
8
|
+
- "-c"
|
9
|
+
- echo 'output1'; echo 'error1' >&2
|
10
|
+
stdout: 'output1
|
11
|
+
|
12
|
+
'
|
13
|
+
stderr: 'error1
|
14
|
+
|
15
|
+
'
|
16
|
+
status: 0
|
17
|
+
recorded_at: '2025-06-10T11:27:40-05:00'
|
@@ -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
|
+
- sh
|
8
|
+
- "-c"
|
9
|
+
- echo 'output'; echo 'error' >&2
|
10
|
+
stdout: 'output
|
11
|
+
|
12
|
+
'
|
13
|
+
stderr: 'error
|
14
|
+
|
15
|
+
'
|
16
|
+
status: 0
|
17
|
+
recorded_at: '2025-05-01T12:00:00Z'
|
@@ -0,0 +1,17 @@
|
|
1
|
+
---
|
2
|
+
first_recorded_at: '2025-06-10T11:02:02-05:00'
|
3
|
+
format_version: '2.0'
|
4
|
+
commands:
|
5
|
+
- command_type: Open3::Capture3
|
6
|
+
args:
|
7
|
+
- sh
|
8
|
+
- "-c"
|
9
|
+
- echo 'output'; echo 'error' >&2; exit 42
|
10
|
+
stdout: 'output
|
11
|
+
|
12
|
+
'
|
13
|
+
stderr: 'error
|
14
|
+
|
15
|
+
'
|
16
|
+
status: 42
|
17
|
+
recorded_at: '2025-06-10T11:02:02-05:00'
|