bard 1.9.6 → 2.0.0.beta

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 (106) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +0 -5
  3. data/MIGRATION_GUIDE.md +9 -24
  4. data/README.md +6 -14
  5. data/README.rdoc +15 -0
  6. data/Rakefile +1 -3
  7. data/features/bard_check.feature +94 -0
  8. data/features/bard_deploy.feature +18 -0
  9. data/features/bard_pull.feature +112 -0
  10. data/features/bard_push.feature +112 -0
  11. data/features/podman_testcontainers.feature +16 -0
  12. data/features/step_definitions/check_steps.rb +47 -0
  13. data/features/step_definitions/git_steps.rb +73 -0
  14. data/features/step_definitions/global_steps.rb +56 -0
  15. data/features/step_definitions/podman_steps.rb +23 -0
  16. data/features/step_definitions/rails_steps.rb +44 -0
  17. data/features/step_definitions/submodule_steps.rb +110 -0
  18. data/features/support/env.rb +39 -14
  19. data/features/support/grit_ext.rb +13 -0
  20. data/features/support/io.rb +32 -0
  21. data/features/support/podman.rb +153 -0
  22. data/lib/bard/ci/github_actions.rb +2 -1
  23. data/lib/bard/ci/jenkins.rb +11 -82
  24. data/lib/bard/ci/local.rb +6 -6
  25. data/lib/bard/ci/runner.rb +1 -35
  26. data/lib/bard/ci.rb +23 -11
  27. data/lib/bard/cli/ci.rb +38 -45
  28. data/lib/bard/cli/deploy.rb +9 -40
  29. data/lib/bard/cli/hurt.rb +15 -10
  30. data/lib/bard/cli/install.rb +12 -7
  31. data/lib/bard/cli/open.rb +16 -12
  32. data/lib/bard/cli/ping.rb +14 -8
  33. data/lib/bard/cli/provision.rb +1 -1
  34. data/lib/bard/cli/run.rb +3 -5
  35. data/lib/bard/cli/stage.rb +1 -9
  36. data/lib/bard/cli/vim.rb +10 -5
  37. data/lib/bard/cli.rb +11 -13
  38. data/lib/bard/command.rb +13 -33
  39. data/lib/bard/config.rb +14 -10
  40. data/lib/bard/copy.rb +33 -12
  41. data/lib/bard/deploy_strategy/github_pages.rb +2 -10
  42. data/lib/bard/deploy_strategy.rb +0 -3
  43. data/lib/bard/github.rb +4 -2
  44. data/lib/bard/provision/apt.rb +1 -1
  45. data/lib/bard/provision/logrotation.rb +1 -1
  46. data/lib/bard/provision/mysql.rb +2 -2
  47. data/lib/bard/provision/passenger.rb +2 -2
  48. data/lib/bard/provision/repo.rb +2 -2
  49. data/lib/bard/provision/ssh.rb +2 -9
  50. data/lib/bard/provision/swapfile.rb +1 -3
  51. data/lib/bard/server.rb +3 -46
  52. data/lib/bard/ssh_server.rb +2 -9
  53. data/lib/bard/target.rb +16 -67
  54. data/lib/bard/version.rb +1 -1
  55. data/spec/acceptance/docker/Dockerfile +1 -2
  56. data/spec/bard/ci/github_actions_spec.rb +13 -116
  57. data/spec/bard/cli/ci_spec.rb +8 -34
  58. data/spec/bard/cli/deploy_spec.rb +8 -46
  59. data/spec/bard/cli/hurt_spec.rb +2 -2
  60. data/spec/bard/cli/install_spec.rb +4 -4
  61. data/spec/bard/cli/open_spec.rb +8 -10
  62. data/spec/bard/cli/ping_spec.rb +5 -5
  63. data/spec/bard/cli/run_spec.rb +1 -20
  64. data/spec/bard/cli/stage_spec.rb +0 -20
  65. data/spec/bard/cli/vim_spec.rb +5 -5
  66. data/spec/bard/command_spec.rb +1 -3
  67. data/spec/bard/config_spec.rb +0 -28
  68. data/spec/bard/copy_spec.rb +3 -3
  69. data/spec/bard/github_spec.rb +1 -1
  70. data/spec/bard/provision/apt_spec.rb +1 -1
  71. data/spec/bard/provision/logrotation_spec.rb +1 -1
  72. data/spec/bard/provision/passenger_spec.rb +1 -1
  73. data/spec/bard/provision/repo_spec.rb +1 -1
  74. data/spec/bard/provision/ssh_spec.rb +4 -17
  75. data/spec/bard/provision/swapfile_spec.rb +1 -2
  76. data/spec/bard/ssh_server_spec.rb +8 -12
  77. data/spec/bard/target_spec.rb +5 -9
  78. data/spec/spec_helper.rb +1 -6
  79. metadata +31 -41
  80. data/CLAUDE.md +0 -76
  81. data/PLUGINS.md +0 -114
  82. data/cucumber.yml +0 -1
  83. data/features/ci.feature +0 -62
  84. data/features/data.feature +0 -12
  85. data/features/deploy.feature +0 -13
  86. data/features/deploy_git_workflow.feature +0 -88
  87. data/features/run.feature +0 -13
  88. data/features/step_definitions/bard_steps.rb +0 -135
  89. data/features/support/bard-coverage +0 -16
  90. data/features/support/test_server.rb +0 -216
  91. data/lib/bard/deprecation.rb +0 -19
  92. data/lib/bard/plugin.rb +0 -100
  93. data/lib/bard/plugins/backup.rb +0 -19
  94. data/lib/bard/plugins/github_pages.rb +0 -34
  95. data/lib/bard/plugins/hurt.rb +0 -5
  96. data/lib/bard/plugins/install.rb +0 -5
  97. data/lib/bard/plugins/jenkins.rb +0 -6
  98. data/lib/bard/plugins/new.rb +0 -5
  99. data/lib/bard/plugins/ping.rb +0 -6
  100. data/lib/bard/plugins/provision.rb +0 -5
  101. data/lib/bard/plugins/vim.rb +0 -5
  102. data/lib/bard/secrets.rb +0 -10
  103. data/spec/bard/ci/jenkins_spec.rb +0 -139
  104. data/spec/bard/ci/runner_spec.rb +0 -61
  105. data/spec/bard/deprecation_spec.rb +0 -281
  106. data/spec/bard/plugin_spec.rb +0 -79
@@ -1,13 +0,0 @@
1
- Feature: bard deploy
2
- Deploy code changes to a remote server.
3
-
4
- Background:
5
- Given a test server is running
6
-
7
- Scenario: deploys code changes to the remote server
8
- Given I create a file "DEPLOYED.txt" with content "deployed by bard"
9
- And I commit the changes with message "Add deployed marker"
10
- When I run: bard deploy --skip-ci
11
- Then the output should contain "Deploy Succeeded"
12
- When I run: bard run "cat DEPLOYED.txt"
13
- Then the output should contain "deployed by bard"
@@ -1,88 +0,0 @@
1
- Feature: bard deploy git workflow
2
- Git workflow behaviors during deploy.
3
-
4
- Background:
5
- Given a test server is running
6
-
7
- Scenario: deploy on master pushes unpushed commits
8
- Given I create a file "local-only.txt" with content "local commit"
9
- And I commit the changes with message "Add local only file"
10
- When I run: bard deploy --skip-ci
11
- Then the output should contain "Deploy Succeeded"
12
- When I run: bard run "cat local-only.txt"
13
- Then the output should contain "local commit"
14
-
15
- Scenario: feature branch fast-forward merge
16
- Given I create and switch to branch "feature-branch"
17
- And I create a file "feature.txt" with content "feature content"
18
- And I commit the changes with message "Add feature"
19
- When I run: bard deploy --skip-ci
20
- Then the output should contain "Deploy Succeeded"
21
- And I should be on branch "master"
22
- And branch "feature-branch" should not exist locally
23
- And branch "feature-branch" should not exist on origin
24
- When I run: bard run "cat feature.txt"
25
- Then the output should contain "feature content"
26
-
27
- Scenario: feature branch requires rebase
28
- Given I create and switch to branch "feature-branch"
29
- And I create a file "feature.txt" with content "feature content"
30
- And I commit the changes with message "Add feature"
31
- And master has an additional commit from another source
32
- When I run: bard deploy --skip-ci
33
- Then the output should contain "The master branch has advanced"
34
- And the output should contain "Attempting rebase"
35
- And the output should contain "Deploy Succeeded"
36
- And I should be on branch "master"
37
- When I run: bard run "cat feature.txt"
38
- Then the output should contain "feature content"
39
- When I run: bard run "cat remote-change.txt"
40
- Then the output should contain "remote change"
41
-
42
- Scenario: feature branch rebase conflict
43
- Given I create and switch to branch "feature-branch"
44
- And I create a file "conflict.txt" with content "feature content"
45
- And I commit the changes with message "Add conflicting file"
46
- And master has a conflicting commit to "conflict.txt"
47
- When I run expecting failure: bard deploy --skip-ci
48
- Then the output should contain "The master branch has advanced"
49
- And the output should contain "Attempting rebase"
50
- And the output should contain "Running command failed"
51
-
52
- Scenario: branch cleanup after deploy
53
- Given I create and switch to branch "cleanup-test"
54
- And I create a file "cleanup.txt" with content "cleanup test"
55
- And I commit the changes with message "Add cleanup test file"
56
- And I push branch "cleanup-test" to origin
57
- When I run: bard deploy --skip-ci
58
- Then the output should contain "Deleting branch: cleanup-test"
59
- And the output should contain "Deploy Succeeded"
60
- And I should be on branch "master"
61
- And branch "cleanup-test" should not exist locally
62
- And branch "cleanup-test" should not exist on origin
63
-
64
- Scenario: deploy a branch without checking it out
65
- Given I create and switch to branch "feature-branch"
66
- And I create a file "feature.txt" with content "feature content"
67
- And I commit the changes with message "Add feature"
68
- And I switch to branch "master"
69
- When I run: bard deploy feature-branch --skip-ci
70
- Then the output should contain "Deploy Succeeded"
71
- And I should be on branch "master"
72
- And branch "feature-branch" should not exist locally
73
- When I run: bard run "cat feature.txt"
74
- Then the output should contain "feature content"
75
-
76
- Scenario: deploy a branch that requires rebase without checking it out
77
- Given I create and switch to branch "feature-branch"
78
- And I create a file "feature.txt" with content "feature content"
79
- And I commit the changes with message "Add feature"
80
- And I switch to branch "master"
81
- And master has an additional commit from another source
82
- When I run: bard deploy feature-branch --skip-ci
83
- Then the output should contain "The master branch has advanced"
84
- And the output should contain "Attempting rebase"
85
- And the output should contain "Deploy Succeeded"
86
- And I should be on branch "master"
87
- When I run: bard run "cat feature.txt"
88
- Then the output should contain "feature content"
data/features/run.feature DELETED
@@ -1,13 +0,0 @@
1
- Feature: bard run
2
- Execute commands on a remote server.
3
-
4
- Background:
5
- Given a test server is running
6
-
7
- Scenario: executes a command on the remote server
8
- When I run: bard run "echo hello"
9
- Then the output should contain "hello"
10
-
11
- Scenario: operates in the configured path
12
- When I run: bard run "pwd"
13
- Then the output should contain "testproject"
@@ -1,135 +0,0 @@
1
- Given /^a test server is running$/ do
2
- raise "Test server failed to start" unless @container && @ssh_port
3
- end
4
-
5
- When /^I run: bard (.+)$/ do |command|
6
- run_bard(command)
7
- unless @status.success?
8
- raise "Command failed with status: #{@status}\nOutput: #{@stdout}"
9
- end
10
- end
11
-
12
- When /^I run expecting failure: bard (.+)$/ do |command|
13
- run_bard(command)
14
- unless !@status.success?
15
- raise "Command succeeded but was expected to fail\nOutput: #{@stdout}"
16
- end
17
- end
18
-
19
- Then /^the output should contain "([^\"]+)"$/ do |expected|
20
- expect(@stdout).to include(expected)
21
- end
22
-
23
- Given /^I create a file "([^\"]+)" with content "([^\"]+)"$/ do |filename, content|
24
- Dir.chdir(@test_dir) do
25
- File.write(filename, content)
26
- end
27
- end
28
-
29
- Given /^I commit the changes with message "([^\"]+)"$/ do |message|
30
- Dir.chdir(@test_dir) do
31
- system("git add -A", out: File::NULL, err: File::NULL)
32
- system("git commit -m '#{message}'", out: File::NULL, err: File::NULL)
33
- end
34
- end
35
-
36
- Then /^a file "([^\"]+)" should exist locally$/ do |filename|
37
- path = File.join(@test_dir, filename)
38
- expect(File.exist?(path)).to be(true), "Expected file #{filename} to exist at #{path}"
39
- end
40
-
41
- # Branch management
42
- Given /^I create and switch to branch "([^"]+)"$/ do |branch_name|
43
- Dir.chdir(@test_dir) do
44
- system("git checkout -b #{branch_name}", out: File::NULL, err: File::NULL)
45
- end
46
- end
47
-
48
- Then /^I should be on branch "([^"]+)"$/ do |expected_branch|
49
- Dir.chdir(@test_dir) do
50
- current = `git rev-parse --abbrev-ref HEAD`.chomp
51
- expect(current).to eq(expected_branch)
52
- end
53
- end
54
-
55
- Given /^I push branch "([^"]+)" to origin$/ do |branch_name|
56
- Dir.chdir(@test_dir) do
57
- system("git push -u origin #{branch_name}", out: File::NULL, err: File::NULL)
58
- end
59
- end
60
-
61
- Then /^branch "([^"]+)" should not exist locally$/ do |branch_name|
62
- Dir.chdir(@test_dir) do
63
- result = system("git rev-parse --verify #{branch_name}", out: File::NULL, err: File::NULL)
64
- expect(result).to be(false), "Expected branch #{branch_name} to not exist locally"
65
- end
66
- end
67
-
68
- Then /^branch "([^"]+)" should not exist on origin$/ do |branch_name|
69
- Dir.chdir(@test_dir) do
70
- system("git fetch --prune origin", out: File::NULL, err: File::NULL)
71
- result = system("git rev-parse --verify origin/#{branch_name}", out: File::NULL, err: File::NULL)
72
- expect(result).to be(false), "Expected branch #{branch_name} to not exist on origin"
73
- end
74
- end
75
-
76
- # Simulating remote changes
77
- Given /^master has an additional commit from another source$/ do
78
- run_ssh "cd ~/testproject && git pull origin master"
79
- run_ssh "cd ~/testproject && echo 'remote change' > remote-change.txt"
80
- run_ssh "cd ~/testproject && git add remote-change.txt"
81
- run_ssh "cd ~/testproject && git commit -m 'Remote commit on master'"
82
- run_ssh "cd ~/testproject && git push origin master"
83
-
84
- Dir.chdir(@test_dir) do
85
- system("git fetch origin", out: File::NULL, err: File::NULL)
86
- end
87
- end
88
-
89
- Given /^master has a conflicting commit to "([^"]+)"$/ do |filename|
90
- run_ssh "cd ~/testproject && git pull origin master"
91
- run_ssh "cd ~/testproject && echo 'conflicting content from remote' > #{filename}"
92
- run_ssh "cd ~/testproject && git add #{filename}"
93
- run_ssh "cd ~/testproject && git commit -m 'Remote conflicting commit'"
94
- run_ssh "cd ~/testproject && git push origin master"
95
-
96
- Dir.chdir(@test_dir) do
97
- system("git fetch origin", out: File::NULL, err: File::NULL)
98
- end
99
- end
100
-
101
- # CI setup
102
- Given /^a local CI script that passes$/ do
103
- Dir.chdir(@test_dir) do
104
- File.write("bin/rake", <<~'SCRIPT')
105
- #!/bin/bash
106
- case "$1" in
107
- ci) echo "All tests passed!"; exit 0 ;;
108
- esac
109
- SCRIPT
110
- FileUtils.chmod(0o755, "bin/rake")
111
- end
112
- end
113
-
114
- Given /^a local CI script that fails with "([^"]+)"$/ do |error_message|
115
- Dir.chdir(@test_dir) do
116
- File.write("bin/rake", <<~SCRIPT)
117
- #!/bin/bash
118
- case "$1" in
119
- ci) echo "#{error_message}"; exit 1 ;;
120
- esac
121
- SCRIPT
122
- FileUtils.chmod(0o755, "bin/rake")
123
- end
124
- end
125
-
126
- Given /^I switch to branch "([^"]+)"$/ do |branch_name|
127
- Dir.chdir(@test_dir) do
128
- system("git checkout #{branch_name}", out: File::NULL, err: File::NULL)
129
- end
130
- end
131
-
132
- # Output negation
133
- Then /^the output should not contain "([^"]+)"$/ do |unexpected|
134
- expect(@stdout).not_to include(unexpected)
135
- end
@@ -1,16 +0,0 @@
1
- #!/usr/bin/env ruby
2
- root = File.expand_path("../../..", __FILE__)
3
-
4
- require "simplecov"
5
- SimpleCov.root(root)
6
- SimpleCov.start do
7
- command_name "Cucumber (subprocess #{$$})"
8
- track_files "lib/**/*.rb"
9
- add_filter "spec/"
10
- add_filter "features/"
11
- coverage_dir "#{root}/coverage"
12
- end
13
-
14
- $LOAD_PATH.unshift("#{root}/lib")
15
- require "bard/cli"
16
- Bard::CLI.start ARGV
@@ -1,216 +0,0 @@
1
- require "fileutils"
2
- require "open3"
3
- require "tmpdir"
4
- require "docker-api"
5
-
6
- module TestServerWorld
7
- class << self
8
- attr_accessor :server_available, :image_built
9
- end
10
-
11
- class PrerequisiteError < StandardError; end
12
-
13
- def ensure_server_available
14
- return if TestServerWorld.server_available
15
-
16
- unless system("command -v podman >/dev/null 2>&1")
17
- raise PrerequisiteError, "podman is not installed"
18
- end
19
-
20
- configure_container_socket
21
- build_test_image
22
- FileUtils.chmod(0o600, ssh_key_path)
23
-
24
- TestServerWorld.server_available = true
25
- end
26
-
27
- def configure_container_socket
28
- if ENV["DOCKER_HOST"]
29
- Docker.url = ENV["DOCKER_HOST"]
30
- return
31
- end
32
-
33
- socket_path = "/run/user/#{Process.uid}/podman/podman.sock"
34
- unless File.exist?(socket_path)
35
- system("systemctl --user start podman.socket 2>/dev/null")
36
- sleep 2
37
- end
38
-
39
- unless File.exist?(socket_path)
40
- raise PrerequisiteError, "Podman socket not available"
41
- end
42
-
43
- ENV["DOCKER_HOST"] = "unix://#{socket_path}"
44
- Docker.url = ENV["DOCKER_HOST"]
45
- end
46
-
47
- def build_test_image
48
- return if TestServerWorld.image_built
49
-
50
- # Check if image already exists (e.g., pre-built in CI)
51
- if image_exists?("bard-test-server")
52
- TestServerWorld.image_built = true
53
- return
54
- end
55
-
56
- system("podman pull ubuntu:22.04 >/dev/null 2>&1")
57
-
58
- docker_dir = File.join(ROOT, "spec/acceptance/docker")
59
- unless system("podman build -t bard-test-server -f #{docker_dir}/Dockerfile #{docker_dir} 2>&1")
60
- raise PrerequisiteError, "Failed to build test image"
61
- end
62
-
63
- TestServerWorld.image_built = true
64
- end
65
-
66
- def image_exists?(name)
67
- Docker::Image.get(name)
68
- true
69
- rescue Docker::Error::NotFoundError
70
- false
71
- end
72
-
73
- def start_test_server
74
- ensure_server_available
75
-
76
- @container = Docker::Container.create(
77
- "Image" => "localhost/bard-test-server:latest",
78
- "ExposedPorts" => { "22/tcp" => {} },
79
- "HostConfig" => {
80
- "PortBindings" => { "22/tcp" => [{ "HostPort" => "" }] },
81
- "PublishAllPorts" => true
82
- }
83
- )
84
- @container.start
85
- @container.refresh!
86
-
87
- @ssh_port = @container.info["NetworkSettings"]["Ports"]["22/tcp"].first["HostPort"].to_i
88
-
89
- wait_for_ssh
90
- setup_test_directory
91
- end
92
-
93
- def wait_for_ssh
94
- 30.times do
95
- return if system(
96
- "ssh", "-o", "StrictHostKeyChecking=no", "-o", "UserKnownHostsFile=/dev/null",
97
- "-o", "ConnectTimeout=1", "-p", @ssh_port.to_s, "-i", ssh_key_path,
98
- "deploy@localhost", "true",
99
- out: File::NULL, err: File::NULL
100
- )
101
- sleep 0.5
102
- end
103
- raise PrerequisiteError, "SSH not ready"
104
- end
105
-
106
- def setup_test_directory
107
- # Set up git repos on the remote container
108
- run_ssh "git config --global user.email 'test@example.com'"
109
- run_ssh "git config --global user.name 'Test User'"
110
- run_ssh "git config --global init.defaultBranch master"
111
- run_ssh "mkdir -p ~/repos/testproject.git"
112
- run_ssh "cd ~/repos/testproject.git && git init --bare"
113
- run_ssh "git clone ~/repos/testproject.git ~/testproject"
114
- run_ssh "mkdir -p ~/testproject/bin ~/testproject/db"
115
-
116
- # bin/setup script
117
- run_ssh "echo '#!/bin/bash' > ~/testproject/bin/setup"
118
- run_ssh "echo 'echo Setup complete' >> ~/testproject/bin/setup"
119
- run_ssh "chmod +x ~/testproject/bin/setup"
120
-
121
- # bin/rake script for db:dump and db:load
122
- run_ssh <<~'SETUP'
123
- cat > ~/testproject/bin/rake << 'SCRIPT'
124
- #!/bin/bash
125
- case "$1" in
126
- db:dump)
127
- echo "production data" | gzip > db/data.sql.gz
128
- ;;
129
- db:load)
130
- gunzip -c db/data.sql.gz > /dev/null
131
- echo "Data loaded"
132
- ;;
133
- esac
134
- SCRIPT
135
- SETUP
136
- run_ssh "chmod +x ~/testproject/bin/rake"
137
- run_ssh "cd ~/testproject && git add . && git commit -m 'Initial commit'"
138
- run_ssh "cd ~/testproject && git push origin master"
139
-
140
- # Set up local git repo in isolated temp directory
141
- setup_local_git_repo
142
- end
143
-
144
- def setup_local_git_repo
145
- @test_dir = Dir.mktmpdir("bard_test")
146
- @ssh_command = "ssh -i #{ssh_key_path} -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null"
147
-
148
- Dir.chdir(@test_dir) do
149
- # Clone directly into the temp directory (pass SSH command via env, not global ENV)
150
- ssh_url = "ssh://deploy@localhost:#{@ssh_port}/home/deploy/repos/testproject.git"
151
- system({ "GIT_SSH_COMMAND" => @ssh_command }, "git clone #{ssh_url} .", out: File::NULL, err: File::NULL)
152
-
153
- # Configure git settings locally in this repo only
154
- system("git config user.email 'test@example.com'", out: File::NULL, err: File::NULL)
155
- system("git config user.name 'Test User'", out: File::NULL, err: File::NULL)
156
- system("git config core.sshCommand '#{@ssh_command}'", out: File::NULL, err: File::NULL)
157
-
158
- # Ensure db directory exists locally
159
- FileUtils.mkdir_p("db")
160
-
161
- # Write bard config in the test directory
162
- File.write("bard.rb", <<~RUBY)
163
- target :production do
164
- ssh "deploy@localhost:#{@ssh_port}",
165
- path: "testproject",
166
- ssh_key: "#{ssh_key_path}"
167
- ping false
168
- end
169
- RUBY
170
- end
171
- end
172
-
173
- def run_ssh(command)
174
- stdout, status = Open3.capture2e(
175
- "ssh", "-o", "StrictHostKeyChecking=no", "-o", "UserKnownHostsFile=/dev/null",
176
- "-p", @ssh_port.to_s, "-i", ssh_key_path,
177
- "deploy@localhost", command
178
- )
179
- unless status.success?
180
- raise PrerequisiteError, "SSH command failed: #{command}\nOutput: #{stdout}"
181
- end
182
- true
183
- end
184
-
185
- def run_bard(command)
186
- Dir.chdir(@test_dir) do
187
- bard_coverage = File.join(ROOT, "features/support/bard-coverage")
188
- @stdout, @status = Open3.capture2e("#{bard_coverage} #{command}")
189
- end
190
- end
191
-
192
- def ssh_key_path
193
- File.join(ROOT, "spec/acceptance/docker/test_key")
194
- end
195
-
196
- def stop_test_server
197
- return unless @container
198
- @container.stop rescue nil
199
- @container.delete(force: true) rescue nil
200
- ensure
201
- @container = nil
202
- @ssh_port = nil
203
- FileUtils.rm_rf(@test_dir) if @test_dir
204
- @test_dir = nil
205
- end
206
- end
207
-
208
- World(TestServerWorld)
209
-
210
- Before do
211
- start_test_server
212
- end
213
-
214
- After do
215
- stop_test_server
216
- end
@@ -1,19 +0,0 @@
1
- module Bard
2
- module Deprecation
3
- @warned = {}
4
-
5
- def self.warn(message, callsite: nil)
6
- callsite ||= caller_locations(2, 1).first
7
- key = "#{callsite.path}:#{callsite.lineno}:#{message}"
8
- return if @warned[key]
9
-
10
- @warned[key] = true
11
- location = "#{callsite.path}:#{callsite.lineno}"
12
- Kernel.warn "[DEPRECATION] #{message} (called from #{location})"
13
- end
14
-
15
- def self.reset!
16
- @warned = {}
17
- end
18
- end
19
- end
data/lib/bard/plugin.rb DELETED
@@ -1,100 +0,0 @@
1
- module Bard
2
- class Plugin
3
- @registry = {}
4
-
5
- class << self
6
- attr_reader :registry
7
-
8
- def register(name, &block)
9
- plugin = new(name)
10
- plugin.instance_eval(&block) if block
11
- @registry[name.to_sym] = plugin
12
- end
13
-
14
- def [](name)
15
- @registry[name.to_sym]
16
- end
17
-
18
- def all
19
- @registry.values
20
- end
21
-
22
- def load_all!
23
- Dir[File.join(__dir__, "plugins", "*.rb")].sort.each { |f| require f }
24
- Dir[File.join(Dir.pwd, "lib", "bard", "plugins", "*.rb")].sort.each { |f| require f }
25
- all.each(&:apply!)
26
- end
27
-
28
- def reset!
29
- @registry = {}
30
- end
31
- end
32
-
33
- attr_reader :name, :cli_modules
34
-
35
- def initialize(name)
36
- @name = name.to_sym
37
- @cli_modules = []
38
- @cli_requires = []
39
- @target_methods = {}
40
- @config_methods = {}
41
- @requires = []
42
- end
43
-
44
- # DSL methods for defining plugins
45
-
46
- def require_file(path)
47
- @requires << path
48
- end
49
-
50
- def cli(mod, require: nil)
51
- @cli_requires << require if require
52
- @cli_modules << mod
53
- end
54
-
55
- def target_method(name, &block)
56
- @target_methods[name] = block
57
- end
58
-
59
- def config_method(name, &block)
60
- @config_methods[name] = block
61
- end
62
-
63
- # Apply plugin to the system (non-CLI parts)
64
- def apply!
65
- @requires.each { |path| require path }
66
- apply_target_methods!
67
- apply_config_methods!
68
- end
69
-
70
- def apply_to_cli(cli_class)
71
- @cli_requires.each { |path| require path }
72
- @cli_modules.each do |mod|
73
- mod = resolve_constant(mod) if mod.is_a?(String)
74
- mod.setup(cli_class)
75
- end
76
- end
77
-
78
- private
79
-
80
- def apply_target_methods!
81
- return if @target_methods.empty?
82
- require "bard/target"
83
- @target_methods.each do |method_name, block|
84
- Target.define_method(method_name, &block)
85
- end
86
- end
87
-
88
- def apply_config_methods!
89
- return if @config_methods.empty?
90
- require "bard/config"
91
- @config_methods.each do |method_name, block|
92
- Config.define_method(method_name, &block)
93
- end
94
- end
95
-
96
- def resolve_constant(name)
97
- name.split("::").reduce(Object) { |mod, const| mod.const_get(const) }
98
- end
99
- end
100
- end
@@ -1,19 +0,0 @@
1
- require "bard/plugin"
2
-
3
- Bard::Plugin.register :backup do
4
- config_method :backup do |value = nil, &block|
5
- if block
6
- @backup = Bard::BackupConfig.new(&block)
7
- elsif value == false
8
- @backup = Bard::BackupConfig.new { disabled }
9
- elsif value.nil? # Getter
10
- @backup ||= Bard::BackupConfig.new { bard }
11
- else
12
- raise ArgumentError, "backup accepts false or a block"
13
- end
14
- end
15
-
16
- config_method :backup_enabled? do
17
- backup == true
18
- end
19
- end
@@ -1,34 +0,0 @@
1
- require "bard/plugin"
2
-
3
- # Load the deploy strategy (auto-registers via inherited hook)
4
- require "bard/deploy_strategy/github_pages"
5
-
6
- Bard::Plugin.register :github_pages do
7
- # Config DSL: github_pages "url" sets up a production target
8
- config_method :github_pages do |url|
9
- urls = []
10
- uri = url.start_with?("http") ? URI.parse(url) : URI.parse("https://#{url}")
11
- hostname = uri.hostname.sub(/^www\./, "")
12
- urls = [hostname]
13
- urls << "www.#{hostname}" if hostname.count(".") < 2
14
-
15
- target :production do
16
- github_pages url
17
- ssh false
18
- ping(*urls) if urls.any?
19
- end
20
-
21
- backup false
22
- end
23
-
24
- # Target DSL: github_pages sets deploy strategy
25
- target_method :github_pages do |url = nil|
26
- if url.nil?
27
- @github_pages_url
28
- else
29
- @deploy_strategy = :github_pages
30
- @github_pages_url = url
31
- enable_capability(:github_pages)
32
- end
33
- end
34
- end
@@ -1,5 +0,0 @@
1
- require "bard/plugin"
2
-
3
- Bard::Plugin.register :hurt do
4
- cli "Bard::CLI::Hurt", require: "bard/cli/hurt"
5
- end
@@ -1,5 +0,0 @@
1
- require "bard/plugin"
2
-
3
- Bard::Plugin.register :install do
4
- cli "Bard::CLI::Install", require: "bard/cli/install"
5
- end
@@ -1,6 +0,0 @@
1
- require "bard/plugin"
2
-
3
- Bard::Plugin.register :jenkins do
4
- # Jenkins CI runner - auto-registers via inherited hook when loaded
5
- require_file "bard/ci/jenkins"
6
- end
@@ -1,5 +0,0 @@
1
- require "bard/plugin"
2
-
3
- Bard::Plugin.register :new do
4
- cli "Bard::CLI::New", require: "bard/cli/new"
5
- end