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.
Files changed (51) hide show
  1. checksums.yaml +4 -4
  2. data/.gem_release.yml +13 -0
  3. data/CHANGELOG.md +5 -7
  4. data/CLAUDE.md +5 -1
  5. data/Gemfile +3 -1
  6. data/Gemfile.lock +3 -1
  7. data/MATCH_ON_USAGE.md +110 -0
  8. data/Rakefile +5 -1
  9. data/backspin.gemspec +6 -3
  10. data/examples/match_on_example.rb +116 -0
  11. data/fixtures/backspin/all_and_fields.yml +15 -0
  12. data/fixtures/backspin/all_bypass_equality.yml +14 -0
  13. data/fixtures/backspin/all_checks_equality.yml +17 -0
  14. data/fixtures/backspin/all_for_logging.yml +13 -0
  15. data/fixtures/backspin/all_matcher_basic.yml +14 -0
  16. data/fixtures/backspin/all_matcher_custom.yml +17 -0
  17. data/fixtures/backspin/all_matcher_demo.yml +14 -0
  18. data/fixtures/backspin/all_matcher_test.yml +14 -0
  19. data/fixtures/backspin/all_no_short_circuit.yml +14 -0
  20. data/fixtures/backspin/all_pass_field_fail.yml +14 -0
  21. data/fixtures/backspin/all_short_circuit.yml +14 -0
  22. data/fixtures/backspin/all_skips_equality.yml +17 -0
  23. data/fixtures/backspin/all_with_equality.yml +17 -0
  24. data/fixtures/backspin/all_with_fields.yml +17 -0
  25. data/fixtures/backspin/combined_fail_demo.yml +14 -0
  26. data/fixtures/backspin/combined_matcher_demo.yml +14 -0
  27. data/fixtures/backspin/field_matcher_demo.yml +17 -0
  28. data/fixtures/backspin/field_matcher_values.yml +14 -0
  29. data/fixtures/backspin/key_confusion_test.yml +14 -0
  30. data/fixtures/backspin/match_on_any_fail.yml +21 -0
  31. data/fixtures/backspin/match_on_bad_format.yml +14 -0
  32. data/fixtures/backspin/match_on_fail.yml +15 -0
  33. data/fixtures/backspin/match_on_invalid.yml +14 -0
  34. data/fixtures/backspin/match_on_multiple.yml +28 -0
  35. data/fixtures/backspin/match_on_nil.yml +14 -0
  36. data/fixtures/backspin/match_on_other_fields.yml +23 -0
  37. data/fixtures/backspin/match_on_run_bang.yml +16 -0
  38. data/fixtures/backspin/match_on_run_bang_fail.yml +15 -0
  39. data/fixtures/backspin/match_on_single.yml +17 -0
  40. data/fixtures/backspin/string_symbol_test.yml +14 -0
  41. data/lib/backspin/command.rb +1 -5
  42. data/lib/backspin/command_diff.rb +98 -16
  43. data/lib/backspin/command_result.rb +2 -4
  44. data/lib/backspin/record.rb +31 -10
  45. data/lib/backspin/record_result.rb +20 -14
  46. data/lib/backspin/recorder.rb +100 -55
  47. data/lib/backspin/version.rb +3 -1
  48. data/lib/backspin.rb +34 -173
  49. data/release.rake +97 -0
  50. data/script/lint +6 -0
  51. metadata +54 -5
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f44a53c1983fd41c2660bc9652c158b2193e880e0e1339fa49c882d26fdd0852
4
- data.tar.gz: 3b53d9ba92db35ad66c128bc049762e06c307472827fe2d4b795427c7e668bdf
3
+ metadata.gz: 055d320685da2ca9e280c3aa8bcb15edb101d788c4d8c4df8ff203d4c2c34dac
4
+ data.tar.gz: cf21c90a588ff5590844ae2a9c50a78707a5c71d44b43ad0d3a571fed0bbe4b5
5
5
  SHA512:
6
- metadata.gz: 28909c63f9befbe8a0ae208328b9c527b3f1ca28417a66e96afad6ee9be41c2fa157ede63e4c5073f049ac59ab9c336a5fde7b97e109b7efc61480942ddc1a58
7
- data.tar.gz: e63c8c4fff6ac690575ffadfe48efd6b4d0bc2267680e1c99637a888edcf3034bb315d96efedc400bfabdf5f8a9aa7912dfef03771b86a6a69769efe1bdcaac6
6
+ metadata.gz: 7c3a0941042e885d5370c4287fdd88323bc1b95d15a7c795afde0d08aa5efe050f7e54838a5774de967d4d633b9e30df82b5700d17c431fa8ea1cce79777bee9
7
+ data.tar.gz: 86584a95060fda843934065c2d9a3ca59acd12a1e21f70dcf3d9bd648f4cd1cec97ff21a57f98f8aa7a133865ccbb38438bdb05402f19e8292bed02c56d51bfe
data/.gem_release.yml ADDED
@@ -0,0 +1,13 @@
1
+ # Configuration for gem-release
2
+ bump:
3
+ commit: true
4
+ message: "Bump version to %{version}"
5
+ skip_ci: false
6
+ push: true
7
+
8
+ tag:
9
+ tag: v%{version}
10
+ sign: false
11
+
12
+ release:
13
+ host: https://rubygems.org
data/CHANGELOG.md CHANGED
@@ -1,21 +1,19 @@
1
1
  # Changelog
2
2
 
3
- ## [0.4.0] - 2025-06-06
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
- ## [0.3.0] - 2025-06-05
7
+ ## 0.3.0 - 2025-06-05
8
8
  - Scrub credentials from command arguments
9
9
 
10
- ## [0.2.0] - 2025-06-05
10
+ ## 0.2.0 - 2025-06-05
11
11
  - First public release of Backspin, extracteed from `name-TBD` CLI tool
12
12
 
13
- ## [0.2.1] - 2025-06-04
13
+ ## 0.2.1 - 2025-06-04
14
14
  - major refactoring, add support for `system` calls
15
15
 
16
- ## [0.1.0] - 2025-06-02
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
- bin/rake standard # Run Standard Ruby linter
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.1)
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: [:spec, :standard]
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
- # Specify which files should be added to the gem when it is released.
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,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
+ - date
8
+ stdout: 'Tue Jun 10 22:50:14 CDT 2025
9
+
10
+ '
11
+ stderr: ''
12
+ status: 0
13
+ recorded_at: '2025-05-01T12:00:00Z'
@@ -0,0 +1,14 @@
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
+ - hello world
9
+ stdout: 'hello world
10
+
11
+ '
12
+ stderr: ''
13
+ status: 0
14
+ 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,14 @@
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
+ - echo
8
+ - test
9
+ stdout: 'test
10
+
11
+ '
12
+ stderr: ''
13
+ status: 0
14
+ recorded_at: '2025-06-10T11:02:02-05:00'
@@ -0,0 +1,14 @@
1
+ ---
2
+ first_recorded_at: '2025-06-10T11:00:57-05:00'
3
+ format_version: '2.0'
4
+ commands:
5
+ - command_type: Open3::Capture3
6
+ args:
7
+ - echo
8
+ - test
9
+ stdout: 'test
10
+
11
+ '
12
+ stderr: ''
13
+ status: 0
14
+ recorded_at: '2025-06-10T11:00:57-05:00'
@@ -0,0 +1,14 @@
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
+ - echo
8
+ - test
9
+ stdout: 'test
10
+
11
+ '
12
+ stderr: ''
13
+ status: 0
14
+ recorded_at: '2025-06-10T11:27:40-05:00'
@@ -0,0 +1,14 @@
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
+ - hello
9
+ stdout: 'hello
10
+
11
+ '
12
+ stderr: ''
13
+ status: 0
14
+ recorded_at: '2025-05-01T12:00:00Z'
@@ -0,0 +1,14 @@
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
+ - test
9
+ stdout: 'test
10
+
11
+ '
12
+ stderr: ''
13
+ status: 0
14
+ 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,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
+ - test
9
+ stdout: 'test
10
+
11
+ '
12
+ stderr: ''
13
+ status: 0
14
+ recorded_at: '2025-06-10T11:02:03-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
+ - test
9
+ stdout: 'test
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-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'
@@ -0,0 +1,14 @@
1
+ ---
2
+ first_recorded_at: '2025-06-10T11:00:57-05:00'
3
+ format_version: '2.0'
4
+ commands:
5
+ - command_type: Open3::Capture3
6
+ args:
7
+ - echo
8
+ - hello
9
+ stdout: 'hello
10
+
11
+ '
12
+ stderr: ''
13
+ status: 0
14
+ recorded_at: '2025-06-10T11:00:57-05:00'