bard 2.2.0 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (96) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +7 -487
  3. data/Rakefile +1 -4
  4. data/bard.gemspec +2 -11
  5. data/lib/bard/config.rb +22 -20
  6. data/lib/bard/plugins/ping/target_methods.rb +0 -9
  7. data/lib/bard/plugins/ssh/connection.rb +2 -35
  8. data/lib/bard/target.rb +0 -15
  9. data/lib/bard/version.rb +1 -1
  10. data/lib/bard.rb +2 -1
  11. data/spec/bard/capability_spec.rb +0 -8
  12. data/spec/bard/config_spec.rb +30 -67
  13. data/spec/bard/target_spec.rb +1 -36
  14. metadata +4 -225
  15. data/ARCHITECTURE.md +0 -957
  16. data/CUSTOM_STRATEGIES.md +0 -701
  17. data/MIGRATION_GUIDE.md +0 -513
  18. data/PLUGINS.md +0 -99
  19. data/bin/bard +0 -4
  20. data/features/ci.feature +0 -63
  21. data/features/data.feature +0 -13
  22. data/features/deploy.feature +0 -14
  23. data/features/deploy_git_workflow.feature +0 -89
  24. data/features/run.feature +0 -14
  25. data/features/step_definitions/bard_steps.rb +0 -136
  26. data/features/support/bard-coverage +0 -16
  27. data/features/support/env.rb +0 -22
  28. data/features/support/test_server.rb +0 -216
  29. data/lib/bard/cli.rb +0 -44
  30. data/lib/bard/command.rb +0 -31
  31. data/lib/bard/copy.rb +0 -45
  32. data/lib/bard/plugins/data.rb +0 -56
  33. data/lib/bard/plugins/deploy/ci/github_actions.rb +0 -202
  34. data/lib/bard/plugins/deploy/ci/jenkins.rb +0 -176
  35. data/lib/bard/plugins/deploy/ci/local.rb +0 -57
  36. data/lib/bard/plugins/deploy/ci/runner.rb +0 -112
  37. data/lib/bard/plugins/deploy/ci/state.rb +0 -40
  38. data/lib/bard/plugins/deploy/ci.rb +0 -38
  39. data/lib/bard/plugins/deploy/ssh_strategy.rb +0 -26
  40. data/lib/bard/plugins/deploy/strategy.rb +0 -60
  41. data/lib/bard/plugins/deploy.rb +0 -260
  42. data/lib/bard/plugins/git.rb +0 -45
  43. data/lib/bard/plugins/github.rb +0 -152
  44. data/lib/bard/plugins/github_pages/strategy.rb +0 -170
  45. data/lib/bard/plugins/github_pages.rb +0 -35
  46. data/lib/bard/plugins/hurt.rb +0 -13
  47. data/lib/bard/plugins/install/.github/dependabot.yml +0 -18
  48. data/lib/bard/plugins/install/.github/workflows/cache-ci.yml +0 -15
  49. data/lib/bard/plugins/install/.github/workflows/ci.yml +0 -74
  50. data/lib/bard/plugins/install/apt_dependencies.rb +0 -33
  51. data/lib/bard/plugins/install/ci +0 -5
  52. data/lib/bard/plugins/install/setup +0 -13
  53. data/lib/bard/plugins/install/specified_bundler.rb +0 -15
  54. data/lib/bard/plugins/install/specified_ruby.rb +0 -59
  55. data/lib/bard/plugins/install.rb +0 -9
  56. data/lib/bard/plugins/open.rb +0 -20
  57. data/lib/bard/plugins/ping/check.rb +0 -66
  58. data/lib/bard/plugins/ping.rb +0 -10
  59. data/lib/bard/plugins/run.rb +0 -19
  60. data/lib/bard/plugins/setup.rb +0 -75
  61. data/lib/bard/plugins/ssh/copy.rb +0 -95
  62. data/lib/bard/plugins/ssh.rb +0 -10
  63. data/lib/bard/plugins/vim.rb +0 -6
  64. data/lib/bard/retryable.rb +0 -25
  65. data/lib/bard/secrets.rb +0 -10
  66. data/spec/acceptance/.gitignore +0 -4
  67. data/spec/acceptance/docker/Dockerfile +0 -36
  68. data/spec/acceptance/docker/test_key +0 -27
  69. data/spec/acceptance/docker/test_key.pub +0 -1
  70. data/spec/bard/ci/github_actions_spec.rb +0 -138
  71. data/spec/bard/ci/jenkins_spec.rb +0 -139
  72. data/spec/bard/ci/runner_spec.rb +0 -61
  73. data/spec/bard/ci_spec.rb +0 -10
  74. data/spec/bard/cli/ci_spec.rb +0 -170
  75. data/spec/bard/cli/data_spec.rb +0 -58
  76. data/spec/bard/cli/deploy_spec.rb +0 -243
  77. data/spec/bard/cli/hurt_spec.rb +0 -17
  78. data/spec/bard/cli/install_spec.rb +0 -19
  79. data/spec/bard/cli/master_key_spec.rb +0 -38
  80. data/spec/bard/cli/open_spec.rb +0 -51
  81. data/spec/bard/cli/ping_spec.rb +0 -32
  82. data/spec/bard/cli/run_spec.rb +0 -57
  83. data/spec/bard/cli/setup_spec.rb +0 -99
  84. data/spec/bard/cli/ssh_spec.rb +0 -40
  85. data/spec/bard/cli/stage_spec.rb +0 -127
  86. data/spec/bard/cli/vim_spec.rb +0 -28
  87. data/spec/bard/command_spec.rb +0 -30
  88. data/spec/bard/copy_spec.rb +0 -69
  89. data/spec/bard/deploy_strategy/github_pages_spec.rb +0 -58
  90. data/spec/bard/deploy_strategy/ssh_spec.rb +0 -135
  91. data/spec/bard/deploy_strategy_spec.rb +0 -107
  92. data/spec/bard/dynamic_dsl_spec.rb +0 -46
  93. data/spec/bard/git_spec.rb +0 -101
  94. data/spec/bard/github_spec.rb +0 -45
  95. data/spec/bard/ping_spec.rb +0 -60
  96. data/spec/bard/ssh_copy_spec.rb +0 -44
@@ -1,36 +0,0 @@
1
- FROM ubuntu:24.04
2
-
3
- # Prevent interactive prompts
4
- ENV DEBIAN_FRONTEND=noninteractive
5
-
6
- # Install SSH server, git, and basic tools
7
- RUN apt-get update && \
8
- apt-get install -y \
9
- openssh-server \
10
- git \
11
- sudo \
12
- && rm -rf /var/lib/apt/lists/*
13
-
14
- # Create deploy user
15
- RUN useradd -m -s /bin/bash deploy && \
16
- echo 'deploy:password' | chpasswd
17
-
18
- # Setup SSH
19
- RUN mkdir /var/run/sshd && \
20
- mkdir -p /home/deploy/.ssh && \
21
- chmod 700 /home/deploy/.ssh
22
-
23
- # Copy SSH authorized key
24
- COPY test_key.pub /home/deploy/.ssh/authorized_keys
25
- RUN chown -R deploy:deploy /home/deploy/.ssh && \
26
- chmod 600 /home/deploy/.ssh/authorized_keys
27
-
28
- # Allow SSH login with keys
29
- RUN sed -i 's/#PubkeyAuthentication yes/PubkeyAuthentication yes/' /etc/ssh/sshd_config && \
30
- sed -i 's/#PasswordAuthentication yes/PasswordAuthentication no/' /etc/ssh/sshd_config
31
-
32
- # Expose SSH port
33
- EXPOSE 22
34
-
35
- # Start SSH service
36
- CMD ["/usr/sbin/sshd", "-D"]
@@ -1,27 +0,0 @@
1
- -----BEGIN OPENSSH PRIVATE KEY-----
2
- b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABFwAAAAdzc2gtcn
3
- NhAAAAAwEAAQAAAQEAuvnrkoVh6AISBhqUOtmvTf6TMoq/Do6i/ayn1aqs9YmbN57tNVnY
4
- XEKBQ15HL5bquY0A4Fcf5mO73LyrHGdUODrJS6vZo4J8wcoyEyKxOC2UYV5ssCUntq13de
5
- E4WVHfSykMEo9z3U7bxFSwtwU8ECYQHKLb4OBmQb4hp/nDvx4EM554laBUByGm8fgSKOlY
6
- GEdWE0KAFVsKfkRW8AiR2RtQ5C1hIT/zCmHo01WTtHMpuyZk4cxpBlS3xz6wsD61f6SgMh
7
- M0X575jfV/MxhbDd3FGkxIk8kM24DtLfLW9idYWDD25dfQuXK3eQZDJ3vcoKa+2W73XfHd
8
- fBrAGrvjaQAAA8jQXv0u0F79LgAAAAdzc2gtcnNhAAABAQC6+euShWHoAhIGGpQ62a9N/p
9
- Myir8OjqL9rKfVqqz1iZs3nu01WdhcQoFDXkcvluq5jQDgVx/mY7vcvKscZ1Q4OslLq9mj
10
- gnzByjITIrE4LZRhXmywJSe2rXd14ThZUd9LKQwSj3PdTtvEVLC3BTwQJhAcotvg4GZBvi
11
- Gn+cO/HgQznniVoFQHIabx+BIo6VgYR1YTQoAVWwp+RFbwCJHZG1DkLWEhP/MKYejTVZO0
12
- cym7JmThzGkGVLfHPrCwPrV/pKAyEzRfnvmN9X8zGFsN3cUaTEiTyQzbgO0t8tb2J1hYMP
13
- bl19C5crd5BkMne9ygpr7Zbvdd8d18GsAau+NpAAAAAwEAAQAAAQACxR+WkYfNtbQkfNcm
14
- gmGXZ0wGeGmUCAxwSNMetlMu0GL+jAn0cPg52660ZmHpxFOwu971Xo0QLyOSGwXHm1ydza
15
- R8TMI3atWO0xWdVMr+gPxdBJavIF8ff3U7h5fmXjEPmRQpn+WbSScL2FEFkRwJRYsWZYTv
16
- kVt/zKw3zm/g4Fo7ieeM51heWDOVbNdCk0dcy2YK0L7Kb0FO+zvu3vxXrvWAqKmuRjxefc
17
- FiumkkgaTn78ZIHdfYZa26PmZPIUxVNxRkauvHxYo921t634O0Ji1gwbT5hK8Y7JoGRIp0
18
- alwgjjdbE80ZPuTspmeHQ7OKephb+c8qvoJu/LC8hQiBAAAAgCFGqbOsY9AcIfXY4hlADt
19
- 94P5ySq5q3FbXeriy/CEklDPVER/w4iZaSRwMUqd7V36iZaLwHZyFQSNgIwiN1ysBPbcsq
20
- c642pv4XuAyNTMtD+y8CxcH1LgL7EOEn6if8cgTJ7ayTGT4qIDaUgzf6Ot8z4wDGNKyCpE
21
- lgPfdb8LKiAAAAgQDbrXnetOikB9+p+vf8M59UlfMYx7X9qLDsj0CUn1S0RyxgPWiJDBQl
22
- fZg7WyYOQwRYF0b0s8JlpGLkhLDM6nhBzT1M+nrN0axTAvYkBZV5MJPNg31F/iHxEtt+/V
23
- fMkH6VhmscVyiwEJkDP212dTAaDW3UremlRk77NIZ1PpPKKQAAAIEA2eRCJwNOvdsHYoJ6
24
- k6mEpwISzglbs+y6tTeIwiI7AVGEzvVuKVTCV3n9ljofmnh0UChczIOyywEKSqJi2pos/B
25
- kJoOmCxYMecB9lCxf61MUKdbpWaKF52+GvqT34Ne+VrYGuUp/0+asSTczVudJWRSzcdCji
26
- NEMB0tV88Vro90EAAAANYmFyZC10ZXN0LWtleQECAwQFBg==
27
- -----END OPENSSH PRIVATE KEY-----
@@ -1 +0,0 @@
1
- ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC6+euShWHoAhIGGpQ62a9N/pMyir8OjqL9rKfVqqz1iZs3nu01WdhcQoFDXkcvluq5jQDgVx/mY7vcvKscZ1Q4OslLq9mjgnzByjITIrE4LZRhXmywJSe2rXd14ThZUd9LKQwSj3PdTtvEVLC3BTwQJhAcotvg4GZBviGn+cO/HgQznniVoFQHIabx+BIo6VgYR1YTQoAVWwp+RFbwCJHZG1DkLWEhP/MKYejTVZO0cym7JmThzGkGVLfHPrCwPrV/pKAyEzRfnvmN9X8zGFsN3cUaTEiTyQzbgO0t8tb2J1hYMPbl19C5crd5BkMne9ygpr7Zbvdd8d18GsAau+Np bard-test-key
@@ -1,138 +0,0 @@
1
- require "spec_helper"
2
- require "bard/plugins/deploy/ci/github_actions"
3
-
4
- BASE_URL = "https://api.github.com/repos/botandrosedesign/metrc"
5
-
6
- RSpec.shared_context "github actions stubs" do
7
- let(:run_id) { 123 }
8
- let(:job_id) { 456 }
9
- let(:started_at) { "2024-01-15T10:00:00Z" }
10
- let(:completed_at) { "2024-01-15T10:01:30Z" }
11
- let(:sha) { "abc123" }
12
-
13
- let(:run_json) do
14
- {
15
- "id" => run_id,
16
- "status" => "completed",
17
- "conclusion" => "success",
18
- "head_branch" => "master",
19
- "head_sha" => sha,
20
- "run_started_at" => started_at,
21
- "updated_at" => completed_at,
22
- }
23
- end
24
-
25
- let(:job_json) do
26
- {
27
- "id" => job_id,
28
- "started_at" => started_at,
29
- "completed_at" => completed_at,
30
- }
31
- end
32
-
33
- before do
34
- allow(Bard::Secrets).to receive(:fetch).with("github-apikey").and_return("test-key")
35
- end
36
- end
37
-
38
- describe Bard::CI::GithubActions::API do
39
- include_context "github actions stubs"
40
-
41
- subject { described_class.new("metrc") }
42
-
43
- describe "#last_successful_run" do
44
- before do
45
- stub_request(:get, "#{BASE_URL}/actions/runs")
46
- .with(query: hash_including("status" => "success"))
47
- .to_return(
48
- headers: { "Content-Type" => "application/json" },
49
- body: JSON.dump("workflow_runs" => [run_json]),
50
- )
51
-
52
- stub_request(:get, "#{BASE_URL}/actions/runs/#{run_id}/jobs")
53
- .with(query: hash_including("filter" => "latest"))
54
- .to_return(
55
- headers: { "Content-Type" => "application/json" },
56
- body: JSON.dump("jobs" => [job_json]),
57
- )
58
- end
59
-
60
- it "has #time_elapsed" do
61
- run = subject.last_successful_run
62
- expect(run.time_elapsed).to eq 90
63
- end
64
-
65
- it "has #console" do
66
- stub_request(:get, "#{BASE_URL}/actions/jobs/#{job_id}/logs")
67
- .to_return(
68
- headers: { "Content-Type" => "text/plain" },
69
- body: "build log output here",
70
- )
71
-
72
- expect(subject.last_successful_run.console).to eq "build log output here"
73
- end
74
- end
75
-
76
- describe "#create_run!" do
77
- it "returns a run" do
78
- stub_request(:post, "#{BASE_URL}/actions/workflows/ci.yml/dispatches")
79
- .to_return(status: 204, body: "")
80
-
81
- allow(subject).to receive(:`).with("git rev-parse master").and_return("#{sha}\n")
82
-
83
- stub_request(:get, "#{BASE_URL}/actions/runs")
84
- .with(query: hash_including("head_sha" => sha))
85
- .to_return(
86
- headers: { "Content-Type" => "application/json" },
87
- body: JSON.dump("workflow_runs" => [run_json]),
88
- )
89
-
90
- run = subject.create_run!("master")
91
- expect(run).to be_a Bard::CI::GithubActions::Run
92
- expect(run.id).to eq run_id
93
- end
94
- end
95
- end
96
-
97
- describe Bard::CI::GithubActions do
98
- include_context "github actions stubs"
99
-
100
- subject { described_class.new("metrc", "master", sha) }
101
-
102
- it "returns true on successful run" do
103
- stub_request(:post, "#{BASE_URL}/actions/workflows/ci.yml/dispatches")
104
- .to_return(status: 204, body: "")
105
-
106
- allow_any_instance_of(Bard::CI::GithubActions::API)
107
- .to receive(:`).with("git rev-parse master").and_return("#{sha}\n")
108
-
109
- stub_request(:get, "#{BASE_URL}/actions/runs")
110
- .with(query: hash_including("head_sha" => sha))
111
- .to_return(
112
- headers: { "Content-Type" => "application/json" },
113
- body: JSON.dump("workflow_runs" => [run_json]),
114
- )
115
-
116
- stub_request(:get, "#{BASE_URL}/actions/runs")
117
- .with(query: hash_including("status" => "success"))
118
- .to_return(
119
- headers: { "Content-Type" => "application/json" },
120
- body: JSON.dump("workflow_runs" => [run_json]),
121
- )
122
-
123
- stub_request(:get, "#{BASE_URL}/actions/runs/#{run_id}/jobs")
124
- .with(query: hash_including("filter" => "latest"))
125
- .to_return(
126
- headers: { "Content-Type" => "application/json" },
127
- body: JSON.dump("jobs" => [job_json]),
128
- )
129
-
130
- stub_request(:get, "#{BASE_URL}/actions/runs/#{run_id}")
131
- .to_return(
132
- headers: { "Content-Type" => "application/json" },
133
- body: JSON.dump(run_json),
134
- )
135
-
136
- expect(subject.run { }).to eq true
137
- end
138
- end
@@ -1,139 +0,0 @@
1
- require "spec_helper"
2
- require "bard/plugins/deploy/ci/jenkins"
3
-
4
- RSpec.describe Bard::CI::Jenkins do
5
- let(:jenkins) { described_class.new("test-project", "master", "abc123") }
6
-
7
- before do
8
- allow(Bard::Secrets).to receive(:fetch).with("jenkins-user").and_return("micah")
9
- allow(Bard::Secrets).to receive(:fetch).with("jenkins-token").and_return("fake-token")
10
- end
11
-
12
- describe "#get_last_time_elapsed" do
13
- it "returns the duration in seconds from the last stable build" do
14
- xml = "<build><duration>120000</duration></build>"
15
- allow(jenkins).to receive(:`).with("curl -s http://micah:fake-token@ci.botandrose.com/job/test-project/lastStableBuild/api/xml").and_return(xml)
16
-
17
- result = jenkins.send(:get_last_time_elapsed)
18
- expect(result).to eq 120
19
- end
20
- end
21
-
22
- describe "#run" do
23
- let(:ci_url) { "http://micah:fake-token@ci.botandrose.com/job/test-project" }
24
-
25
- before do
26
- allow(jenkins).to receive(:sleep)
27
- state = instance_double(Bard::CI::State, save: nil, delete: nil)
28
- allow(jenkins).to receive(:state).and_return(state)
29
- end
30
-
31
- it "waits until the build has started before polling" do
32
- allow(jenkins).to receive(:`).with("curl -s -I -X POST -L '#{ci_url}/buildWithParameters?GIT_REF=master'").and_return("Location: http://ci.botandrose.com/queue/item/99/\r\n")
33
- allow(jenkins).to receive(:`).with("curl -s #{ci_url}/lastStableBuild/api/xml").and_return("<build><duration>60000</duration></build>")
34
- allow(jenkins).to receive(:`).with("curl -s -g '#{ci_url}/api/json?depth=1&tree=builds[queueId,number]'").and_return(
35
- '{"builds":[{"queueId":1,"number":1}]}',
36
- '{"builds":[{"queueId":99,"number":5}]}',
37
- '{"builds":[{"queueId":99,"number":5}]}'
38
- )
39
- allow(jenkins).to receive(:`).with("curl -s #{ci_url}/5/api/json?tree=building,result").and_return('{"building":false,"result":"SUCCESS"}')
40
-
41
- result = jenkins.run { |elapsed, last_time| }
42
- expect(result).to eq true
43
- end
44
- end
45
-
46
- describe "#started?" do
47
- before do
48
- jenkins.instance_variable_set(:@queueId, 99)
49
- end
50
-
51
- it "retries when builds list is empty (job just created)" do
52
- allow(jenkins).to receive(:`).with(/api\/json\?depth=1/).and_return(
53
- '{"builds":[]}',
54
- '{"builds":[{"queueId":99,"number":1}]}'
55
- )
56
- allow(jenkins).to receive(:sleep)
57
-
58
- expect(jenkins.send(:started?)).to eq true
59
- end
60
- end
61
-
62
- describe "#exists?" do
63
- it "returns truthy when the job exists" do
64
- allow(jenkins).to receive(:`).with(/curl -s -I/).and_return("HTTP/1.1 200 OK\r\n")
65
-
66
- expect(jenkins.exists?).to be_truthy
67
- end
68
-
69
- it "auto-creates the job when it does not exist" do
70
- allow(jenkins).to receive(:`).with(/curl -s -I/).and_return("HTTP/1.1 404 Not Found\r\n")
71
- allow(jenkins).to receive(:`).with("git remote get-url origin").and_return("git@gitlab.com:botandrose/test-project.git\n")
72
- allow(File).to receive(:exist?).with("config/master.key").and_return(false)
73
- expect(jenkins).to receive(:`).with(/curl -s -X POST.*createItem\?name=test-project.*Content-Type: application\/xml/)
74
-
75
- jenkins.exists?
76
- end
77
-
78
- it "includes a master key build step when config/master.key exists" do
79
- allow(jenkins).to receive(:`).with(/curl -s -I/).and_return("HTTP/1.1 404 Not Found\r\n")
80
- allow(jenkins).to receive(:`).with("git remote get-url origin").and_return("git@gitlab.com:botandrose/test-project.git\n")
81
- allow(File).to receive(:exist?).with("config/master.key").and_return(true)
82
- allow(File).to receive(:read).with("config/master.key").and_return("abc123secret")
83
-
84
- config_xml = nil
85
- allow(jenkins).to receive(:`).with(/createItem/) do |cmd|
86
- config_xml = cmd
87
- ""
88
- end
89
-
90
- jenkins.exists?
91
- expect(config_xml).to include("abc123secret")
92
- expect(config_xml).to include("config/master.key")
93
- end
94
- end
95
-
96
- describe "#building? and #success?" do
97
- before do
98
- jenkins.instance_variable_set(:@job_id, 42)
99
- end
100
-
101
- it "detects a successful build" do
102
- allow(jenkins).to receive(:`).with("curl -s http://micah:fake-token@ci.botandrose.com/job/test-project/42/api/json?tree=building,result").and_return('{"building":false,"result":"SUCCESS"}')
103
-
104
- expect(jenkins.send(:building?)).to eq false
105
- expect(jenkins.send(:success?)).to eq true
106
- end
107
-
108
- it "detects a failed build" do
109
- allow(jenkins).to receive(:`).with("curl -s http://micah:fake-token@ci.botandrose.com/job/test-project/42/api/json?tree=building,result").and_return('{"building":false,"result":"FAILURE"}')
110
-
111
- expect(jenkins.send(:building?)).to eq false
112
- expect(jenkins.send(:success?)).to eq false
113
- end
114
-
115
- it "detects a build in progress" do
116
- allow(jenkins).to receive(:`).with("curl -s http://micah:fake-token@ci.botandrose.com/job/test-project/42/api/json?tree=building,result").and_return('{"building":true,"result":null}')
117
-
118
- expect(jenkins.send(:building?)).to eq true
119
- end
120
-
121
- it "handles JSON with spaces in keys" do
122
- allow(jenkins).to receive(:`).with("curl -s http://micah:fake-token@ci.botandrose.com/job/test-project/42/api/json?tree=building,result").and_return('{"_class":"hudson.model.FreeStyleBuild","building":false,"result":"SUCCESS"}')
123
-
124
- expect(jenkins.send(:building?)).to eq false
125
- expect(jenkins.send(:success?)).to eq true
126
- end
127
-
128
- it "success? reflects the last response from building?" do
129
- allow(jenkins).to receive(:`).with("curl -s http://micah:fake-token@ci.botandrose.com/job/test-project/42/api/json?tree=building,result").and_return(
130
- '{"building":true,"result":null}',
131
- '{"building":false,"result":"SUCCESS"}'
132
- )
133
-
134
- jenkins.send(:building?) # first call — still building
135
- jenkins.send(:building?) # second call — done
136
- expect(jenkins.send(:success?)).to eq true
137
- end
138
- end
139
- end
@@ -1,61 +0,0 @@
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 DELETED
@@ -1,10 +0,0 @@
1
- require "bard/plugins/deploy/ci"
2
-
3
- describe Bard::CI do
4
- subject { described_class.new("tracker", "master") }
5
-
6
- describe "#exists?"
7
- describe "#status"
8
- describe "#console"
9
- describe "#run"
10
- end
@@ -1,170 +0,0 @@
1
- require "spec_helper"
2
- require "bard/cli"
3
- require "ostruct"
4
-
5
- describe "bard ci" do
6
- let(:cli) { Bard::CLI.new }
7
- let(:ci_runner) { double("ci_runner") }
8
-
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")
12
- allow(cli).to receive(:puts)
13
- allow(cli).to receive(:print)
14
- allow(cli).to receive(:exit)
15
- allow(cli).to receive(:red).and_return("")
16
- allow($stdout).to receive(:flush)
17
- allow(Bard::Git).to receive(:current_branch).and_return("feature-branch")
18
- allow(Bard::CI).to receive(:new).and_return(ci_runner)
19
- end
20
-
21
- describe "#ci" do
22
- it "should have a ci command" do
23
- expect(cli).to respond_to(:ci)
24
- end
25
-
26
- context "when CI exists and status option is set" do
27
- it "prints CI status and returns early" do
28
- allow(cli).to receive(:options).and_return({ "status" => true })
29
- allow(ci_runner).to receive(:exists?).and_return(true)
30
- allow(ci_runner).to receive(:status).and_return("Build #123: SUCCESS")
31
-
32
- expect(cli).to receive(:puts).with("Build #123: SUCCESS")
33
- expect(ci_runner).not_to receive(:run)
34
-
35
- cli.ci
36
- end
37
- end
38
-
39
- context "when CI exists and running normally" do
40
- before do
41
- allow(cli).to receive(:options).and_return({})
42
- allow(ci_runner).to receive(:exists?).and_return(true)
43
- end
44
-
45
- it "starts CI build and handles success" do
46
- allow(ci_runner).to receive(:run).and_yield(30, 60).and_return(true)
47
-
48
- expect(cli).to receive(:puts).with("Continuous integration: starting build on feature-branch...")
49
- expect(cli).to receive(:puts).with("Continuous integration: success!")
50
-
51
- cli.ci
52
- end
53
-
54
- it "handles CI failure" do
55
- allow(ci_runner).to receive(:run).and_yield(30, 60).and_return(false)
56
- allow(ci_runner).to receive(:console).and_return("Test failed: spec/model_spec.rb")
57
-
58
- expect(cli).to receive(:puts).with("Continuous integration: starting build on feature-branch...")
59
- expect(cli).to receive(:puts).with("Test failed: spec/model_spec.rb")
60
- expect(cli).to receive(:puts) # The puts with newline
61
- expect(cli).to receive(:puts) # The "Automated tests failed!" message
62
- expect(cli).to receive(:exit).with(1)
63
-
64
- cli.ci
65
- end
66
-
67
- it "displays progress with estimated completion time" do
68
- allow(ci_runner).to receive(:run).and_yield(30, 60).and_return(true)
69
-
70
- expect(cli).to receive(:print).with("\x08" * " Estimated completion: 50%".length)
71
- expect(cli).to receive(:print).with(" Estimated completion: 50%")
72
-
73
- cli.ci
74
- end
75
-
76
- it "displays progress without estimated completion time" do
77
- allow(ci_runner).to receive(:run).and_yield(45, nil).and_return(true)
78
-
79
- expect(cli).to receive(:print).with("\x08" * " No estimated completion time. Elapsed time: 45 sec".length)
80
- expect(cli).to receive(:print).with(" No estimated completion time. Elapsed time: 45 sec")
81
-
82
- cli.ci
83
- end
84
- end
85
-
86
- context "when CI doesn't exist" do
87
- it "shows error message and exits" do
88
- allow(cli).to receive(:options).and_return({})
89
- allow(ci_runner).to receive(:exists?).and_return(false)
90
- allow(cli).to receive(:exit).with(1).and_raise(SystemExit)
91
-
92
- expect { cli.ci }.to raise_error(SystemExit)
93
- end
94
- end
95
-
96
- context "with custom branch" do
97
- it "uses the specified branch" do
98
- allow(cli).to receive(:options).and_return({})
99
- allow(ci_runner).to receive(:exists?).and_return(true)
100
- allow(ci_runner).to receive(:run).and_return(true)
101
-
102
- expect(Bard::CI).to receive(:new).with("test_project", "develop", runner_name: nil)
103
- expect(cli).to receive(:puts).with("Continuous integration: starting build on develop...")
104
-
105
- cli.ci("develop")
106
- end
107
- end
108
-
109
- context "with local-ci option" do
110
- it "passes local runner_name to CI" do
111
- allow(cli).to receive(:options).and_return({ "local-ci" => true })
112
- allow(ci_runner).to receive(:exists?).and_return(true)
113
- allow(ci_runner).to receive(:run).and_return(true)
114
-
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)
140
-
141
- cli.ci
142
- end
143
- end
144
-
145
- context "with resume option" do
146
- it "calls resume instead of run" do
147
- allow(cli).to receive(:options).and_return({ "resume" => true })
148
- allow(ci_runner).to receive(:exists?).and_return(true)
149
- allow(ci_runner).to receive(:resume).and_yield(30, 60).and_return(true)
150
-
151
- expect(cli).to receive(:puts).with("Continuous integration: resuming build...")
152
- expect(cli).to receive(:puts).with("Continuous integration: success!")
153
- expect(ci_runner).not_to receive(:run)
154
-
155
- cli.ci
156
- end
157
-
158
- it "displays progress when resuming" do
159
- allow(cli).to receive(:options).and_return({ "resume" => true })
160
- allow(ci_runner).to receive(:exists?).and_return(true)
161
- allow(ci_runner).to receive(:resume).and_yield(30, 60).and_return(true)
162
-
163
- expect(cli).to receive(:print).with("\x08" * " Estimated completion: 50%".length)
164
- expect(cli).to receive(:print).with(" Estimated completion: 50%")
165
-
166
- cli.ci
167
- end
168
- end
169
- end
170
- end
@@ -1,58 +0,0 @@
1
- require "spec_helper"
2
- require "bard/cli"
3
-
4
- describe "bard data" do
5
- let(:cli) { Bard::CLI.new }
6
-
7
- it "should have a data command" do
8
- expect(cli).to respond_to(:data)
9
- end
10
-
11
- context "data" do
12
- let(:from) { double("from", key: :production, run!: nil, require_capability!: nil) }
13
- let(:to) { double("to", key: :local, run!: nil) }
14
-
15
- let(:config) do
16
- double("config", data: [], :[] => nil).tap do |config|
17
- allow(config).to receive(:[]).with("production").and_return(from)
18
- allow(config).to receive(:[]).with("local").and_return(to)
19
- end
20
- end
21
-
22
- before do
23
- allow(cli).to receive(:config).and_return(config)
24
- allow(cli).to receive(:options).and_return({from: "production", to: "local"})
25
- allow(cli).to receive(:puts)
26
- end
27
-
28
- it "should run the data command" do
29
- expect(from).to receive(:run!).with("bin/rake db:dump")
30
- expect(Bard::Copy).to receive(:file).with("db/data.sql.gz", from: from, to: to, verbose: true)
31
- expect(to).to receive(:run!).with("bin/rake db:load")
32
- cli.data
33
- end
34
-
35
- context "pushing to production" do
36
- let(:to) { double("to", key: :production, url: "https://example.com", run!: nil, require_capability!: nil) }
37
-
38
- before do
39
- allow(cli).to receive(:options).and_return({from: "local", to: "production"})
40
- allow(config).to receive(:[]).with("production").and_return(to)
41
- allow(config).to receive(:[]).with("local").and_return(from)
42
- end
43
-
44
- it "should prevent pushing to production if the user does not confirm" do
45
- expect(cli).to receive(:ask).and_return("no")
46
- expect { cli.data }.to raise_error(SystemExit)
47
- end
48
-
49
- it "should allow pushing to production if the user confirms" do
50
- expect(cli).to receive(:ask).and_return("https://example.com")
51
- expect(from).to receive(:run!).with("bin/rake db:dump")
52
- expect(Bard::Copy).to receive(:file).with("db/data.sql.gz", from: from, to: to, verbose: true)
53
- expect(to).to receive(:run!).with("bin/rake db:load")
54
- cli.data
55
- end
56
- end
57
- end
58
- end