bard 2.0.0.beta → 2.0.1
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/.github/workflows/ci.yml +6 -1
- data/CLAUDE.md +76 -0
- data/MIGRATION_GUIDE.md +24 -9
- data/PLUGINS.md +99 -0
- data/README.md +14 -6
- data/Rakefile +3 -1
- data/bard.gemspec +2 -1
- data/cucumber.yml +1 -0
- data/features/ci.feature +63 -0
- data/features/data.feature +13 -0
- data/features/deploy.feature +14 -0
- data/features/deploy_git_workflow.feature +89 -0
- data/features/run.feature +14 -0
- data/features/step_definitions/bard_steps.rb +136 -0
- data/features/support/bard-coverage +16 -0
- data/features/support/env.rb +14 -39
- data/features/support/test_server.rb +216 -0
- data/lib/bard/cli.rb +14 -31
- data/lib/bard/command.rb +10 -69
- data/lib/bard/config.rb +40 -183
- data/lib/bard/copy.rb +28 -103
- data/lib/bard/plugins/data.rb +56 -0
- data/lib/bard/{ci → plugins/deploy/ci}/github_actions.rb +3 -4
- data/lib/bard/plugins/deploy/ci/jenkins.rb +176 -0
- data/lib/bard/{ci → plugins/deploy/ci}/local.rb +7 -7
- data/lib/bard/{ci → plugins/deploy/ci}/runner.rb +38 -4
- data/lib/bard/plugins/deploy/ci.rb +38 -0
- data/lib/bard/plugins/deploy/ssh_strategy.rb +27 -0
- data/lib/bard/{deploy_strategy.rb → plugins/deploy/strategy.rb} +1 -1
- data/lib/bard/plugins/deploy.rb +240 -0
- data/lib/bard/{git.rb → plugins/git.rb} +6 -3
- data/lib/bard/{github.rb → plugins/github.rb} +4 -6
- data/lib/bard/{deploy_strategy/github_pages.rb → plugins/github_pages/strategy.rb} +41 -13
- data/lib/bard/plugins/github_pages.rb +30 -0
- data/lib/bard/plugins/hurt.rb +13 -0
- data/{install_files → lib/bard/plugins/install}/.github/dependabot.yml +2 -1
- data/{install_files → lib/bard/plugins/install}/.github/workflows/cache-ci.yml +1 -1
- data/{install_files → lib/bard/plugins/install}/.github/workflows/ci.yml +2 -2
- data/lib/bard/plugins/install.rb +9 -0
- data/lib/bard/plugins/open.rb +20 -0
- data/lib/bard/{ping.rb → plugins/ping/check.rb} +4 -4
- data/lib/bard/plugins/ping/target_methods.rb +23 -0
- data/lib/bard/plugins/ping.rb +10 -0
- data/lib/bard/plugins/run.rb +19 -0
- data/lib/bard/plugins/setup.rb +54 -0
- data/lib/bard/plugins/ssh/connection.rb +75 -0
- data/lib/bard/plugins/ssh/copy.rb +95 -0
- data/lib/bard/{ssh_server.rb → plugins/ssh/server.rb} +17 -42
- data/lib/bard/plugins/ssh/target_methods.rb +20 -0
- data/lib/bard/plugins/ssh.rb +10 -0
- data/lib/bard/plugins/url/target_methods.rb +23 -0
- data/lib/bard/plugins/url.rb +1 -0
- data/lib/bard/plugins/vim.rb +6 -0
- data/lib/bard/retryable.rb +25 -0
- data/lib/bard/secrets.rb +10 -0
- data/lib/bard/target.rb +27 -185
- data/lib/bard/version.rb +1 -1
- data/lib/bard.rb +1 -3
- data/spec/acceptance/docker/Dockerfile +3 -2
- data/spec/bard/capability_spec.rb +8 -50
- data/spec/bard/ci/github_actions_spec.rb +117 -14
- data/spec/bard/ci/jenkins_spec.rb +139 -0
- data/spec/bard/ci/runner_spec.rb +61 -0
- data/spec/bard/ci_spec.rb +1 -1
- data/spec/bard/cli/ci_spec.rb +34 -27
- data/spec/bard/cli/data_spec.rb +7 -26
- data/spec/bard/cli/deploy_spec.rb +87 -46
- data/spec/bard/cli/hurt_spec.rb +3 -9
- data/spec/bard/cli/install_spec.rb +5 -11
- data/spec/bard/cli/master_key_spec.rb +5 -19
- data/spec/bard/cli/open_spec.rb +14 -30
- data/spec/bard/cli/ping_spec.rb +8 -23
- data/spec/bard/cli/run_spec.rb +27 -21
- data/spec/bard/cli/setup_spec.rb +10 -27
- data/spec/bard/cli/ssh_spec.rb +10 -25
- data/spec/bard/cli/stage_spec.rb +28 -23
- data/spec/bard/cli/vim_spec.rb +3 -9
- data/spec/bard/command_spec.rb +1 -8
- data/spec/bard/config_spec.rb +78 -98
- data/spec/bard/copy_spec.rb +54 -18
- data/spec/bard/deploy_strategy/ssh_spec.rb +65 -7
- data/spec/bard/deploy_strategy_spec.rb +1 -1
- data/spec/bard/dynamic_dsl_spec.rb +18 -98
- data/spec/bard/git_spec.rb +9 -5
- data/spec/bard/github_spec.rb +2 -2
- data/spec/bard/ping_spec.rb +5 -5
- data/spec/bard/ssh_copy_spec.rb +44 -0
- data/spec/bard/ssh_server_spec.rb +8 -101
- data/spec/bard/target_spec.rb +66 -109
- data/spec/spec_helper.rb +6 -1
- metadata +79 -143
- data/README.rdoc +0 -15
- data/features/bard_check.feature +0 -94
- data/features/bard_deploy.feature +0 -18
- data/features/bard_pull.feature +0 -112
- data/features/bard_push.feature +0 -112
- data/features/podman_testcontainers.feature +0 -16
- data/features/step_definitions/check_steps.rb +0 -47
- data/features/step_definitions/git_steps.rb +0 -73
- data/features/step_definitions/global_steps.rb +0 -56
- data/features/step_definitions/podman_steps.rb +0 -23
- data/features/step_definitions/rails_steps.rb +0 -44
- data/features/step_definitions/submodule_steps.rb +0 -110
- data/features/support/grit_ext.rb +0 -13
- data/features/support/io.rb +0 -32
- data/features/support/podman.rb +0 -153
- data/lib/bard/ci/jenkins.rb +0 -105
- data/lib/bard/ci/retryable.rb +0 -27
- data/lib/bard/ci.rb +0 -50
- data/lib/bard/cli/ci.rb +0 -66
- data/lib/bard/cli/command.rb +0 -26
- data/lib/bard/cli/data.rb +0 -45
- data/lib/bard/cli/deploy.rb +0 -85
- data/lib/bard/cli/hurt.rb +0 -20
- data/lib/bard/cli/install.rb +0 -16
- data/lib/bard/cli/master_key.rb +0 -17
- data/lib/bard/cli/new.rb +0 -101
- data/lib/bard/cli/new_rails_template.rb +0 -197
- data/lib/bard/cli/open.rb +0 -22
- data/lib/bard/cli/ping.rb +0 -18
- data/lib/bard/cli/provision.rb +0 -34
- data/lib/bard/cli/run.rb +0 -24
- data/lib/bard/cli/setup.rb +0 -56
- data/lib/bard/cli/ssh.rb +0 -14
- data/lib/bard/cli/stage.rb +0 -27
- data/lib/bard/cli/vim.rb +0 -13
- data/lib/bard/default_config.rb +0 -35
- data/lib/bard/deploy_strategy/ssh.rb +0 -19
- data/lib/bard/github_pages.rb +0 -134
- data/lib/bard/provision/app.rb +0 -10
- data/lib/bard/provision/apt.rb +0 -16
- data/lib/bard/provision/authorizedkeys.rb +0 -25
- data/lib/bard/provision/data.rb +0 -27
- data/lib/bard/provision/deploy.rb +0 -10
- data/lib/bard/provision/http.rb +0 -16
- data/lib/bard/provision/logrotation.rb +0 -30
- data/lib/bard/provision/masterkey.rb +0 -18
- data/lib/bard/provision/mysql.rb +0 -22
- data/lib/bard/provision/passenger.rb +0 -37
- data/lib/bard/provision/repo.rb +0 -72
- data/lib/bard/provision/rvm.rb +0 -22
- data/lib/bard/provision/ssh.rb +0 -72
- data/lib/bard/provision/swapfile.rb +0 -21
- data/lib/bard/provision/user.rb +0 -42
- data/lib/bard/provision.rb +0 -16
- data/lib/bard/server.rb +0 -117
- data/spec/bard/cli/command_spec.rb +0 -50
- data/spec/bard/cli/new_spec.rb +0 -73
- data/spec/bard/cli/provision_spec.rb +0 -42
- data/spec/bard/github_pages_spec.rb +0 -143
- data/spec/bard/provision/app_spec.rb +0 -33
- data/spec/bard/provision/apt_spec.rb +0 -39
- data/spec/bard/provision/authorizedkeys_spec.rb +0 -40
- data/spec/bard/provision/data_spec.rb +0 -54
- data/spec/bard/provision/deploy_spec.rb +0 -33
- data/spec/bard/provision/http_spec.rb +0 -57
- data/spec/bard/provision/logrotation_spec.rb +0 -34
- data/spec/bard/provision/masterkey_spec.rb +0 -63
- data/spec/bard/provision/mysql_spec.rb +0 -55
- data/spec/bard/provision/passenger_spec.rb +0 -81
- data/spec/bard/provision/repo_spec.rb +0 -208
- data/spec/bard/provision/rvm_spec.rb +0 -49
- data/spec/bard/provision/ssh_spec.rb +0 -229
- data/spec/bard/provision/swapfile_spec.rb +0 -32
- data/spec/bard/provision/user_spec.rb +0 -103
- data/spec/bard/provision_spec.rb +0 -28
- data/spec/bard/server_spec.rb +0 -127
- /data/lib/bard/{ci → plugins/deploy/ci}/state.rb +0 -0
- /data/{install_files → lib/bard/plugins/install}/apt_dependencies.rb +0 -0
- /data/{install_files → lib/bard/plugins/install}/ci +0 -0
- /data/{install_files → lib/bard/plugins/install}/setup +0 -0
- /data/{install_files → lib/bard/plugins/install}/specified_bundler.rb +0 -0
- /data/{install_files → lib/bard/plugins/install}/specified_ruby.rb +0 -0
data/spec/bard/copy_spec.rb
CHANGED
|
@@ -2,32 +2,68 @@ require "spec_helper"
|
|
|
2
2
|
require "bard/copy"
|
|
3
3
|
|
|
4
4
|
describe Bard::Copy do
|
|
5
|
-
let(:
|
|
6
|
-
let(:
|
|
5
|
+
let(:local) { double("local", key: :local, has_capability?: false) }
|
|
6
|
+
let(:production) { double("production", key: :production, has_capability?: true) }
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
8
|
+
around do |example|
|
|
9
|
+
original_handlers = Bard::Copy.instance_variable_get(:@handlers).dup
|
|
10
|
+
example.run
|
|
11
|
+
Bard::Copy.instance_variable_set(:@handlers, original_handlers)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
describe "auto-registration" do
|
|
15
|
+
it "registers handlers via inherited hook" do
|
|
16
|
+
handler = Class.new(Bard::Copy) do
|
|
17
|
+
def self.can_handle?(from, to) = true
|
|
18
|
+
def file = "copied"
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
copy = handler.new("path", local, production, false)
|
|
22
|
+
expect(copy.file).to eq("copied")
|
|
12
23
|
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
describe ".file" do
|
|
27
|
+
it "dispatches to the handler that can handle the pair" do
|
|
28
|
+
Class.new(Bard::Copy) do
|
|
29
|
+
def self.can_handle?(from, to) = true
|
|
30
|
+
def file = "file_copied"
|
|
31
|
+
end
|
|
13
32
|
|
|
14
|
-
|
|
15
|
-
expect(Bard::Command).to receive(:run!).with("scp path/to/file user@example.com:/path/to/file", verbose: false)
|
|
16
|
-
Bard::Copy.file "path/to/file", from: local, to: production
|
|
33
|
+
expect(Bard::Copy.file("db/data.sql.gz", from: local, to: production)).to eq("file_copied")
|
|
17
34
|
end
|
|
18
35
|
end
|
|
19
36
|
|
|
20
|
-
|
|
21
|
-
it "
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
37
|
+
describe ".dir" do
|
|
38
|
+
it "dispatches to the handler that can handle the pair" do
|
|
39
|
+
Class.new(Bard::Copy) do
|
|
40
|
+
def self.can_handle?(from, to) = true
|
|
41
|
+
def dir = "dir_copied"
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
expect(Bard::Copy.dir("storage/", from: local, to: production)).to eq("dir_copied")
|
|
25
45
|
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
describe ".handler_for!" do
|
|
49
|
+
it "raises when no handler matches" do
|
|
50
|
+
expect {
|
|
51
|
+
Bard::Copy.file("file", from: local, to: local)
|
|
52
|
+
}.to raise_error(/No copy handler for local -> local/)
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
describe "#initialize" do
|
|
57
|
+
it "stores path, from, to, verbose" do
|
|
58
|
+
handler = Class.new(Bard::Copy) do
|
|
59
|
+
def self.can_handle?(from, to) = true
|
|
60
|
+
end
|
|
26
61
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
expect(
|
|
30
|
-
|
|
62
|
+
copy = handler.new("db/data.sql.gz", local, production, true)
|
|
63
|
+
expect(copy.path).to eq("db/data.sql.gz")
|
|
64
|
+
expect(copy.from).to eq(local)
|
|
65
|
+
expect(copy.to).to eq(production)
|
|
66
|
+
expect(copy.verbose).to eq(true)
|
|
31
67
|
end
|
|
32
68
|
end
|
|
33
69
|
end
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
require "spec_helper"
|
|
2
|
-
require "bard/
|
|
3
|
-
require "bard/
|
|
2
|
+
require "bard/plugins/deploy/strategy"
|
|
3
|
+
require "bard/plugins/deploy/ssh_strategy"
|
|
4
4
|
|
|
5
5
|
describe Bard::DeployStrategy::SSH do
|
|
6
6
|
let(:config) { double("config", project_name: "testapp") }
|
|
@@ -17,12 +17,12 @@ describe Bard::DeployStrategy::SSH do
|
|
|
17
17
|
strategy_without_ssh = described_class.new(target_without_ssh)
|
|
18
18
|
|
|
19
19
|
expect { strategy_without_ssh.deploy }
|
|
20
|
-
.to raise_error(/
|
|
20
|
+
.to raise_error(/ssh capability not configured/)
|
|
21
21
|
end
|
|
22
22
|
|
|
23
23
|
it "runs git pull on remote server" do
|
|
24
24
|
expect(target).to receive(:run!)
|
|
25
|
-
.with(
|
|
25
|
+
.with("git pull --ff-only origin master")
|
|
26
26
|
|
|
27
27
|
allow(target).to receive(:run!).with(/bin\/setup/)
|
|
28
28
|
|
|
@@ -42,12 +42,69 @@ describe Bard::DeployStrategy::SSH do
|
|
|
42
42
|
target.instance_variable_set(:@branch, "main")
|
|
43
43
|
|
|
44
44
|
expect(target).to receive(:run!)
|
|
45
|
-
.with(
|
|
45
|
+
.with("git pull --ff-only origin main")
|
|
46
46
|
|
|
47
47
|
allow(target).to receive(:run!).with(/bin\/setup/)
|
|
48
48
|
|
|
49
49
|
strategy.deploy
|
|
50
50
|
end
|
|
51
|
+
|
|
52
|
+
context "with force: true" do
|
|
53
|
+
it "force-checks-out the given branch on the remote server" do
|
|
54
|
+
expect(target).to receive(:run!).with("git fetch origin feature-x").ordered
|
|
55
|
+
expect(target).to receive(:run!).with("git checkout -f origin/feature-x").ordered
|
|
56
|
+
|
|
57
|
+
allow(target).to receive(:run!).with(/bin\/setup/)
|
|
58
|
+
|
|
59
|
+
strategy.deploy(branch: "feature-x", force: true)
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
context "with clone" do
|
|
64
|
+
let(:local_target) { double("local") }
|
|
65
|
+
|
|
66
|
+
before do
|
|
67
|
+
allow(config).to receive(:[]).with(:local).and_return(local_target)
|
|
68
|
+
allow(Bard::Copy).to receive(:file)
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
it "clones the repository" do
|
|
72
|
+
expect(target).to receive(:run!)
|
|
73
|
+
.with("git clone git@github.com:botandrosedesign/testapp /app", home: true)
|
|
74
|
+
allow(target).to receive(:run!).with("bin/setup")
|
|
75
|
+
allow(target).to receive(:run!).with("bard setup")
|
|
76
|
+
|
|
77
|
+
strategy.deploy(clone: "testapp")
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
it "copies master key from local" do
|
|
81
|
+
allow(target).to receive(:run!).with(/git clone/, home: true)
|
|
82
|
+
expect(Bard::Copy).to receive(:file)
|
|
83
|
+
.with("config/master.key", from: local_target, to: target)
|
|
84
|
+
allow(target).to receive(:run!).with("bin/setup")
|
|
85
|
+
allow(target).to receive(:run!).with("bard setup")
|
|
86
|
+
|
|
87
|
+
strategy.deploy(clone: "testapp")
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
it "runs bin/setup and bard setup" do
|
|
91
|
+
allow(target).to receive(:run!).with(/git clone/, home: true)
|
|
92
|
+
expect(target).to receive(:run!).with("bin/setup")
|
|
93
|
+
expect(target).to receive(:run!).with("bard setup")
|
|
94
|
+
|
|
95
|
+
strategy.deploy(clone: "testapp")
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
it "does not run git pull" do
|
|
99
|
+
allow(target).to receive(:run!).with(/git clone/, home: true)
|
|
100
|
+
allow(target).to receive(:run!).with("bin/setup")
|
|
101
|
+
allow(target).to receive(:run!).with("bard setup")
|
|
102
|
+
|
|
103
|
+
expect(target).not_to receive(:run!).with(/git pull/)
|
|
104
|
+
|
|
105
|
+
strategy.deploy(clone: "testapp")
|
|
106
|
+
end
|
|
107
|
+
end
|
|
51
108
|
end
|
|
52
109
|
|
|
53
110
|
describe "auto-registration" do
|
|
@@ -57,11 +114,12 @@ describe Bard::DeployStrategy::SSH do
|
|
|
57
114
|
end
|
|
58
115
|
|
|
59
116
|
describe "integration with target" do
|
|
60
|
-
it "is
|
|
117
|
+
it "is the default strategy when SSH is configured" do
|
|
118
|
+
require "bard/plugins/deploy"
|
|
61
119
|
new_target = Bard::Target.new(:staging, config)
|
|
62
120
|
new_target.ssh("deploy@staging.example.com:22")
|
|
63
121
|
|
|
64
|
-
expect(new_target.
|
|
122
|
+
expect(new_target.deploy_strategy_instance).to be_a(described_class)
|
|
65
123
|
end
|
|
66
124
|
end
|
|
67
125
|
end
|
|
@@ -1,118 +1,31 @@
|
|
|
1
1
|
require "spec_helper"
|
|
2
2
|
require "bard/target"
|
|
3
|
-
require "bard/
|
|
3
|
+
require "bard/plugins/deploy"
|
|
4
4
|
|
|
5
|
-
describe "
|
|
5
|
+
describe "Deploy strategy target methods" do
|
|
6
6
|
let(:config) { double("config", project_name: "testapp") }
|
|
7
7
|
let(:target) { Bard::Target.new(:production, config) }
|
|
8
8
|
|
|
9
|
-
before do
|
|
10
|
-
# Register test strategies
|
|
11
|
-
class Bard::DeployStrategy::Jets < Bard::DeployStrategy
|
|
12
|
-
def deploy
|
|
13
|
-
# test implementation
|
|
14
|
-
end
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
class Bard::DeployStrategy::Docker < Bard::DeployStrategy
|
|
18
|
-
def deploy
|
|
19
|
-
# test implementation
|
|
20
|
-
end
|
|
21
|
-
end
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
describe "method_missing for strategies" do
|
|
25
|
-
it "enables strategy when method name matches registered strategy" do
|
|
26
|
-
target.jets("https://api.example.com")
|
|
27
|
-
expect(target.deploy_strategy).to eq(:jets)
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
it "stores strategy options" do
|
|
31
|
-
target.jets("https://api.example.com", run_tests: true, env: "production")
|
|
32
|
-
options = target.strategy_options(:jets)
|
|
33
|
-
expect(options[:run_tests]).to be true
|
|
34
|
-
expect(options[:env]).to eq("production")
|
|
35
|
-
end
|
|
36
|
-
|
|
37
|
-
it "auto-configures ping URL from first argument if it's a URL" do
|
|
38
|
-
target.jets("https://api.example.com")
|
|
39
|
-
expect(target.ping_urls).to include("https://api.example.com")
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
it "works with multiple strategies" do
|
|
43
|
-
target1 = Bard::Target.new(:production, config)
|
|
44
|
-
target2 = Bard::Target.new(:staging, config)
|
|
45
|
-
|
|
46
|
-
target1.jets("https://api.example.com")
|
|
47
|
-
target2.docker("https://app.example.com")
|
|
48
|
-
|
|
49
|
-
expect(target1.deploy_strategy).to eq(:jets)
|
|
50
|
-
expect(target2.deploy_strategy).to eq(:docker)
|
|
51
|
-
end
|
|
52
|
-
|
|
53
|
-
it "raises NoMethodError for unknown methods" do
|
|
54
|
-
expect { target.unknown_method("arg") }
|
|
55
|
-
.to raise_error(NoMethodError)
|
|
56
|
-
end
|
|
57
|
-
end
|
|
58
|
-
|
|
59
|
-
describe "strategy DSL integration" do
|
|
60
|
-
it "allows chaining with other configuration methods" do
|
|
61
|
-
target.jets("https://api.example.com", run_tests: true)
|
|
62
|
-
target.ssh("deploy@example.com:22", path: "app")
|
|
63
|
-
|
|
64
|
-
expect(target.deploy_strategy).to eq(:jets)
|
|
65
|
-
expect(target.has_capability?(:ssh)).to be true
|
|
66
|
-
end
|
|
67
|
-
|
|
68
|
-
it "allows strategy configuration without ping URL" do
|
|
69
|
-
target.docker(skip_build: true)
|
|
70
|
-
options = target.strategy_options(:docker)
|
|
71
|
-
expect(options[:skip_build]).to be true
|
|
72
|
-
end
|
|
73
|
-
end
|
|
74
|
-
|
|
75
|
-
describe "#strategy_options" do
|
|
76
|
-
it "returns options for the specified strategy" do
|
|
77
|
-
target.jets("https://api.example.com", run_tests: true, env: "prod")
|
|
78
|
-
options = target.strategy_options(:jets)
|
|
79
|
-
expect(options[:run_tests]).to be true
|
|
80
|
-
expect(options[:env]).to eq("prod")
|
|
81
|
-
end
|
|
82
|
-
|
|
83
|
-
it "returns empty hash if strategy not configured" do
|
|
84
|
-
options = target.strategy_options(:unknown)
|
|
85
|
-
expect(options).to eq({})
|
|
86
|
-
end
|
|
87
|
-
|
|
88
|
-
it "filters out URL from options" do
|
|
89
|
-
target.jets("https://api.example.com", run_tests: true)
|
|
90
|
-
options = target.strategy_options(:jets)
|
|
91
|
-
expect(options[:run_tests]).to be true
|
|
92
|
-
expect(options).not_to have_key(:url)
|
|
93
|
-
end
|
|
94
|
-
end
|
|
95
|
-
|
|
96
9
|
describe "#deploy_strategy" do
|
|
97
|
-
it "returns the configured strategy symbol" do
|
|
98
|
-
target.jets("https://api.example.com")
|
|
99
|
-
expect(target.deploy_strategy).to eq(:jets)
|
|
100
|
-
end
|
|
101
|
-
|
|
102
10
|
it "returns nil if no strategy configured" do
|
|
103
11
|
expect(target.deploy_strategy).to be_nil
|
|
104
12
|
end
|
|
13
|
+
|
|
14
|
+
it "returns :ssh after ssh is configured via deploy_strategy_instance" do
|
|
15
|
+
target.ssh("deploy@example.com:22")
|
|
16
|
+
expect(target.deploy_strategy_instance).to be_a(Bard::DeployStrategy::SSH)
|
|
17
|
+
end
|
|
105
18
|
end
|
|
106
19
|
|
|
107
20
|
describe "#deploy_strategy_instance" do
|
|
108
|
-
it "
|
|
109
|
-
target.
|
|
21
|
+
it "defaults to SSH strategy when SSH capability is present" do
|
|
22
|
+
target.ssh("deploy@example.com:22")
|
|
110
23
|
instance = target.deploy_strategy_instance
|
|
111
|
-
expect(instance).to be_a(Bard::DeployStrategy::
|
|
24
|
+
expect(instance).to be_a(Bard::DeployStrategy::SSH)
|
|
112
25
|
expect(instance.target).to eq(target)
|
|
113
26
|
end
|
|
114
27
|
|
|
115
|
-
it "raises error if no strategy configured" do
|
|
28
|
+
it "raises error if no strategy configured and no SSH capability" do
|
|
116
29
|
expect { target.deploy_strategy_instance }
|
|
117
30
|
.to raise_error(/No deployment strategy configured/)
|
|
118
31
|
end
|
|
@@ -123,4 +36,11 @@ describe "Dynamic DSL Methods" do
|
|
|
123
36
|
.to raise_error(/Unknown deployment strategy: unknown/)
|
|
124
37
|
end
|
|
125
38
|
end
|
|
39
|
+
|
|
40
|
+
describe "#strategy_options" do
|
|
41
|
+
it "returns empty hash if strategy not configured" do
|
|
42
|
+
options = target.strategy_options(:unknown)
|
|
43
|
+
expect(options).to eq({})
|
|
44
|
+
end
|
|
45
|
+
end
|
|
126
46
|
end
|
data/spec/bard/git_spec.rb
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
require "spec_helper"
|
|
2
|
-
require "bard/git"
|
|
2
|
+
require "bard/plugins/git"
|
|
3
3
|
|
|
4
4
|
describe Bard::Git do
|
|
5
5
|
describe ".current_branch" do
|
|
@@ -46,14 +46,18 @@ describe Bard::Git do
|
|
|
46
46
|
|
|
47
47
|
describe ".sha_of" do
|
|
48
48
|
it "should return the sha of a ref" do
|
|
49
|
-
allow(Bard::Git).to receive(:`).with("git rev-parse ref 2>/dev/null")
|
|
50
|
-
|
|
49
|
+
allow(Bard::Git).to receive(:`).with("git rev-parse ref 2>/dev/null") {
|
|
50
|
+
`true` # sets $? to success
|
|
51
|
+
"sha\n"
|
|
52
|
+
}
|
|
51
53
|
expect(Bard::Git.sha_of("ref")).to eq("sha")
|
|
52
54
|
end
|
|
53
55
|
|
|
54
56
|
it "should return nil if the ref does not exist" do
|
|
55
|
-
allow(Bard::Git).to receive(:`).with("git rev-parse ref 2>/dev/null")
|
|
56
|
-
|
|
57
|
+
allow(Bard::Git).to receive(:`).with("git rev-parse ref 2>/dev/null") {
|
|
58
|
+
`false` # sets $? to failure
|
|
59
|
+
"ref: fatal: ambiguous argument 'ref': unknown revision or path not in the working tree.\n"
|
|
60
|
+
}
|
|
57
61
|
expect(Bard::Git.sha_of("ref")).to be_nil
|
|
58
62
|
end
|
|
59
63
|
end
|
data/spec/bard/github_spec.rb
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
require "spec_helper"
|
|
2
|
-
require "bard/github"
|
|
2
|
+
require "bard/plugins/github"
|
|
3
3
|
|
|
4
4
|
describe Bard::Github do
|
|
5
5
|
let(:github) { Bard::Github.new("test-project") }
|
|
6
6
|
|
|
7
7
|
before do
|
|
8
|
-
allow(
|
|
8
|
+
allow(Bard::Secrets).to receive(:fetch).with("github-apikey").and_return("12345")
|
|
9
9
|
end
|
|
10
10
|
|
|
11
11
|
describe "#get" do
|
data/spec/bard/ping_spec.rb
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
require "spec_helper"
|
|
2
|
-
require "bard/ping"
|
|
2
|
+
require "bard/plugins/ping/check"
|
|
3
3
|
|
|
4
4
|
describe Bard::Ping do
|
|
5
|
-
let(:
|
|
6
|
-
let(:ping) { described_class.new(
|
|
5
|
+
let(:target) { double("target", ping: ["http://example.com"]) }
|
|
6
|
+
let(:ping) { described_class.new(target) }
|
|
7
7
|
|
|
8
8
|
def success_response
|
|
9
9
|
Net::HTTPSuccess.new(1.0, "200", "OK")
|
|
@@ -13,14 +13,14 @@ describe Bard::Ping do
|
|
|
13
13
|
Net::HTTPNotFound.new(1.0, "404", "Not Found")
|
|
14
14
|
end
|
|
15
15
|
|
|
16
|
-
context "when the
|
|
16
|
+
context "when the target is reachable" do
|
|
17
17
|
it "returns an empty array" do
|
|
18
18
|
allow(ping).to receive(:http_get).and_return(success_response)
|
|
19
19
|
expect(ping.call).to be_empty
|
|
20
20
|
end
|
|
21
21
|
end
|
|
22
22
|
|
|
23
|
-
context "when the
|
|
23
|
+
context "when the target is not reachable" do
|
|
24
24
|
it "returns the url" do
|
|
25
25
|
allow(ping).to receive(:http_get).and_return(not_found_response)
|
|
26
26
|
expect(ping.call).to eq(["http://example.com"])
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
require "spec_helper"
|
|
2
|
+
require "bard/plugins/ssh/copy"
|
|
3
|
+
|
|
4
|
+
describe Bard::SSH::Copy do
|
|
5
|
+
let(:ssh_server) { double("ssh_server", gateway: nil, ssh_key: nil, port: "22", ssh_uri: double(port: 22, user: "user", host: "example.com")) }
|
|
6
|
+
let(:production) { double("production", key: :production, server: ssh_server, scp_uri: "user@example.com:/path/to/file", rsync_uri: "user@example.com:/path/to/", path: "/path/to", has_capability?: true) }
|
|
7
|
+
let(:local) { double("local", key: :local, has_capability?: false) }
|
|
8
|
+
|
|
9
|
+
describe ".can_handle?" do
|
|
10
|
+
it "handles pairs where at least one target has ssh capability" do
|
|
11
|
+
expect(Bard::SSH::Copy.can_handle?(local, production)).to be true
|
|
12
|
+
expect(Bard::SSH::Copy.can_handle?(production, local)).to be true
|
|
13
|
+
expect(Bard::SSH::Copy.can_handle?(production, production)).to be true
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
it "does not handle pairs where neither target has ssh capability" do
|
|
17
|
+
expect(Bard::SSH::Copy.can_handle?(local, local)).to be false
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
context ".file via Bard::Copy dispatch" do
|
|
22
|
+
it "should copy a file from a remote server to the local machine" do
|
|
23
|
+
expect(Bard::Command).to receive(:run!).with("scp -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o LogLevel=ERROR user@example.com:/path/to/file path/to/file", verbose: false)
|
|
24
|
+
Bard::Copy.file "path/to/file", from: production, to: local
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
it "should copy a file from the local machine to a remote server" do
|
|
28
|
+
expect(Bard::Command).to receive(:run!).with("scp -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o LogLevel=ERROR path/to/file user@example.com:/path/to/file", verbose: false)
|
|
29
|
+
Bard::Copy.file "path/to/file", from: local, to: production
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
context ".dir via Bard::Copy dispatch" do
|
|
34
|
+
it "should copy a directory from a remote server to the local machine" do
|
|
35
|
+
expect(Bard::Command).to receive(:run!).with("rsync -e'ssh -p22' --delete --info=progress2 -az user@example.com:/path/to/ ./path/", verbose: false)
|
|
36
|
+
Bard::Copy.dir "path/to", from: production, to: local
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
it "should copy a directory from the local machine to a remote server" do
|
|
40
|
+
expect(Bard::Command).to receive(:run!).with("rsync -e'ssh -p22' --delete --info=progress2 -az ./path/to user@example.com:/path/to/", verbose: false)
|
|
41
|
+
Bard::Copy.dir "path/to", from: local, to: production
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
require "spec_helper"
|
|
2
|
-
require "bard/
|
|
2
|
+
require "bard/plugins/ssh/server"
|
|
3
3
|
|
|
4
4
|
describe Bard::SSHServer do
|
|
5
5
|
describe "#initialize" do
|
|
@@ -40,14 +40,18 @@ describe Bard::SSHServer do
|
|
|
40
40
|
end
|
|
41
41
|
|
|
42
42
|
describe "#ssh_uri" do
|
|
43
|
-
it "returns
|
|
43
|
+
it "returns a URI object" do
|
|
44
44
|
server = described_class.new("deploy@example.com:22")
|
|
45
|
-
expect(server.ssh_uri).to
|
|
45
|
+
expect(server.ssh_uri).to be_a(URI::Generic)
|
|
46
|
+
expect(server.ssh_uri.scheme).to eq("ssh")
|
|
47
|
+
expect(server.ssh_uri.user).to eq("deploy")
|
|
48
|
+
expect(server.ssh_uri.host).to eq("example.com")
|
|
49
|
+
expect(server.ssh_uri.port).to eq(22)
|
|
46
50
|
end
|
|
47
51
|
|
|
48
52
|
it "includes port if non-standard" do
|
|
49
53
|
server = described_class.new("deploy@example.com:2222")
|
|
50
|
-
expect(server.ssh_uri).to eq(
|
|
54
|
+
expect(server.ssh_uri.port).to eq(2222)
|
|
51
55
|
end
|
|
52
56
|
end
|
|
53
57
|
|
|
@@ -69,101 +73,4 @@ describe Bard::SSHServer do
|
|
|
69
73
|
expect(server.connection_string).to eq("deploy@example.com")
|
|
70
74
|
end
|
|
71
75
|
end
|
|
72
|
-
|
|
73
|
-
describe "#run" do
|
|
74
|
-
let(:server) do
|
|
75
|
-
described_class.new("deploy@example.com:22", path: "/app")
|
|
76
|
-
end
|
|
77
|
-
|
|
78
|
-
it "executes command via SSH" do
|
|
79
|
-
expect(Open3).to receive(:capture3)
|
|
80
|
-
.with(/ssh.*deploy@example.com.*cd \/app && ls/)
|
|
81
|
-
.and_return(["output", "", 0])
|
|
82
|
-
|
|
83
|
-
server.run("ls")
|
|
84
|
-
end
|
|
85
|
-
|
|
86
|
-
it "includes environment variables if configured" do
|
|
87
|
-
server_with_env = described_class.new("deploy@example.com:22",
|
|
88
|
-
path: "/app",
|
|
89
|
-
env: "RAILS_ENV=production"
|
|
90
|
-
)
|
|
91
|
-
|
|
92
|
-
expect(Open3).to receive(:capture3)
|
|
93
|
-
.with(/RAILS_ENV=production/)
|
|
94
|
-
.and_return(["output", "", 0])
|
|
95
|
-
|
|
96
|
-
server_with_env.run("ls")
|
|
97
|
-
end
|
|
98
|
-
end
|
|
99
|
-
|
|
100
|
-
describe "#run!" do
|
|
101
|
-
let(:server) do
|
|
102
|
-
described_class.new("deploy@example.com:22", path: "/app")
|
|
103
|
-
end
|
|
104
|
-
|
|
105
|
-
it "executes command via SSH" do
|
|
106
|
-
expect(Open3).to receive(:capture3)
|
|
107
|
-
.with(/ssh.*deploy@example.com.*cd \/app && ls/)
|
|
108
|
-
.and_return(["output", "", 0])
|
|
109
|
-
|
|
110
|
-
server.run!("ls")
|
|
111
|
-
end
|
|
112
|
-
|
|
113
|
-
it "raises error if command fails" do
|
|
114
|
-
expect(Open3).to receive(:capture3)
|
|
115
|
-
.and_return(["", "error", 1])
|
|
116
|
-
|
|
117
|
-
expect { server.run!("false") }.to raise_error(Bard::Command::Error)
|
|
118
|
-
end
|
|
119
|
-
end
|
|
120
|
-
|
|
121
|
-
describe "#exec!" do
|
|
122
|
-
let(:server) do
|
|
123
|
-
described_class.new("deploy@example.com:22", path: "/app")
|
|
124
|
-
end
|
|
125
|
-
|
|
126
|
-
it "replaces current process with SSH command" do
|
|
127
|
-
expect(server).to receive(:exec)
|
|
128
|
-
.with(/ssh.*deploy@example.com.*cd \/app && ls/)
|
|
129
|
-
|
|
130
|
-
server.exec!("ls")
|
|
131
|
-
end
|
|
132
|
-
end
|
|
133
|
-
|
|
134
|
-
describe "path handling" do
|
|
135
|
-
it "uses path in commands if configured" do
|
|
136
|
-
server = described_class.new("deploy@example.com:22", path: "/var/www/app")
|
|
137
|
-
|
|
138
|
-
expect(Open3).to receive(:capture3)
|
|
139
|
-
.with(/cd \/var\/www\/app && ls/)
|
|
140
|
-
.and_return(["output", "", 0])
|
|
141
|
-
|
|
142
|
-
server.run("ls")
|
|
143
|
-
end
|
|
144
|
-
|
|
145
|
-
it "works without path" do
|
|
146
|
-
server = described_class.new("deploy@example.com:22")
|
|
147
|
-
|
|
148
|
-
expect(Open3).to receive(:capture3)
|
|
149
|
-
.with(/ssh.*ls/)
|
|
150
|
-
.and_return(["output", "", 0])
|
|
151
|
-
|
|
152
|
-
server.run("ls")
|
|
153
|
-
end
|
|
154
|
-
end
|
|
155
|
-
|
|
156
|
-
describe "gateway/bastion support" do
|
|
157
|
-
it "uses ProxyJump for gateway" do
|
|
158
|
-
server = described_class.new("deploy@private.example.com:22",
|
|
159
|
-
gateway: "bastion@public.example.com:22"
|
|
160
|
-
)
|
|
161
|
-
|
|
162
|
-
expect(Open3).to receive(:capture3)
|
|
163
|
-
.with(/-o ProxyJump=bastion@public.example.com:22/)
|
|
164
|
-
.and_return(["output", "", 0])
|
|
165
|
-
|
|
166
|
-
server.run("ls")
|
|
167
|
-
end
|
|
168
|
-
end
|
|
169
76
|
end
|