bard 2.0.0.beta → 2.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 (174) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +6 -1
  3. data/CLAUDE.md +76 -0
  4. data/MIGRATION_GUIDE.md +24 -9
  5. data/PLUGINS.md +99 -0
  6. data/README.md +14 -6
  7. data/Rakefile +3 -1
  8. data/bard.gemspec +2 -1
  9. data/cucumber.yml +1 -0
  10. data/features/ci.feature +63 -0
  11. data/features/data.feature +13 -0
  12. data/features/deploy.feature +14 -0
  13. data/features/deploy_git_workflow.feature +89 -0
  14. data/features/run.feature +14 -0
  15. data/features/step_definitions/bard_steps.rb +136 -0
  16. data/features/support/bard-coverage +16 -0
  17. data/features/support/env.rb +14 -39
  18. data/features/support/test_server.rb +216 -0
  19. data/lib/bard/cli.rb +14 -31
  20. data/lib/bard/command.rb +10 -69
  21. data/lib/bard/config.rb +40 -183
  22. data/lib/bard/copy.rb +28 -103
  23. data/lib/bard/plugins/data.rb +56 -0
  24. data/lib/bard/{ci → plugins/deploy/ci}/github_actions.rb +3 -4
  25. data/lib/bard/plugins/deploy/ci/jenkins.rb +176 -0
  26. data/lib/bard/{ci → plugins/deploy/ci}/local.rb +7 -7
  27. data/lib/bard/{ci → plugins/deploy/ci}/runner.rb +38 -4
  28. data/lib/bard/plugins/deploy/ci.rb +38 -0
  29. data/lib/bard/plugins/deploy/ssh_strategy.rb +27 -0
  30. data/lib/bard/{deploy_strategy.rb → plugins/deploy/strategy.rb} +1 -1
  31. data/lib/bard/plugins/deploy.rb +240 -0
  32. data/lib/bard/{git.rb → plugins/git.rb} +6 -3
  33. data/lib/bard/{github.rb → plugins/github.rb} +4 -6
  34. data/lib/bard/{deploy_strategy/github_pages.rb → plugins/github_pages/strategy.rb} +13 -6
  35. data/lib/bard/plugins/github_pages.rb +30 -0
  36. data/lib/bard/plugins/hurt.rb +13 -0
  37. data/{install_files → lib/bard/plugins/install}/.github/dependabot.yml +2 -1
  38. data/{install_files → lib/bard/plugins/install}/.github/workflows/cache-ci.yml +1 -1
  39. data/{install_files → lib/bard/plugins/install}/.github/workflows/ci.yml +2 -2
  40. data/lib/bard/plugins/install.rb +9 -0
  41. data/lib/bard/plugins/open.rb +20 -0
  42. data/lib/bard/{ping.rb → plugins/ping/check.rb} +4 -4
  43. data/lib/bard/plugins/ping/target_methods.rb +23 -0
  44. data/lib/bard/plugins/ping.rb +10 -0
  45. data/lib/bard/plugins/run.rb +19 -0
  46. data/lib/bard/plugins/setup.rb +54 -0
  47. data/lib/bard/plugins/ssh/connection.rb +75 -0
  48. data/lib/bard/plugins/ssh/copy.rb +95 -0
  49. data/lib/bard/{ssh_server.rb → plugins/ssh/server.rb} +17 -42
  50. data/lib/bard/plugins/ssh/target_methods.rb +20 -0
  51. data/lib/bard/plugins/ssh.rb +10 -0
  52. data/lib/bard/plugins/url/target_methods.rb +23 -0
  53. data/lib/bard/plugins/url.rb +1 -0
  54. data/lib/bard/plugins/vim.rb +6 -0
  55. data/lib/bard/retryable.rb +25 -0
  56. data/lib/bard/secrets.rb +10 -0
  57. data/lib/bard/target.rb +27 -185
  58. data/lib/bard/version.rb +1 -1
  59. data/lib/bard.rb +1 -3
  60. data/spec/acceptance/docker/Dockerfile +3 -2
  61. data/spec/bard/capability_spec.rb +8 -50
  62. data/spec/bard/ci/github_actions_spec.rb +117 -14
  63. data/spec/bard/ci/jenkins_spec.rb +139 -0
  64. data/spec/bard/ci/runner_spec.rb +61 -0
  65. data/spec/bard/ci_spec.rb +1 -1
  66. data/spec/bard/cli/ci_spec.rb +34 -27
  67. data/spec/bard/cli/data_spec.rb +7 -26
  68. data/spec/bard/cli/deploy_spec.rb +87 -46
  69. data/spec/bard/cli/hurt_spec.rb +3 -9
  70. data/spec/bard/cli/install_spec.rb +5 -11
  71. data/spec/bard/cli/master_key_spec.rb +5 -19
  72. data/spec/bard/cli/open_spec.rb +14 -30
  73. data/spec/bard/cli/ping_spec.rb +8 -23
  74. data/spec/bard/cli/run_spec.rb +27 -21
  75. data/spec/bard/cli/setup_spec.rb +10 -27
  76. data/spec/bard/cli/ssh_spec.rb +10 -25
  77. data/spec/bard/cli/stage_spec.rb +28 -23
  78. data/spec/bard/cli/vim_spec.rb +3 -9
  79. data/spec/bard/command_spec.rb +1 -8
  80. data/spec/bard/config_spec.rb +78 -98
  81. data/spec/bard/copy_spec.rb +54 -18
  82. data/spec/bard/deploy_strategy/ssh_spec.rb +65 -7
  83. data/spec/bard/deploy_strategy_spec.rb +1 -1
  84. data/spec/bard/dynamic_dsl_spec.rb +18 -98
  85. data/spec/bard/git_spec.rb +9 -5
  86. data/spec/bard/github_spec.rb +2 -2
  87. data/spec/bard/ping_spec.rb +5 -5
  88. data/spec/bard/ssh_copy_spec.rb +44 -0
  89. data/spec/bard/ssh_server_spec.rb +8 -101
  90. data/spec/bard/target_spec.rb +66 -109
  91. data/spec/spec_helper.rb +6 -1
  92. metadata +79 -143
  93. data/README.rdoc +0 -15
  94. data/features/bard_check.feature +0 -94
  95. data/features/bard_deploy.feature +0 -18
  96. data/features/bard_pull.feature +0 -112
  97. data/features/bard_push.feature +0 -112
  98. data/features/podman_testcontainers.feature +0 -16
  99. data/features/step_definitions/check_steps.rb +0 -47
  100. data/features/step_definitions/git_steps.rb +0 -73
  101. data/features/step_definitions/global_steps.rb +0 -56
  102. data/features/step_definitions/podman_steps.rb +0 -23
  103. data/features/step_definitions/rails_steps.rb +0 -44
  104. data/features/step_definitions/submodule_steps.rb +0 -110
  105. data/features/support/grit_ext.rb +0 -13
  106. data/features/support/io.rb +0 -32
  107. data/features/support/podman.rb +0 -153
  108. data/lib/bard/ci/jenkins.rb +0 -105
  109. data/lib/bard/ci/retryable.rb +0 -27
  110. data/lib/bard/ci.rb +0 -50
  111. data/lib/bard/cli/ci.rb +0 -66
  112. data/lib/bard/cli/command.rb +0 -26
  113. data/lib/bard/cli/data.rb +0 -45
  114. data/lib/bard/cli/deploy.rb +0 -85
  115. data/lib/bard/cli/hurt.rb +0 -20
  116. data/lib/bard/cli/install.rb +0 -16
  117. data/lib/bard/cli/master_key.rb +0 -17
  118. data/lib/bard/cli/new.rb +0 -101
  119. data/lib/bard/cli/new_rails_template.rb +0 -197
  120. data/lib/bard/cli/open.rb +0 -22
  121. data/lib/bard/cli/ping.rb +0 -18
  122. data/lib/bard/cli/provision.rb +0 -34
  123. data/lib/bard/cli/run.rb +0 -24
  124. data/lib/bard/cli/setup.rb +0 -56
  125. data/lib/bard/cli/ssh.rb +0 -14
  126. data/lib/bard/cli/stage.rb +0 -27
  127. data/lib/bard/cli/vim.rb +0 -13
  128. data/lib/bard/default_config.rb +0 -35
  129. data/lib/bard/deploy_strategy/ssh.rb +0 -19
  130. data/lib/bard/github_pages.rb +0 -134
  131. data/lib/bard/provision/app.rb +0 -10
  132. data/lib/bard/provision/apt.rb +0 -16
  133. data/lib/bard/provision/authorizedkeys.rb +0 -25
  134. data/lib/bard/provision/data.rb +0 -27
  135. data/lib/bard/provision/deploy.rb +0 -10
  136. data/lib/bard/provision/http.rb +0 -16
  137. data/lib/bard/provision/logrotation.rb +0 -30
  138. data/lib/bard/provision/masterkey.rb +0 -18
  139. data/lib/bard/provision/mysql.rb +0 -22
  140. data/lib/bard/provision/passenger.rb +0 -37
  141. data/lib/bard/provision/repo.rb +0 -72
  142. data/lib/bard/provision/rvm.rb +0 -22
  143. data/lib/bard/provision/ssh.rb +0 -72
  144. data/lib/bard/provision/swapfile.rb +0 -21
  145. data/lib/bard/provision/user.rb +0 -42
  146. data/lib/bard/provision.rb +0 -16
  147. data/lib/bard/server.rb +0 -117
  148. data/spec/bard/cli/command_spec.rb +0 -50
  149. data/spec/bard/cli/new_spec.rb +0 -73
  150. data/spec/bard/cli/provision_spec.rb +0 -42
  151. data/spec/bard/github_pages_spec.rb +0 -143
  152. data/spec/bard/provision/app_spec.rb +0 -33
  153. data/spec/bard/provision/apt_spec.rb +0 -39
  154. data/spec/bard/provision/authorizedkeys_spec.rb +0 -40
  155. data/spec/bard/provision/data_spec.rb +0 -54
  156. data/spec/bard/provision/deploy_spec.rb +0 -33
  157. data/spec/bard/provision/http_spec.rb +0 -57
  158. data/spec/bard/provision/logrotation_spec.rb +0 -34
  159. data/spec/bard/provision/masterkey_spec.rb +0 -63
  160. data/spec/bard/provision/mysql_spec.rb +0 -55
  161. data/spec/bard/provision/passenger_spec.rb +0 -81
  162. data/spec/bard/provision/repo_spec.rb +0 -208
  163. data/spec/bard/provision/rvm_spec.rb +0 -49
  164. data/spec/bard/provision/ssh_spec.rb +0 -229
  165. data/spec/bard/provision/swapfile_spec.rb +0 -32
  166. data/spec/bard/provision/user_spec.rb +0 -103
  167. data/spec/bard/provision_spec.rb +0 -28
  168. data/spec/bard/server_spec.rb +0 -127
  169. /data/lib/bard/{ci → plugins/deploy/ci}/state.rb +0 -0
  170. /data/{install_files → lib/bard/plugins/install}/apt_dependencies.rb +0 -0
  171. /data/{install_files → lib/bard/plugins/install}/ci +0 -0
  172. /data/{install_files → lib/bard/plugins/install}/setup +0 -0
  173. /data/{install_files → lib/bard/plugins/install}/specified_bundler.rb +0 -0
  174. /data/{install_files → lib/bard/plugins/install}/specified_ruby.rb +0 -0
@@ -1,27 +1,14 @@
1
1
  require "spec_helper"
2
2
  require "bard/cli"
3
- require "bard/cli/ssh"
4
- require "thor"
5
3
 
6
- class TestSSHCLI < Thor
7
- include Bard::CLI::SSH
8
-
9
- attr_reader :config, :options
10
-
11
- def initialize
12
- super
13
- @config = {}
14
- @options = {}
15
- end
16
- end
17
-
18
- describe Bard::CLI::SSH do
19
- let(:server) { double("server") }
20
- let(:config) { { production: server } }
21
- let(:cli) { TestSSHCLI.new }
4
+ describe "bard ssh" do
5
+ let(:target) { double("target") }
6
+ let(:config) { { production: target } }
7
+ let(:cli) { Bard::CLI.new }
22
8
 
23
9
  before do
24
10
  allow(cli).to receive(:config).and_return(config)
11
+ allow(cli).to receive(:options).and_return({ home: false })
25
12
  end
26
13
 
27
14
  describe "#ssh" do
@@ -29,27 +16,25 @@ describe Bard::CLI::SSH do
29
16
  expect(cli).to respond_to(:ssh)
30
17
  end
31
18
 
32
- it "should execute shell on production server by default" do
33
- allow(cli).to receive(:options).and_return({ home: false })
34
- expect(server).to receive(:exec!).with("exec $SHELL -l", home: false)
19
+ it "should execute shell on production target by default" do
20
+ expect(target).to receive(:exec!).with("exec $SHELL -l", home: false)
35
21
 
36
22
  cli.ssh
37
23
  end
38
24
 
39
25
  it "should execute shell with home option when specified" do
40
26
  allow(cli).to receive(:options).and_return({ home: true })
41
- expect(server).to receive(:exec!).with("exec $SHELL -l", home: true)
27
+ expect(target).to receive(:exec!).with("exec $SHELL -l", home: true)
42
28
 
43
29
  cli.ssh
44
30
  end
45
31
 
46
- it "should connect to specified server" do
32
+ it "should connect to specified target" do
47
33
  staging_server = double("staging")
48
34
  allow(config).to receive(:[]).with(:staging).and_return(staging_server)
49
- allow(cli).to receive(:options).and_return({ home: false })
50
35
  expect(staging_server).to receive(:exec!).with("exec $SHELL -l", home: false)
51
36
 
52
37
  cli.ssh(:staging)
53
38
  end
54
39
  end
55
- end
40
+ end
@@ -1,24 +1,13 @@
1
1
  require "spec_helper"
2
2
  require "bard/cli"
3
- require "bard/cli/stage"
4
- require "thor"
5
3
 
6
- class TestStageCLI < Thor
7
- include Bard::CLI::Stage
8
-
9
- attr_reader :config
10
-
11
- def initialize
12
- super
13
- @config = nil
14
- end
15
- end
16
-
17
- describe Bard::CLI::Stage do
18
- let(:staging_server) { double("staging") }
19
- let(:servers) { { production: double("production"), staging: staging_server } }
20
- let(:config) { double("config", servers: servers) }
21
- let(:cli) { TestStageCLI.new }
4
+ describe "bard stage" do
5
+ let(:staging_strategy) { double("staging_strategy", deploy: true) }
6
+ let(:staging_server) { double("staging", deploy_strategy: :ssh, deploy_strategy_instance: staging_strategy) }
7
+ let(:production_server) { double("production") }
8
+ let(:targets) { { production: production_server, staging: staging_server } }
9
+ let(:config) { double("config", targets: targets) }
10
+ let(:cli) { Bard::CLI.new }
22
11
 
23
12
  before do
24
13
  allow(cli).to receive(:config).and_return(config)
@@ -31,6 +20,7 @@ describe Bard::CLI::Stage do
31
20
  allow(cli).to receive(:yellow).and_return("")
32
21
  allow(Bard::Git).to receive(:current_branch).and_return("main")
33
22
  allow(config).to receive(:[]).with(:staging).and_return(staging_server)
23
+ allow(config).to receive(:[]).with(:production).and_return(production_server)
34
24
  end
35
25
 
36
26
  describe "#stage" do
@@ -41,7 +31,7 @@ describe Bard::CLI::Stage do
41
31
  context "when production server is defined" do
42
32
  it "pushes branch and stages it" do
43
33
  expect(cli).to receive(:run!).with("git push -u origin main", verbose: true)
44
- expect(staging_server).to receive(:run!).with("git fetch && git checkout -f origin/main && bin/setup")
34
+ expect(staging_strategy).to receive(:deploy)
45
35
  expect(cli).to receive(:ping).with(:staging)
46
36
 
47
37
  cli.stage
@@ -49,14 +39,29 @@ describe Bard::CLI::Stage do
49
39
 
50
40
  it "accepts custom branch" do
51
41
  expect(cli).to receive(:run!).with("git push -u origin develop", verbose: true)
52
- expect(staging_server).to receive(:run!).with("git fetch && git checkout -f origin/develop && bin/setup")
42
+ expect(staging_strategy).to receive(:deploy)
53
43
 
54
44
  cli.stage("develop")
55
45
  end
56
46
  end
57
47
 
58
- context "when production server is not defined" do
59
- let(:servers) { { staging: staging_server } }
48
+ context "when staging target has a deploy strategy" do
49
+ let(:strategy_instance) { double("strategy") }
50
+ let(:staging_server) { double("staging", deploy_strategy: :fake, deploy_strategy_instance: strategy_instance) }
51
+
52
+ it "uses the deploy strategy" do
53
+ expect(cli).to receive(:run!).with("git push -u origin main", verbose: true)
54
+ expect(strategy_instance).to receive(:deploy)
55
+ expect(cli).to receive(:ping).with(:staging)
56
+
57
+ cli.stage
58
+ end
59
+ end
60
+
61
+ context "when production target is equivalent to staging" do
62
+ before do
63
+ allow(config).to receive(:[]).with(:production).and_return(staging_server)
64
+ end
60
65
 
61
66
  it "raises an error" do
62
67
  expect { cli.stage }.to raise_error(Thor::Error, /bard stage.*is disabled/)
@@ -74,4 +79,4 @@ describe Bard::CLI::Stage do
74
79
  end
75
80
  end
76
81
  end
77
- end
82
+ end
@@ -1,14 +1,8 @@
1
1
  require "spec_helper"
2
2
  require "bard/cli"
3
- require "bard/cli/vim"
4
- require "thor"
5
3
 
6
- class TestVimCLI < Thor
7
- include Bard::CLI::Vim
8
- end
9
-
10
- describe Bard::CLI::Vim do
11
- let(:cli) { TestVimCLI.new }
4
+ describe "bard vim" do
5
+ let(:cli) { Bard::CLI.new }
12
6
 
13
7
  before do
14
8
  allow(cli).to receive(:exec)
@@ -31,4 +25,4 @@ describe Bard::CLI::Vim do
31
25
  cli.vim("develop")
32
26
  end
33
27
  end
34
- end
28
+ end
@@ -2,18 +2,11 @@ require "spec_helper"
2
2
  require "bard/command"
3
3
 
4
4
  describe Bard::Command do
5
- let(:remote) { double("remote", to_sym: :remote, ssh: true, env: nil, path: "/path/to", ssh_key: nil, ssh_uri: "user@example.com", gateway: nil) }
6
-
7
5
  describe ".run" do
8
6
  it "should run a command locally" do
9
7
  expect(Open3).to receive(:capture3).with("ls -l").and_return(["output", "", 0])
10
8
  Bard::Command.run "ls -l"
11
9
  end
12
-
13
- it "should run a command on a remote server" do
14
- expect(Open3).to receive(:capture3).with("ssh -tt user@example.com 'cd /path/to && ls -l'").and_return(["output", "", 0])
15
- Bard::Command.run "ls -l", on: remote
16
- end
17
10
  end
18
11
 
19
12
  describe ".run!" do
@@ -30,7 +23,7 @@ describe Bard::Command do
30
23
 
31
24
  describe ".exec!" do
32
25
  it "should exec a command locally" do
33
- expect_any_instance_of(Bard::Command).to receive(:exec).with("ls -l")
26
+ expect(Kernel).to receive(:exec).with("ls -l")
34
27
  Bard::Command.exec! "ls -l"
35
28
  end
36
29
  end
@@ -1,6 +1,51 @@
1
1
  require "bard/config"
2
+ require "bard/plugins/ssh/target_methods"
3
+ require "bard/plugins/data"
4
+ require "bard/plugins/github_pages"
2
5
 
3
6
  describe Bard::Config do
7
+ describe ".detect_project_name" do
8
+ let(:tmpdir) { Dir.mktmpdir("bard-detect-test") }
9
+ after { FileUtils.rm_rf(tmpdir) }
10
+
11
+ def init_repo(path)
12
+ FileUtils.mkdir_p(path)
13
+ Dir.chdir(path) do
14
+ system("git init -q")
15
+ system("git commit --allow-empty -q -m init")
16
+ end
17
+ end
18
+
19
+ it "returns the repo dir basename when run from the main checkout" do
20
+ repo = File.join(tmpdir, "myproject")
21
+ init_repo(repo)
22
+
23
+ Dir.chdir(repo) do
24
+ expect(described_class.detect_project_name).to eq("myproject")
25
+ end
26
+ end
27
+
28
+ it "returns the main repo basename when run from a sibling worktree" do
29
+ repo = File.join(tmpdir, "myproject")
30
+ init_repo(repo)
31
+ Dir.chdir(repo) { system("git worktree add -q ../wt-feature -b feature") }
32
+
33
+ Dir.chdir(File.join(tmpdir, "wt-feature")) do
34
+ expect(described_class.detect_project_name).to eq("myproject")
35
+ end
36
+ end
37
+
38
+ it "returns the main repo basename when run from a nested worktree" do
39
+ repo = File.join(tmpdir, "myproject")
40
+ init_repo(repo)
41
+ Dir.chdir(repo) { system("git worktree add -q tmp/worktrees/wt-feature -b feature") }
42
+
43
+ Dir.chdir(File.join(repo, "tmp/worktrees/wt-feature")) do
44
+ expect(described_class.detect_project_name).to eq("myproject")
45
+ end
46
+ end
47
+ end
48
+
4
49
  context "empty" do
5
50
  subject { described_class.new("tracker") }
6
51
 
@@ -10,15 +55,22 @@ describe Bard::Config do
10
55
  end
11
56
  end
12
57
 
13
- describe "#servers" do
14
- it "is prefilled with many servers" do
15
- expect(subject.servers.keys).to eq %i[local gubs ci staging]
58
+ describe "#targets" do
59
+ it "is prefilled with default targets" do
60
+ expect(subject.targets.keys).to eq %i[local gubs ci staging production]
61
+ end
62
+
63
+ it "creates Target instances for defaults" do
64
+ subject.targets.each_value do |target|
65
+ expect(target).to be_a(Bard::Target)
66
+ end
16
67
  end
17
68
  end
18
69
 
19
70
  describe "#[]" do
20
- it "promotes staging to production when production doesn't exist" do
71
+ it "defines a default production target equivalent to staging" do
21
72
  expect(subject[:production]).to eq subject[:staging]
73
+ expect(subject[:production]).not_to equal subject[:staging]
22
74
  end
23
75
  end
24
76
 
@@ -27,26 +79,16 @@ describe Bard::Config do
27
79
  expect(subject.data).to eq []
28
80
  end
29
81
  end
30
-
31
- describe "#backup" do
32
- it "returns a BackupConfig with bard enabled by default" do
33
- backup = subject.backup
34
- expect(backup).to be_a(Bard::BackupConfig)
35
- expect(backup.bard?).to eq true
36
- expect(backup.destinations).to be_empty
37
- end
38
- end
39
82
  end
40
83
 
41
84
  context "with production definition" do
42
85
  subject { described_class.new("tracker", source: <<~SOURCE) }
43
- server :production do
86
+ target :production do
44
87
  ssh "www@ssh.botandrose.com:22022"
45
- ping "tracker.botandrose.com"
88
+ url "tracker.botandrose.com"
46
89
  end
47
90
 
48
91
  data "public/system", "public/ckeditor"
49
- backup false
50
92
  SOURCE
51
93
 
52
94
  describe "#project_name" do
@@ -55,18 +97,18 @@ describe Bard::Config do
55
97
  end
56
98
  end
57
99
 
58
- describe "#servers" do
59
- it "contains the defined server" do
60
- expect(subject.servers.keys).to eq %i[local gubs ci staging production]
100
+ describe "#targets" do
101
+ it "contains the defined target" do
102
+ expect(subject.targets.keys).to eq %i[local gubs ci staging production]
61
103
  end
62
104
  end
63
105
 
64
- describe "#server" do
106
+ describe "#target" do
65
107
  it "can overwrite existing definition" do
66
- subject.server :staging do
108
+ subject.target :staging do
67
109
  ssh "www@tracker-staging.botandrose.com:22022"
68
110
  end
69
- expect(subject[:staging].ssh).to eq "www@tracker-staging.botandrose.com:22022"
111
+ expect(subject[:staging].server.to_s).to eq "www@tracker-staging.botandrose.com:22022"
70
112
  end
71
113
  end
72
114
 
@@ -75,96 +117,34 @@ describe Bard::Config do
75
117
  expect(subject.data).to eq ["public/system", "public/ckeditor"]
76
118
  end
77
119
  end
78
-
79
- describe "#backup" do
80
- it "returns the backup setting" do
81
- expect(subject.backup).to be_disabled
82
- end
83
- end
84
120
  end
85
121
 
86
- context "with new backup block syntax" do
87
- describe "#backup with bard directive" do
88
- subject { described_class.new("test", source: "backup { bard }") }
89
-
90
- it "returns a BackupConfig with bard enabled" do
91
- backup = subject.backup
92
- expect(backup).to be_a(Bard::BackupConfig)
93
- expect(backup.bard?).to eq true
94
- expect(backup.destinations).to be_empty
95
- expect(backup.self_managed?).to eq false
96
- end
97
- end
98
-
99
- describe "#backup with s3 directive" do
100
- subject { described_class.new("test", source: "backup { s3 :primary, path: 'bucket/path' }") }
101
-
102
- it "returns a BackupConfig with s3 destination" do
103
- backup = subject.backup
104
- expect(backup).to be_a(Bard::BackupConfig)
105
- expect(backup.bard?).to eq false
106
- expect(backup.destinations.length).to eq 1
107
- expect(backup.self_managed?).to eq true
108
-
109
- dest = backup.destinations.first
110
- expect(dest[:name]).to eq :primary
111
- expect(dest[:type]).to eq :s3
112
- expect(dest[:path]).to eq 'bucket/path'
113
- end
114
- end
115
-
116
- describe "#backup with both bard and s3 directives" do
117
- subject { described_class.new("test", source: "backup { bard; s3 :custom, path: 'bucket/path' }") }
118
-
119
- it "returns a BackupConfig with bard and s3 destination" do
120
- backup = subject.backup
121
- expect(backup).to be_a(Bard::BackupConfig)
122
- expect(backup.bard?).to eq true
123
- expect(backup.destinations.length).to eq 1
124
- expect(backup.self_managed?).to eq true
125
- end
126
- end
127
-
128
- describe "#backup with multiple s3 destinations" do
129
- subject do
130
- described_class.new("test", source: <<~SOURCE)
131
- backup do
132
- s3 :primary, path: 'bucket1/path'
133
- s3 :secondary, path: 'bucket2/path'
134
- end
135
- SOURCE
122
+ context "with remove_target" do
123
+ subject { described_class.new("tracker", source: <<~SOURCE) }
124
+ remove_target :staging
125
+ target :staging do
126
+ ssh "deploy@new-host.com"
136
127
  end
128
+ SOURCE
137
129
 
138
- it "returns a BackupConfig with multiple destinations" do
139
- backup = subject.backup
140
- expect(backup).to be_a(Bard::BackupConfig)
141
- expect(backup.bard?).to eq false
142
- expect(backup.destinations.length).to eq 2
143
- expect(backup.self_managed?).to eq true
144
-
145
- expect(backup.destinations[0][:name]).to eq :primary
146
- expect(backup.destinations[1][:name]).to eq :secondary
147
- end
130
+ it "replaces the default with a fresh target" do
131
+ staging = subject[:staging]
132
+ expect(staging).to be_a(Bard::Target)
133
+ expect(staging.ssh.to_s).to eq "deploy@new-host.com"
134
+ expect(staging.url).to eq "https://new-host.com"
148
135
  end
149
136
  end
150
137
 
151
138
  context "with github_pages directive" do
152
139
  subject { described_class.new("test", source: "github_pages 'example.com'") }
153
140
 
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
141
+ describe "#target" do
142
+ it "creates a production target with github_pages enabled" do
162
143
  production = subject[:production]
163
144
  expect(production).not_to be_nil
164
145
  expect(production.github_pages).to eq "example.com"
165
- expect(production.ssh).to eq false
146
+ expect(production.ssh).to be_nil
166
147
  end
167
148
  end
168
149
  end
169
150
  end
170
-
@@ -2,32 +2,68 @@ require "spec_helper"
2
2
  require "bard/copy"
3
3
 
4
4
  describe Bard::Copy do
5
- let(:production) { double("production", key: :production, scp_uri: "user@example.com:/path/to/file", rsync_uri: "user@example.com:/path/to/", gateway: nil, ssh_key: nil, path: "/path/to") }
6
- let(:local) { double("local", key: :local) }
5
+ let(:local) { double("local", key: :local, has_capability?: false) }
6
+ let(:production) { double("production", key: :production, has_capability?: true) }
7
7
 
8
- context ".file" do
9
- it "should copy a file from a remote server to the local machine" do
10
- expect(Bard::Command).to receive(:run!).with("scp user@example.com:/path/to/file path/to/file", verbose: false)
11
- Bard::Copy.file "path/to/file", from: production, to: local
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
- it "should copy a file from the local machine to a remote server" do
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
- context ".dir" do
21
- it "should copy a directory from a remote server to the local machine" do
22
- allow(production).to receive_message_chain("ssh_uri.port").and_return(22)
23
- expect(Bard::Command).to receive(:run!).with("rsync -e'ssh -p22' --delete --info=progress2 -az user@example.com:/path/to/ ./path/", verbose: false)
24
- Bard::Copy.dir "path/to", from: production, to: local
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
- it "should copy a directory from the local machine to a remote server" do
28
- allow(production).to receive_message_chain("ssh_uri.port").and_return(22)
29
- expect(Bard::Command).to receive(:run!).with("rsync -e'ssh -p22' --delete --info=progress2 -az ./path/to user@example.com:/path/to/", verbose: false)
30
- Bard::Copy.dir "path/to", from: local, to: production
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/deploy_strategy"
3
- require "bard/deploy_strategy/ssh"
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(/SSH not configured/)
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(/git pull origin master/)
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(/git pull origin main/)
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 enabled by ssh DSL method" do
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.deploy_strategy).to eq(:ssh)
122
+ expect(new_target.deploy_strategy_instance).to be_a(described_class)
65
123
  end
66
124
  end
67
125
  end
@@ -1,5 +1,5 @@
1
1
  require "spec_helper"
2
- require "bard/deploy_strategy"
2
+ require "bard/plugins/deploy/strategy"
3
3
 
4
4
  describe Bard::DeployStrategy do
5
5
  describe "auto-registration" do