backspin 0.11.0 → 0.12.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/.circleci/config.yml +3 -0
- data/CHANGELOG.md +6 -4
- data/Gemfile.lock +3 -1
- data/README.md +60 -0
- data/Rakefile +27 -0
- data/backspin.gemspec +2 -0
- data/fixtures/projects/dummy_cli_gem/.rspec +3 -0
- data/fixtures/projects/dummy_cli_gem/Gemfile +12 -0
- data/fixtures/projects/dummy_cli_gem/Gemfile.lock +55 -0
- data/fixtures/projects/dummy_cli_gem/LICENSE.txt +1 -0
- data/fixtures/projects/dummy_cli_gem/README.md +7 -0
- data/fixtures/projects/dummy_cli_gem/Rakefile +8 -0
- data/fixtures/projects/dummy_cli_gem/dummy_cli_gem.gemspec +22 -0
- data/fixtures/projects/dummy_cli_gem/exe/dummy_cli_gem +8 -0
- data/fixtures/projects/dummy_cli_gem/fixtures/backspin/dummy_echo.yml +18 -0
- data/fixtures/projects/dummy_cli_gem/fixtures/backspin/dummy_ls.yml +18 -0
- data/fixtures/projects/dummy_cli_gem/lib/dummy_cli_gem/cli.rb +35 -0
- data/fixtures/projects/dummy_cli_gem/lib/dummy_cli_gem/version.rb +5 -0
- data/fixtures/projects/dummy_cli_gem/lib/dummy_cli_gem.rb +7 -0
- data/fixtures/projects/dummy_cli_gem/mise.toml +2 -0
- data/fixtures/projects/dummy_cli_gem/spec/dummy_cli_gem_backspin_spec.rb +46 -0
- data/fixtures/projects/dummy_cli_gem/spec/fixtures/backspin/dummy_echo.yml +18 -0
- data/fixtures/projects/dummy_cli_gem/spec/fixtures/backspin/dummy_ls.yml +18 -0
- data/fixtures/projects/dummy_cli_gem/spec/fixtures/listing_target/alpha.txt +1 -0
- data/fixtures/projects/dummy_cli_gem/spec/spec_helper.rb +22 -0
- data/lib/backspin/configuration.rb +13 -0
- data/lib/backspin/version.rb +1 -1
- data/lib/backspin.rb +22 -2
- data/mise.toml +2 -0
- metadata +36 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 6373427307003e8469435ce1c461e6f9bf6ff307c952bce87f07c393470f5fdc
|
|
4
|
+
data.tar.gz: 3e8487ba8345a4fef0b8419487de0e84b756c302ada8b313e2bf0e5cd6c1ec1a
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: d7f1915e4632d8fb4b08ae6a8ff0e6e9846ed3f1cd783c7dcc283ca2d3816afb518173a50cd519b5859eb6d991be7636a81a48e34fb63f0176d14c9a2bdd500a
|
|
7
|
+
data.tar.gz: 7307a43c18730ec430f39dbadecb301eaad177ecc3795906f9682ec3e4781e9d5d9ec2b8c913220f8c5985393ae90e73974e5f2855a40ea17d33f87914b5a527
|
data/.circleci/config.yml
CHANGED
data/CHANGELOG.md
CHANGED
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.12.0
|
|
4
|
+
* Added `BACKSPIN_MODE` environment variable to globally override recording mode (`auto`, `record`, `verify`).
|
|
5
|
+
* Explicit `mode:` kwarg still takes highest precedence, followed by the env var, then auto-detection.
|
|
6
|
+
* Added configurable logger to `Backspin::Configuration` (defaults to WARN level, logfmt-lite format, and can be disabled with `config.logger = nil`).
|
|
7
|
+
|
|
3
8
|
## 0.11.0 - 2026-02-11
|
|
4
9
|
* Added immutable top-level `first_recorded_at` metadata for record files.
|
|
5
10
|
* Added mutable top-level `recorded_at` metadata that updates on each successful re-record.
|
|
6
11
|
* Added top-level `record_count`, incremented on each successful record write.
|
|
7
|
-
*
|
|
8
|
-
* Added acceptance coverage for v4.1 schema and 4.0-to-4.1 upgrade behavior.
|
|
9
|
-
* Removed legacy committed `.yml` record fixtures from old schema versions.
|
|
12
|
+
* Bumped record format to 4.1; loading remains backward-compatible with 4.0 record files.
|
|
10
13
|
|
|
11
14
|
## 0.10.0 - 2026-02-11
|
|
12
15
|
* Added `filter_on` to `Backspin.run` and `Backspin.capture` (`:both` default, `:record` opt-out).
|
|
@@ -19,7 +22,6 @@
|
|
|
19
22
|
* Breaking: result convenience accessors (`result.stdout`, `result.stderr`, `result.status`) were removed in favor of snapshot access.
|
|
20
23
|
* Breaking: record format bumped to 4.0 and now persists a single `snapshot` object (v3 records are rejected).
|
|
21
24
|
* Simplification: removed legacy `Command`, `CommandResult`, and `RecordResult` layers; matcher/diff now operate directly on snapshots.
|
|
22
|
-
* Added focused coverage for the new result contract and capture stream restoration behavior.
|
|
23
25
|
* Updated project docs to reflect the BackspinResult + Snapshot API surface.
|
|
24
26
|
|
|
25
27
|
## 0.8.0 - 2026-02-05
|
data/Gemfile.lock
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: .
|
|
3
3
|
specs:
|
|
4
|
-
backspin (0.
|
|
4
|
+
backspin (0.12.0)
|
|
5
|
+
logger
|
|
5
6
|
|
|
6
7
|
GEM
|
|
7
8
|
remote: https://rubygems.org/
|
|
@@ -11,6 +12,7 @@ GEM
|
|
|
11
12
|
json (2.16.0)
|
|
12
13
|
language_server-protocol (3.17.0.5)
|
|
13
14
|
lint_roller (1.1.0)
|
|
15
|
+
logger (1.7.0)
|
|
14
16
|
parallel (1.27.0)
|
|
15
17
|
parser (3.3.10.0)
|
|
16
18
|
ast (~> 2.4.1)
|
data/README.md
CHANGED
|
@@ -91,6 +91,26 @@ result = Backspin.run(["echo", "hello"], name: "echo_test", mode: :verify)
|
|
|
91
91
|
expect(result.verified?).to be true
|
|
92
92
|
```
|
|
93
93
|
|
|
94
|
+
### Environment Variable Mode Override
|
|
95
|
+
|
|
96
|
+
Set `BACKSPIN_MODE` to globally force a recording mode without changing any test code:
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
# Re-record all fixtures
|
|
100
|
+
BACKSPIN_MODE=record bundle exec rspec
|
|
101
|
+
|
|
102
|
+
# Verify-only (CI, no accidental re-records)
|
|
103
|
+
BACKSPIN_MODE=verify bundle exec rspec
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
Precedence (highest to lowest):
|
|
107
|
+
|
|
108
|
+
1. Explicit `mode:` kwarg (`:record` or `:verify`)
|
|
109
|
+
2. `BACKSPIN_MODE` environment variable
|
|
110
|
+
3. Auto-detection (record if no file exists, verify if it does)
|
|
111
|
+
|
|
112
|
+
Allowed values: `auto`, `record`, `verify` (case-insensitive). Invalid values raise `ArgumentError`.
|
|
113
|
+
|
|
94
114
|
### Record Metadata
|
|
95
115
|
|
|
96
116
|
Backspin writes records using `format_version: "4.1"` with top-level metadata:
|
|
@@ -243,6 +263,34 @@ result = Backspin.run(["echo", "different"], name: "my_test")
|
|
|
243
263
|
Backspin.reset_configuration!
|
|
244
264
|
```
|
|
245
265
|
|
|
266
|
+
### Logging
|
|
267
|
+
|
|
268
|
+
Backspin includes a configurable logger for diagnostics. By default it is set to WARN level; but most messages are logged at DEBUG level.
|
|
269
|
+
So if you are looking for more detailed logs, you can set the logger to DEBUG level:
|
|
270
|
+
|
|
271
|
+
```ruby
|
|
272
|
+
Backspin.configure do |config|
|
|
273
|
+
config.logger = Logger.new($stdout)
|
|
274
|
+
config.logger.level = Logger::DEBUG
|
|
275
|
+
end
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
To replace the logger entirely:
|
|
279
|
+
|
|
280
|
+
```ruby
|
|
281
|
+
Backspin.configure do |config|
|
|
282
|
+
config.logger = Logger.new("log/backspin.log")
|
|
283
|
+
end
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
To disable Backspin logging entirely (for example in tests):
|
|
287
|
+
|
|
288
|
+
```ruby
|
|
289
|
+
Backspin.configure do |config|
|
|
290
|
+
config.logger = nil
|
|
291
|
+
end
|
|
292
|
+
```
|
|
293
|
+
|
|
246
294
|
### Credential Scrubbing
|
|
247
295
|
|
|
248
296
|
If the CLI interaction you are recording contains sensitive data in stdout/stderr, you should be careful to make sure it is not recorded to YAML.
|
|
@@ -274,6 +322,18 @@ Automatic scrubbing includes:
|
|
|
274
322
|
|
|
275
323
|
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests.
|
|
276
324
|
|
|
325
|
+
This repo also includes a decoupled full-stack fixture gem at `fixtures/projects/dummy_cli_gem` that uses Backspin the way downstream projects do. Run it with:
|
|
326
|
+
|
|
327
|
+
```bash
|
|
328
|
+
bundle exec rake full_stack:dummy_app
|
|
329
|
+
```
|
|
330
|
+
|
|
331
|
+
To re-record that fixture's committed YAML snapshots:
|
|
332
|
+
|
|
333
|
+
```bash
|
|
334
|
+
bundle exec rake full_stack:record_dummy_app
|
|
335
|
+
```
|
|
336
|
+
|
|
277
337
|
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
|
278
338
|
|
|
279
339
|
## Contributing
|
data/Rakefile
CHANGED
|
@@ -6,6 +6,33 @@ require "standard/rake"
|
|
|
6
6
|
|
|
7
7
|
RSpec::Core::RakeTask.new(:spec)
|
|
8
8
|
|
|
9
|
+
def run_in_fake_gem(command)
|
|
10
|
+
dummy_app_dir = File.expand_path("fixtures/projects/dummy_cli_gem", __dir__)
|
|
11
|
+
|
|
12
|
+
Bundler.with_unbundled_env do
|
|
13
|
+
Dir.chdir(dummy_app_dir) do
|
|
14
|
+
sh "bundle check || bundle install"
|
|
15
|
+
sh command
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
namespace :spec do
|
|
21
|
+
desc "Run the dummy fixture gem specs with Backspin (decoupled from main suite)"
|
|
22
|
+
task :fake_gem do
|
|
23
|
+
run_in_fake_gem("bundle exec rspec")
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
desc "Re-record Backspin YAML fixtures for the dummy fixture gem"
|
|
27
|
+
task :fake_gem_record do
|
|
28
|
+
original_record_mode = ENV["RECORD_MODE"]
|
|
29
|
+
ENV["RECORD_MODE"] = "record"
|
|
30
|
+
run_in_fake_gem("bundle exec rspec")
|
|
31
|
+
ensure
|
|
32
|
+
ENV["RECORD_MODE"] = original_record_mode
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
9
36
|
task default: %i[spec standard]
|
|
10
37
|
|
|
11
38
|
load "release.rake" if File.exist?("release.rake")
|
data/backspin.gemspec
CHANGED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
PATH
|
|
2
|
+
remote: ../../..
|
|
3
|
+
specs:
|
|
4
|
+
backspin (0.11.0)
|
|
5
|
+
logger
|
|
6
|
+
|
|
7
|
+
PATH
|
|
8
|
+
remote: .
|
|
9
|
+
specs:
|
|
10
|
+
dummy_cli_gem (0.1.0)
|
|
11
|
+
|
|
12
|
+
GEM
|
|
13
|
+
remote: https://rubygems.org/
|
|
14
|
+
specs:
|
|
15
|
+
diff-lcs (1.6.2)
|
|
16
|
+
logger (1.7.0)
|
|
17
|
+
rake (13.3.1)
|
|
18
|
+
rspec (3.13.2)
|
|
19
|
+
rspec-core (~> 3.13.0)
|
|
20
|
+
rspec-expectations (~> 3.13.0)
|
|
21
|
+
rspec-mocks (~> 3.13.0)
|
|
22
|
+
rspec-core (3.13.6)
|
|
23
|
+
rspec-support (~> 3.13.0)
|
|
24
|
+
rspec-expectations (3.13.5)
|
|
25
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
|
26
|
+
rspec-support (~> 3.13.0)
|
|
27
|
+
rspec-mocks (3.13.7)
|
|
28
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
|
29
|
+
rspec-support (~> 3.13.0)
|
|
30
|
+
rspec-support (3.13.7)
|
|
31
|
+
|
|
32
|
+
PLATFORMS
|
|
33
|
+
aarch64-linux
|
|
34
|
+
ruby
|
|
35
|
+
|
|
36
|
+
DEPENDENCIES
|
|
37
|
+
backspin!
|
|
38
|
+
dummy_cli_gem!
|
|
39
|
+
rake (~> 13)
|
|
40
|
+
rspec (~> 3)
|
|
41
|
+
|
|
42
|
+
CHECKSUMS
|
|
43
|
+
backspin (0.11.0)
|
|
44
|
+
diff-lcs (1.6.2) sha256=9ae0d2cba7d4df3075fe8cd8602a8604993efc0dfa934cff568969efb1909962
|
|
45
|
+
dummy_cli_gem (0.1.0)
|
|
46
|
+
logger (1.7.0) sha256=196edec7cc44b66cfb40f9755ce11b392f21f7967696af15d274dde7edff0203
|
|
47
|
+
rake (13.3.1) sha256=8c9e89d09f66a26a01264e7e3480ec0607f0c497a861ef16063604b1b08eb19c
|
|
48
|
+
rspec (3.13.2) sha256=206284a08ad798e61f86d7ca3e376718d52c0bc944626b2349266f239f820587
|
|
49
|
+
rspec-core (3.13.6) sha256=a8823c6411667b60a8bca135364351dda34cd55e44ff94c4be4633b37d828b2d
|
|
50
|
+
rspec-expectations (3.13.5) sha256=33a4d3a1d95060aea4c94e9f237030a8f9eae5615e9bd85718fe3a09e4b58836
|
|
51
|
+
rspec-mocks (3.13.7) sha256=0979034e64b1d7a838aaaddf12bf065ea4dc40ef3d4c39f01f93ae2c66c62b1c
|
|
52
|
+
rspec-support (3.13.7) sha256=0640e5570872aafefd79867901deeeeb40b0c9875a36b983d85f54fb7381c47c
|
|
53
|
+
|
|
54
|
+
BUNDLED WITH
|
|
55
|
+
4.0.5
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
MIT License
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
# DummyCliGem Fixture
|
|
2
|
+
|
|
3
|
+
This is a minimal fixture gem used by Backspin's full-stack integration checks.
|
|
4
|
+
|
|
5
|
+
- It shells out to standard unix utilities (`echo`, `ls`).
|
|
6
|
+
- Its RSpec suite verifies command output through `Backspin.run`.
|
|
7
|
+
- Snapshot YAML records are stored in-repo under `spec/fixtures/backspin`.
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "lib/dummy_cli_gem/version"
|
|
4
|
+
|
|
5
|
+
Gem::Specification.new do |spec|
|
|
6
|
+
spec.name = "dummy_cli_gem"
|
|
7
|
+
spec.version = DummyCliGem::VERSION
|
|
8
|
+
spec.authors = ["Backspin"]
|
|
9
|
+
spec.email = ["noreply@example.com"]
|
|
10
|
+
spec.summary = "Dummy CLI gem fixture for Backspin full-stack verification"
|
|
11
|
+
spec.description = "Fixture gem that shells out to unix utilities and is tested via Backspin snapshots."
|
|
12
|
+
spec.homepage = "https://example.com/dummy_cli_gem"
|
|
13
|
+
spec.license = "MIT"
|
|
14
|
+
spec.required_ruby_version = Gem::Requirement.new(">= 3.1.0")
|
|
15
|
+
|
|
16
|
+
spec.files = Dir.chdir(__dir__) do
|
|
17
|
+
Dir["lib/**/*.rb", "exe/*", "spec/**/*", "script/**/*", "README.md", "LICENSE.txt"]
|
|
18
|
+
end
|
|
19
|
+
spec.bindir = "exe"
|
|
20
|
+
spec.executables = ["dummy_cli_gem"]
|
|
21
|
+
spec.require_paths = ["lib"]
|
|
22
|
+
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
---
|
|
2
|
+
format_version: '4.1'
|
|
3
|
+
first_recorded_at: '2026-02-11T01:57:42-06:00'
|
|
4
|
+
recorded_at: '2026-02-11T01:57:42-06:00'
|
|
5
|
+
record_count: 1
|
|
6
|
+
snapshot:
|
|
7
|
+
command_type: Open3::Capture3
|
|
8
|
+
args:
|
|
9
|
+
- ruby
|
|
10
|
+
- exe/dummy_cli_gem
|
|
11
|
+
- echo
|
|
12
|
+
- hello from dummy gem
|
|
13
|
+
stdout: 'hello from dummy gem
|
|
14
|
+
|
|
15
|
+
'
|
|
16
|
+
stderr: ''
|
|
17
|
+
status: 0
|
|
18
|
+
recorded_at: '2026-02-11T01:57:42-06:00'
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
---
|
|
2
|
+
format_version: '4.1'
|
|
3
|
+
first_recorded_at: '2026-02-11T01:57:42-06:00'
|
|
4
|
+
recorded_at: '2026-02-11T01:57:42-06:00'
|
|
5
|
+
record_count: 1
|
|
6
|
+
snapshot:
|
|
7
|
+
command_type: Open3::Capture3
|
|
8
|
+
args:
|
|
9
|
+
- ruby
|
|
10
|
+
- exe/dummy_cli_gem
|
|
11
|
+
- list
|
|
12
|
+
- spec/fixtures/listing_target
|
|
13
|
+
stdout: 'alpha.txt
|
|
14
|
+
|
|
15
|
+
'
|
|
16
|
+
stderr: ''
|
|
17
|
+
status: 0
|
|
18
|
+
recorded_at: '2026-02-11T01:57:42-06:00'
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "open3"
|
|
4
|
+
|
|
5
|
+
module DummyCliGem
|
|
6
|
+
module CLI
|
|
7
|
+
module_function
|
|
8
|
+
|
|
9
|
+
def run(argv, out: $stdout, err: $stderr)
|
|
10
|
+
command = argv.first
|
|
11
|
+
|
|
12
|
+
case command
|
|
13
|
+
when "echo"
|
|
14
|
+
text = argv[1]
|
|
15
|
+
return usage(err) if text.nil? || text.empty?
|
|
16
|
+
|
|
17
|
+
stdout, stderr, status = Open3.capture3("echo", text)
|
|
18
|
+
when "list"
|
|
19
|
+
target = argv[1] || "."
|
|
20
|
+
stdout, stderr, status = Open3.capture3("ls", "-1", target)
|
|
21
|
+
else
|
|
22
|
+
return usage(err)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
out.print(stdout)
|
|
26
|
+
err.print(stderr)
|
|
27
|
+
status.exitstatus
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def usage(err)
|
|
31
|
+
err.puts("usage: dummy_cli_gem echo <text> | dummy_cli_gem list <path>")
|
|
32
|
+
1
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "spec_helper"
|
|
4
|
+
|
|
5
|
+
RSpec.describe "DummyCliGem Backspin full-stack fixture" do
|
|
6
|
+
let(:project_root) { Pathname(__dir__).join("..").expand_path }
|
|
7
|
+
|
|
8
|
+
it "verifies echo command output from committed YAML" do
|
|
9
|
+
expect(BACKSPIN_DIR.join("dummy_echo.yml")).to exist
|
|
10
|
+
|
|
11
|
+
result = Backspin.run(
|
|
12
|
+
["ruby", "exe/dummy_cli_gem", "echo", "hello from dummy gem"],
|
|
13
|
+
name: "dummy_echo"
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
expect(result).to be_verified
|
|
17
|
+
expect(result.actual.stdout).to eq("hello from dummy gem\n")
|
|
18
|
+
expect(result.actual.stderr).to eq("")
|
|
19
|
+
expect(result.actual.status).to eq(0)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
it "verifies list command output from committed YAML" do
|
|
23
|
+
expect(BACKSPIN_DIR.join("dummy_ls.yml")).to exist
|
|
24
|
+
|
|
25
|
+
result = Backspin.run(
|
|
26
|
+
["ruby", "exe/dummy_cli_gem", "list", "spec/fixtures/listing_target"],
|
|
27
|
+
name: "dummy_ls"
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
expect(result).to be_verified
|
|
31
|
+
expect(result.actual.stdout).to eq("alpha.txt\n")
|
|
32
|
+
expect(result.actual.stderr).to eq("")
|
|
33
|
+
expect(result.actual.status).to eq(0)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
it "uses current Backspin record format for fixture YAML files" do
|
|
37
|
+
%w[dummy_echo dummy_ls].each do |record_name|
|
|
38
|
+
record_path = BACKSPIN_DIR.join("#{record_name}.yml")
|
|
39
|
+
expect(record_path).to exist
|
|
40
|
+
|
|
41
|
+
record_data = YAML.load_file(record_path)
|
|
42
|
+
expect(record_data["format_version"]).to eq("4.1")
|
|
43
|
+
expect(record_data["snapshot"]["command_type"]).to eq("Open3::Capture3")
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
---
|
|
2
|
+
format_version: '4.1'
|
|
3
|
+
first_recorded_at: '2026-02-11T07:43:21+00:00'
|
|
4
|
+
recorded_at: '2026-02-11T07:43:21+00:00'
|
|
5
|
+
record_count: 1
|
|
6
|
+
snapshot:
|
|
7
|
+
command_type: Open3::Capture3
|
|
8
|
+
args:
|
|
9
|
+
- ruby
|
|
10
|
+
- exe/dummy_cli_gem
|
|
11
|
+
- echo
|
|
12
|
+
- hello from dummy gem
|
|
13
|
+
stdout: 'hello from dummy gem
|
|
14
|
+
|
|
15
|
+
'
|
|
16
|
+
stderr: ''
|
|
17
|
+
status: 0
|
|
18
|
+
recorded_at: '2026-02-11T07:43:21+00:00'
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
---
|
|
2
|
+
format_version: '4.1'
|
|
3
|
+
first_recorded_at: '2026-02-11T07:43:21+00:00'
|
|
4
|
+
recorded_at: '2026-02-11T07:43:21+00:00'
|
|
5
|
+
record_count: 1
|
|
6
|
+
snapshot:
|
|
7
|
+
command_type: Open3::Capture3
|
|
8
|
+
args:
|
|
9
|
+
- ruby
|
|
10
|
+
- exe/dummy_cli_gem
|
|
11
|
+
- list
|
|
12
|
+
- spec/fixtures/listing_target
|
|
13
|
+
stdout: 'alpha.txt
|
|
14
|
+
|
|
15
|
+
'
|
|
16
|
+
stderr: ''
|
|
17
|
+
status: 0
|
|
18
|
+
recorded_at: '2026-02-11T07:43:21+00:00'
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
alpha fixture file
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "bundler/setup"
|
|
4
|
+
require "pathname"
|
|
5
|
+
require "yaml"
|
|
6
|
+
require "backspin"
|
|
7
|
+
require "dummy_cli_gem"
|
|
8
|
+
|
|
9
|
+
BACKSPIN_DIR = Pathname(__dir__).join("fixtures", "backspin")
|
|
10
|
+
|
|
11
|
+
Backspin.configure do |config|
|
|
12
|
+
config.backspin_dir = BACKSPIN_DIR
|
|
13
|
+
config.logger = nil
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
RSpec.configure do |config|
|
|
17
|
+
config.disable_monkey_patching!
|
|
18
|
+
|
|
19
|
+
config.expect_with :rspec do |expectations|
|
|
20
|
+
expectations.syntax = :expect
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require "logger"
|
|
3
4
|
require "pathname"
|
|
4
5
|
|
|
5
6
|
module Backspin
|
|
@@ -10,6 +11,8 @@ module Backspin
|
|
|
10
11
|
attr_accessor :backspin_dir
|
|
11
12
|
# Whether to raise an exception when verification fails in `run`/`capture` - defaults to true
|
|
12
13
|
attr_accessor :raise_on_verification_failure
|
|
14
|
+
# Logger for Backspin diagnostics - defaults to WARN level, logfmt-lite format
|
|
15
|
+
attr_accessor :logger
|
|
13
16
|
# Regex patterns to scrub from saved output
|
|
14
17
|
attr_reader :credential_patterns
|
|
15
18
|
|
|
@@ -18,6 +21,7 @@ module Backspin
|
|
|
18
21
|
@raise_on_verification_failure = true
|
|
19
22
|
@credential_patterns = default_credential_patterns
|
|
20
23
|
@backspin_dir = Pathname(Dir.pwd).join("fixtures", "backspin")
|
|
24
|
+
@logger = default_logger
|
|
21
25
|
end
|
|
22
26
|
|
|
23
27
|
def add_credential_pattern(pattern)
|
|
@@ -34,6 +38,15 @@ module Backspin
|
|
|
34
38
|
|
|
35
39
|
private
|
|
36
40
|
|
|
41
|
+
def default_logger
|
|
42
|
+
logger = Logger.new($stdout)
|
|
43
|
+
logger.level = Logger::WARN
|
|
44
|
+
logger.formatter = proc { |severity, _time, _progname, msg|
|
|
45
|
+
"level=#{severity.downcase} lib=backspin #{msg}\n"
|
|
46
|
+
}
|
|
47
|
+
logger
|
|
48
|
+
end
|
|
49
|
+
|
|
37
50
|
# Some default patterns for common credential types
|
|
38
51
|
def default_credential_patterns
|
|
39
52
|
[
|
data/lib/backspin/version.rb
CHANGED
data/lib/backspin.rb
CHANGED
|
@@ -14,6 +14,8 @@ require "backspin/backspin_result"
|
|
|
14
14
|
require "backspin/recorder"
|
|
15
15
|
|
|
16
16
|
module Backspin
|
|
17
|
+
VALID_MODES = %i[auto record verify].freeze
|
|
18
|
+
|
|
17
19
|
class RecordNotFoundError < StandardError; end
|
|
18
20
|
|
|
19
21
|
class VerificationError < StandardError
|
|
@@ -242,8 +244,26 @@ module Backspin
|
|
|
242
244
|
def determine_mode(mode_option, record_path)
|
|
243
245
|
return mode_option if mode_option && mode_option != :auto
|
|
244
246
|
|
|
245
|
-
|
|
246
|
-
|
|
247
|
+
env_mode = mode_from_env
|
|
248
|
+
if env_mode && env_mode != :auto
|
|
249
|
+
configuration.logger&.debug { "event=mode_resolved mode=#{env_mode} source=env record=#{record_path}" }
|
|
250
|
+
return env_mode
|
|
251
|
+
end
|
|
252
|
+
|
|
253
|
+
resolved = File.exist?(record_path) ? :verify : :record
|
|
254
|
+
configuration.logger&.debug { "event=mode_resolved mode=#{resolved} source=auto record=#{record_path}" }
|
|
255
|
+
resolved
|
|
256
|
+
end
|
|
257
|
+
|
|
258
|
+
def mode_from_env
|
|
259
|
+
raw = ENV["BACKSPIN_MODE"]
|
|
260
|
+
return if raw.nil? || raw.strip.empty?
|
|
261
|
+
|
|
262
|
+
mode = raw.strip.downcase.to_sym
|
|
263
|
+
return mode if VALID_MODES.include?(mode)
|
|
264
|
+
|
|
265
|
+
raise ArgumentError,
|
|
266
|
+
"Invalid BACKSPIN_MODE value: #{raw.inspect}. Allowed values: auto, record, verify"
|
|
247
267
|
end
|
|
248
268
|
|
|
249
269
|
def validate_mode!(mode)
|
data/mise.toml
ADDED
metadata
CHANGED
|
@@ -1,14 +1,28 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: backspin
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.12.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Rob Sanheim
|
|
8
8
|
bindir: exe
|
|
9
9
|
cert_chain: []
|
|
10
10
|
date: 1980-01-02 00:00:00.000000000 Z
|
|
11
|
-
dependencies:
|
|
11
|
+
dependencies:
|
|
12
|
+
- !ruby/object:Gem::Dependency
|
|
13
|
+
name: logger
|
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
|
15
|
+
requirements:
|
|
16
|
+
- - ">="
|
|
17
|
+
- !ruby/object:Gem::Version
|
|
18
|
+
version: '0'
|
|
19
|
+
type: :runtime
|
|
20
|
+
prerelease: false
|
|
21
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
22
|
+
requirements:
|
|
23
|
+
- - ">="
|
|
24
|
+
- !ruby/object:Gem::Version
|
|
25
|
+
version: '0'
|
|
12
26
|
description: Backspin is a Ruby library for characterization testing of command-line
|
|
13
27
|
interfaces. Inspired by VCR's cassette-based approach, it records and replays CLI
|
|
14
28
|
interactions to make testing faster and more deterministic.
|
|
@@ -40,6 +54,25 @@ files:
|
|
|
40
54
|
- docs/backspin-result-api-sketch.md
|
|
41
55
|
- examples/match_on_example.rb
|
|
42
56
|
- fixtures/backspin/.gitkeep
|
|
57
|
+
- fixtures/projects/dummy_cli_gem/.rspec
|
|
58
|
+
- fixtures/projects/dummy_cli_gem/Gemfile
|
|
59
|
+
- fixtures/projects/dummy_cli_gem/Gemfile.lock
|
|
60
|
+
- fixtures/projects/dummy_cli_gem/LICENSE.txt
|
|
61
|
+
- fixtures/projects/dummy_cli_gem/README.md
|
|
62
|
+
- fixtures/projects/dummy_cli_gem/Rakefile
|
|
63
|
+
- fixtures/projects/dummy_cli_gem/dummy_cli_gem.gemspec
|
|
64
|
+
- fixtures/projects/dummy_cli_gem/exe/dummy_cli_gem
|
|
65
|
+
- fixtures/projects/dummy_cli_gem/fixtures/backspin/dummy_echo.yml
|
|
66
|
+
- fixtures/projects/dummy_cli_gem/fixtures/backspin/dummy_ls.yml
|
|
67
|
+
- fixtures/projects/dummy_cli_gem/lib/dummy_cli_gem.rb
|
|
68
|
+
- fixtures/projects/dummy_cli_gem/lib/dummy_cli_gem/cli.rb
|
|
69
|
+
- fixtures/projects/dummy_cli_gem/lib/dummy_cli_gem/version.rb
|
|
70
|
+
- fixtures/projects/dummy_cli_gem/mise.toml
|
|
71
|
+
- fixtures/projects/dummy_cli_gem/spec/dummy_cli_gem_backspin_spec.rb
|
|
72
|
+
- fixtures/projects/dummy_cli_gem/spec/fixtures/backspin/dummy_echo.yml
|
|
73
|
+
- fixtures/projects/dummy_cli_gem/spec/fixtures/backspin/dummy_ls.yml
|
|
74
|
+
- fixtures/projects/dummy_cli_gem/spec/fixtures/listing_target/alpha.txt
|
|
75
|
+
- fixtures/projects/dummy_cli_gem/spec/spec_helper.rb
|
|
43
76
|
- lib/backspin.rb
|
|
44
77
|
- lib/backspin/backspin_result.rb
|
|
45
78
|
- lib/backspin/command_diff.rb
|
|
@@ -49,6 +82,7 @@ files:
|
|
|
49
82
|
- lib/backspin/recorder.rb
|
|
50
83
|
- lib/backspin/snapshot.rb
|
|
51
84
|
- lib/backspin/version.rb
|
|
85
|
+
- mise.toml
|
|
52
86
|
- release.rake
|
|
53
87
|
- script/lint
|
|
54
88
|
- script/run_affected_tests
|