bard 1.8.0 → 1.9.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CLAUDE.md +76 -0
- data/PLUGINS.md +114 -0
- data/README.md +14 -6
- data/features/ci.feature +62 -0
- data/features/deploy_git_workflow.feature +88 -0
- data/features/step_definitions/bard_steps.rb +96 -0
- data/features/support/bard-coverage +16 -0
- data/features/support/env.rb +10 -1
- data/features/support/test_server.rb +2 -1
- data/lib/bard/ci/github_actions.rb +1 -2
- data/lib/bard/ci/jenkins.rb +82 -11
- data/lib/bard/ci/local.rb +6 -6
- data/lib/bard/ci/runner.rb +35 -1
- data/lib/bard/ci.rb +11 -23
- data/lib/bard/cli/ci.rb +45 -38
- data/lib/bard/cli/deploy.rb +40 -8
- data/lib/bard/cli/hurt.rb +10 -15
- data/lib/bard/cli/install.rb +7 -12
- data/lib/bard/cli/open.rb +12 -16
- data/lib/bard/cli/ping.rb +8 -14
- data/lib/bard/cli/run.rb +5 -3
- data/lib/bard/cli/stage.rb +10 -1
- data/lib/bard/cli/vim.rb +5 -10
- data/lib/bard/cli.rb +13 -11
- data/lib/bard/command.rb +3 -3
- data/lib/bard/config.rb +4 -14
- data/lib/bard/github.rb +2 -4
- data/lib/bard/plugin.rb +99 -0
- data/lib/bard/plugins/backup.rb +19 -0
- data/lib/bard/plugins/github_pages.rb +34 -0
- data/lib/bard/plugins/hurt.rb +5 -0
- data/lib/bard/plugins/install.rb +5 -0
- data/lib/bard/plugins/jenkins.rb +6 -0
- data/lib/bard/plugins/new.rb +5 -0
- data/lib/bard/plugins/ping.rb +6 -0
- data/lib/bard/plugins/provision.rb +5 -0
- data/lib/bard/plugins/vim.rb +5 -0
- data/lib/bard/provision/ssh.rb +9 -2
- data/lib/bard/secrets.rb +10 -0
- data/lib/bard/server.rb +3 -2
- data/lib/bard/target.rb +3 -2
- data/lib/bard/version.rb +1 -1
- data/spec/bard/ci/github_actions_spec.rb +116 -13
- data/spec/bard/ci/jenkins_spec.rb +139 -0
- data/spec/bard/ci/runner_spec.rb +61 -0
- data/spec/bard/cli/ci_spec.rb +34 -8
- data/spec/bard/cli/deploy_spec.rb +20 -8
- data/spec/bard/cli/hurt_spec.rb +2 -2
- data/spec/bard/cli/install_spec.rb +4 -4
- data/spec/bard/cli/open_spec.rb +10 -8
- data/spec/bard/cli/ping_spec.rb +5 -5
- data/spec/bard/cli/run_spec.rb +20 -1
- data/spec/bard/cli/stage_spec.rb +20 -0
- data/spec/bard/cli/vim_spec.rb +5 -5
- data/spec/bard/config_spec.rb +12 -0
- data/spec/bard/github_spec.rb +1 -1
- data/spec/bard/plugin_spec.rb +79 -0
- data/spec/bard/provision/ssh_spec.rb +17 -4
- data/spec/spec_helper.rb +6 -1
- metadata +27 -3
- data/README.rdoc +0 -15
data/lib/bard/cli.rb
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
# this file gets loaded in the CLI context, not the Rails boot context
|
|
2
2
|
|
|
3
3
|
require "thor"
|
|
4
|
+
require "bard/version"
|
|
4
5
|
require "bard/config"
|
|
5
6
|
require "bard/command"
|
|
7
|
+
require "bard/plugin"
|
|
6
8
|
require "term/ansicolor"
|
|
7
9
|
|
|
8
10
|
module Bard
|
|
@@ -19,23 +21,23 @@ module Bard
|
|
|
19
21
|
master_key: "MasterKey",
|
|
20
22
|
setup: "Setup",
|
|
21
23
|
run: "Run",
|
|
22
|
-
open: "Open",
|
|
23
24
|
ssh: "SSH",
|
|
24
|
-
install: "Install",
|
|
25
|
-
ping: "Ping",
|
|
26
|
-
hurt: "Hurt",
|
|
27
|
-
vim: "Vim",
|
|
28
25
|
}.each do |command, klass|
|
|
29
26
|
require "bard/cli/#{command}"
|
|
30
27
|
include const_get(klass)
|
|
31
28
|
end
|
|
32
29
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
30
|
+
Plugin.load_all!
|
|
31
|
+
Plugin.all.each { |plugin| plugin.apply_to_cli(self) }
|
|
32
|
+
|
|
33
|
+
# Load core CI runners AFTER plugins so GithubActions is the default (last registered wins)
|
|
34
|
+
require "bard/ci/local"
|
|
35
|
+
require "bard/ci/github_actions"
|
|
36
|
+
|
|
37
|
+
map "--version" => :version
|
|
38
|
+
desc "version", "Display version"
|
|
39
|
+
def version
|
|
40
|
+
puts Bard::VERSION
|
|
39
41
|
end
|
|
40
42
|
|
|
41
43
|
def self.exit_on_failure? = true
|
data/lib/bard/command.rb
CHANGED
|
@@ -17,9 +17,9 @@ module Bard
|
|
|
17
17
|
end
|
|
18
18
|
|
|
19
19
|
def run! verbose: false, quiet: false
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
20
|
+
result = run(verbose:, quiet:)
|
|
21
|
+
raise Error.new(full_command) unless result
|
|
22
|
+
result
|
|
23
23
|
end
|
|
24
24
|
|
|
25
25
|
def run verbose: false, quiet: false
|
data/lib/bard/config.rb
CHANGED
|
@@ -52,7 +52,9 @@ module Bard
|
|
|
52
52
|
# New v2.0 API - creates Target instances
|
|
53
53
|
def target(key, &block)
|
|
54
54
|
key = key.to_sym
|
|
55
|
-
@servers[key]
|
|
55
|
+
unless @servers[key].is_a?(Target)
|
|
56
|
+
@servers[key] = Target.new(key, self)
|
|
57
|
+
end
|
|
56
58
|
@servers[key].instance_eval(&block) if block
|
|
57
59
|
@servers[key]
|
|
58
60
|
end
|
|
@@ -131,19 +133,7 @@ module Bard
|
|
|
131
133
|
return nil if @ci_system == false
|
|
132
134
|
|
|
133
135
|
require "bard/ci"
|
|
134
|
-
|
|
135
|
-
# Use the existing CI class which handles auto-detection
|
|
136
|
-
case @ci_system
|
|
137
|
-
when :local
|
|
138
|
-
CI.new(project_name, branch, local: true)
|
|
139
|
-
when :github_actions, :jenkins, nil
|
|
140
|
-
# CI class auto-detects between github_actions and jenkins
|
|
141
|
-
CI.new(project_name, branch)
|
|
142
|
-
when false
|
|
143
|
-
nil
|
|
144
|
-
else
|
|
145
|
-
CI.new(project_name, branch)
|
|
146
|
-
end
|
|
136
|
+
CI.new(project_name, branch, runner_name: @ci_system)
|
|
147
137
|
end
|
|
148
138
|
|
|
149
139
|
private
|
data/lib/bard/github.rb
CHANGED
|
@@ -3,6 +3,7 @@ require "json"
|
|
|
3
3
|
require "base64"
|
|
4
4
|
require "rbnacl"
|
|
5
5
|
require "bard/ci/retryable"
|
|
6
|
+
require "bard/secrets"
|
|
6
7
|
|
|
7
8
|
module Bard
|
|
8
9
|
class Github < Struct.new(:project_name)
|
|
@@ -107,10 +108,7 @@ module Bard
|
|
|
107
108
|
private
|
|
108
109
|
|
|
109
110
|
def api_key
|
|
110
|
-
@api_key ||=
|
|
111
|
-
raw = `git ls-remote -t git@github.com:botandrosedesign/secrets`
|
|
112
|
-
raw[/github-apikey\|(.+)$/, 1]
|
|
113
|
-
end
|
|
111
|
+
@api_key ||= Bard::Secrets.fetch("github-apikey")
|
|
114
112
|
end
|
|
115
113
|
|
|
116
114
|
def request path, &block
|
data/lib/bard/plugin.rb
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
module Bard
|
|
2
|
+
class Plugin
|
|
3
|
+
@registry = {}
|
|
4
|
+
|
|
5
|
+
class << self
|
|
6
|
+
attr_reader :registry
|
|
7
|
+
|
|
8
|
+
def register(name, &block)
|
|
9
|
+
plugin = new(name)
|
|
10
|
+
plugin.instance_eval(&block) if block
|
|
11
|
+
@registry[name.to_sym] = plugin
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def [](name)
|
|
15
|
+
@registry[name.to_sym]
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def all
|
|
19
|
+
@registry.values
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def load_all!
|
|
23
|
+
Dir[File.join(__dir__, "plugins", "*.rb")].sort.each { |f| require f }
|
|
24
|
+
all.each(&:apply!)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def reset!
|
|
28
|
+
@registry = {}
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
attr_reader :name, :cli_modules
|
|
33
|
+
|
|
34
|
+
def initialize(name)
|
|
35
|
+
@name = name.to_sym
|
|
36
|
+
@cli_modules = []
|
|
37
|
+
@cli_requires = []
|
|
38
|
+
@target_methods = {}
|
|
39
|
+
@config_methods = {}
|
|
40
|
+
@requires = []
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# DSL methods for defining plugins
|
|
44
|
+
|
|
45
|
+
def require_file(path)
|
|
46
|
+
@requires << path
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def cli(mod, require: nil)
|
|
50
|
+
@cli_requires << require if require
|
|
51
|
+
@cli_modules << mod
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def target_method(name, &block)
|
|
55
|
+
@target_methods[name] = block
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def config_method(name, &block)
|
|
59
|
+
@config_methods[name] = block
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
# Apply plugin to the system (non-CLI parts)
|
|
63
|
+
def apply!
|
|
64
|
+
@requires.each { |path| require path }
|
|
65
|
+
apply_target_methods!
|
|
66
|
+
apply_config_methods!
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def apply_to_cli(cli_class)
|
|
70
|
+
@cli_requires.each { |path| require path }
|
|
71
|
+
@cli_modules.each do |mod|
|
|
72
|
+
mod = resolve_constant(mod) if mod.is_a?(String)
|
|
73
|
+
mod.setup(cli_class)
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
private
|
|
78
|
+
|
|
79
|
+
def apply_target_methods!
|
|
80
|
+
return if @target_methods.empty?
|
|
81
|
+
require "bard/target"
|
|
82
|
+
@target_methods.each do |method_name, block|
|
|
83
|
+
Target.define_method(method_name, &block)
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def apply_config_methods!
|
|
88
|
+
return if @config_methods.empty?
|
|
89
|
+
require "bard/config"
|
|
90
|
+
@config_methods.each do |method_name, block|
|
|
91
|
+
Config.define_method(method_name, &block)
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def resolve_constant(name)
|
|
96
|
+
name.split("::").reduce(Object) { |mod, const| mod.const_get(const) }
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
require "bard/plugin"
|
|
2
|
+
|
|
3
|
+
Bard::Plugin.register :backup do
|
|
4
|
+
config_method :backup do |value = nil, &block|
|
|
5
|
+
if block
|
|
6
|
+
@backup = Bard::BackupConfig.new(&block)
|
|
7
|
+
elsif value == false
|
|
8
|
+
@backup = Bard::BackupConfig.new { disabled }
|
|
9
|
+
elsif value.nil? # Getter
|
|
10
|
+
@backup ||= Bard::BackupConfig.new { bard }
|
|
11
|
+
else
|
|
12
|
+
raise ArgumentError, "backup accepts false or a block"
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
config_method :backup_enabled? do
|
|
17
|
+
backup == true
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
require "bard/plugin"
|
|
2
|
+
|
|
3
|
+
# Load the deploy strategy (auto-registers via inherited hook)
|
|
4
|
+
require "bard/deploy_strategy/github_pages"
|
|
5
|
+
|
|
6
|
+
Bard::Plugin.register :github_pages do
|
|
7
|
+
# Config DSL: github_pages "url" sets up a production target
|
|
8
|
+
config_method :github_pages do |url|
|
|
9
|
+
urls = []
|
|
10
|
+
uri = url.start_with?("http") ? URI.parse(url) : URI.parse("https://#{url}")
|
|
11
|
+
hostname = uri.hostname.sub(/^www\./, "")
|
|
12
|
+
urls = [hostname]
|
|
13
|
+
urls << "www.#{hostname}" if hostname.count(".") < 2
|
|
14
|
+
|
|
15
|
+
target :production do
|
|
16
|
+
github_pages url
|
|
17
|
+
ssh false
|
|
18
|
+
ping(*urls) if urls.any?
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
backup false
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# Target DSL: github_pages sets deploy strategy
|
|
25
|
+
target_method :github_pages do |url = nil|
|
|
26
|
+
if url.nil?
|
|
27
|
+
@github_pages_url
|
|
28
|
+
else
|
|
29
|
+
@deploy_strategy = :github_pages
|
|
30
|
+
@github_pages_url = url
|
|
31
|
+
enable_capability(:github_pages)
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
data/lib/bard/provision/ssh.rb
CHANGED
|
@@ -19,7 +19,14 @@ class Bard::Provision::SSH < Bard::Provision
|
|
|
19
19
|
add_ssh_known_host!(provision_server.ssh_uri)
|
|
20
20
|
end
|
|
21
21
|
print " Reconfiguring port to #{target_port},"
|
|
22
|
-
provision_server.run! %(echo "Port #{target_port}" | sudo tee /etc/ssh/sshd_config.d/port_#{target_port}.conf
|
|
22
|
+
provision_server.run! %(echo "Port #{target_port}" | sudo tee /etc/ssh/sshd_config.d/port_#{target_port}.conf && sudo service ssh restart), home: true
|
|
23
|
+
5.times do
|
|
24
|
+
sleep 1
|
|
25
|
+
break if ssh_available?(provision_server.ssh_uri, port: target_port)
|
|
26
|
+
end
|
|
27
|
+
if !ssh_available?(provision_server.ssh_uri, port: target_port)
|
|
28
|
+
raise "reconfigured SSH to port #{target_port} but it's not responding — check firewall and sshd_config Include directive"
|
|
29
|
+
end
|
|
23
30
|
end
|
|
24
31
|
|
|
25
32
|
if !ssh_known_host?(provision_server.ssh_uri)
|
|
@@ -65,7 +72,7 @@ class Bard::Provision::SSH < Bard::Provision
|
|
|
65
72
|
|
|
66
73
|
def disable_password_auth!
|
|
67
74
|
provision_server.run!(
|
|
68
|
-
%q{echo "PasswordAuthentication no" | sudo tee /etc/ssh/sshd_config.d/disable_password_auth.conf
|
|
75
|
+
%q{echo "PasswordAuthentication no" | sudo tee /etc/ssh/sshd_config.d/disable_password_auth.conf && sudo service ssh restart},
|
|
69
76
|
home: true
|
|
70
77
|
)
|
|
71
78
|
end
|
data/lib/bard/secrets.rb
ADDED
data/lib/bard/server.rb
CHANGED
|
@@ -135,8 +135,9 @@ module Bard
|
|
|
135
135
|
key
|
|
136
136
|
end
|
|
137
137
|
|
|
138
|
-
def run! command, home: false, verbose: false, quiet: false
|
|
139
|
-
Bard::Command.run!
|
|
138
|
+
def run! command, home: false, verbose: false, quiet: false, capture: false
|
|
139
|
+
result = Bard::Command.run!(command, on: self, home:, verbose:, quiet:)
|
|
140
|
+
result if capture
|
|
140
141
|
end
|
|
141
142
|
|
|
142
143
|
def run command, home: false, verbose: false, quiet: false
|
data/lib/bard/target.rb
CHANGED
|
@@ -217,9 +217,10 @@ module Bard
|
|
|
217
217
|
end
|
|
218
218
|
|
|
219
219
|
# Remote command execution
|
|
220
|
-
def run!(command, home: false, verbose: false, quiet: false)
|
|
220
|
+
def run!(command, home: false, verbose: false, quiet: false, capture: false)
|
|
221
221
|
require_capability!(:ssh)
|
|
222
|
-
Command.run!(command, on: self, home: home, verbose: verbose, quiet: quiet)
|
|
222
|
+
result = Command.run!(command, on: self, home: home, verbose: verbose, quiet: quiet)
|
|
223
|
+
result if capture
|
|
223
224
|
end
|
|
224
225
|
|
|
225
226
|
def run(command, home: false, verbose: false, quiet: false)
|
data/lib/bard/version.rb
CHANGED
|
@@ -1,35 +1,138 @@
|
|
|
1
|
+
require "spec_helper"
|
|
1
2
|
require "bard/ci/github_actions"
|
|
2
3
|
|
|
3
|
-
|
|
4
|
-
|
|
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
|
|
5
24
|
|
|
6
|
-
|
|
7
|
-
|
|
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")
|
|
8
35
|
end
|
|
9
36
|
end
|
|
10
37
|
|
|
11
38
|
describe Bard::CI::GithubActions::API do
|
|
39
|
+
include_context "github actions stubs"
|
|
40
|
+
|
|
12
41
|
subject { described_class.new("metrc") }
|
|
13
42
|
|
|
14
43
|
describe "#last_successful_run" do
|
|
15
|
-
|
|
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
|
|
16
61
|
run = subject.last_successful_run
|
|
17
|
-
run.time_elapsed
|
|
62
|
+
expect(run.time_elapsed).to eq 90
|
|
18
63
|
end
|
|
19
64
|
|
|
20
|
-
|
|
21
|
-
|
|
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"
|
|
22
73
|
end
|
|
23
74
|
end
|
|
24
75
|
|
|
25
76
|
describe "#create_run!" do
|
|
26
|
-
|
|
27
|
-
|
|
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
|
|
28
93
|
end
|
|
29
94
|
end
|
|
30
95
|
end
|
|
31
96
|
|
|
32
|
-
describe Bard::
|
|
33
|
-
|
|
34
|
-
|
|
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")
|
|
35
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
|