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.
- checksums.yaml +4 -4
- data/README.md +7 -487
- data/Rakefile +1 -4
- data/bard.gemspec +2 -11
- data/lib/bard/config.rb +22 -20
- data/lib/bard/plugins/ping/target_methods.rb +0 -9
- data/lib/bard/plugins/ssh/connection.rb +2 -35
- data/lib/bard/target.rb +0 -15
- data/lib/bard/version.rb +1 -1
- data/lib/bard.rb +2 -1
- data/spec/bard/capability_spec.rb +0 -8
- data/spec/bard/config_spec.rb +30 -67
- data/spec/bard/target_spec.rb +1 -36
- metadata +4 -225
- data/ARCHITECTURE.md +0 -957
- data/CUSTOM_STRATEGIES.md +0 -701
- data/MIGRATION_GUIDE.md +0 -513
- data/PLUGINS.md +0 -99
- data/bin/bard +0 -4
- data/features/ci.feature +0 -63
- data/features/data.feature +0 -13
- data/features/deploy.feature +0 -14
- data/features/deploy_git_workflow.feature +0 -89
- data/features/run.feature +0 -14
- data/features/step_definitions/bard_steps.rb +0 -136
- data/features/support/bard-coverage +0 -16
- data/features/support/env.rb +0 -22
- data/features/support/test_server.rb +0 -216
- data/lib/bard/cli.rb +0 -44
- data/lib/bard/command.rb +0 -31
- data/lib/bard/copy.rb +0 -45
- data/lib/bard/plugins/data.rb +0 -56
- data/lib/bard/plugins/deploy/ci/github_actions.rb +0 -202
- data/lib/bard/plugins/deploy/ci/jenkins.rb +0 -176
- data/lib/bard/plugins/deploy/ci/local.rb +0 -57
- data/lib/bard/plugins/deploy/ci/runner.rb +0 -112
- data/lib/bard/plugins/deploy/ci/state.rb +0 -40
- data/lib/bard/plugins/deploy/ci.rb +0 -38
- data/lib/bard/plugins/deploy/ssh_strategy.rb +0 -26
- data/lib/bard/plugins/deploy/strategy.rb +0 -60
- data/lib/bard/plugins/deploy.rb +0 -260
- data/lib/bard/plugins/git.rb +0 -45
- data/lib/bard/plugins/github.rb +0 -152
- data/lib/bard/plugins/github_pages/strategy.rb +0 -170
- data/lib/bard/plugins/github_pages.rb +0 -35
- data/lib/bard/plugins/hurt.rb +0 -13
- data/lib/bard/plugins/install/.github/dependabot.yml +0 -18
- data/lib/bard/plugins/install/.github/workflows/cache-ci.yml +0 -15
- data/lib/bard/plugins/install/.github/workflows/ci.yml +0 -74
- data/lib/bard/plugins/install/apt_dependencies.rb +0 -33
- data/lib/bard/plugins/install/ci +0 -5
- data/lib/bard/plugins/install/setup +0 -13
- data/lib/bard/plugins/install/specified_bundler.rb +0 -15
- data/lib/bard/plugins/install/specified_ruby.rb +0 -59
- data/lib/bard/plugins/install.rb +0 -9
- data/lib/bard/plugins/open.rb +0 -20
- data/lib/bard/plugins/ping/check.rb +0 -66
- data/lib/bard/plugins/ping.rb +0 -10
- data/lib/bard/plugins/run.rb +0 -19
- data/lib/bard/plugins/setup.rb +0 -75
- data/lib/bard/plugins/ssh/copy.rb +0 -95
- data/lib/bard/plugins/ssh.rb +0 -10
- data/lib/bard/plugins/vim.rb +0 -6
- data/lib/bard/retryable.rb +0 -25
- data/lib/bard/secrets.rb +0 -10
- data/spec/acceptance/.gitignore +0 -4
- data/spec/acceptance/docker/Dockerfile +0 -36
- data/spec/acceptance/docker/test_key +0 -27
- data/spec/acceptance/docker/test_key.pub +0 -1
- data/spec/bard/ci/github_actions_spec.rb +0 -138
- data/spec/bard/ci/jenkins_spec.rb +0 -139
- data/spec/bard/ci/runner_spec.rb +0 -61
- data/spec/bard/ci_spec.rb +0 -10
- data/spec/bard/cli/ci_spec.rb +0 -170
- data/spec/bard/cli/data_spec.rb +0 -58
- data/spec/bard/cli/deploy_spec.rb +0 -243
- data/spec/bard/cli/hurt_spec.rb +0 -17
- data/spec/bard/cli/install_spec.rb +0 -19
- data/spec/bard/cli/master_key_spec.rb +0 -38
- data/spec/bard/cli/open_spec.rb +0 -51
- data/spec/bard/cli/ping_spec.rb +0 -32
- data/spec/bard/cli/run_spec.rb +0 -57
- data/spec/bard/cli/setup_spec.rb +0 -99
- data/spec/bard/cli/ssh_spec.rb +0 -40
- data/spec/bard/cli/stage_spec.rb +0 -127
- data/spec/bard/cli/vim_spec.rb +0 -28
- data/spec/bard/command_spec.rb +0 -30
- data/spec/bard/copy_spec.rb +0 -69
- data/spec/bard/deploy_strategy/github_pages_spec.rb +0 -58
- data/spec/bard/deploy_strategy/ssh_spec.rb +0 -135
- data/spec/bard/deploy_strategy_spec.rb +0 -107
- data/spec/bard/dynamic_dsl_spec.rb +0 -46
- data/spec/bard/git_spec.rb +0 -101
- data/spec/bard/github_spec.rb +0 -45
- data/spec/bard/ping_spec.rb +0 -60
- data/spec/bard/ssh_copy_spec.rb +0 -44
|
@@ -1,202 +0,0 @@
|
|
|
1
|
-
require "time"
|
|
2
|
-
require "bard/plugins/github"
|
|
3
|
-
require "bard/plugins/deploy/ci/runner"
|
|
4
|
-
|
|
5
|
-
module Bard
|
|
6
|
-
class CI
|
|
7
|
-
class GithubActions < Runner
|
|
8
|
-
def exists?
|
|
9
|
-
File.exist?(".github/workflows/ci.yml")
|
|
10
|
-
end
|
|
11
|
-
|
|
12
|
-
def console
|
|
13
|
-
@run.console
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
def status
|
|
17
|
-
last_run = api.last_run
|
|
18
|
-
if last_run.building?
|
|
19
|
-
"Building..."
|
|
20
|
-
elsif last_run.success?
|
|
21
|
-
"Succeeded!"
|
|
22
|
-
elsif last_run.failure?
|
|
23
|
-
"Failed!\n\n#{last_run.console}"
|
|
24
|
-
else
|
|
25
|
-
raise "Unknown job status: #{last_run.inspect}"
|
|
26
|
-
end
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
protected
|
|
30
|
-
|
|
31
|
-
def start
|
|
32
|
-
@run = api.create_run!(branch)
|
|
33
|
-
end
|
|
34
|
-
|
|
35
|
-
def get_last_time_elapsed
|
|
36
|
-
api.last_successful_run&.time_elapsed
|
|
37
|
-
end
|
|
38
|
-
|
|
39
|
-
def building?
|
|
40
|
-
@run.building?
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
def success?
|
|
44
|
-
@run.success?
|
|
45
|
-
end
|
|
46
|
-
|
|
47
|
-
def get_state_data
|
|
48
|
-
{
|
|
49
|
-
"project_name" => project_name,
|
|
50
|
-
"branch" => branch,
|
|
51
|
-
"run_id" => @run.id,
|
|
52
|
-
"start_time" => @start_time,
|
|
53
|
-
"last_time_elapsed" => @last_time_elapsed
|
|
54
|
-
}
|
|
55
|
-
end
|
|
56
|
-
|
|
57
|
-
def restore_state(data)
|
|
58
|
-
@run = api.find_run(data["run_id"])
|
|
59
|
-
@start_time = data["start_time"]
|
|
60
|
-
@last_time_elapsed = data["last_time_elapsed"]
|
|
61
|
-
end
|
|
62
|
-
|
|
63
|
-
def poll_until_complete
|
|
64
|
-
while @run.building?
|
|
65
|
-
elapsed_time = Time.new.to_i - @start_time
|
|
66
|
-
yield elapsed_time, @last_time_elapsed
|
|
67
|
-
save_state
|
|
68
|
-
sleep(2)
|
|
69
|
-
@run = api.find_run(@run.id)
|
|
70
|
-
end
|
|
71
|
-
end
|
|
72
|
-
|
|
73
|
-
private
|
|
74
|
-
|
|
75
|
-
def api
|
|
76
|
-
@api ||= API.new(project_name)
|
|
77
|
-
end
|
|
78
|
-
|
|
79
|
-
class API < Struct.new(:project_name)
|
|
80
|
-
def last_run
|
|
81
|
-
response = client.get("actions/runs", event: "workflow_dispatch", per_page: 1)
|
|
82
|
-
if json = response["workflow_runs"][0]
|
|
83
|
-
Run.new(self, json)
|
|
84
|
-
end
|
|
85
|
-
end
|
|
86
|
-
|
|
87
|
-
def last_successful_run
|
|
88
|
-
successful_runs = client.get("actions/runs", event: "workflow_dispatch", status: "success", per_page: 1)
|
|
89
|
-
if json = successful_runs["workflow_runs"][0]
|
|
90
|
-
Run.new(self, json)
|
|
91
|
-
end
|
|
92
|
-
end
|
|
93
|
-
|
|
94
|
-
def find_run id
|
|
95
|
-
json = client.get("actions/runs/#{id}")
|
|
96
|
-
Run.new(self, json)
|
|
97
|
-
end
|
|
98
|
-
|
|
99
|
-
def create_run! branch
|
|
100
|
-
start_time = Time.now
|
|
101
|
-
client.post("actions/workflows/ci.yml/dispatches", ref: branch, inputs: { "git-ref": branch })
|
|
102
|
-
sha = `git rev-parse #{branch}`.chomp
|
|
103
|
-
|
|
104
|
-
loop do
|
|
105
|
-
runs = client.get("actions/runs", event: "workflow_dispatch", head_sha: sha, created: ">#{start_time.iso8601}")
|
|
106
|
-
if json = runs["workflow_runs"].first
|
|
107
|
-
return Run.new(self, json)
|
|
108
|
-
end
|
|
109
|
-
sleep 1
|
|
110
|
-
end
|
|
111
|
-
end
|
|
112
|
-
|
|
113
|
-
def find_job_by_run_id run_id
|
|
114
|
-
jobs = client.get("actions/runs/#{run_id}/jobs", filter: "latest", per_page: 1)
|
|
115
|
-
job_json = jobs["jobs"][0]
|
|
116
|
-
Job.new(self, job_json)
|
|
117
|
-
end
|
|
118
|
-
|
|
119
|
-
def download_logs_by_job_id job_id
|
|
120
|
-
client.get("actions/jobs/#{job_id}/logs")
|
|
121
|
-
end
|
|
122
|
-
|
|
123
|
-
private
|
|
124
|
-
|
|
125
|
-
def client
|
|
126
|
-
@client ||= Bard::Github.new(project_name)
|
|
127
|
-
end
|
|
128
|
-
end
|
|
129
|
-
|
|
130
|
-
class Run < Struct.new(:api, :json)
|
|
131
|
-
def id
|
|
132
|
-
json["id"]
|
|
133
|
-
end
|
|
134
|
-
|
|
135
|
-
def time_elapsed
|
|
136
|
-
job.time_elapsed
|
|
137
|
-
end
|
|
138
|
-
|
|
139
|
-
def building?
|
|
140
|
-
%w[in_progress queued requested waiting pending]
|
|
141
|
-
.include?(json["status"])
|
|
142
|
-
end
|
|
143
|
-
|
|
144
|
-
def success?
|
|
145
|
-
status == "completed" && conclusion == "success"
|
|
146
|
-
end
|
|
147
|
-
|
|
148
|
-
def failure?
|
|
149
|
-
conclusion == "failure"
|
|
150
|
-
end
|
|
151
|
-
|
|
152
|
-
def job
|
|
153
|
-
@job ||= api.find_job_by_run_id(id)
|
|
154
|
-
end
|
|
155
|
-
|
|
156
|
-
def console
|
|
157
|
-
job.logs
|
|
158
|
-
end
|
|
159
|
-
|
|
160
|
-
def branch
|
|
161
|
-
json["head_branch"]
|
|
162
|
-
end
|
|
163
|
-
|
|
164
|
-
def sha
|
|
165
|
-
json["head_sha"]
|
|
166
|
-
end
|
|
167
|
-
|
|
168
|
-
def status
|
|
169
|
-
json["status"]
|
|
170
|
-
end
|
|
171
|
-
|
|
172
|
-
def conclusion
|
|
173
|
-
json["conclusion"]
|
|
174
|
-
end
|
|
175
|
-
|
|
176
|
-
def started_at
|
|
177
|
-
Time.parse(json["run_started_at"])
|
|
178
|
-
end
|
|
179
|
-
|
|
180
|
-
def updated_at
|
|
181
|
-
Time.parse(json["updated_at"])
|
|
182
|
-
end
|
|
183
|
-
end
|
|
184
|
-
|
|
185
|
-
class Job < Struct.new(:api, :json)
|
|
186
|
-
def id
|
|
187
|
-
json["id"]
|
|
188
|
-
end
|
|
189
|
-
|
|
190
|
-
def time_elapsed
|
|
191
|
-
Time.parse(json["completed_at"]).to_i -
|
|
192
|
-
Time.parse(json["started_at"]).to_i
|
|
193
|
-
end
|
|
194
|
-
|
|
195
|
-
def logs
|
|
196
|
-
@logs ||= api.download_logs_by_job_id(id)
|
|
197
|
-
end
|
|
198
|
-
end
|
|
199
|
-
end
|
|
200
|
-
end
|
|
201
|
-
end
|
|
202
|
-
|
|
@@ -1,176 +0,0 @@
|
|
|
1
|
-
require "json"
|
|
2
|
-
require "bard/plugins/deploy/ci/runner"
|
|
3
|
-
require "bard/secrets"
|
|
4
|
-
|
|
5
|
-
module Bard
|
|
6
|
-
class CI
|
|
7
|
-
class Jenkins < Runner
|
|
8
|
-
def exists?
|
|
9
|
-
`curl -s -I #{ci_host}/` =~ /\b200 OK\b/ or create!
|
|
10
|
-
end
|
|
11
|
-
|
|
12
|
-
private def create!
|
|
13
|
-
git_url = `git remote get-url origin`.strip
|
|
14
|
-
config = JOB_CONFIG_XML.sub("GIT_URL", git_url)
|
|
15
|
-
if File.exist?("config/master.key")
|
|
16
|
-
master_key = File.read("config/master.key").strip
|
|
17
|
-
master_key_step = <<~XML.chomp
|
|
18
|
-
<hudson.tasks.Shell>
|
|
19
|
-
<command>echo #{master_key} > config/master.key</command>
|
|
20
|
-
</hudson.tasks.Shell>
|
|
21
|
-
|
|
22
|
-
XML
|
|
23
|
-
config = config.sub("<builders>\n", "<builders>\n #{master_key_step}")
|
|
24
|
-
end
|
|
25
|
-
`curl -s -X POST "http://#{auth}@ci.botandrose.com/createItem?name=#{project_name}" -H "Content-Type: application/xml" -d '#{config}'`
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
def console
|
|
29
|
-
raw = `curl -s #{ci_host}/lastBuild/console`
|
|
30
|
-
raw[%r{<pre.*?>(.+)</pre>}m, 1]
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
attr_accessor :last_response
|
|
34
|
-
|
|
35
|
-
protected
|
|
36
|
-
|
|
37
|
-
def wait_until_started
|
|
38
|
-
sleep(2) until started?
|
|
39
|
-
end
|
|
40
|
-
|
|
41
|
-
def start
|
|
42
|
-
command = "curl -s -I -X POST -L '#{ci_host}/buildWithParameters?GIT_REF=#{branch}'"
|
|
43
|
-
output = `#{command}`
|
|
44
|
-
@queueId = output[%r{Location: .+/queue/item/(\d+)/}, 1].to_i
|
|
45
|
-
end
|
|
46
|
-
|
|
47
|
-
def building?
|
|
48
|
-
retry_with_backoff do
|
|
49
|
-
self.last_response = `curl -s #{ci_host}/#{job_id}/api/json?tree=building,result`
|
|
50
|
-
raise "Blank response from CI" if last_response.empty?
|
|
51
|
-
end
|
|
52
|
-
last_response.include? '"building":true'
|
|
53
|
-
end
|
|
54
|
-
|
|
55
|
-
def success?
|
|
56
|
-
last_response.include? '"result":"SUCCESS"'
|
|
57
|
-
end
|
|
58
|
-
|
|
59
|
-
def get_state_data
|
|
60
|
-
{
|
|
61
|
-
"project_name" => project_name,
|
|
62
|
-
"branch" => branch,
|
|
63
|
-
"queue_id" => @queueId,
|
|
64
|
-
"job_id" => @job_id,
|
|
65
|
-
"start_time" => @start_time,
|
|
66
|
-
"last_time_elapsed" => @last_time_elapsed
|
|
67
|
-
}
|
|
68
|
-
end
|
|
69
|
-
|
|
70
|
-
def restore_state(data)
|
|
71
|
-
@queueId = data["queue_id"]
|
|
72
|
-
@job_id = data["job_id"]
|
|
73
|
-
@start_time = data["start_time"]
|
|
74
|
-
@last_time_elapsed = data["last_time_elapsed"]
|
|
75
|
-
end
|
|
76
|
-
|
|
77
|
-
private
|
|
78
|
-
|
|
79
|
-
def get_last_time_elapsed
|
|
80
|
-
response = retry_with_backoff do
|
|
81
|
-
response = `curl -s #{ci_host}/lastStableBuild/api/xml`
|
|
82
|
-
raise "Blank response from CI" if response.empty?
|
|
83
|
-
response
|
|
84
|
-
end
|
|
85
|
-
response.match(/<duration>(\d+)<\/duration>/)
|
|
86
|
-
$1 ? $1.to_i / 1000 : nil
|
|
87
|
-
rescue => e
|
|
88
|
-
puts " Warning: Could not get last build duration: #{e.message}"
|
|
89
|
-
nil
|
|
90
|
-
end
|
|
91
|
-
|
|
92
|
-
def auth
|
|
93
|
-
@auth ||= "#{Bard::Secrets.fetch("jenkins-user")}:#{Bard::Secrets.fetch("jenkins-token")}"
|
|
94
|
-
end
|
|
95
|
-
|
|
96
|
-
def ci_host
|
|
97
|
-
"http://#{auth}@ci.botandrose.com/job/#{project_name}"
|
|
98
|
-
end
|
|
99
|
-
|
|
100
|
-
def started?
|
|
101
|
-
retry_with_backoff do
|
|
102
|
-
command = "curl -s -g '#{ci_host}/api/json?depth=1&tree=builds[queueId,number]'"
|
|
103
|
-
output = `#{command}`
|
|
104
|
-
raise "Blank response from CI" if output.empty?
|
|
105
|
-
builds = JSON.parse(output)["builds"]
|
|
106
|
-
raise "Build not found in builds list" if builds.empty?
|
|
107
|
-
builds.first["queueId"] == @queueId
|
|
108
|
-
end
|
|
109
|
-
end
|
|
110
|
-
|
|
111
|
-
def job_id
|
|
112
|
-
@job_id ||= begin
|
|
113
|
-
retry_with_backoff do
|
|
114
|
-
output = `curl -s -g '#{ci_host}/api/json?depth=1&tree=builds[queueId,number]'`
|
|
115
|
-
raise "Blank response from CI" if output.empty?
|
|
116
|
-
builds = JSON.parse(output)["builds"]
|
|
117
|
-
build = builds.find { |b| b["queueId"] == @queueId }
|
|
118
|
-
build["number"]
|
|
119
|
-
end
|
|
120
|
-
end
|
|
121
|
-
end
|
|
122
|
-
JOB_CONFIG_XML = <<~XML
|
|
123
|
-
<?xml version="1.0" encoding="UTF-8"?>
|
|
124
|
-
<project>
|
|
125
|
-
<actions/>
|
|
126
|
-
<description></description>
|
|
127
|
-
<keepDependencies>false</keepDependencies>
|
|
128
|
-
<properties>
|
|
129
|
-
<hudson.model.ParametersDefinitionProperty>
|
|
130
|
-
<parameterDefinitions>
|
|
131
|
-
<hudson.model.StringParameterDefinition>
|
|
132
|
-
<name>GIT_REF</name>
|
|
133
|
-
<description></description>
|
|
134
|
-
<defaultValue>master</defaultValue>
|
|
135
|
-
</hudson.model.StringParameterDefinition>
|
|
136
|
-
</parameterDefinitions>
|
|
137
|
-
</hudson.model.ParametersDefinitionProperty>
|
|
138
|
-
</properties>
|
|
139
|
-
<scm class="hudson.plugins.git.GitSCM" plugin="git@3.3.0">
|
|
140
|
-
<configVersion>2</configVersion>
|
|
141
|
-
<userRemoteConfigs>
|
|
142
|
-
<hudson.plugins.git.UserRemoteConfig>
|
|
143
|
-
<url>GIT_URL</url>
|
|
144
|
-
</hudson.plugins.git.UserRemoteConfig>
|
|
145
|
-
</userRemoteConfigs>
|
|
146
|
-
<branches>
|
|
147
|
-
<hudson.plugins.git.BranchSpec>
|
|
148
|
-
<name>$GIT_REF</name>
|
|
149
|
-
</hudson.plugins.git.BranchSpec>
|
|
150
|
-
</branches>
|
|
151
|
-
<doGenerateSubmoduleConfigurations>false</doGenerateSubmoduleConfigurations>
|
|
152
|
-
<submoduleCfg class="list"/>
|
|
153
|
-
<extensions/>
|
|
154
|
-
</scm>
|
|
155
|
-
<canRoam>true</canRoam>
|
|
156
|
-
<disabled>false</disabled>
|
|
157
|
-
<blockBuildWhenDownstreamBuilding>false</blockBuildWhenDownstreamBuilding>
|
|
158
|
-
<blockBuildWhenUpstreamBuilding>false</blockBuildWhenUpstreamBuilding>
|
|
159
|
-
<triggers/>
|
|
160
|
-
<concurrentBuild>false</concurrentBuild>
|
|
161
|
-
<builders>
|
|
162
|
-
<hudson.tasks.Shell>
|
|
163
|
-
<command>bash -l -c bin/setup</command>
|
|
164
|
-
</hudson.tasks.Shell>
|
|
165
|
-
<hudson.tasks.Shell>
|
|
166
|
-
<command>bash -l -c bin/ci</command>
|
|
167
|
-
</hudson.tasks.Shell>
|
|
168
|
-
</builders>
|
|
169
|
-
<publishers/>
|
|
170
|
-
<buildWrappers/>
|
|
171
|
-
</project>
|
|
172
|
-
XML
|
|
173
|
-
end
|
|
174
|
-
end
|
|
175
|
-
end
|
|
176
|
-
|
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
require "tempfile"
|
|
2
|
-
require "bard/plugins/deploy/ci/runner"
|
|
3
|
-
|
|
4
|
-
module Bard
|
|
5
|
-
class CI
|
|
6
|
-
class Local < Runner
|
|
7
|
-
def exists?
|
|
8
|
-
true
|
|
9
|
-
end
|
|
10
|
-
|
|
11
|
-
def console
|
|
12
|
-
@console
|
|
13
|
-
end
|
|
14
|
-
|
|
15
|
-
protected
|
|
16
|
-
|
|
17
|
-
def start
|
|
18
|
-
@output_file = Tempfile.new("bard-ci")
|
|
19
|
-
@wait_thread = Process.detach(spawn("CLEAN=true bin/rake ci", [:out, :err] => @output_file))
|
|
20
|
-
end
|
|
21
|
-
|
|
22
|
-
def building?
|
|
23
|
-
![nil, false].include?(@wait_thread.status)
|
|
24
|
-
end
|
|
25
|
-
|
|
26
|
-
def success?
|
|
27
|
-
@wait_thread.value.success?
|
|
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
|
-
@output_file.rewind
|
|
51
|
-
@console = @output_file.read
|
|
52
|
-
@output_file.close!
|
|
53
|
-
end
|
|
54
|
-
end
|
|
55
|
-
end
|
|
56
|
-
end
|
|
57
|
-
|
|
@@ -1,112 +0,0 @@
|
|
|
1
|
-
require "bard/plugins/deploy/ci/state"
|
|
2
|
-
require "bard/retryable"
|
|
3
|
-
|
|
4
|
-
module Bard
|
|
5
|
-
class CI
|
|
6
|
-
class Runner < Struct.new(:project_name, :branch, :sha)
|
|
7
|
-
include Bard::Retryable
|
|
8
|
-
|
|
9
|
-
@runners = {}
|
|
10
|
-
|
|
11
|
-
class << self
|
|
12
|
-
attr_reader :runners
|
|
13
|
-
|
|
14
|
-
def inherited(subclass)
|
|
15
|
-
super
|
|
16
|
-
name = extract_runner_name(subclass)
|
|
17
|
-
runners[name] = subclass if name
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
def [](name)
|
|
21
|
-
runners[name.to_sym]
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
# Returns the last registered runner (most recently loaded wins)
|
|
25
|
-
def default
|
|
26
|
-
runners.values.last
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
private
|
|
30
|
-
|
|
31
|
-
def extract_runner_name(klass)
|
|
32
|
-
klass.name&.split("::")&.last
|
|
33
|
-
&.gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2')
|
|
34
|
-
&.gsub(/([a-z\d])([A-Z])/, '\1_\2')
|
|
35
|
-
&.downcase
|
|
36
|
-
&.to_sym
|
|
37
|
-
end
|
|
38
|
-
end
|
|
39
|
-
|
|
40
|
-
def run
|
|
41
|
-
start
|
|
42
|
-
@start_time = Time.new.to_i
|
|
43
|
-
@last_time_elapsed = get_last_time_elapsed
|
|
44
|
-
save_state
|
|
45
|
-
wait_until_started
|
|
46
|
-
|
|
47
|
-
poll_until_complete { |elapsed, last_time| yield elapsed, last_time }
|
|
48
|
-
|
|
49
|
-
state.delete
|
|
50
|
-
success?
|
|
51
|
-
end
|
|
52
|
-
|
|
53
|
-
def resume
|
|
54
|
-
saved_state = state.load
|
|
55
|
-
raise "No saved CI state found for #{project_name}. Start a new build with 'bard ci'." if saved_state.nil?
|
|
56
|
-
|
|
57
|
-
restore_state(saved_state)
|
|
58
|
-
poll_until_complete { |elapsed, last_time| yield elapsed, last_time }
|
|
59
|
-
|
|
60
|
-
state.delete
|
|
61
|
-
success?
|
|
62
|
-
end
|
|
63
|
-
|
|
64
|
-
protected
|
|
65
|
-
|
|
66
|
-
def poll_until_complete
|
|
67
|
-
while building?
|
|
68
|
-
elapsed_time = Time.new.to_i - @start_time
|
|
69
|
-
yield elapsed_time, @last_time_elapsed
|
|
70
|
-
save_state
|
|
71
|
-
sleep(2)
|
|
72
|
-
end
|
|
73
|
-
end
|
|
74
|
-
|
|
75
|
-
def save_state
|
|
76
|
-
state.save(get_state_data)
|
|
77
|
-
end
|
|
78
|
-
|
|
79
|
-
def state
|
|
80
|
-
@state ||= State.new(project_name)
|
|
81
|
-
end
|
|
82
|
-
|
|
83
|
-
# Abstract methods - override in subclasses
|
|
84
|
-
def start
|
|
85
|
-
raise NotImplementedError, "#{self.class}#start not implemented"
|
|
86
|
-
end
|
|
87
|
-
|
|
88
|
-
def building?
|
|
89
|
-
raise NotImplementedError, "#{self.class}#building? not implemented"
|
|
90
|
-
end
|
|
91
|
-
|
|
92
|
-
def success?
|
|
93
|
-
raise NotImplementedError, "#{self.class}#success? not implemented"
|
|
94
|
-
end
|
|
95
|
-
|
|
96
|
-
def wait_until_started
|
|
97
|
-
end
|
|
98
|
-
|
|
99
|
-
def get_last_time_elapsed
|
|
100
|
-
nil
|
|
101
|
-
end
|
|
102
|
-
|
|
103
|
-
def get_state_data
|
|
104
|
-
raise NotImplementedError, "#{self.class}#get_state_data not implemented"
|
|
105
|
-
end
|
|
106
|
-
|
|
107
|
-
def restore_state(data)
|
|
108
|
-
raise NotImplementedError, "#{self.class}#restore_state not implemented"
|
|
109
|
-
end
|
|
110
|
-
end
|
|
111
|
-
end
|
|
112
|
-
end
|
|
@@ -1,40 +0,0 @@
|
|
|
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
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
require "forwardable"
|
|
2
|
-
require "bard/plugins/deploy/ci/runner"
|
|
3
|
-
|
|
4
|
-
module Bard
|
|
5
|
-
class CI
|
|
6
|
-
def initialize(project_name, branch, runner_name: nil)
|
|
7
|
-
@project_name = project_name
|
|
8
|
-
@branch = branch
|
|
9
|
-
@runner_name = runner_name
|
|
10
|
-
end
|
|
11
|
-
|
|
12
|
-
extend Forwardable
|
|
13
|
-
delegate [:run, :resume, :exists?, :console, :status] => :runner
|
|
14
|
-
|
|
15
|
-
private
|
|
16
|
-
|
|
17
|
-
def runner
|
|
18
|
-
@runner ||= choose_runner_class.new(@project_name, @branch, sha)
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
def sha
|
|
22
|
-
@sha ||= `git rev-parse #{@branch}`.chomp
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
def choose_runner_class
|
|
26
|
-
if @runner_name
|
|
27
|
-
runner_class = Runner[@runner_name]
|
|
28
|
-
raise "Unknown CI runner: #{@runner_name}" unless runner_class
|
|
29
|
-
runner_class
|
|
30
|
-
else
|
|
31
|
-
runner_class = Runner.default
|
|
32
|
-
raise "No CI runner available" unless runner_class
|
|
33
|
-
runner_class
|
|
34
|
-
end
|
|
35
|
-
end
|
|
36
|
-
end
|
|
37
|
-
end
|
|
38
|
-
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
require "bard/plugins/deploy/strategy"
|
|
2
|
-
require "bard/copy"
|
|
3
|
-
require "bard/plugins/ssh"
|
|
4
|
-
|
|
5
|
-
module Bard
|
|
6
|
-
class DeployStrategy
|
|
7
|
-
class SSH < DeployStrategy
|
|
8
|
-
def deploy(clone: nil, branch: "master", force: false)
|
|
9
|
-
target.require_capability!(:ssh)
|
|
10
|
-
|
|
11
|
-
if clone
|
|
12
|
-
target.run! "git clone --branch #{branch} git@github.com:botandrosedesign/#{clone} #{target.path}", home: true
|
|
13
|
-
Bard::Copy.file "config/master.key", from: target.config[:local], to: target
|
|
14
|
-
elsif force
|
|
15
|
-
target.run! "git fetch origin #{branch}"
|
|
16
|
-
target.run! "git checkout -f origin/#{branch}"
|
|
17
|
-
else
|
|
18
|
-
target.run! "git pull --ff-only origin #{branch}"
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
target.run! "bin/setup"
|
|
22
|
-
target.run! "bard setup" if clone
|
|
23
|
-
end
|
|
24
|
-
end
|
|
25
|
-
end
|
|
26
|
-
end
|