bard 2.2.0 → 3.0.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.
Files changed (96) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +7 -487
  3. data/Rakefile +1 -4
  4. data/bard.gemspec +2 -11
  5. data/lib/bard/config.rb +22 -20
  6. data/lib/bard/plugins/ping/target_methods.rb +0 -9
  7. data/lib/bard/plugins/ssh/connection.rb +2 -35
  8. data/lib/bard/target.rb +0 -15
  9. data/lib/bard/version.rb +1 -1
  10. data/lib/bard.rb +2 -1
  11. data/spec/bard/capability_spec.rb +0 -8
  12. data/spec/bard/config_spec.rb +30 -67
  13. data/spec/bard/target_spec.rb +1 -36
  14. metadata +4 -225
  15. data/ARCHITECTURE.md +0 -957
  16. data/CUSTOM_STRATEGIES.md +0 -701
  17. data/MIGRATION_GUIDE.md +0 -513
  18. data/PLUGINS.md +0 -99
  19. data/bin/bard +0 -4
  20. data/features/ci.feature +0 -63
  21. data/features/data.feature +0 -13
  22. data/features/deploy.feature +0 -14
  23. data/features/deploy_git_workflow.feature +0 -89
  24. data/features/run.feature +0 -14
  25. data/features/step_definitions/bard_steps.rb +0 -136
  26. data/features/support/bard-coverage +0 -16
  27. data/features/support/env.rb +0 -22
  28. data/features/support/test_server.rb +0 -216
  29. data/lib/bard/cli.rb +0 -44
  30. data/lib/bard/command.rb +0 -31
  31. data/lib/bard/copy.rb +0 -45
  32. data/lib/bard/plugins/data.rb +0 -56
  33. data/lib/bard/plugins/deploy/ci/github_actions.rb +0 -202
  34. data/lib/bard/plugins/deploy/ci/jenkins.rb +0 -176
  35. data/lib/bard/plugins/deploy/ci/local.rb +0 -57
  36. data/lib/bard/plugins/deploy/ci/runner.rb +0 -112
  37. data/lib/bard/plugins/deploy/ci/state.rb +0 -40
  38. data/lib/bard/plugins/deploy/ci.rb +0 -38
  39. data/lib/bard/plugins/deploy/ssh_strategy.rb +0 -26
  40. data/lib/bard/plugins/deploy/strategy.rb +0 -60
  41. data/lib/bard/plugins/deploy.rb +0 -260
  42. data/lib/bard/plugins/git.rb +0 -45
  43. data/lib/bard/plugins/github.rb +0 -152
  44. data/lib/bard/plugins/github_pages/strategy.rb +0 -170
  45. data/lib/bard/plugins/github_pages.rb +0 -35
  46. data/lib/bard/plugins/hurt.rb +0 -13
  47. data/lib/bard/plugins/install/.github/dependabot.yml +0 -18
  48. data/lib/bard/plugins/install/.github/workflows/cache-ci.yml +0 -15
  49. data/lib/bard/plugins/install/.github/workflows/ci.yml +0 -74
  50. data/lib/bard/plugins/install/apt_dependencies.rb +0 -33
  51. data/lib/bard/plugins/install/ci +0 -5
  52. data/lib/bard/plugins/install/setup +0 -13
  53. data/lib/bard/plugins/install/specified_bundler.rb +0 -15
  54. data/lib/bard/plugins/install/specified_ruby.rb +0 -59
  55. data/lib/bard/plugins/install.rb +0 -9
  56. data/lib/bard/plugins/open.rb +0 -20
  57. data/lib/bard/plugins/ping/check.rb +0 -66
  58. data/lib/bard/plugins/ping.rb +0 -10
  59. data/lib/bard/plugins/run.rb +0 -19
  60. data/lib/bard/plugins/setup.rb +0 -75
  61. data/lib/bard/plugins/ssh/copy.rb +0 -95
  62. data/lib/bard/plugins/ssh.rb +0 -10
  63. data/lib/bard/plugins/vim.rb +0 -6
  64. data/lib/bard/retryable.rb +0 -25
  65. data/lib/bard/secrets.rb +0 -10
  66. data/spec/acceptance/.gitignore +0 -4
  67. data/spec/acceptance/docker/Dockerfile +0 -36
  68. data/spec/acceptance/docker/test_key +0 -27
  69. data/spec/acceptance/docker/test_key.pub +0 -1
  70. data/spec/bard/ci/github_actions_spec.rb +0 -138
  71. data/spec/bard/ci/jenkins_spec.rb +0 -139
  72. data/spec/bard/ci/runner_spec.rb +0 -61
  73. data/spec/bard/ci_spec.rb +0 -10
  74. data/spec/bard/cli/ci_spec.rb +0 -170
  75. data/spec/bard/cli/data_spec.rb +0 -58
  76. data/spec/bard/cli/deploy_spec.rb +0 -243
  77. data/spec/bard/cli/hurt_spec.rb +0 -17
  78. data/spec/bard/cli/install_spec.rb +0 -19
  79. data/spec/bard/cli/master_key_spec.rb +0 -38
  80. data/spec/bard/cli/open_spec.rb +0 -51
  81. data/spec/bard/cli/ping_spec.rb +0 -32
  82. data/spec/bard/cli/run_spec.rb +0 -57
  83. data/spec/bard/cli/setup_spec.rb +0 -99
  84. data/spec/bard/cli/ssh_spec.rb +0 -40
  85. data/spec/bard/cli/stage_spec.rb +0 -127
  86. data/spec/bard/cli/vim_spec.rb +0 -28
  87. data/spec/bard/command_spec.rb +0 -30
  88. data/spec/bard/copy_spec.rb +0 -69
  89. data/spec/bard/deploy_strategy/github_pages_spec.rb +0 -58
  90. data/spec/bard/deploy_strategy/ssh_spec.rb +0 -135
  91. data/spec/bard/deploy_strategy_spec.rb +0 -107
  92. data/spec/bard/dynamic_dsl_spec.rb +0 -46
  93. data/spec/bard/git_spec.rb +0 -101
  94. data/spec/bard/github_spec.rb +0 -45
  95. data/spec/bard/ping_spec.rb +0 -60
  96. data/spec/bard/ssh_copy_spec.rb +0 -44
@@ -1,89 +0,0 @@
1
- @server
2
- Feature: bard deploy git workflow
3
- Git workflow behaviors during deploy.
4
-
5
- Background:
6
- Given a test server is running
7
-
8
- Scenario: deploy on master pushes unpushed commits
9
- Given I create a file "local-only.txt" with content "local commit"
10
- And I commit the changes with message "Add local only file"
11
- When I run: bard deploy --skip-ci
12
- Then the output should contain "Deploy Succeeded"
13
- When I run: bard run "cat local-only.txt"
14
- Then the output should contain "local commit"
15
-
16
- Scenario: feature branch fast-forward merge
17
- Given I create and switch to branch "feature-branch"
18
- And I create a file "feature.txt" with content "feature content"
19
- And I commit the changes with message "Add feature"
20
- When I run: bard deploy --skip-ci
21
- Then the output should contain "Deploy Succeeded"
22
- And I should be on branch "master"
23
- And branch "feature-branch" should not exist locally
24
- And branch "feature-branch" should not exist on origin
25
- When I run: bard run "cat feature.txt"
26
- Then the output should contain "feature content"
27
-
28
- Scenario: feature branch requires rebase
29
- Given I create and switch to branch "feature-branch"
30
- And I create a file "feature.txt" with content "feature content"
31
- And I commit the changes with message "Add feature"
32
- And master has an additional commit from another source
33
- When I run: bard deploy --skip-ci
34
- Then the output should contain "The master branch has advanced"
35
- And the output should contain "Attempting rebase"
36
- And the output should contain "Deploy Succeeded"
37
- And I should be on branch "master"
38
- When I run: bard run "cat feature.txt"
39
- Then the output should contain "feature content"
40
- When I run: bard run "cat remote-change.txt"
41
- Then the output should contain "remote change"
42
-
43
- Scenario: feature branch rebase conflict
44
- Given I create and switch to branch "feature-branch"
45
- And I create a file "conflict.txt" with content "feature content"
46
- And I commit the changes with message "Add conflicting file"
47
- And master has a conflicting commit to "conflict.txt"
48
- When I run expecting failure: bard deploy --skip-ci
49
- Then the output should contain "The master branch has advanced"
50
- And the output should contain "Attempting rebase"
51
- And the output should contain "Running command failed"
52
-
53
- Scenario: branch cleanup after deploy
54
- Given I create and switch to branch "cleanup-test"
55
- And I create a file "cleanup.txt" with content "cleanup test"
56
- And I commit the changes with message "Add cleanup test file"
57
- And I push branch "cleanup-test" to origin
58
- When I run: bard deploy --skip-ci
59
- Then the output should contain "Deleting branch: cleanup-test"
60
- And the output should contain "Deploy Succeeded"
61
- And I should be on branch "master"
62
- And branch "cleanup-test" should not exist locally
63
- And branch "cleanup-test" should not exist on origin
64
-
65
- Scenario: deploy a branch without checking it out
66
- Given I create and switch to branch "feature-branch"
67
- And I create a file "feature.txt" with content "feature content"
68
- And I commit the changes with message "Add feature"
69
- And I switch to branch "master"
70
- When I run: bard deploy feature-branch --skip-ci
71
- Then the output should contain "Deploy Succeeded"
72
- And I should be on branch "master"
73
- And branch "feature-branch" should not exist locally
74
- When I run: bard run "cat feature.txt"
75
- Then the output should contain "feature content"
76
-
77
- Scenario: deploy a branch that requires rebase without checking it out
78
- Given I create and switch to branch "feature-branch"
79
- And I create a file "feature.txt" with content "feature content"
80
- And I commit the changes with message "Add feature"
81
- And I switch to branch "master"
82
- And master has an additional commit from another source
83
- When I run: bard deploy feature-branch --skip-ci
84
- Then the output should contain "The master branch has advanced"
85
- And the output should contain "Attempting rebase"
86
- And the output should contain "Deploy Succeeded"
87
- And I should be on branch "master"
88
- When I run: bard run "cat feature.txt"
89
- Then the output should contain "feature content"
data/features/run.feature DELETED
@@ -1,14 +0,0 @@
1
- @server
2
- Feature: bard run
3
- Execute commands on a remote server.
4
-
5
- Background:
6
- Given a test server is running
7
-
8
- Scenario: executes a command on the remote server
9
- When I run: bard run "echo hello"
10
- Then the output should contain "hello"
11
-
12
- Scenario: operates in the configured path
13
- When I run: bard run "pwd"
14
- Then the output should contain "testproject"
@@ -1,136 +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
136
-
@@ -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,22 +0,0 @@
1
- require "simplecov"
2
- SimpleCov.start do
3
- command_name "Cucumber"
4
- track_files "lib/**/*.rb"
5
- add_filter "spec/"
6
- add_filter "features/"
7
- end
8
-
9
- $LOAD_PATH.unshift(File.dirname(__FILE__) + '/../../lib')
10
- require "bard"
11
- require 'rspec/expectations'
12
- require 'fileutils'
13
-
14
- ENV["PATH"] = "#{File.dirname(File.expand_path(__FILE__))}:#{ENV['PATH']}"
15
- ENV["GIT_DIR"] = nil
16
- ENV["GIT_WORK_TREE"] = nil
17
- ENV["GIT_INDEX_FILE"] = nil
18
-
19
- ROOT = File.expand_path(File.dirname(__FILE__) + '/../..')
20
-
21
- # Ensure tmp directory exists
22
- FileUtils.mkdir_p(File.join(ROOT, "tmp"))
@@ -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:24.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("@server") do
211
- start_test_server
212
- end
213
-
214
- After("@server") do
215
- stop_test_server
216
- end
data/lib/bard/cli.rb DELETED
@@ -1,44 +0,0 @@
1
- # this file gets loaded in the CLI context, not the Rails boot context
2
-
3
- require "thor"
4
- require "bard/version"
5
- require "bard/config"
6
- require "bard/command"
7
-
8
- module Bard
9
- class CLI < Thor
10
- class_option :verbose, type: :boolean, aliases: :v
11
-
12
- map "--version" => :version
13
- desc "version", "Display version"
14
- def version
15
- puts Bard::VERSION
16
- end
17
-
18
- def self.exit_on_failure? = true
19
-
20
- no_commands do
21
- def red(text) = "\e[31m#{text}\e[0m"
22
- def yellow(text) = "\e[33m#{text}\e[0m"
23
- def green(text) = "\e[32m#{text}\e[0m"
24
-
25
- def run!(...)
26
- Bard::Command.run!(...)
27
- rescue Bard::Command::Error => e
28
- puts red("!!! ") + "Running command failed: #{yellow(e.message)}"
29
- exit 1
30
- end
31
-
32
- def config
33
- @config ||= Bard::Config.current
34
- end
35
-
36
- def project_name
37
- config.project_name
38
- end
39
- end
40
-
41
- # load plugins from bard and other gems
42
- Gem.find_files("bard/plugins/*.rb").sort.each { |path| require path }
43
- end
44
- end
data/lib/bard/command.rb DELETED
@@ -1,31 +0,0 @@
1
- require "open3"
2
-
3
- module Bard
4
- module Command
5
- class Error < RuntimeError; end
6
-
7
- def self.run!(command, verbose: false, quiet: false)
8
- result = run(command, verbose:, quiet:)
9
- raise Error.new(command) unless result
10
- result
11
- end
12
-
13
- def self.run(command, verbose: false, quiet: false)
14
- if verbose
15
- system command
16
- else
17
- stdout, stderr, status = Open3.capture3(command)
18
- failed = status.to_i.nonzero?
19
- if failed && !quiet
20
- $stdout.puts stdout
21
- $stderr.puts stderr
22
- end
23
- !failed && stdout
24
- end
25
- end
26
-
27
- def self.exec!(command)
28
- Kernel.exec command
29
- end
30
- end
31
- end
data/lib/bard/copy.rb DELETED
@@ -1,45 +0,0 @@
1
- module Bard
2
- class Copy
3
- @handlers = []
4
-
5
- class << self
6
- def inherited(subclass)
7
- super
8
- @handlers.unshift(subclass)
9
- end
10
-
11
- def file(path, from:, to:, verbose: false)
12
- handler_for!(from, to).new(path, from, to, verbose).file
13
- end
14
-
15
- def dir(path, from:, to:, verbose: false)
16
- handler_for!(from, to).new(path, from, to, verbose).dir
17
- end
18
-
19
- private
20
-
21
- def handler_for!(from, to)
22
- handler = @handlers.find { |h| h.can_handle?(from, to) }
23
- raise "No copy handler for #{from.key} -> #{to.key}" unless handler
24
- handler
25
- end
26
- end
27
-
28
- attr_reader :path, :from, :to, :verbose
29
-
30
- def initialize(path, from, to, verbose)
31
- @path = path
32
- @from = from
33
- @to = to
34
- @verbose = verbose
35
- end
36
-
37
- def file
38
- raise NotImplementedError
39
- end
40
-
41
- def dir
42
- raise NotImplementedError
43
- end
44
- end
45
- end
@@ -1,56 +0,0 @@
1
- require "bard/command"
2
- require "bard/copy"
3
- require "bard/plugins/ssh"
4
- require "bard/plugins/url"
5
-
6
- class Bard::CLI
7
- option :from, default: "production"
8
- option :to, default: "local"
9
- desc "data --from=production --to=local", "copy database and assets from from to to"
10
- def data
11
- from = config[options[:from]]
12
- to = config[options[:to]]
13
-
14
- from.require_capability!(:ssh) unless from.key == :local
15
- to.require_capability!(:ssh) unless to.key == :local
16
-
17
- if to.key == :production
18
- url = to.url
19
- puts yellow "WARNING: You are about to push data to production, overwriting everything that is there!"
20
- answer = ask("If you really want to do this, please type in the full HTTPS url of the production server:")
21
- if answer != url
22
- puts red("!!! ") + "Failed! We expected #{url}. Is this really where you want to overwrite all the data?"
23
- exit 1
24
- end
25
- end
26
-
27
- puts "Dumping #{from.key} database to file..."
28
- from.run! "bin/rake db:dump"
29
-
30
- puts "Transfering file from #{from.key} to #{to.key}..."
31
- Bard::Copy.file "db/data.sql.gz", from: from, to: to, verbose: true
32
-
33
- puts "Loading file into #{to.key} database..."
34
- to.run! "bin/rake db:load"
35
-
36
- config.data.each do |path|
37
- puts "Synchronizing files in #{path}..."
38
- Bard::Copy.dir path, from: from, to: to, verbose: true
39
- end
40
- rescue Bard::Command::Error => e
41
- puts red("!!! ") + "Running command failed: #{yellow(e.message)}"
42
- exit 1
43
- end
44
- end
45
-
46
- require "bard/config"
47
-
48
- class Bard::Config
49
- def data(*paths)
50
- if paths.empty?
51
- @data_paths ||= []
52
- else
53
- @data_paths = paths
54
- end
55
- end
56
- end