bard 1.6.0 → 1.7.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 21d6d4352d9957502860997ea4c05c9df90cffd4eab76391041c913483892c7f
4
- data.tar.gz: ad893862a2a2a3968f12c8c034a08c8c92d3f07aade157ba60ab676e39f10ae0
3
+ metadata.gz: a11cf0d4ee1ff435809dbe0e48beb1dcff72f2a4191fa39c40ef8932bbf64915
4
+ data.tar.gz: 4861d2109f0cb0d438dd281425865ac8c0496019c8529560464fab55c05b5da7
5
5
  SHA512:
6
- metadata.gz: 7036c5b3d97b827c62905238d4cf66c53e56aeac82f847c29877ae7482dabeece807f6ffec6cf9bfbf9b2c4796ae33e40d2713509b906ee8754aa2f4cc1521be
7
- data.tar.gz: 895b98dc68a3144eee0d4ad72a4a47d38bfffdbdf520d5f029a8484a356f57d80b447e7d335d2f67e49cae2e566e7e7601c4109fc2b6664be0078040b6224d35
6
+ metadata.gz: 53d527f268f68f7b5a61cae324e583f83c26246bd69f4717a37e10c2e1ae44ca53d7d3b194a60454a82c1471ba8588f1182177dd7994b41c193739889a0d5a36
7
+ data.tar.gz: 669b2ae00f5c9983fed2747e1426f48710c5da142b3d43cda7bb0c7c3c160dc9ee52385f606ea65dbf087803733461bf4ce71d15b3bb8ed5373737555dd441a8
data/Gemfile CHANGED
@@ -6,4 +6,4 @@ gemspec
6
6
  group :test do
7
7
  gem "simplecov", require: false
8
8
  gem "webmock", require: false
9
- end
9
+ end
data/bard.gemspec CHANGED
@@ -26,5 +26,6 @@ Gem::Specification.new do |spec|
26
26
  spec.add_development_dependency "rake"
27
27
  spec.add_development_dependency "rspec"
28
28
  spec.add_development_dependency "debug"
29
+ spec.add_development_dependency "cucumber"
29
30
  spec.add_development_dependency "testcontainers"
30
31
  end
@@ -0,0 +1,16 @@
1
+ @podman
2
+ Feature: bard run against a podman TestContainers host
3
+ Background:
4
+ Given a podman testcontainer is ready for bard
5
+
6
+ Scenario: Running ls via bard run
7
+ Given a remote file "test-file.txt" exists in the test container
8
+ When I run bard "ls" against the test container
9
+ Then the bard command should succeed
10
+ And the bard output should include "test-file.txt"
11
+
12
+ Scenario: Running commands in isolated containers
13
+ Given a remote file "another-file.txt" containing "content" exists in the test container
14
+ When I run bard "cat another-file.txt" against the test container
15
+ Then the bard command should succeed
16
+ And the bard output should include "content"
@@ -0,0 +1,23 @@
1
+ Given /^a podman testcontainer is ready for bard$/ do
2
+ raise "Podman testcontainer failed to start" unless @podman_container && @podman_ssh_port
3
+ end
4
+
5
+ Given /^a remote file "([^\"]+)" exists in the test container$/ do |filename|
6
+ run_ssh("touch testproject/#{filename}").should be_true
7
+ end
8
+
9
+ Given /^a remote file "([^\"]+)" containing "([^\"]+)" exists in the test container$/ do |filename, content|
10
+ run_ssh("echo #{Shellwords.escape(content)} > testproject/#{filename}").should be_true
11
+ end
12
+
13
+ When /^I run bard "([^\"]+)" against the test container$/ do |command|
14
+ run_bard_against_container(command)
15
+ end
16
+
17
+ Then /^the bard command should succeed$/ do
18
+ @status.success?.should be_true
19
+ end
20
+
21
+ Then /^the bard output should include "([^\"]+)"$/ do |expected|
22
+ @stdout.should include(expected)
23
+ end
@@ -0,0 +1,153 @@
1
+ require "fileutils"
2
+ require "open3"
3
+ require "securerandom"
4
+ require "shellwords"
5
+ require "testcontainers"
6
+
7
+ module PodmanWorld
8
+ class << self
9
+ attr_accessor :podman_available, :podman_image_built
10
+ end
11
+
12
+ class PrerequisiteError < StandardError; end
13
+
14
+ def ensure_podman_available
15
+ return if @podman_available || PodmanWorld.podman_available
16
+
17
+ raise PrerequisiteError, "podman is not installed or not on PATH" unless system("command -v podman >/dev/null 2>&1")
18
+
19
+ configure_podman_socket
20
+ ensure_bard_test_image
21
+ FileUtils.chmod(0o600, podman_ssh_key_path)
22
+
23
+ PodmanWorld.podman_available = true
24
+ @podman_available = true
25
+ end
26
+
27
+ def configure_podman_socket
28
+ return if ENV["DOCKER_HOST"]
29
+
30
+ podman_socket = "/run/user/#{Process.uid}/podman/podman.sock"
31
+ unless File.exist?(podman_socket)
32
+ system("systemctl --user start podman.socket 2>/dev/null || podman system service --time=0 unix://#{podman_socket} &")
33
+ sleep 2
34
+ end
35
+
36
+ raise PrerequisiteError, "Podman socket not available at #{podman_socket}" unless File.exist?(podman_socket)
37
+
38
+ ENV["DOCKER_HOST"] = "unix://#{podman_socket}"
39
+ end
40
+
41
+ def ensure_bard_test_image
42
+ return if @podman_image_built || PodmanWorld.podman_image_built
43
+
44
+ raise PrerequisiteError, "Unable to pull ubuntu:22.04 image" unless system("podman pull ubuntu:22.04 >/dev/null 2>&1")
45
+
46
+ docker_dir = File.join(ROOT, "spec/acceptance/docker")
47
+ dockerfile = File.join(docker_dir, "Dockerfile")
48
+ unless system("podman build -t bard-test-server -f #{dockerfile} #{docker_dir} 2>&1")
49
+ raise PrerequisiteError, "Failed to build bard test image"
50
+ end
51
+
52
+ PodmanWorld.podman_image_built = true
53
+ @podman_image_built = true
54
+ end
55
+
56
+ def start_podman_container
57
+ ensure_podman_available
58
+
59
+ @podman_container = Testcontainers::DockerContainer
60
+ .new("localhost/bard-test-server:latest")
61
+ .with_exposed_port(22)
62
+ .with_name("bard-test-#{SecureRandom.hex(4)}")
63
+ .start
64
+
65
+ @podman_ssh_port = @podman_container.mapped_port(22)
66
+ wait_for_ssh
67
+ run_ssh("mkdir -p testproject")
68
+ write_bard_config
69
+ end
70
+
71
+ def wait_for_ssh
72
+ 30.times do
73
+ return if run_ssh("echo ready", quiet: true)
74
+ sleep 0.5
75
+ end
76
+
77
+ raise PrerequisiteError, "SSH in podman container did not become ready"
78
+ end
79
+
80
+ def write_bard_config
81
+ FileUtils.mkdir_p(File.join(ROOT, "tmp"))
82
+ @bard_config_path = File.join(ROOT, "tmp", "test_bard_#{SecureRandom.hex(4)}.rb")
83
+
84
+ File.write(@bard_config_path, <<~RUBY)
85
+ server :production do
86
+ ssh "deploy@localhost:#{@podman_ssh_port}"
87
+ path "testproject"
88
+ ssh_key "#{podman_ssh_key_path}"
89
+ ping false
90
+ end
91
+ RUBY
92
+ end
93
+
94
+ def run_ssh(command, quiet: false)
95
+ escaped = Shellwords.escape(command)
96
+ ssh_command = [
97
+ "ssh",
98
+ "-o", "StrictHostKeyChecking=no",
99
+ "-o", "ConnectTimeout=1",
100
+ "-p", @podman_ssh_port.to_s,
101
+ "-i", podman_ssh_key_path,
102
+ "deploy@localhost",
103
+ "--",
104
+ "bash",
105
+ "-lc",
106
+ escaped
107
+ ].join(" ")
108
+
109
+ quiet ? system("#{ssh_command} >/dev/null 2>&1") : system(ssh_command)
110
+ end
111
+
112
+ def run_bard_against_container(command)
113
+ Dir.chdir(File.join(ROOT, "tmp")) do
114
+ FileUtils.cp(@bard_config_path, "bard.rb")
115
+ @stdout, @status = Open3.capture2e(@env || {}, "bard run #{command}")
116
+ @stderr = ""
117
+ FileUtils.rm_f("bard.rb")
118
+ end
119
+ end
120
+
121
+ def podman_ssh_key_path
122
+ @podman_ssh_key_path ||= File.expand_path(File.join(ROOT, "spec/acceptance/docker/test_key"))
123
+ end
124
+
125
+ def stop_podman_container
126
+ FileUtils.rm_f(@bard_config_path) if @bard_config_path
127
+ return unless @podman_container
128
+
129
+ @podman_container.stop
130
+ @podman_container.remove
131
+ rescue StandardError => e
132
+ warn "Failed to cleanup podman container: #{e.message}"
133
+ ensure
134
+ @podman_container = nil
135
+ @podman_ssh_port = nil
136
+ end
137
+ end
138
+
139
+ World(PodmanWorld)
140
+
141
+ Before("@podman") do
142
+ @env ||= {}
143
+
144
+ begin
145
+ start_podman_container
146
+ rescue PodmanWorld::PrerequisiteError => e
147
+ pending(e.message)
148
+ end
149
+ end
150
+
151
+ After("@podman") do
152
+ stop_podman_container
153
+ end
data/lib/bard/config.rb CHANGED
@@ -2,6 +2,12 @@ require "bard/server"
2
2
 
3
3
  module Bard
4
4
  class Config
5
+ def self.current(working_directory: Dir.getwd)
6
+ project_name = File.basename(working_directory)
7
+ path = File.join(working_directory, "bard.rb")
8
+ new(project_name, path: path)
9
+ end
10
+
5
11
  def initialize project_name, path: nil, source: nil
6
12
  @project_name = project_name
7
13
  @servers = {
@@ -69,30 +75,23 @@ module Bard
69
75
  if block_given?
70
76
  @backup = BackupConfig.new(&block)
71
77
  elsif value == false
72
- @backup = false
73
- elsif value == true
74
- # Backward compatibility: backup true
75
- @backup = BackupConfig.new { bard }
76
- elsif value.nil?
77
- # Getter
78
- return @backup if defined?(@backup)
79
- @backup = BackupConfig.new { bard } # Default
78
+ @backup = BackupConfig.new { disabled }
79
+ elsif value.nil? # Getter
80
+ @backup ||= BackupConfig.new { bard }
80
81
  else
81
- raise ArgumentError, "backup accepts a block, true, or false"
82
+ raise ArgumentError, "backup accepts false or a block"
82
83
  end
83
84
  end
84
85
 
85
86
  # short-hand for michael
86
87
 
87
- def github_pages url=nil
88
+ def github_pages url
88
89
  urls = []
89
- if url.present?
90
- uri = url.start_with?("http") ? URI.parse(url) : URI.parse("https://#{url}")
91
- hostname = uri.hostname.sub(/^www\./, '')
92
- urls = [hostname]
93
- if hostname.count(".") < 2
94
- urls << "www.#{hostname}"
95
- end
90
+ uri = url.start_with?("http") ? URI.parse(url) : URI.parse("https://#{url}")
91
+ hostname = uri.hostname.sub(/^www\./, '')
92
+ urls = [hostname]
93
+ if hostname.count(".") < 2
94
+ urls << "www.#{hostname}"
96
95
  end
97
96
 
98
97
  server :production do
@@ -106,31 +105,41 @@ module Bard
106
105
  end
107
106
 
108
107
  class BackupConfig
109
- attr_reader :bard_enabled, :destinations
108
+ attr_reader :destinations
110
109
 
111
110
  def initialize(&block)
112
- @bard_enabled = false
113
111
  @destinations = []
114
112
  instance_eval(&block) if block_given?
115
113
  end
116
114
 
117
115
  def bard
118
- @bard_enabled = true
116
+ @bard = true
117
+ end
118
+
119
+ def bard?
120
+ !!@bard
121
+ end
122
+
123
+ def disabled
124
+ @disabled = true
119
125
  end
120
126
 
121
- def s3(name, credentials:, path:)
127
+ def disabled?
128
+ !!@disabled
129
+ end
130
+
131
+ def enabled?
132
+ !disabled?
133
+ end
134
+
135
+ def s3(name, **kwargs)
122
136
  @destinations << {
123
137
  name: name,
124
138
  type: :s3,
125
- credentials: credentials,
126
- path: path
139
+ **kwargs,
127
140
  }
128
141
  end
129
142
 
130
- def bard?
131
- @bard_enabled
132
- end
133
-
134
143
  def self_managed?
135
144
  @destinations.any?
136
145
  end
data/lib/bard/version.rb CHANGED
@@ -1,4 +1,4 @@
1
1
  module Bard
2
- VERSION = "1.6.0"
2
+ VERSION = "1.7.0"
3
3
  end
4
4
 
@@ -78,7 +78,7 @@ describe Bard::Config do
78
78
 
79
79
  describe "#backup" do
80
80
  it "returns the backup setting" do
81
- expect(subject.backup).to eq false
81
+ expect(subject.backup).to be_disabled
82
82
  end
83
83
  end
84
84
  end
@@ -97,7 +97,7 @@ describe Bard::Config do
97
97
  end
98
98
 
99
99
  describe "#backup with s3 directive" do
100
- subject { described_class.new("test", source: "backup { s3 :primary, credentials: :backup, path: 'bucket/path' }") }
100
+ subject { described_class.new("test", source: "backup { s3 :primary, path: 'bucket/path' }") }
101
101
 
102
102
  it "returns a BackupConfig with s3 destination" do
103
103
  backup = subject.backup
@@ -109,13 +109,12 @@ describe Bard::Config do
109
109
  dest = backup.destinations.first
110
110
  expect(dest[:name]).to eq :primary
111
111
  expect(dest[:type]).to eq :s3
112
- expect(dest[:credentials]).to eq :backup
113
112
  expect(dest[:path]).to eq 'bucket/path'
114
113
  end
115
114
  end
116
115
 
117
116
  describe "#backup with both bard and s3 directives" do
118
- subject { described_class.new("test", source: "backup { bard; s3 :custom, credentials: :backup, path: 'bucket/path' }") }
117
+ subject { described_class.new("test", source: "backup { bard; s3 :custom, path: 'bucket/path' }") }
119
118
 
120
119
  it "returns a BackupConfig with bard and s3 destination" do
121
120
  backup = subject.backup
@@ -130,8 +129,8 @@ describe Bard::Config do
130
129
  subject do
131
130
  described_class.new("test", source: <<~SOURCE)
132
131
  backup do
133
- s3 :primary, credentials: :backup1, path: 'bucket1/path'
134
- s3 :secondary, credentials: :backup2, path: 'bucket2/path'
132
+ s3 :primary, path: 'bucket1/path'
133
+ s3 :secondary, path: 'bucket2/path'
135
134
  end
136
135
  SOURCE
137
136
  end
@@ -147,15 +146,23 @@ describe Bard::Config do
147
146
  expect(backup.destinations[1][:name]).to eq :secondary
148
147
  end
149
148
  end
149
+ end
150
150
 
151
- describe "#backup true (backward compatibility)" do
152
- subject { described_class.new("test", source: "backup true") }
151
+ context "with github_pages directive" do
152
+ subject { described_class.new("test", source: "github_pages 'example.com'") }
153
153
 
154
- it "returns a BackupConfig with bard enabled" do
155
- backup = subject.backup
156
- expect(backup).to be_a(Bard::BackupConfig)
157
- expect(backup.bard?).to eq true
158
- expect(backup.destinations).to be_empty
154
+ describe "#backup" do
155
+ it "sets backup to false" do
156
+ expect(subject.backup).to be_disabled
157
+ end
158
+ end
159
+
160
+ describe "#server" do
161
+ it "creates a production server with github_pages enabled" do
162
+ production = subject[:production]
163
+ expect(production).not_to be_nil
164
+ expect(production.github_pages).to eq true
165
+ expect(production.ssh).to eq false
159
166
  end
160
167
  end
161
168
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bard
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.6.0
4
+ version: 1.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Micah Geisel
8
8
  bindir: bin
9
9
  cert_chain: []
10
- date: 2025-12-06 00:00:00.000000000 Z
10
+ date: 2025-12-11 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: thor
@@ -121,6 +121,20 @@ dependencies:
121
121
  - - ">="
122
122
  - !ruby/object:Gem::Version
123
123
  version: '0'
124
+ - !ruby/object:Gem::Dependency
125
+ name: cucumber
126
+ requirement: !ruby/object:Gem::Requirement
127
+ requirements:
128
+ - - ">="
129
+ - !ruby/object:Gem::Version
130
+ version: '0'
131
+ type: :development
132
+ prerelease: false
133
+ version_requirements: !ruby/object:Gem::Requirement
134
+ requirements:
135
+ - - ">="
136
+ - !ruby/object:Gem::Version
137
+ version: '0'
124
138
  - !ruby/object:Gem::Dependency
125
139
  name: testcontainers
126
140
  requirement: !ruby/object:Gem::Requirement
@@ -157,14 +171,17 @@ files:
157
171
  - features/bard_deploy.feature
158
172
  - features/bard_pull.feature
159
173
  - features/bard_push.feature
174
+ - features/podman_testcontainers.feature
160
175
  - features/step_definitions/check_steps.rb
161
176
  - features/step_definitions/git_steps.rb
162
177
  - features/step_definitions/global_steps.rb
178
+ - features/step_definitions/podman_steps.rb
163
179
  - features/step_definitions/rails_steps.rb
164
180
  - features/step_definitions/submodule_steps.rb
165
181
  - features/support/env.rb
166
182
  - features/support/grit_ext.rb
167
183
  - features/support/io.rb
184
+ - features/support/podman.rb
168
185
  - install_files/.github/dependabot.yml
169
186
  - install_files/.github/workflows/cache-ci.yml
170
187
  - install_files/.github/workflows/ci.yml
@@ -228,7 +245,6 @@ files:
228
245
  - spec/acceptance/docker/Dockerfile
229
246
  - spec/acceptance/docker/test_key
230
247
  - spec/acceptance/docker/test_key.pub
231
- - spec/acceptance/podman_testcontainers_spec.rb
232
248
  - spec/bard/ci/github_actions_spec.rb
233
249
  - spec/bard/ci_spec.rb
234
250
  - spec/bard/cli/ci_spec.rb
@@ -301,19 +317,21 @@ test_files:
301
317
  - features/bard_deploy.feature
302
318
  - features/bard_pull.feature
303
319
  - features/bard_push.feature
320
+ - features/podman_testcontainers.feature
304
321
  - features/step_definitions/check_steps.rb
305
322
  - features/step_definitions/git_steps.rb
306
323
  - features/step_definitions/global_steps.rb
324
+ - features/step_definitions/podman_steps.rb
307
325
  - features/step_definitions/rails_steps.rb
308
326
  - features/step_definitions/submodule_steps.rb
309
327
  - features/support/env.rb
310
328
  - features/support/grit_ext.rb
311
329
  - features/support/io.rb
330
+ - features/support/podman.rb
312
331
  - spec/acceptance/.gitignore
313
332
  - spec/acceptance/docker/Dockerfile
314
333
  - spec/acceptance/docker/test_key
315
334
  - spec/acceptance/docker/test_key.pub
316
- - spec/acceptance/podman_testcontainers_spec.rb
317
335
  - spec/bard/ci/github_actions_spec.rb
318
336
  - spec/bard/ci_spec.rb
319
337
  - spec/bard/cli/ci_spec.rb
@@ -1,140 +0,0 @@
1
- # Acceptance test for Bard using Podman + TestContainers
2
- #
3
- # This test validates end-to-end functionality of `bard run ls` by:
4
- # 1. Starting an SSH server container using TestContainers
5
- # 2. Configuring Bard to connect to it
6
- # 3. Running bard commands against the container
7
- # 4. Automatically cleaning up when done
8
- #
9
- # Prerequisites:
10
- # - gem install testcontainers
11
- # - podman installed
12
- # - podman socket running (systemctl --user start podman.socket)
13
- # - Set DOCKER_HOST to podman socket
14
-
15
- require 'spec_helper'
16
- require 'testcontainers'
17
- require 'open3'
18
-
19
- RSpec.describe "Bard acceptance test with Podman + TestContainers", type: :acceptance do
20
- # Disable WebMock for acceptance tests - we need real HTTP connections to Podman
21
- before(:all) do
22
- WebMock.allow_net_connect!
23
- end
24
-
25
- after(:all) do
26
- WebMock.disable_net_connect!
27
- end
28
- # Configure TestContainers to use Podman
29
- before(:all) do
30
- # Set up podman socket for TestContainers
31
- # Use existing DOCKER_HOST if set (e.g., in CI), otherwise use default location
32
- unless ENV['DOCKER_HOST']
33
- podman_socket = "/run/user/#{Process.uid}/podman/podman.sock"
34
-
35
- # Start podman socket if not running
36
- unless File.exist?(podman_socket)
37
- system("systemctl --user start podman.socket 2>/dev/null || podman system service --time=0 unix://#{podman_socket} &")
38
- sleep 2
39
- end
40
-
41
- # Configure TestContainers to use podman
42
- ENV['DOCKER_HOST'] = "unix://#{podman_socket}"
43
- end
44
-
45
- # Ensure SSH key has correct permissions
46
- system("chmod 600 spec/acceptance/docker/test_key")
47
-
48
- # Check if we can pull images
49
- unless system("podman pull ubuntu:22.04 >/dev/null 2>&1")
50
- skip "Cannot pull images in this environment. Run in a network-enabled environment."
51
- end
52
-
53
- # Build the test image
54
- unless system("podman build -t bard-test-server -f spec/acceptance/docker/Dockerfile spec/acceptance/docker 2>&1")
55
- skip "Failed to build test image"
56
- end
57
- end
58
-
59
- # TestContainers will automatically manage this container
60
- let(:container) do
61
- Testcontainers::DockerContainer.new("localhost/bard-test-server:latest")
62
- .with_exposed_port(22)
63
- .with_name("bard-test-#{SecureRandom.hex(4)}")
64
- .start
65
- end
66
-
67
- let(:ssh_port) { container.mapped_port(22) }
68
-
69
- before(:each) do
70
- # Ensure container is started
71
- container
72
-
73
- # Wait for SSH to be ready
74
- 30.times do
75
- break if system("ssh -o StrictHostKeyChecking=no -o ConnectTimeout=1 -p #{ssh_port} deploy@localhost -i spec/acceptance/docker/test_key 'echo ready' 2>/dev/null")
76
- sleep 0.5
77
- end
78
-
79
- # Create test project directory
80
- system("ssh -o StrictHostKeyChecking=no -p #{ssh_port} deploy@localhost -i spec/acceptance/docker/test_key 'mkdir -p testproject'")
81
-
82
- # Create bard config for this container
83
- @bard_config_path = "tmp/test_bard_#{SecureRandom.hex(4)}.rb"
84
- FileUtils.mkdir_p("tmp")
85
- ssh_key_path = File.expand_path("spec/acceptance/docker/test_key")
86
- File.write(@bard_config_path, <<~RUBY)
87
- server :production do
88
- ssh "deploy@localhost:#{ssh_port}"
89
- path "testproject"
90
- ssh_key "#{ssh_key_path}"
91
- ping false
92
- end
93
- RUBY
94
- end
95
-
96
- after(:each) do
97
- # Clean up bard config
98
- FileUtils.rm_f(@bard_config_path) if @bard_config_path
99
-
100
- # TestContainers will automatically stop and remove the container
101
- container.stop if container
102
- container.remove if container
103
- end
104
-
105
- it "runs ls command via bard run" do
106
- # Create a test file in the container
107
- result = system("ssh -o StrictHostKeyChecking=no -p #{ssh_port} deploy@localhost -i spec/acceptance/docker/test_key 'touch testproject/test-file.txt'")
108
- expect(result).to be true
109
-
110
- # Run bard command
111
- Dir.chdir("tmp") do
112
- # Copy config to bard.rb
113
- FileUtils.cp("../#{@bard_config_path}", "bard.rb")
114
-
115
- output, status = Open3.capture2e("bard run ls")
116
-
117
- # Clean up
118
- FileUtils.rm_f("bard.rb")
119
-
120
- # Verify the command succeeded
121
- expect(status).to be_success, "bard run failed with output: #{output}"
122
- expect(output).to include("test-file.txt")
123
- end
124
- end
125
-
126
- it "runs multiple commands in isolated containers" do
127
- # Each test gets its own container automatically!
128
- result = system("ssh -o StrictHostKeyChecking=no -p #{ssh_port} deploy@localhost -i spec/acceptance/docker/test_key 'echo content > testproject/another-file.txt'")
129
- expect(result).to be true
130
-
131
- Dir.chdir("tmp") do
132
- FileUtils.cp("../#{@bard_config_path}", "bard.rb")
133
- output, status = Open3.capture2e("bard run 'cat another-file.txt'")
134
- FileUtils.rm_f("bard.rb")
135
-
136
- expect(status).to be_success, "bard run failed with output: #{output}"
137
- expect(output).to include("content")
138
- end
139
- end
140
- end