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.
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} +41 -13
  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
@@ -0,0 +1,61 @@
1
+ require "bard/plugins/deploy/ci/runner"
2
+
3
+ RSpec.describe Bard::CI::Runner do
4
+ describe ".runners" do
5
+ it "is a hash registry" do
6
+ expect(described_class.runners).to be_a(Hash)
7
+ end
8
+ end
9
+
10
+ describe ".[]" do
11
+ before do
12
+ require "bard/plugins/deploy/ci/local"
13
+ require "bard/plugins/deploy/ci/github_actions"
14
+ end
15
+
16
+ it "looks up runners by name" do
17
+ expect(described_class[:local]).to eq Bard::CI::Local
18
+ expect(described_class[:github_actions]).to eq Bard::CI::GithubActions
19
+ end
20
+
21
+ it "returns nil for unknown runners" do
22
+ expect(described_class[:nonexistent]).to be_nil
23
+ end
24
+ end
25
+
26
+ describe ".default" do
27
+ it "returns the last registered runner" do
28
+ # Whatever was registered last in the current test run
29
+ expect(described_class.default).to be_a(Class)
30
+ expect(described_class.default.ancestors).to include(Bard::CI::Runner)
31
+ end
32
+ end
33
+
34
+ describe "auto-registration via inherited" do
35
+ it "registers subclasses automatically" do
36
+ eval <<-RUBY
37
+ module Bard
38
+ class CI
39
+ class SpecTestRunner < Runner
40
+ end
41
+ end
42
+ end
43
+ RUBY
44
+
45
+ expect(described_class[:spec_test_runner]).to eq Bard::CI::SpecTestRunner
46
+ end
47
+
48
+ it "newly registered runner becomes the default" do
49
+ eval <<-RUBY
50
+ module Bard
51
+ class CI
52
+ class AnotherTestRunner < Runner
53
+ end
54
+ end
55
+ end
56
+ RUBY
57
+
58
+ expect(described_class.default).to eq Bard::CI::AnotherTestRunner
59
+ end
60
+ end
61
+ end
data/spec/bard/ci_spec.rb CHANGED
@@ -1,4 +1,4 @@
1
- require "bard/ci"
1
+ require "bard/plugins/deploy/ci"
2
2
 
3
3
  describe Bard::CI do
4
4
  subject { described_class.new("tracker", "master") }
@@ -1,28 +1,14 @@
1
1
  require "spec_helper"
2
2
  require "bard/cli"
3
- require "bard/cli/ci"
4
- require "thor"
3
+ require "ostruct"
5
4
 
6
- class TestCICLI < Thor
7
- include Bard::CLI::CI
8
-
9
- attr_reader :options
10
-
11
- def initialize
12
- super
13
- @options = {}
14
- end
15
-
16
- def project_name
17
- "test_project"
18
- end
19
- end
20
-
21
- describe Bard::CLI::CI do
22
- let(:cli) { TestCICLI.new }
5
+ describe "bard ci" do
6
+ let(:cli) { Bard::CLI.new }
23
7
  let(:ci_runner) { double("ci_runner") }
24
8
 
25
9
  before do
10
+ allow(cli).to receive(:config).and_return(OpenStruct.new(ci: nil))
11
+ allow(cli).to receive(:project_name).and_return("test_project")
26
12
  allow(cli).to receive(:puts)
27
13
  allow(cli).to receive(:print)
28
14
  allow(cli).to receive(:exit)
@@ -101,12 +87,9 @@ describe Bard::CLI::CI do
101
87
  it "shows error message and exits" do
102
88
  allow(cli).to receive(:options).and_return({})
103
89
  allow(ci_runner).to receive(:exists?).and_return(false)
90
+ allow(cli).to receive(:exit).with(1).and_raise(SystemExit)
104
91
 
105
- expect(cli).to receive(:puts) # "No CI found for test_project!"
106
- expect(cli).to receive(:puts) # "Re-run with --skip-ci to bypass CI..."
107
- expect(cli).to receive(:exit).with(1)
108
-
109
- cli.ci
92
+ expect { cli.ci }.to raise_error(SystemExit)
110
93
  end
111
94
  end
112
95
 
@@ -116,7 +99,7 @@ describe Bard::CLI::CI do
116
99
  allow(ci_runner).to receive(:exists?).and_return(true)
117
100
  allow(ci_runner).to receive(:run).and_return(true)
118
101
 
119
- expect(Bard::CI).to receive(:new).with("test_project", "develop", local: nil)
102
+ expect(Bard::CI).to receive(:new).with("test_project", "develop", runner_name: nil)
120
103
  expect(cli).to receive(:puts).with("Continuous integration: starting build on develop...")
121
104
 
122
105
  cli.ci("develop")
@@ -124,12 +107,36 @@ describe Bard::CLI::CI do
124
107
  end
125
108
 
126
109
  context "with local-ci option" do
127
- it "passes local option to CI runner" do
110
+ it "passes local runner_name to CI" do
128
111
  allow(cli).to receive(:options).and_return({ "local-ci" => true })
129
112
  allow(ci_runner).to receive(:exists?).and_return(true)
130
113
  allow(ci_runner).to receive(:run).and_return(true)
131
114
 
132
- expect(Bard::CI).to receive(:new).with("test_project", "feature-branch", local: true)
115
+ expect(Bard::CI).to receive(:new).with("test_project", "feature-branch", runner_name: :local)
116
+
117
+ cli.ci
118
+ end
119
+ end
120
+
121
+ context "with ci option" do
122
+ it "passes specified runner_name to CI" do
123
+ allow(cli).to receive(:options).and_return({ "ci" => "jenkins" })
124
+ allow(ci_runner).to receive(:exists?).and_return(true)
125
+ allow(ci_runner).to receive(:run).and_return(true)
126
+
127
+ expect(Bard::CI).to receive(:new).with("test_project", "feature-branch", runner_name: :jenkins)
128
+
129
+ cli.ci
130
+ end
131
+ end
132
+
133
+ context "with both local-ci and ci options" do
134
+ it "local-ci takes precedence" do
135
+ allow(cli).to receive(:options).and_return({ "local-ci" => true, "ci" => "jenkins" })
136
+ allow(ci_runner).to receive(:exists?).and_return(true)
137
+ allow(ci_runner).to receive(:run).and_return(true)
138
+
139
+ expect(Bard::CI).to receive(:new).with("test_project", "feature-branch", runner_name: :local)
133
140
 
134
141
  cli.ci
135
142
  end
@@ -1,35 +1,15 @@
1
1
  require "spec_helper"
2
2
  require "bard/cli"
3
- require "bard/cli/data"
4
3
 
5
- require "thor"
6
-
7
- require "term/ansicolor"
8
-
9
- class TestCLI < Thor
10
- include Bard::CLI::Data
11
- include Term::ANSIColor
12
-
13
- attr_reader :config
14
-
15
- def initialize
16
- @config = {}
17
- end
18
-
19
- def options
20
- {}
21
- end
22
- end
23
-
24
- describe Bard::CLI::Data do
25
- let(:cli) { TestCLI.new }
4
+ describe "bard data" do
5
+ let(:cli) { Bard::CLI.new }
26
6
 
27
7
  it "should have a data command" do
28
8
  expect(cli).to respond_to(:data)
29
9
  end
30
10
 
31
11
  context "data" do
32
- let(:from) { double("from", key: :production, run!: nil, copy_file: nil, copy_dir: nil) }
12
+ let(:from) { double("from", key: :production, run!: nil, require_capability!: nil) }
33
13
  let(:to) { double("to", key: :local, run!: nil) }
34
14
 
35
15
  let(:config) do
@@ -42,17 +22,18 @@ describe Bard::CLI::Data do
42
22
  before do
43
23
  allow(cli).to receive(:config).and_return(config)
44
24
  allow(cli).to receive(:options).and_return({from: "production", to: "local"})
25
+ allow(cli).to receive(:puts)
45
26
  end
46
27
 
47
28
  it "should run the data command" do
48
29
  expect(from).to receive(:run!).with("bin/rake db:dump")
49
- expect(from).to receive(:copy_file).with("db/data.sql.gz", to: to, verbose: true)
30
+ expect(Bard::Copy).to receive(:file).with("db/data.sql.gz", from: from, to: to, verbose: true)
50
31
  expect(to).to receive(:run!).with("bin/rake db:load")
51
32
  cli.data
52
33
  end
53
34
 
54
35
  context "pushing to production" do
55
- let(:to) { double("to", key: :production, ping: ["https://example.com"]) }
36
+ let(:to) { double("to", key: :production, url: "https://example.com", run!: nil, require_capability!: nil) }
56
37
 
57
38
  before do
58
39
  allow(cli).to receive(:options).and_return({from: "local", to: "production"})
@@ -68,7 +49,7 @@ describe Bard::CLI::Data do
68
49
  it "should allow pushing to production if the user confirms" do
69
50
  expect(cli).to receive(:ask).and_return("https://example.com")
70
51
  expect(from).to receive(:run!).with("bin/rake db:dump")
71
- expect(from).to receive(:copy_file).with("db/data.sql.gz", to: to, verbose: true)
52
+ expect(Bard::Copy).to receive(:file).with("db/data.sql.gz", from: from, to: to, verbose: true)
72
53
  expect(to).to receive(:run!).with("bin/rake db:load")
73
54
  cli.data
74
55
  end
@@ -1,42 +1,29 @@
1
1
  require "spec_helper"
2
2
  require "bard/cli"
3
- require "bard/cli/deploy"
4
- require "thor"
5
3
 
6
- class TestDeployCLI < Thor
7
- include Bard::CLI::Deploy
8
-
9
- attr_reader :config, :options
10
-
11
- def initialize
12
- super
13
- @config = {}
14
- @options = {}
15
- end
16
-
17
- def project_name
18
- "test_project"
19
- end
20
- end
21
-
22
- describe Bard::CLI::Deploy do
23
- let(:production_server) { double("production", run!: true, github_pages: false, path: "/var/www/test_project") }
4
+ describe "bard deploy" do
5
+ let(:deploy_strategy) { double("deploy_strategy", deploy: true) }
6
+ let(:production_server) { double("production", run!: true, path: "/var/www/test_project", deploy_strategy: :ssh, deploy_strategy_instance: deploy_strategy) }
24
7
  let(:config) { { production: production_server } }
25
- let(:cli) { TestDeployCLI.new }
8
+ let(:cli) { Bard::CLI.new }
26
9
 
27
10
  before do
11
+ allow(config).to receive(:ci).and_return(nil)
28
12
  allow(cli).to receive(:config).and_return(config)
13
+ allow(cli).to receive(:options).and_return({ target: "production" })
29
14
  allow(cli).to receive(:puts)
30
15
  allow(cli).to receive(:exit)
31
16
  allow(cli).to receive(:run!)
32
17
  allow(cli).to receive(:invoke)
33
18
  allow(cli).to receive(:ping)
19
+ allow(cli).to receive(:project_name).and_return("test_project")
34
20
  allow(cli).to receive(:green).and_return("")
35
21
  allow(cli).to receive(:red).and_return("")
36
22
  allow(cli).to receive(:yellow).and_return("")
37
23
  allow(Bard::Git).to receive(:current_branch).and_return("feature-branch")
38
24
  allow(Bard::Git).to receive(:up_to_date_with_remote?).and_return(true)
39
25
  allow(Bard::Git).to receive(:fast_forward_merge?).and_return(true)
26
+ allow(Bard::Git).to receive(:in_linked_worktree?).and_return(false)
40
27
  allow(cli).to receive(:`).and_return("")
41
28
  end
42
29
 
@@ -48,7 +35,7 @@ describe Bard::CLI::Deploy do
48
35
  context "when on master branch" do
49
36
  before do
50
37
  allow(Bard::Git).to receive(:current_branch).and_return("master")
51
- allow(cli).to receive(:options).and_return({})
38
+ allow(cli).to receive(:options).and_return({ target: "production" })
52
39
  end
53
40
 
54
41
  context "when up to date with remote" do
@@ -57,8 +44,7 @@ describe Bard::CLI::Deploy do
57
44
 
58
45
  expect(cli).not_to receive(:run!).with(/git push/)
59
46
  expect(cli).to receive(:invoke).with(:ci, ["master"], {})
60
- expect(production_server).to receive(:run!).with("git pull origin master && bin/setup")
61
- expect(cli).to receive(:puts) # "Deploy Succeeded"
47
+ expect(deploy_strategy).to receive(:deploy)
62
48
  expect(cli).to receive(:ping).with(:production)
63
49
 
64
50
  cli.deploy
@@ -71,7 +57,7 @@ describe Bard::CLI::Deploy do
71
57
 
72
58
  expect(cli).to receive(:run!).with("git push origin master:master")
73
59
  expect(cli).to receive(:invoke).with(:ci, ["master"], {})
74
- expect(production_server).to receive(:run!).with("git pull origin master && bin/setup")
60
+ expect(deploy_strategy).to receive(:deploy)
75
61
 
76
62
  cli.deploy
77
63
  end
@@ -79,10 +65,21 @@ describe Bard::CLI::Deploy do
79
65
 
80
66
  context "with skip-ci option" do
81
67
  it "skips CI step" do
82
- allow(cli).to receive(:options).and_return({ "skip-ci" => true })
68
+ allow(cli).to receive(:options).and_return({ "skip-ci" => true, target: "production" })
69
+
70
+ expect(cli).not_to receive(:invoke).with(:ci, anything, anything)
71
+ expect(deploy_strategy).to receive(:deploy)
72
+
73
+ cli.deploy
74
+ end
75
+ end
76
+
77
+ context "with ci disabled in config" do
78
+ it "skips CI step" do
79
+ allow(config).to receive(:ci).and_return(false)
83
80
 
84
81
  expect(cli).not_to receive(:invoke).with(:ci, anything, anything)
85
- expect(production_server).to receive(:run!).with("git pull origin master && bin/setup")
82
+ expect(deploy_strategy).to receive(:deploy)
86
83
 
87
84
  cli.deploy
88
85
  end
@@ -91,17 +88,17 @@ describe Bard::CLI::Deploy do
91
88
 
92
89
  context "when on feature branch" do
93
90
  before do
94
- allow(cli).to receive(:options).and_return({})
91
+ allow(cli).to receive(:options).and_return({ target: "production" })
95
92
  end
96
93
 
97
94
  context "with fast-forward merge possible" do
98
95
  it "fetches master, pushes branch, runs CI, merges to master, and deploys" do
99
- expect(cli).to receive(:run!).with("git fetch origin master:master")
96
+ expect(cli).to receive(:run!).with("git fetch origin")
97
+ expect(cli).to receive(:run!).with("git fetch origin master:master").twice
100
98
  expect(cli).to receive(:run!).with("git push -f origin feature-branch:feature-branch")
101
99
  expect(cli).to receive(:invoke).with(:ci, ["feature-branch"], {})
102
100
  expect(cli).to receive(:run!).with("git push origin feature-branch:master")
103
- expect(cli).to receive(:run!).with("git fetch origin master:master")
104
- expect(production_server).to receive(:run!).with("git pull origin master && bin/setup")
101
+ expect(deploy_strategy).to receive(:deploy)
105
102
 
106
103
  cli.deploy
107
104
  end
@@ -116,6 +113,27 @@ describe Bard::CLI::Deploy do
116
113
  end
117
114
  end
118
115
 
116
+ context "when run from a linked worktree" do
117
+ before do
118
+ allow(Bard::Git).to receive(:in_linked_worktree?).and_return(true)
119
+ allow(cli).to receive(:`).with("git rev-parse --git-common-dir").and_return("/main/checkout/.git\n")
120
+ allow(Dir).to receive(:pwd).and_return("/main/checkout/tmp/worktrees/feature-branch")
121
+ allow(Dir).to receive(:chdir).with("/main/checkout")
122
+ end
123
+
124
+ it "skips writes to local master, removes the worktree, and reports where to cd back" do
125
+ expect(cli).not_to receive(:run!).with("git fetch origin master:master")
126
+ expect(cli).not_to receive(:run!).with("git checkout master")
127
+ expect(cli).to receive(:run!).with("git fetch origin master")
128
+ expect(Dir).to receive(:chdir).with("/main/checkout")
129
+ expect(cli).to receive(:run!).with("git worktree remove /main/checkout/tmp/worktrees/feature-branch")
130
+ expect(cli).to receive(:run!).with("git branch -D feature-branch")
131
+ expect(cli).to receive(:puts).with("Worktree removed. Run: cd /main/checkout")
132
+
133
+ cli.deploy
134
+ end
135
+ end
136
+
119
137
  context "when rebase is needed" do
120
138
  it "attempts rebase before proceeding" do
121
139
  allow(Bard::Git).to receive(:fast_forward_merge?).and_return(false)
@@ -129,6 +147,20 @@ describe Bard::CLI::Deploy do
129
147
  end
130
148
  end
131
149
 
150
+ context "when on feature branch with ci disabled in config" do
151
+ before do
152
+ allow(cli).to receive(:options).and_return({ target: "production" })
153
+ allow(config).to receive(:ci).and_return(false)
154
+ end
155
+
156
+ it "skips CI step" do
157
+ expect(cli).not_to receive(:invoke).with(:ci, anything, anything)
158
+ expect(deploy_strategy).to receive(:deploy)
159
+
160
+ cli.deploy
161
+ end
162
+ end
163
+
132
164
  context "with github remote" do
133
165
  it "pushes to github remote" do
134
166
  allow(cli).to receive(:`).with("git remote").and_return("origin\ngithub\n")
@@ -140,41 +172,40 @@ describe Bard::CLI::Deploy do
140
172
  end
141
173
 
142
174
  context "with clone option" do
143
- it "clones repository and sets up application" do
144
- allow(cli).to receive(:options).and_return({ clone: true })
175
+ it "deploys with clone option to strategy" do
176
+ allow(cli).to receive(:options).and_return({ clone: true, target: "production" })
145
177
 
146
- expect(production_server).to receive(:run!).with("git clone git@github.com:botandrosedesign/test_project /var/www/test_project", home: true)
147
- expect(cli).to receive(:invoke).with(:master_key, [], from: "local", to: :production)
148
- expect(production_server).to receive(:run!).with("bin/setup && bard setup")
178
+ expect(deploy_strategy).to receive(:deploy).with(clone: "test_project")
149
179
 
150
180
  cli.deploy
151
181
  end
152
182
  end
153
183
 
154
184
  context "with github pages" do
155
- it "deploys to github pages" do
156
- allow(production_server).to receive(:github_pages).and_return(true)
157
- github_pages = double("github_pages")
158
- allow(Bard::GithubPages).to receive(:new).and_return(github_pages)
185
+ let(:deploy_strategy) { double("github_pages_strategy") }
186
+ let(:production_server) { double("production", run!: true, path: "/var/www/test_project", deploy_strategy: :github_pages, deploy_strategy_instance: deploy_strategy) }
159
187
 
160
- expect(github_pages).to receive(:deploy).with(production_server)
188
+ it "deploys using deploy strategy" do
189
+ expect(deploy_strategy).to receive(:deploy)
161
190
 
162
191
  cli.deploy
163
192
  end
164
193
  end
165
194
 
166
195
  context "with custom deployment target" do
167
- let(:staging_server) { double("staging", run!: true, github_pages: false) }
196
+ let(:staging_strategy) { double("staging_strategy", deploy: true) }
197
+ let(:staging_server) { double("staging", run!: true, deploy_strategy: :ssh, deploy_strategy_instance: staging_strategy) }
168
198
 
169
199
  before do
170
200
  allow(config).to receive(:[]).with(:staging).and_return(staging_server)
201
+ allow(cli).to receive(:options).and_return({ target: "staging" })
171
202
  end
172
203
 
173
204
  it "deploys to specified target" do
174
- expect(staging_server).to receive(:run!).with("git pull origin master && bin/setup")
205
+ expect(staging_strategy).to receive(:deploy)
175
206
  expect(cli).to receive(:ping).with(:staging)
176
207
 
177
- cli.deploy(:staging)
208
+ cli.deploy
178
209
  end
179
210
  end
180
211
 
@@ -191,12 +222,22 @@ describe Bard::CLI::Deploy do
191
222
 
192
223
  context "with local-ci option" do
193
224
  it "passes local-ci option to CI invocation" do
194
- allow(cli).to receive(:options).and_return({ "local-ci" => true })
225
+ allow(cli).to receive(:options).and_return({ "local-ci" => true, target: "production" })
195
226
 
196
227
  expect(cli).to receive(:invoke).with(:ci, ["feature-branch"], { "local-ci" => true })
197
228
 
198
229
  cli.deploy
199
230
  end
200
231
  end
232
+
233
+ context "with ci option" do
234
+ it "passes ci option to CI invocation" do
235
+ allow(cli).to receive(:options).and_return({ "ci" => "jenkins", target: "production" })
236
+
237
+ expect(cli).to receive(:invoke).with(:ci, ["feature-branch"], { "ci" => "jenkins" })
238
+
239
+ cli.deploy
240
+ end
241
+ end
201
242
  end
202
- end
243
+ end
@@ -1,14 +1,8 @@
1
1
  require "spec_helper"
2
2
  require "bard/cli"
3
- require "bard/cli/hurt"
4
- require "thor"
5
3
 
6
- class TestHurtCLI < Thor
7
- include Bard::CLI::Hurt
8
- end
9
-
10
- describe Bard::CLI::Hurt do
11
- let(:cli) { TestHurtCLI.new }
4
+ describe "bard hurt" do
5
+ let(:cli) { Bard::CLI.new }
12
6
 
13
7
  before do
14
8
  allow(cli).to receive(:puts)
@@ -20,4 +14,4 @@ describe Bard::CLI::Hurt do
20
14
  expect(cli).to respond_to(:hurt)
21
15
  end
22
16
  end
23
- end
17
+ end
@@ -1,14 +1,8 @@
1
1
  require "spec_helper"
2
2
  require "bard/cli"
3
- require "bard/cli/install"
4
- require "thor"
5
3
 
6
- class TestInstallCLI < Thor
7
- include Bard::CLI::Install
8
- end
9
-
10
- describe Bard::CLI::Install do
11
- let(:cli) { TestInstallCLI.new }
4
+ describe "bard install" do
5
+ let(:cli) { Bard::CLI.new }
12
6
 
13
7
  describe "#install" do
14
8
  it "should have an install command" do
@@ -16,10 +10,10 @@ describe Bard::CLI::Install do
16
10
  end
17
11
 
18
12
  it "should copy install files to bin directory" do
19
- expect(cli).to receive(:system).with(/cp -R .*install_files\/\* bin\//)
20
- expect(cli).to receive(:system).with(/cp -R .*install_files\/\.github \.\//)
13
+ expect(cli).to receive(:system).with(/cp -R .*plugins\/install\/\* bin\//)
14
+ expect(cli).to receive(:system).with(/cp -R .*plugins\/install\/\.github \.\//)
21
15
 
22
16
  cli.install
23
17
  end
24
18
  end
25
- end
19
+ end
@@ -1,25 +1,11 @@
1
1
  require "spec_helper"
2
2
  require "bard/cli"
3
- require "bard/cli/master_key"
4
- require "thor"
5
3
 
6
- class TestMasterKeyCLI < Thor
7
- include Bard::CLI::MasterKey
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::MasterKey do
4
+ describe "bard master_key" do
19
5
  let(:from_server) { double("production") }
20
6
  let(:to_server) { double("local") }
21
7
  let(:config) { { production: from_server, local: to_server } }
22
- let(:cli) { TestMasterKeyCLI.new }
8
+ let(:cli) { Bard::CLI.new }
23
9
 
24
10
  before do
25
11
  allow(cli).to receive(:config).and_return(config)
@@ -34,7 +20,7 @@ describe Bard::CLI::MasterKey do
34
20
  allow(config).to receive(:[]).with("production").and_return(from_server)
35
21
  allow(config).to receive(:[]).with("local").and_return(to_server)
36
22
  allow(cli).to receive(:options).and_return({ from: "production", to: "local" })
37
- expect(from_server).to receive(:copy_file).with("config/master.key", to: to_server)
23
+ expect(Bard::Copy).to receive(:file).with("config/master.key", from: from_server, to: to_server)
38
24
 
39
25
  cli.master_key
40
26
  end
@@ -44,9 +30,9 @@ describe Bard::CLI::MasterKey do
44
30
  allow(config).to receive(:[]).with("production").and_return(staging_server)
45
31
  allow(config).to receive(:[]).with("local").and_return(to_server)
46
32
  allow(cli).to receive(:options).and_return({ from: "production", to: "local" })
47
- expect(staging_server).to receive(:copy_file).with("config/master.key", to: to_server)
33
+ expect(Bard::Copy).to receive(:file).with("config/master.key", from: staging_server, to: to_server)
48
34
 
49
35
  cli.master_key
50
36
  end
51
37
  end
52
- end
38
+ end
@@ -1,30 +1,14 @@
1
1
  require "spec_helper"
2
2
  require "bard/cli"
3
- require "bard/cli/open"
4
- require "thor"
5
3
 
6
- class TestOpenCLI < Thor
7
- include Bard::CLI::Open
8
-
9
- attr_reader :config
10
-
11
- def initialize
12
- super
13
- @config = {}
14
- end
15
-
16
- def project_name
17
- "test_project"
18
- end
19
- end
20
-
21
- describe Bard::CLI::Open do
22
- let(:server) { double("server", ping: ["https://example.com"]) }
23
- let(:config) { { production: server } }
24
- let(:cli) { TestOpenCLI.new }
4
+ describe "bard open" do
5
+ let(:target) { double("target", url: "https://example.com", require_capability!: nil) }
6
+ let(:config) { { production: target } }
7
+ let(:cli) { Bard::CLI.new }
25
8
 
26
9
  before do
27
10
  allow(cli).to receive(:config).and_return(config)
11
+ allow(cli).to receive(:project_name).and_return("test_project")
28
12
  allow(cli).to receive(:exec)
29
13
  end
30
14
 
@@ -33,14 +17,14 @@ describe Bard::CLI::Open do
33
17
  expect(cli).to respond_to(:open)
34
18
  end
35
19
 
36
- it "should open production server URL by default" do
20
+ it "should open production target URL by default" do
37
21
  expect(cli).to receive(:exec).with("xdg-open https://example.com")
38
22
 
39
23
  cli.open
40
24
  end
41
25
 
42
- it "should open specified server URL" do
43
- staging_server = double("staging", ping: ["https://staging.example.com"])
26
+ it "should open specified target URL" do
27
+ staging_server = double("staging", url: "https://staging.example.com", require_capability!: nil)
44
28
  allow(config).to receive(:[]).with(:staging).and_return(staging_server)
45
29
 
46
30
  expect(cli).to receive(:exec).with("xdg-open https://staging.example.com")
@@ -48,7 +32,7 @@ describe Bard::CLI::Open do
48
32
  cli.open(:staging)
49
33
  end
50
34
 
51
- it "should open CI URL when server is ci" do
35
+ it "should open CI URL when target is ci" do
52
36
  expect(cli).to receive(:exec).with("xdg-open https://github.com/botandrosedesign/test_project/actions/workflows/ci.yml")
53
37
 
54
38
  cli.open(:ci)
@@ -56,12 +40,12 @@ describe Bard::CLI::Open do
56
40
  end
57
41
 
58
42
  describe "#open_url" do
59
- it "returns CI URL for ci server" do
60
- expect(cli.send(:open_url, :ci)).to eq("https://github.com/botandrosedesign/test_project/actions/workflows/ci.yml")
43
+ it "returns CI URL for ci target" do
44
+ expect(cli.open_url(:ci)).to eq("https://github.com/botandrosedesign/test_project/actions/workflows/ci.yml")
61
45
  end
62
46
 
63
- it "returns server ping URL for other servers" do
64
- expect(cli.send(:open_url, :production)).to eq("https://example.com")
47
+ it "returns target url for other targets" do
48
+ expect(cli.open_url(:production)).to eq("https://example.com")
65
49
  end
66
50
  end
67
- end
51
+ end