bard 1.4.10 → 1.5.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.
- checksums.yaml +4 -4
- data/lib/bard/ci/github_actions.rb +46 -15
- data/lib/bard/ci/jenkins.rb +62 -42
- data/lib/bard/ci/local.rb +28 -18
- data/lib/bard/ci/retryable.rb +27 -0
- data/lib/bard/ci/runner.rb +78 -0
- data/lib/bard/ci/state.rb +40 -0
- data/lib/bard/ci.rb +1 -1
- data/lib/bard/cli/ci.rb +26 -11
- data/lib/bard/github.rb +21 -17
- data/lib/bard/version.rb +1 -1
- data/spec/bard/cli/ci_spec.rb +26 -2
- metadata +4 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: d0f636850eb0b2f55f75b125dfef31c7bea2bfc0d9927fbb9714431c32694369
|
|
4
|
+
data.tar.gz: 66c491d452f1eda598647bfced569674d367d79289d8203b1fefc145e524c6df
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: c87fd3c0723f0be35ca017d74348e7c3e711aa36a7b0ad1042ca9b1f09c0a7f675499eabc963a96d7d474693dc96adc8e887e0e2e1067efd291f379d801c9b87
|
|
7
|
+
data.tar.gz: 2c0a7de1674bc3db706ea4990549393c0a4fe8cc289f1a78e8171650e2343b9140158bb2c07796787e1206df40af1c0ac679118436edcaf0c7cb8e9a03f9256b
|
|
@@ -1,23 +1,10 @@
|
|
|
1
1
|
require "time"
|
|
2
2
|
require "bard/github"
|
|
3
|
+
require "bard/ci/runner"
|
|
3
4
|
|
|
4
5
|
module Bard
|
|
5
6
|
class CI
|
|
6
|
-
class GithubActions <
|
|
7
|
-
def run
|
|
8
|
-
last_time_elapsed = api.last_successful_run&.time_elapsed
|
|
9
|
-
@run = api.create_run!(branch)
|
|
10
|
-
|
|
11
|
-
start_time = Time.new.to_i
|
|
12
|
-
while @run.building?
|
|
13
|
-
elapsed_time = Time.new.to_i - start_time
|
|
14
|
-
yield elapsed_time, last_time_elapsed
|
|
15
|
-
sleep(2)
|
|
16
|
-
@run = api.find_run(@run.id)
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
@run.success?
|
|
20
|
-
end
|
|
7
|
+
class GithubActions < Runner
|
|
21
8
|
|
|
22
9
|
def exists?
|
|
23
10
|
true
|
|
@@ -40,6 +27,50 @@ module Bard
|
|
|
40
27
|
end
|
|
41
28
|
end
|
|
42
29
|
|
|
30
|
+
protected
|
|
31
|
+
|
|
32
|
+
def start
|
|
33
|
+
@run = api.create_run!(branch)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def get_last_time_elapsed
|
|
37
|
+
api.last_successful_run&.time_elapsed
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def building?
|
|
41
|
+
@run.building?
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def success?
|
|
45
|
+
@run.success?
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def get_state_data
|
|
49
|
+
{
|
|
50
|
+
"project_name" => project_name,
|
|
51
|
+
"branch" => branch,
|
|
52
|
+
"run_id" => @run.id,
|
|
53
|
+
"start_time" => @start_time,
|
|
54
|
+
"last_time_elapsed" => @last_time_elapsed
|
|
55
|
+
}
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def restore_state(data)
|
|
59
|
+
@run = api.find_run(data["run_id"])
|
|
60
|
+
@start_time = data["start_time"]
|
|
61
|
+
@last_time_elapsed = data["last_time_elapsed"]
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def poll_until_complete
|
|
65
|
+
while @run.building?
|
|
66
|
+
elapsed_time = Time.new.to_i - @start_time
|
|
67
|
+
yield elapsed_time, @last_time_elapsed
|
|
68
|
+
save_state
|
|
69
|
+
sleep(2)
|
|
70
|
+
@run = api.find_run(@run.id)
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
|
|
43
74
|
private
|
|
44
75
|
|
|
45
76
|
def api
|
data/lib/bard/ci/jenkins.rb
CHANGED
|
@@ -1,22 +1,9 @@
|
|
|
1
1
|
require "json"
|
|
2
|
+
require "bard/ci/runner"
|
|
2
3
|
|
|
3
4
|
module Bard
|
|
4
5
|
class CI
|
|
5
|
-
class Jenkins <
|
|
6
|
-
def run
|
|
7
|
-
last_time_elapsed = get_last_time_elapsed
|
|
8
|
-
start
|
|
9
|
-
sleep(2) until started?
|
|
10
|
-
|
|
11
|
-
start_time = Time.new.to_i
|
|
12
|
-
while building?
|
|
13
|
-
elapsed_time = Time.new.to_i - start_time
|
|
14
|
-
yield elapsed_time, last_time_elapsed
|
|
15
|
-
sleep(2)
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
success?
|
|
19
|
-
end
|
|
6
|
+
class Jenkins < Runner
|
|
20
7
|
|
|
21
8
|
def exists?
|
|
22
9
|
`curl -s -I #{ci_host}/` =~ /\b200 OK\b/
|
|
@@ -29,12 +16,61 @@ module Bard
|
|
|
29
16
|
|
|
30
17
|
attr_accessor :last_response
|
|
31
18
|
|
|
19
|
+
protected
|
|
20
|
+
|
|
21
|
+
def wait_until_started
|
|
22
|
+
sleep(2) until started?
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def start
|
|
26
|
+
command = "curl -s -I -X POST -L '#{ci_host}/buildWithParameters?GIT_REF=#{sha}'"
|
|
27
|
+
output = `#{command}`
|
|
28
|
+
@queueId = output[%r{Location: .+/queue/item/(\d+)/}, 1].to_i
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def building?
|
|
32
|
+
retry_with_backoff do
|
|
33
|
+
self.last_response = `curl -s #{ci_host}/#{job_id}/api/json?tree=building,result`
|
|
34
|
+
raise "Blank response from CI" if last_response.blank?
|
|
35
|
+
end
|
|
36
|
+
last_response.include? '"building":true'
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def success?
|
|
40
|
+
last_response.include? '"result":"SUCCESS"'
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def get_state_data
|
|
44
|
+
{
|
|
45
|
+
"project_name" => project_name,
|
|
46
|
+
"branch" => branch,
|
|
47
|
+
"queue_id" => @queueId,
|
|
48
|
+
"job_id" => @job_id,
|
|
49
|
+
"start_time" => @start_time,
|
|
50
|
+
"last_time_elapsed" => @last_time_elapsed
|
|
51
|
+
}
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def restore_state(data)
|
|
55
|
+
@queueId = data["queue_id"]
|
|
56
|
+
@job_id = data["job_id"]
|
|
57
|
+
@start_time = data["start_time"]
|
|
58
|
+
@last_time_elapsed = data["last_time_elapsed"]
|
|
59
|
+
end
|
|
60
|
+
|
|
32
61
|
private
|
|
33
62
|
|
|
34
63
|
def get_last_time_elapsed
|
|
35
|
-
|
|
64
|
+
retry_with_backoff do
|
|
65
|
+
response = `curl -s #{ci_host}/lastStableBuild/api/xml`
|
|
66
|
+
raise "Blank response from CI" if response.blank?
|
|
67
|
+
response
|
|
68
|
+
end
|
|
36
69
|
response.match(/<duration>(\d+)<\/duration>/)
|
|
37
70
|
$1 ? $1.to_i / 1000 : nil
|
|
71
|
+
rescue => e
|
|
72
|
+
puts " Warning: Could not get last build duration: #{e.message}"
|
|
73
|
+
nil
|
|
38
74
|
end
|
|
39
75
|
|
|
40
76
|
def auth
|
|
@@ -45,39 +81,23 @@ module Bard
|
|
|
45
81
|
"http://#{auth}@ci.botandrose.com/job/#{project_name}"
|
|
46
82
|
end
|
|
47
83
|
|
|
48
|
-
def start
|
|
49
|
-
command = "curl -s -I -X POST -L '#{ci_host}/buildWithParameters?GIT_REF=#{sha}'"
|
|
50
|
-
output = `#{command}`
|
|
51
|
-
@queueId = output[%r{Location: .+/queue/item/(\d+)/}, 1].to_i
|
|
52
|
-
end
|
|
53
|
-
|
|
54
84
|
def started?
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
85
|
+
retry_with_backoff do
|
|
86
|
+
command = "curl -s -g '#{ci_host}/api/json?depth=1&tree=builds[queueId,number]'"
|
|
87
|
+
output = `#{command}`
|
|
88
|
+
raise "Blank response from CI" if output.blank?
|
|
89
|
+
JSON.parse(output)["builds"][0]["queueId"] == @queueId
|
|
90
|
+
end
|
|
58
91
|
end
|
|
59
92
|
|
|
60
93
|
def job_id
|
|
61
94
|
@job_id ||= begin
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
def building?
|
|
68
|
-
self.last_response = `curl -s #{ci_host}/#{job_id}/api/json?tree=building,result`
|
|
69
|
-
if last_response.blank?
|
|
70
|
-
sleep(2) # retry
|
|
71
|
-
self.last_response = `curl -s #{ci_host}/#{job_id}/api/json?tree=building,result`
|
|
72
|
-
if last_response.blank?
|
|
73
|
-
raise "Blank response from CI twice in a row. Aborting!"
|
|
95
|
+
retry_with_backoff do
|
|
96
|
+
output = `curl -s -g '#{ci_host}/api/json?depth=1&tree=builds[queueId,number]'`
|
|
97
|
+
raise "Blank response from CI" if output.blank?
|
|
98
|
+
output[/"number":(\d+),"queueId":#{@queueId}\b/, 1].to_i
|
|
74
99
|
end
|
|
75
100
|
end
|
|
76
|
-
last_response.include? '"building":true'
|
|
77
|
-
end
|
|
78
|
-
|
|
79
|
-
def success?
|
|
80
|
-
last_response.include? '"result":"SUCCESS"'
|
|
81
101
|
end
|
|
82
102
|
end
|
|
83
103
|
end
|
data/lib/bard/ci/local.rb
CHANGED
|
@@ -1,24 +1,9 @@
|
|
|
1
1
|
require "open3"
|
|
2
|
+
require "bard/ci/runner"
|
|
2
3
|
|
|
3
4
|
module Bard
|
|
4
5
|
class CI
|
|
5
|
-
class Local <
|
|
6
|
-
def run
|
|
7
|
-
start
|
|
8
|
-
|
|
9
|
-
start_time = Time.new.to_i
|
|
10
|
-
while building?
|
|
11
|
-
elapsed_time = Time.new.to_i - start_time
|
|
12
|
-
yield elapsed_time, nil
|
|
13
|
-
sleep(2)
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
@stdin.close
|
|
17
|
-
@console = @stdout_and_stderr.read
|
|
18
|
-
@stdout_and_stderr.close
|
|
19
|
-
|
|
20
|
-
success?
|
|
21
|
-
end
|
|
6
|
+
class Local < Runner
|
|
22
7
|
|
|
23
8
|
def exists?
|
|
24
9
|
true
|
|
@@ -28,7 +13,7 @@ module Bard
|
|
|
28
13
|
@console
|
|
29
14
|
end
|
|
30
15
|
|
|
31
|
-
|
|
16
|
+
protected
|
|
32
17
|
|
|
33
18
|
def start
|
|
34
19
|
@stdin, @stdout_and_stderr, @wait_thread = Open3.popen2e("CLEAN=true bin/rake ci")
|
|
@@ -41,6 +26,31 @@ module Bard
|
|
|
41
26
|
def success?
|
|
42
27
|
@wait_thread.value.success?
|
|
43
28
|
end
|
|
29
|
+
|
|
30
|
+
def get_state_data
|
|
31
|
+
{
|
|
32
|
+
"project_name" => project_name,
|
|
33
|
+
"branch" => branch,
|
|
34
|
+
"start_time" => @start_time
|
|
35
|
+
}
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def restore_state(data)
|
|
39
|
+
raise "Cannot resume local CI: process is no longer running. Start a new build with 'bard ci'."
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def poll_until_complete
|
|
43
|
+
while building?
|
|
44
|
+
elapsed_time = Time.new.to_i - @start_time
|
|
45
|
+
yield elapsed_time, nil
|
|
46
|
+
save_state
|
|
47
|
+
sleep(2)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
@stdin.close
|
|
51
|
+
@console = @stdout_and_stderr.read
|
|
52
|
+
@stdout_and_stderr.close
|
|
53
|
+
end
|
|
44
54
|
end
|
|
45
55
|
end
|
|
46
56
|
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
module Bard
|
|
2
|
+
class CI
|
|
3
|
+
module Retryable
|
|
4
|
+
MAX_RETRIES = 5
|
|
5
|
+
INITIAL_DELAY = 1
|
|
6
|
+
|
|
7
|
+
def retry_with_backoff(max_retries: MAX_RETRIES)
|
|
8
|
+
retries = 0
|
|
9
|
+
delay = INITIAL_DELAY
|
|
10
|
+
|
|
11
|
+
begin
|
|
12
|
+
yield
|
|
13
|
+
rescue => e
|
|
14
|
+
if retries < max_retries
|
|
15
|
+
retries += 1
|
|
16
|
+
puts " Network error (attempt #{retries}/#{max_retries}): #{e.message}. Retrying in #{delay}s..."
|
|
17
|
+
sleep(delay)
|
|
18
|
+
delay *= 2
|
|
19
|
+
retry
|
|
20
|
+
else
|
|
21
|
+
raise "Network error after #{max_retries} attempts: #{e.message}"
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
require "bard/ci/state"
|
|
2
|
+
require "bard/ci/retryable"
|
|
3
|
+
|
|
4
|
+
module Bard
|
|
5
|
+
class CI
|
|
6
|
+
class Runner < Struct.new(:project_name, :branch, :sha)
|
|
7
|
+
include Retryable
|
|
8
|
+
|
|
9
|
+
def run
|
|
10
|
+
start
|
|
11
|
+
@start_time = Time.new.to_i
|
|
12
|
+
@last_time_elapsed = get_last_time_elapsed
|
|
13
|
+
save_state
|
|
14
|
+
wait_until_started if respond_to?(:wait_until_started)
|
|
15
|
+
|
|
16
|
+
poll_until_complete { |elapsed, last_time| yield elapsed, last_time }
|
|
17
|
+
|
|
18
|
+
state.delete
|
|
19
|
+
success?
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def resume
|
|
23
|
+
saved_state = state.load
|
|
24
|
+
raise "No saved CI state found for #{project_name}. Start a new build with 'bard ci'." if saved_state.nil?
|
|
25
|
+
|
|
26
|
+
restore_state(saved_state)
|
|
27
|
+
poll_until_complete { |elapsed, last_time| yield elapsed, last_time }
|
|
28
|
+
|
|
29
|
+
state.delete
|
|
30
|
+
success?
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
protected
|
|
34
|
+
|
|
35
|
+
def poll_until_complete
|
|
36
|
+
while building?
|
|
37
|
+
elapsed_time = Time.new.to_i - @start_time
|
|
38
|
+
yield elapsed_time, @last_time_elapsed
|
|
39
|
+
save_state
|
|
40
|
+
sleep(2)
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def save_state
|
|
45
|
+
state.save(get_state_data)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def state
|
|
49
|
+
@state ||= State.new(project_name)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# Abstract methods - override in subclasses
|
|
53
|
+
def start
|
|
54
|
+
raise NotImplementedError, "#{self.class}#start not implemented"
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def building?
|
|
58
|
+
raise NotImplementedError, "#{self.class}#building? not implemented"
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def success?
|
|
62
|
+
raise NotImplementedError, "#{self.class}#success? not implemented"
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def get_last_time_elapsed
|
|
66
|
+
nil
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def get_state_data
|
|
70
|
+
raise NotImplementedError, "#{self.class}#get_state_data not implemented"
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def restore_state(data)
|
|
74
|
+
raise NotImplementedError, "#{self.class}#restore_state not implemented"
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
require "json"
|
|
2
|
+
require "fileutils"
|
|
3
|
+
|
|
4
|
+
module Bard
|
|
5
|
+
class CI
|
|
6
|
+
class State
|
|
7
|
+
def initialize project_name
|
|
8
|
+
@project_name = project_name
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def save data
|
|
12
|
+
FileUtils.mkdir_p(state_dir)
|
|
13
|
+
File.write(state_file, JSON.generate(data))
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def load
|
|
17
|
+
return nil unless File.exist?(state_file)
|
|
18
|
+
JSON.parse(File.read(state_file))
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def delete
|
|
22
|
+
File.delete(state_file) if File.exist?(state_file)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def exists?
|
|
26
|
+
File.exist?(state_file)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
private
|
|
30
|
+
|
|
31
|
+
def state_dir
|
|
32
|
+
File.join(Dir.pwd, "tmp", "bard", "ci")
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def state_file
|
|
36
|
+
File.join(state_dir, "#{@project_name}.json")
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
data/lib/bard/ci.rb
CHANGED
data/lib/bard/cli/ci.rb
CHANGED
|
@@ -7,30 +7,45 @@ module Bard::CLI::CI
|
|
|
7
7
|
|
|
8
8
|
option :"local-ci", type: :boolean
|
|
9
9
|
option :status, type: :boolean
|
|
10
|
+
option :resume, type: :boolean
|
|
10
11
|
desc "ci [branch=HEAD]", "runs ci against BRANCH"
|
|
11
12
|
def ci branch=Bard::Git.current_branch
|
|
12
13
|
ci = Bard::CI.new(project_name, branch, local: options["local-ci"])
|
|
13
14
|
if ci.exists?
|
|
14
15
|
return puts ci.status if options["status"]
|
|
15
16
|
|
|
16
|
-
|
|
17
|
+
if options["resume"]
|
|
18
|
+
puts "Continuous integration: resuming build..."
|
|
19
|
+
success = ci.resume do |elapsed_time, last_time|
|
|
20
|
+
if last_time
|
|
21
|
+
percentage = (elapsed_time.to_f / last_time.to_f * 100).to_i
|
|
22
|
+
output = " Estimated completion: #{percentage}%"
|
|
23
|
+
else
|
|
24
|
+
output = " No estimated completion time. Elapsed time: #{elapsed_time} sec"
|
|
25
|
+
end
|
|
26
|
+
print "\x08" * output.length
|
|
27
|
+
print output
|
|
28
|
+
$stdout.flush
|
|
29
|
+
end
|
|
30
|
+
else
|
|
31
|
+
puts "Continuous integration: starting build on #{branch}..."
|
|
17
32
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
33
|
+
success = ci.run do |elapsed_time, last_time|
|
|
34
|
+
if last_time
|
|
35
|
+
percentage = (elapsed_time.to_f / last_time.to_f * 100).to_i
|
|
36
|
+
output = " Estimated completion: #{percentage}%"
|
|
37
|
+
else
|
|
38
|
+
output = " No estimated completion time. Elapsed time: #{elapsed_time} sec"
|
|
39
|
+
end
|
|
40
|
+
print "\x08" * output.length
|
|
41
|
+
print output
|
|
42
|
+
$stdout.flush
|
|
24
43
|
end
|
|
25
|
-
print "\x08" * output.length
|
|
26
|
-
print output
|
|
27
|
-
$stdout.flush
|
|
28
44
|
end
|
|
29
45
|
|
|
30
46
|
if success
|
|
31
47
|
puts
|
|
32
48
|
puts "Continuous integration: success!"
|
|
33
|
-
puts "Deploying..."
|
|
34
49
|
else
|
|
35
50
|
puts
|
|
36
51
|
puts ci.console
|
data/lib/bard/github.rb
CHANGED
|
@@ -2,9 +2,11 @@ require "net/http"
|
|
|
2
2
|
require "json"
|
|
3
3
|
require "base64"
|
|
4
4
|
require "rbnacl"
|
|
5
|
+
require "bard/ci/retryable"
|
|
5
6
|
|
|
6
7
|
module Bard
|
|
7
8
|
class Github < Struct.new(:project_name)
|
|
9
|
+
include CI::Retryable
|
|
8
10
|
def get path, params={}
|
|
9
11
|
request(path) do |uri|
|
|
10
12
|
uri.query = URI.encode_www_form(params)
|
|
@@ -117,26 +119,28 @@ module Bard
|
|
|
117
119
|
end
|
|
118
120
|
end
|
|
119
121
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
122
|
+
retry_with_backoff do
|
|
123
|
+
req = nil
|
|
124
|
+
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
|
|
125
|
+
req = block.call(uri)
|
|
126
|
+
req["Accept"] = "application/vnd.github+json"
|
|
127
|
+
req["Authorization"] = "Bearer #{github_apikey}"
|
|
128
|
+
req["X-GitHub-Api-Version"] = "2022-11-28"
|
|
129
|
+
http.request(req)
|
|
130
|
+
end
|
|
128
131
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
132
|
+
case response
|
|
133
|
+
when Net::HTTPRedirection then
|
|
134
|
+
Net::HTTP.get(URI(response["Location"]))
|
|
135
|
+
when Net::HTTPSuccess then
|
|
136
|
+
if response["Content-Type"].to_s.include?("/json")
|
|
137
|
+
JSON.load(response.body)
|
|
138
|
+
else
|
|
139
|
+
response.body
|
|
140
|
+
end
|
|
135
141
|
else
|
|
136
|
-
response.body
|
|
142
|
+
raise [req.method, req.uri, req.to_hash, response, response.body].inspect
|
|
137
143
|
end
|
|
138
|
-
else
|
|
139
|
-
raise [req.method, req.uri, req.to_hash, response, response.body].inspect
|
|
140
144
|
end
|
|
141
145
|
end
|
|
142
146
|
end
|
data/lib/bard/version.rb
CHANGED
data/spec/bard/cli/ci_spec.rb
CHANGED
|
@@ -61,7 +61,6 @@ describe Bard::CLI::CI do
|
|
|
61
61
|
|
|
62
62
|
expect(cli).to receive(:puts).with("Continuous integration: starting build on feature-branch...")
|
|
63
63
|
expect(cli).to receive(:puts).with("Continuous integration: success!")
|
|
64
|
-
expect(cli).to receive(:puts).with("Deploying...")
|
|
65
64
|
|
|
66
65
|
cli.ci
|
|
67
66
|
end
|
|
@@ -135,5 +134,30 @@ describe Bard::CLI::CI do
|
|
|
135
134
|
cli.ci
|
|
136
135
|
end
|
|
137
136
|
end
|
|
137
|
+
|
|
138
|
+
context "with resume option" do
|
|
139
|
+
it "calls resume instead of run" do
|
|
140
|
+
allow(cli).to receive(:options).and_return({ "resume" => true })
|
|
141
|
+
allow(ci_runner).to receive(:exists?).and_return(true)
|
|
142
|
+
allow(ci_runner).to receive(:resume).and_yield(30, 60).and_return(true)
|
|
143
|
+
|
|
144
|
+
expect(cli).to receive(:puts).with("Continuous integration: resuming build...")
|
|
145
|
+
expect(cli).to receive(:puts).with("Continuous integration: success!")
|
|
146
|
+
expect(ci_runner).not_to receive(:run)
|
|
147
|
+
|
|
148
|
+
cli.ci
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
it "displays progress when resuming" do
|
|
152
|
+
allow(cli).to receive(:options).and_return({ "resume" => true })
|
|
153
|
+
allow(ci_runner).to receive(:exists?).and_return(true)
|
|
154
|
+
allow(ci_runner).to receive(:resume).and_yield(30, 60).and_return(true)
|
|
155
|
+
|
|
156
|
+
expect(cli).to receive(:print).with("\x08" * " Estimated completion: 50%".length)
|
|
157
|
+
expect(cli).to receive(:print).with(" Estimated completion: 50%")
|
|
158
|
+
|
|
159
|
+
cli.ci
|
|
160
|
+
end
|
|
161
|
+
end
|
|
138
162
|
end
|
|
139
|
-
end
|
|
163
|
+
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: bard
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.
|
|
4
|
+
version: 1.5.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Micah Geisel
|
|
@@ -164,6 +164,9 @@ files:
|
|
|
164
164
|
- lib/bard/ci/github_actions.rb
|
|
165
165
|
- lib/bard/ci/jenkins.rb
|
|
166
166
|
- lib/bard/ci/local.rb
|
|
167
|
+
- lib/bard/ci/retryable.rb
|
|
168
|
+
- lib/bard/ci/runner.rb
|
|
169
|
+
- lib/bard/ci/state.rb
|
|
167
170
|
- lib/bard/cli.rb
|
|
168
171
|
- lib/bard/cli/ci.rb
|
|
169
172
|
- lib/bard/cli/command.rb
|