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,208 +0,0 @@
1
- require "spec_helper"
2
- require "bard/provision"
3
- require "bard/provision/repo"
4
-
5
- describe Bard::Provision::Repo do
6
- let(:ssh_uri) { double("ssh_uri", user: "deploy", host: "example.com") }
7
- let(:server) { double("server", ssh_uri: ssh_uri, project_name: "test_project") }
8
- let(:config) { { production: server } }
9
- let(:ssh_url) { "deploy@example.com" }
10
- let(:provision_server) { double("provision_server") }
11
- let(:github_api) { double("github_api") }
12
- let(:repo_provisioner) { Bard::Provision::Repo.new(config, ssh_url) }
13
-
14
- before do
15
- allow(repo_provisioner).to receive(:server).and_return(server)
16
- allow(repo_provisioner).to receive(:provision_server).and_return(provision_server)
17
- allow(repo_provisioner).to receive(:print)
18
- allow(repo_provisioner).to receive(:puts)
19
- allow(Bard::Github).to receive(:new).and_return(github_api)
20
- end
21
-
22
- describe "#call" do
23
- context "when repository is already cloned" do
24
- context "when not on latest master" do
25
- it "updates to latest master" do
26
- allow(repo_provisioner).to receive(:already_cloned?).and_return(true)
27
- allow(repo_provisioner).to receive(:on_latest_master?).and_return(false)
28
-
29
- expect(repo_provisioner).to receive(:update_to_latest_master!)
30
- expect(github_api).not_to receive(:add_deploy_key)
31
-
32
- repo_provisioner.call
33
- end
34
-
35
- it "prints status message when updating to latest master" do
36
- allow(repo_provisioner).to receive(:already_cloned?).and_return(true)
37
- allow(repo_provisioner).to receive(:on_latest_master?).and_return(false)
38
- allow(repo_provisioner).to receive(:update_to_latest_master!)
39
-
40
- expect(repo_provisioner).to receive(:print).with("Repo:")
41
- expect(repo_provisioner).to receive(:print).with(" Updating to latest master,")
42
- expect(repo_provisioner).to receive(:puts).with(" ✓")
43
-
44
- repo_provisioner.call
45
- end
46
- end
47
-
48
- context "when already on latest master" do
49
- it "skips update" do
50
- allow(repo_provisioner).to receive(:already_cloned?).and_return(true)
51
- allow(repo_provisioner).to receive(:on_latest_master?).and_return(true)
52
-
53
- expect(repo_provisioner).not_to receive(:update_to_latest_master!)
54
- expect(github_api).not_to receive(:add_deploy_key)
55
-
56
- repo_provisioner.call
57
- end
58
-
59
- it "only prints repo header and checkbox" do
60
- allow(repo_provisioner).to receive(:already_cloned?).and_return(true)
61
- allow(repo_provisioner).to receive(:on_latest_master?).and_return(true)
62
-
63
- expect(repo_provisioner).to receive(:print).with("Repo:")
64
- expect(repo_provisioner).not_to receive(:print).with(" Updating to latest master,")
65
- expect(repo_provisioner).to receive(:puts).with(" ✓")
66
-
67
- repo_provisioner.call
68
- end
69
- end
70
- end
71
-
72
- context "when repository is not cloned but can be cloned" do
73
- it "clones the repository directly" do
74
- allow(repo_provisioner).to receive(:already_cloned?).and_return(false)
75
- allow(repo_provisioner).to receive(:can_clone_project?).and_return(true)
76
-
77
- expect(provision_server).to receive(:run!).with("git clone git@github.com:botandrosedesign/test_project", home: true)
78
- expect(github_api).not_to receive(:add_deploy_key)
79
-
80
- repo_provisioner.call
81
- end
82
- end
83
-
84
- context "when repository cannot be cloned and SSH keypair exists" do
85
- it "adds deploy key and clones repository" do
86
- allow(repo_provisioner).to receive(:already_cloned?).and_return(false)
87
- allow(repo_provisioner).to receive(:can_clone_project?).and_return(false)
88
- allow(repo_provisioner).to receive(:ssh_keypair?).and_return(true)
89
- allow(provision_server).to receive(:run).with("cat ~/.ssh/id_rsa.pub", home: true).and_return("ssh-rsa AAAAB3...")
90
-
91
- expect(github_api).to receive(:add_deploy_key).with(title: "deploy@example.com", key: "ssh-rsa AAAAB3...")
92
- expect(provision_server).to receive(:run!).with("git clone git@github.com:botandrosedesign/test_project", home: true)
93
-
94
- repo_provisioner.call
95
- end
96
- end
97
-
98
- context "when repository cannot be cloned and no SSH keypair exists" do
99
- it "generates keypair, adds deploy key, and clones repository" do
100
- allow(repo_provisioner).to receive(:already_cloned?).and_return(false)
101
- allow(repo_provisioner).to receive(:can_clone_project?).and_return(false)
102
- allow(repo_provisioner).to receive(:ssh_keypair?).and_return(false)
103
- allow(provision_server).to receive(:run).with("cat ~/.ssh/id_rsa.pub", home: true).and_return("ssh-rsa AAAAB3...")
104
-
105
- expect(provision_server).to receive(:run!).with('ssh-keygen -t rsa -b 2048 -f ~/.ssh/id_rsa -q -N ""', home: true)
106
- expect(github_api).to receive(:add_deploy_key).with(title: "deploy@example.com", key: "ssh-rsa AAAAB3...")
107
- expect(provision_server).to receive(:run!).with("git clone git@github.com:botandrosedesign/test_project", home: true)
108
-
109
- repo_provisioner.call
110
- end
111
-
112
- it "prints status messages during setup" do
113
- allow(repo_provisioner).to receive(:already_cloned?).and_return(false)
114
- allow(repo_provisioner).to receive(:can_clone_project?).and_return(false)
115
- allow(repo_provisioner).to receive(:ssh_keypair?).and_return(false)
116
- allow(provision_server).to receive(:run).and_return("ssh-rsa AAAAB3...")
117
- allow(provision_server).to receive(:run!)
118
- allow(github_api).to receive(:add_deploy_key)
119
-
120
- expect(repo_provisioner).to receive(:print).with("Repo:")
121
- expect(repo_provisioner).to receive(:print).with(" Generating keypair in ~/.ssh,")
122
- expect(repo_provisioner).to receive(:print).with(" Add public key to GitHub repo deploy keys,")
123
- expect(repo_provisioner).to receive(:print).with(" Cloning repo,")
124
- expect(repo_provisioner).to receive(:puts).with(" ✓")
125
-
126
- repo_provisioner.call
127
- end
128
- end
129
-
130
- it "always prints success message" do
131
- allow(repo_provisioner).to receive(:already_cloned?).and_return(true)
132
- allow(repo_provisioner).to receive(:on_latest_master?).and_return(true)
133
-
134
- expect(repo_provisioner).to receive(:print).with("Repo:")
135
- expect(repo_provisioner).to receive(:puts).with(" ✓")
136
-
137
- repo_provisioner.call
138
- end
139
- end
140
-
141
- describe "private methods" do
142
- describe "#ssh_keypair?" do
143
- it "checks if SSH public key exists" do
144
- expect(provision_server).to receive(:run).with("[ -f ~/.ssh/id_rsa.pub ]", home: true, quiet: true)
145
-
146
- repo_provisioner.send(:ssh_keypair?)
147
- end
148
- end
149
-
150
- describe "#already_cloned?" do
151
- it "checks if git directory exists" do
152
- expect(provision_server).to receive(:run).with("[ -d ~/test_project/.git ]", home: true, quiet: true)
153
-
154
- repo_provisioner.send(:already_cloned?)
155
- end
156
- end
157
-
158
- describe "#can_clone_project?" do
159
- it "tests if repository can be cloned" do
160
- expected_commands = [
161
- "needle=$(ssh-keyscan -t ed25519 github.com 2>/dev/null | cut -d \" \" -f 2-3)",
162
- "grep -q \"$needle\" ~/.ssh/known_hosts || ssh-keyscan -H github.com >> ~/.ssh/known_hosts 2>/dev/null",
163
- "git ls-remote git@github.com:botandrosedesign/test_project"
164
- ].join("; ")
165
-
166
- expect(provision_server).to receive(:run).with(expected_commands, home: true, quiet: true)
167
-
168
- repo_provisioner.send(:can_clone_project?)
169
- end
170
- end
171
-
172
- describe "#project_name" do
173
- it "returns the server's project name" do
174
- expect(repo_provisioner.send(:project_name)).to eq("test_project")
175
- end
176
- end
177
-
178
- describe "#on_latest_master?" do
179
- it "checks if current HEAD matches origin/master after fetching" do
180
- expected_command = "cd ~/test_project && git fetch origin && [ $(git rev-parse HEAD) = $(git rev-parse origin/master) ]"
181
- expect(provision_server).to receive(:run).with(expected_command, home: true, quiet: true)
182
-
183
- repo_provisioner.send(:on_latest_master?)
184
- end
185
-
186
- it "returns true when on latest master" do
187
- allow(provision_server).to receive(:run).and_return(true)
188
-
189
- expect(repo_provisioner.send(:on_latest_master?)).to be true
190
- end
191
-
192
- it "returns false when not on latest master" do
193
- allow(provision_server).to receive(:run).and_return(false)
194
-
195
- expect(repo_provisioner.send(:on_latest_master?)).to be false
196
- end
197
- end
198
-
199
- describe "#update_to_latest_master!" do
200
- it "checks out master and resets to origin/master" do
201
- expected_command = "cd ~/test_project && git checkout master && git reset --hard origin/master"
202
- expect(provision_server).to receive(:run!).with(expected_command, home: true)
203
-
204
- repo_provisioner.send(:update_to_latest_master!)
205
- end
206
- end
207
- end
208
- end
@@ -1,49 +0,0 @@
1
- require "spec_helper"
2
- require "bard/provision"
3
- require "bard/provision/rvm"
4
-
5
- describe Bard::Provision::RVM do
6
- let(:config) { { production: double("production") } }
7
- let(:ssh_url) { "user@example.com" }
8
- let(:provision_server) { double("provision_server") }
9
- let(:rvm) { Bard::Provision::RVM.new(config, ssh_url) }
10
-
11
- before do
12
- allow(rvm).to receive(:provision_server).and_return(provision_server)
13
- allow(rvm).to receive(:print)
14
- allow(rvm).to receive(:puts)
15
- allow(File).to receive(:read).with(".ruby-version").and_return("3.2.0\n")
16
- end
17
-
18
- describe "#call" do
19
- context "when RVM is not installed" do
20
- it "installs RVM and Ruby" do
21
- allow(provision_server).to receive(:run).with("[ -d ~/.rvm ]", quiet: true).and_return(false)
22
-
23
- expect(provision_server).to receive(:run!).with(/sed -i.*bashrc/)
24
- expect(provision_server).to receive(:run!).with("rvm install 3.2.0")
25
-
26
- rvm.call
27
- end
28
- end
29
-
30
- context "when RVM is already installed" do
31
- it "skips installation" do
32
- allow(provision_server).to receive(:run).with("[ -d ~/.rvm ]", quiet: true).and_return(true)
33
-
34
- expect(provision_server).not_to receive(:run!)
35
-
36
- rvm.call
37
- end
38
- end
39
-
40
- it "prints status messages" do
41
- allow(provision_server).to receive(:run).and_return(true)
42
-
43
- expect(rvm).to receive(:print).with("RVM:")
44
- expect(rvm).to receive(:puts).with(" ✓")
45
-
46
- rvm.call
47
- end
48
- end
49
- end
@@ -1,229 +0,0 @@
1
- require "spec_helper"
2
- require "bard/provision"
3
- require "bard/provision/ssh"
4
-
5
- describe Bard::Provision::SSH do
6
- let(:ssh_uri) { double("ssh_uri", host: "example.com", port: 2222) }
7
- let(:provision_ssh_uri) { double("provision_ssh_uri", host: "example.com", port: nil) }
8
- let(:server) { double("server", ssh_uri: ssh_uri) }
9
- let(:config) { { production: server } }
10
- let(:ssh_url) { "user@example.com" }
11
- let(:provision_server) { double("provision_server", ssh_uri: provision_ssh_uri) }
12
- let(:ssh_provisioner) { Bard::Provision::SSH.new(config, ssh_url) }
13
-
14
- before do
15
- allow(ssh_provisioner).to receive(:server).and_return(server)
16
- allow(ssh_provisioner).to receive(:provision_server).and_return(provision_server)
17
- allow(ssh_provisioner).to receive(:print)
18
- allow(ssh_provisioner).to receive(:puts)
19
- allow(ssh_provisioner).to receive(:system)
20
- end
21
-
22
- describe "#call" do
23
- context "when SSH is already available on target port" do
24
- it "skips port reconfiguration but checks known hosts" do
25
- allow(ssh_provisioner).to receive(:password_auth_enabled?).and_return(false)
26
- allow(ssh_provisioner).to receive(:ssh_available?).with(provision_ssh_uri, port: 2222).and_return(true)
27
- allow(ssh_provisioner).to receive(:ssh_known_host?).with(provision_ssh_uri).and_return(true)
28
-
29
- expect(provision_server).not_to receive(:run!)
30
-
31
- ssh_provisioner.call
32
- end
33
-
34
- it "adds to known hosts if not present" do
35
- allow(ssh_provisioner).to receive(:password_auth_enabled?).and_return(false)
36
- allow(ssh_provisioner).to receive(:ssh_available?).with(provision_ssh_uri, port: 2222).and_return(true)
37
- allow(ssh_provisioner).to receive(:ssh_known_host?).with(provision_ssh_uri).and_return(false)
38
-
39
- expect(ssh_provisioner).to receive(:add_ssh_known_host!).with(provision_ssh_uri)
40
-
41
- ssh_provisioner.call
42
- end
43
- end
44
-
45
- context "when SSH is not available on target port but available on default port" do
46
- it "reconfigures SSH port and adds to known hosts" do
47
- allow(ssh_provisioner).to receive(:password_auth_enabled?).and_return(false)
48
- allow(ssh_provisioner).to receive(:ssh_available?).with(provision_ssh_uri, port: 2222).and_return(false)
49
- allow(ssh_provisioner).to receive(:ssh_available?).with(provision_ssh_uri).and_return(true)
50
- allow(ssh_provisioner).to receive(:ssh_known_host?).with(provision_ssh_uri).and_return(false)
51
-
52
- expect(ssh_provisioner).to receive(:add_ssh_known_host!).with(provision_ssh_uri).twice
53
- expect(provision_server).to receive(:run!).with(
54
- 'echo "Port 2222" | sudo tee /etc/ssh/sshd_config.d/port_2222.conf; sudo service ssh restart',
55
- home: true
56
- )
57
-
58
- ssh_provisioner.call
59
- end
60
-
61
- it "prints status messages during reconfiguration" do
62
- allow(ssh_provisioner).to receive(:password_auth_enabled?).and_return(false)
63
- allow(ssh_provisioner).to receive(:ssh_available?).with(provision_ssh_uri, port: 2222).and_return(false)
64
- allow(ssh_provisioner).to receive(:ssh_available?).with(provision_ssh_uri).and_return(true)
65
- allow(ssh_provisioner).to receive(:ssh_known_host?).and_return(false)
66
- allow(ssh_provisioner).to receive(:add_ssh_known_host!)
67
- allow(provision_server).to receive(:run!)
68
-
69
- expect(ssh_provisioner).to receive(:print).with("SSH:")
70
- expect(ssh_provisioner).to receive(:print).with(" Adding known host,")
71
- expect(ssh_provisioner).to receive(:print).with(" Reconfiguring port to 2222,")
72
- expect(ssh_provisioner).to receive(:print).with(" Adding known host,")
73
- expect(ssh_provisioner).to receive(:puts).with(" ✓")
74
-
75
- ssh_provisioner.call
76
- end
77
- end
78
-
79
- context "when SSH is not available on either port" do
80
- it "raises an error" do
81
- allow(ssh_provisioner).to receive(:password_auth_enabled?).and_return(false)
82
- allow(ssh_provisioner).to receive(:ssh_available?).with(provision_ssh_uri, port: 2222).and_return(false)
83
- allow(ssh_provisioner).to receive(:ssh_available?).with(provision_ssh_uri).and_return(false)
84
-
85
- expect { ssh_provisioner.call }.to raise_error("can't find SSH on port 2222 or 22")
86
- end
87
- end
88
-
89
- context "when password authentication is enabled" do
90
- it "disables password authentication" do
91
- allow(ssh_provisioner).to receive(:password_auth_enabled?).and_return(true)
92
- allow(ssh_provisioner).to receive(:ssh_available?).with(provision_ssh_uri, port: 2222).and_return(true)
93
- allow(ssh_provisioner).to receive(:ssh_known_host?).and_return(true)
94
-
95
- expect(ssh_provisioner).to receive(:disable_password_auth!)
96
-
97
- ssh_provisioner.call
98
- end
99
-
100
- it "prints status message when disabling password authentication" do
101
- allow(ssh_provisioner).to receive(:password_auth_enabled?).and_return(true)
102
- allow(ssh_provisioner).to receive(:disable_password_auth!)
103
- allow(ssh_provisioner).to receive(:ssh_available?).with(provision_ssh_uri, port: 2222).and_return(true)
104
- allow(ssh_provisioner).to receive(:ssh_known_host?).and_return(true)
105
-
106
- expect(ssh_provisioner).to receive(:print).with("SSH:")
107
- expect(ssh_provisioner).to receive(:print).with(" Disabling password authentication,")
108
- expect(ssh_provisioner).to receive(:puts).with(" ✓")
109
-
110
- ssh_provisioner.call
111
- end
112
- end
113
-
114
- context "when password authentication is already disabled" do
115
- it "skips disabling password authentication" do
116
- allow(ssh_provisioner).to receive(:password_auth_enabled?).and_return(false)
117
- allow(ssh_provisioner).to receive(:ssh_available?).with(provision_ssh_uri, port: 2222).and_return(true)
118
- allow(ssh_provisioner).to receive(:ssh_known_host?).and_return(true)
119
-
120
- expect(ssh_provisioner).not_to receive(:disable_password_auth!)
121
-
122
- ssh_provisioner.call
123
- end
124
- end
125
-
126
- it "updates the SSH URL with the target port" do
127
- allow(ssh_provisioner).to receive(:password_auth_enabled?).and_return(false)
128
- allow(ssh_provisioner).to receive(:ssh_available?).with(provision_ssh_uri, port: 2222).and_return(true)
129
- allow(ssh_provisioner).to receive(:ssh_known_host?).and_return(true)
130
-
131
- ssh_provisioner.call
132
- end
133
- end
134
-
135
- describe "private methods" do
136
- describe "#target_port" do
137
- it "returns the server's SSH port" do
138
- expect(ssh_provisioner.send(:target_port)).to eq(2222)
139
- end
140
-
141
- it "defaults to 22 if no port is specified" do
142
- allow(ssh_uri).to receive(:port).and_return(nil)
143
- expect(ssh_provisioner.send(:target_port)).to eq(22)
144
- end
145
- end
146
-
147
- describe "#ssh_available?" do
148
- it "tests SSH connectivity on specified port" do
149
- expect(ssh_provisioner).to receive(:system).with("nc -zv example.com 2222 2>/dev/null")
150
-
151
- ssh_provisioner.send(:ssh_available?, provision_ssh_uri, port: 2222)
152
- end
153
-
154
- it "uses SSH URI port if no port specified" do
155
- allow(provision_ssh_uri).to receive(:port).and_return(2222)
156
- expect(ssh_provisioner).to receive(:system).with("nc -zv example.com 2222 2>/dev/null")
157
-
158
- ssh_provisioner.send(:ssh_available?, provision_ssh_uri)
159
- end
160
-
161
- it "defaults to port 22 if no port in URI or parameter" do
162
- expect(ssh_provisioner).to receive(:system).with("nc -zv example.com 22 2>/dev/null")
163
-
164
- ssh_provisioner.send(:ssh_available?, provision_ssh_uri)
165
- end
166
- end
167
-
168
- describe "#ssh_known_host?" do
169
- it "checks if host is in known_hosts file" do
170
- expected_command = 'grep -q "$(ssh-keyscan -t ed25519 -p22 example.com 2>/dev/null | cut -d \' \' -f 2-3)" ~/.ssh/known_hosts'
171
- expect(ssh_provisioner).to receive(:system).with(expected_command)
172
-
173
- ssh_provisioner.send(:ssh_known_host?, provision_ssh_uri)
174
- end
175
- end
176
-
177
- describe "#add_ssh_known_host!" do
178
- it "adds host to known_hosts file" do
179
- expected_command = "ssh-keyscan -p22 -H example.com >> ~/.ssh/known_hosts 2>/dev/null"
180
- expect(ssh_provisioner).to receive(:system).with(expected_command)
181
-
182
- ssh_provisioner.send(:add_ssh_known_host!, provision_ssh_uri)
183
- end
184
- end
185
-
186
- describe "#password_auth_enabled?" do
187
- it "returns true when password authentication is enabled" do
188
- expect(provision_server).to receive(:run!).with(
189
- %q{grep -E '^\s*PasswordAuthentication\s+yes' /etc/ssh/sshd_config /etc/ssh/sshd_config.d/*.conf 2>/dev/null || true},
190
- home: true,
191
- capture: true
192
- ).and_return("PasswordAuthentication yes\n")
193
-
194
- expect(ssh_provisioner.send(:password_auth_enabled?)).to be true
195
- end
196
-
197
- it "returns false when password authentication is disabled" do
198
- expect(provision_server).to receive(:run!).with(
199
- %q{grep -E '^\s*PasswordAuthentication\s+yes' /etc/ssh/sshd_config /etc/ssh/sshd_config.d/*.conf 2>/dev/null || true},
200
- home: true,
201
- capture: true
202
- ).and_return("")
203
-
204
- expect(ssh_provisioner.send(:password_auth_enabled?)).to be false
205
- end
206
-
207
- it "returns false when grep returns nil" do
208
- expect(provision_server).to receive(:run!).with(
209
- %q{grep -E '^\s*PasswordAuthentication\s+yes' /etc/ssh/sshd_config /etc/ssh/sshd_config.d/*.conf 2>/dev/null || true},
210
- home: true,
211
- capture: true
212
- ).and_return(nil)
213
-
214
- expect(ssh_provisioner.send(:password_auth_enabled?)).to be false
215
- end
216
- end
217
-
218
- describe "#disable_password_auth!" do
219
- it "creates sshd config file to disable password authentication and restarts ssh" do
220
- expect(provision_server).to receive(:run!).with(
221
- %q{echo "PasswordAuthentication no" | sudo tee /etc/ssh/sshd_config.d/disable_password_auth.conf; sudo service ssh restart},
222
- home: true
223
- )
224
-
225
- ssh_provisioner.send(:disable_password_auth!)
226
- end
227
- end
228
- end
229
- end
@@ -1,32 +0,0 @@
1
- require "spec_helper"
2
- require "bard/provision"
3
- require "bard/provision/swapfile"
4
-
5
- describe Bard::Provision::Swapfile do
6
- let(:config) { { production: double("production") } }
7
- let(:ssh_url) { "user@example.com" }
8
- let(:provision_server) { double("provision_server") }
9
- let(:swapfile) { Bard::Provision::Swapfile.new(config, ssh_url) }
10
-
11
- before do
12
- allow(swapfile).to receive(:provision_server).and_return(provision_server)
13
- allow(swapfile).to receive(:print)
14
- allow(swapfile).to receive(:puts)
15
- end
16
-
17
- describe "#call" do
18
- it "sets up swapfile on the server" do
19
- expect(provision_server).to receive(:run!).with(/if \[ ! -f \/swapfile \]/)
20
-
21
- swapfile.call
22
- end
23
-
24
- it "prints status messages" do
25
- allow(provision_server).to receive(:run!)
26
- expect(swapfile).to receive(:print).with("Swapfile:")
27
- expect(swapfile).to receive(:puts).with(" ✓")
28
-
29
- swapfile.call
30
- end
31
- end
32
- end
@@ -1,103 +0,0 @@
1
- require "spec_helper"
2
- require "bard/provision"
3
- require "bard/provision/user"
4
-
5
- describe Bard::Provision::User do
6
- let(:old_ssh_uri) { double("old_ssh_uri", user: "root", host: "example.com", port: 22) }
7
- let(:new_ssh_uri) { double("new_ssh_uri", user: "deploy", host: "example.com", port: 22) }
8
- let(:server) { double("server", ssh_uri: new_ssh_uri) }
9
- let(:config) { { production: server } }
10
- let(:ssh_url) { "root@example.com" }
11
- let(:provision_server) { double("provision_server", ssh_uri: old_ssh_uri) }
12
- let(:user_provisioner) { Bard::Provision::User.new(config, ssh_url) }
13
-
14
- before do
15
- allow(user_provisioner).to receive(:server).and_return(server)
16
- allow(user_provisioner).to receive(:provision_server).and_return(provision_server)
17
- allow(user_provisioner).to receive(:print)
18
- allow(user_provisioner).to receive(:puts)
19
- allow(user_provisioner).to receive(:system)
20
- end
21
-
22
- describe "#call" do
23
- context "when new user already exists" do
24
- it "skips user creation" do
25
- allow(user_provisioner).to receive(:ssh_with_user?).with(old_ssh_uri, user: "deploy").and_return(true)
26
-
27
- expect(provision_server).not_to receive(:run!)
28
-
29
- user_provisioner.call
30
- end
31
- end
32
-
33
- context "when new user doesn't exist but old user works" do
34
- it "creates the new user" do
35
- allow(user_provisioner).to receive(:ssh_with_user?).with(old_ssh_uri, user: "deploy").and_return(false)
36
- allow(user_provisioner).to receive(:ssh_with_user?).with(old_ssh_uri).and_return(true)
37
-
38
- expected_commands = [
39
- "sudo useradd -m -s /bin/bash deploy",
40
- "sudo usermod -aG sudo deploy",
41
- "echo \"deploy ALL=(ALL) NOPASSWD:ALL\" | sudo tee -a /etc/sudoers",
42
- "sudo mkdir -p ~deploy/.ssh",
43
- "sudo cp ~/.ssh/authorized_keys ~deploy/.ssh/authorized_keys",
44
- "sudo chown -R deploy:deploy ~deploy/.ssh",
45
- "sudo chmod +rx ~deploy"
46
- ].join("; ")
47
-
48
- expect(provision_server).to receive(:run!).with(expected_commands, home: true)
49
-
50
- user_provisioner.call
51
- end
52
-
53
- it "prints status messages during user creation" do
54
- allow(user_provisioner).to receive(:ssh_with_user?).with(old_ssh_uri, user: "deploy").and_return(false)
55
- allow(user_provisioner).to receive(:ssh_with_user?).with(old_ssh_uri).and_return(true)
56
- allow(provision_server).to receive(:run!)
57
-
58
- expect(user_provisioner).to receive(:print).with("User:")
59
- expect(user_provisioner).to receive(:print).with(" Adding user deploy,")
60
- expect(user_provisioner).to receive(:puts).with(" ✓")
61
-
62
- user_provisioner.call
63
- end
64
- end
65
-
66
- context "when neither old nor new user can SSH" do
67
- it "raises an error" do
68
- allow(user_provisioner).to receive(:ssh_with_user?).with(old_ssh_uri, user: "deploy").and_return(false)
69
- allow(user_provisioner).to receive(:ssh_with_user?).with(old_ssh_uri).and_return(false)
70
-
71
- expect { user_provisioner.call }.to raise_error("can't ssh in with user deploy or root")
72
- end
73
- end
74
- end
75
-
76
- describe "#ssh_with_user?" do
77
- it "tests SSH connection with specified user" do
78
- expect(user_provisioner).to receive(:system).with("ssh -o ConnectTimeout=2 -p22 deploy@example.com : >/dev/null 2>&1")
79
-
80
- user_provisioner.send(:ssh_with_user?, old_ssh_uri, user: "deploy")
81
- end
82
-
83
- it "uses default user from SSH URI if not specified" do
84
- expect(user_provisioner).to receive(:system).with("ssh -o ConnectTimeout=2 -p22 root@example.com : >/dev/null 2>&1")
85
-
86
- user_provisioner.send(:ssh_with_user?, old_ssh_uri)
87
- end
88
- end
89
-
90
- describe "private methods" do
91
- describe "#new_user" do
92
- it "returns the target user from server SSH URI" do
93
- expect(user_provisioner.send(:new_user)).to eq("deploy")
94
- end
95
- end
96
-
97
- describe "#old_user" do
98
- it "returns the current user from provision server SSH URI" do
99
- expect(user_provisioner.send(:old_user)).to eq("root")
100
- end
101
- end
102
- end
103
- end
@@ -1,28 +0,0 @@
1
- require "spec_helper"
2
- require "bard/provision"
3
-
4
- describe Bard::Provision do
5
- let(:config) { { production: double("production", key: :production) } }
6
- let(:ssh_url) { "user@example.com" }
7
- let(:provision) { Bard::Provision.new(config, ssh_url) }
8
-
9
- describe ".call" do
10
- it "creates a new instance and calls it" do
11
- expect_any_instance_of(Bard::Provision).to receive(:call)
12
- Bard::Provision.call(config, ssh_url)
13
- end
14
- end
15
-
16
- describe "#server" do
17
- it "returns the production server from config" do
18
- expect(provision.send(:server)).to eq(config[:production])
19
- end
20
- end
21
-
22
- describe "#provision_server" do
23
- it "returns server with ssh_url" do
24
- expect(config[:production]).to receive(:with).with(ssh: ssh_url)
25
- provision.send(:provision_server)
26
- end
27
- end
28
- end