escobar 0.3.22 → 0.4.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/escobar.gemspec +1 -0
- data/lib/escobar.rb +4 -0
- data/lib/escobar/github/client.rb +1 -1
- data/lib/escobar/heroku/app.rb +5 -1
- data/lib/escobar/heroku/build_request.rb +1 -6
- data/lib/escobar/heroku/client.rb +4 -1
- data/lib/escobar/heroku/pipeline.rb +17 -0
- data/lib/escobar/heroku/pipeline_promotion.rb +56 -0
- data/lib/escobar/heroku/pipeline_promotion_request.rb +138 -0
- data/lib/escobar/heroku/pipeline_promotion_targets.rb +62 -0
- data/lib/escobar/heroku/release.rb +9 -1
- data/lib/escobar/heroku/slug.rb +24 -0
- data/lib/escobar/version.rb +1 -1
- metadata +6 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9319e5ced60dbfb825a5d97d8c39ddc69a847d7a
|
4
|
+
data.tar.gz: 5fa1d246746ad8385b7ec4d07dff3615f1f5e09c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 807b6c257647c7841612393639816fefb4805a73fa86453dd52fb00afc260de468057e9b078be6022a85340e2fecc6f72793e4c2a31d91aa162f79a328952ba0
|
7
|
+
data.tar.gz: 61c0411e0c87a88153c3024ffbb3eecff890452f862f04444fec51057b5d0c96cacce459c8991c682071530fe6df5d580de72542ba8854463f0617db93c17f3b
|
data/escobar.gemspec
CHANGED
data/lib/escobar.rb
CHANGED
@@ -70,3 +70,7 @@ require_relative "./escobar/heroku/release"
|
|
70
70
|
require_relative "./escobar/heroku/coupling"
|
71
71
|
require_relative "./escobar/heroku/pipeline"
|
72
72
|
require_relative "./escobar/heroku/config_vars"
|
73
|
+
require_relative "./escobar/heroku/slug"
|
74
|
+
require_relative "./escobar/heroku/pipeline_promotion"
|
75
|
+
require_relative "./escobar/heroku/pipeline_promotion_request"
|
76
|
+
require_relative "./escobar/heroku/pipeline_promotion_targets"
|
@@ -56,7 +56,7 @@ module Escobar
|
|
56
56
|
def create_deployment(options)
|
57
57
|
body = {
|
58
58
|
ref: options[:ref] || "master",
|
59
|
-
task: "deploy",
|
59
|
+
task: options[:task] || "deploy",
|
60
60
|
auto_merge: false,
|
61
61
|
required_contexts: options[:required_contexts] || [],
|
62
62
|
payload: options[:payload] || {},
|
data/lib/escobar/heroku/app.rb
CHANGED
@@ -28,6 +28,10 @@ module Escobar
|
|
28
28
|
end
|
29
29
|
end
|
30
30
|
|
31
|
+
def current_release_ref
|
32
|
+
releases.first.ref
|
33
|
+
end
|
34
|
+
|
31
35
|
def dynos
|
32
36
|
@dynos ||= Escobar::Heroku::Dynos.new(client, id)
|
33
37
|
end
|
@@ -50,7 +54,7 @@ module Escobar
|
|
50
54
|
|
51
55
|
# Accepts either google authenticator or yubikey second_factor formatting
|
52
56
|
def preauth(second_factor)
|
53
|
-
|
57
|
+
client.heroku.put("/apps/#{id}/pre-authorizations", second_factor).none?
|
54
58
|
end
|
55
59
|
|
56
60
|
def locked?
|
@@ -165,12 +165,7 @@ module Escobar
|
|
165
165
|
|
166
166
|
def required_commit_contexts
|
167
167
|
return [] if forced || environment != "production"
|
168
|
-
|
169
|
-
if context == "continuous-integration/travis-ci"
|
170
|
-
context = "continuous-integration/travis-ci/push"
|
171
|
-
end
|
172
|
-
context
|
173
|
-
end
|
168
|
+
pipeline.required_commit_contexts(false)
|
174
169
|
end
|
175
170
|
|
176
171
|
def github_client
|
@@ -42,11 +42,14 @@ module Escobar
|
|
42
42
|
end
|
43
43
|
end
|
44
44
|
|
45
|
-
def post(path, body)
|
45
|
+
def post(path, body, second_factor = nil)
|
46
46
|
with_error_handling do
|
47
47
|
response = client.post do |request|
|
48
48
|
request.url path
|
49
49
|
request_defaults(request)
|
50
|
+
if second_factor
|
51
|
+
request.headers["Heroku-Two-Factor-Code"] = second_factor.to_s
|
52
|
+
end
|
50
53
|
request.body = body.to_json
|
51
54
|
end
|
52
55
|
|
@@ -130,6 +130,23 @@ module Escobar
|
|
130
130
|
heroku_build
|
131
131
|
end
|
132
132
|
|
133
|
+
# source: A Escobar::Heroku::App to promote from
|
134
|
+
# targets: An array of Escobar::Heroku::App to promote to
|
135
|
+
# environment: The pipeline stage applying to the promotion
|
136
|
+
# force: true if github commit status checks shouldn't be verified
|
137
|
+
# payload: Extra info to insert into the github deployment API
|
138
|
+
# second_factor: an OTP credential for protected resources
|
139
|
+
# rubocop:disable Metrics/ParameterLists
|
140
|
+
# rubocop:disable Metrics/LineLength
|
141
|
+
def promote(source, targets, environment, force = false, payload = {}, second_factor = nil)
|
142
|
+
promotion_request = Escobar::Heroku::PipelinePromotionRequest.new(
|
143
|
+
client, self, source, targets, second_factor
|
144
|
+
)
|
145
|
+
promotion_request.create(environment, force, payload)
|
146
|
+
end
|
147
|
+
# rubocop:enable Metrics/ParameterLists
|
148
|
+
# rubocop:enable Metrics/LineLength
|
149
|
+
|
133
150
|
def get(path)
|
134
151
|
response = kolkrabbi_client.get do |request|
|
135
152
|
request.url path
|
@@ -0,0 +1,56 @@
|
|
1
|
+
module Escobar
|
2
|
+
module Heroku
|
3
|
+
# Class reperesenting a Heroku Pipeline Promotion
|
4
|
+
class PipelinePromotion
|
5
|
+
attr_reader :client, :id, :name, :pipeline,
|
6
|
+
:source, :targets, :second_factor
|
7
|
+
def initialize(client, pipeline, source, targets, second_factor)
|
8
|
+
@id = pipeline.id
|
9
|
+
@client = client
|
10
|
+
@source = source
|
11
|
+
@targets = targets
|
12
|
+
@pipeline = pipeline
|
13
|
+
@second_factor = second_factor
|
14
|
+
end
|
15
|
+
|
16
|
+
def promotion_path
|
17
|
+
"/pipeline-promotions"
|
18
|
+
end
|
19
|
+
|
20
|
+
def create
|
21
|
+
response = client.heroku.post(promotion_path, body, second_factor)
|
22
|
+
case response["id"]
|
23
|
+
when Escobar::UUID_REGEX
|
24
|
+
results = Escobar::Heroku::PipelinePromotionTargets.new(
|
25
|
+
self, response
|
26
|
+
)
|
27
|
+
results.releases
|
28
|
+
when "two_factor"
|
29
|
+
raise_2fa_error
|
30
|
+
else
|
31
|
+
raise ArgumentError, response.to_json
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
class RequiresTwoFactorError < ArgumentError
|
36
|
+
end
|
37
|
+
|
38
|
+
class MissingContextsError < \
|
39
|
+
Escobar::Heroku::BuildRequest::MissingContextsError
|
40
|
+
end
|
41
|
+
|
42
|
+
def raise_2fa_error
|
43
|
+
message = "Pipeline requires second factor: #{pipeline.name}"
|
44
|
+
raise RequiresTwoFactorError, message
|
45
|
+
end
|
46
|
+
|
47
|
+
def body
|
48
|
+
{
|
49
|
+
pipeline: { id: id },
|
50
|
+
source: { app: { id: source.id } },
|
51
|
+
targets: targets.map { |t| { app: { id: t.id } } }
|
52
|
+
}
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,138 @@
|
|
1
|
+
module Escobar
|
2
|
+
module Heroku
|
3
|
+
# Class reperesenting a request for Pipeline Promotion
|
4
|
+
class PipelinePromotionRequest
|
5
|
+
attr_reader :client, :id, :name, :pipeline, :source, :targets
|
6
|
+
attr_reader :github_deployment_url, :sha
|
7
|
+
|
8
|
+
attr_accessor :environment, :forced, :custom_payload, :second_factor
|
9
|
+
|
10
|
+
def initialize(client, pipeline, source, targets, second_factor)
|
11
|
+
@id = pipeline.id
|
12
|
+
@client = client
|
13
|
+
@pipeline = pipeline
|
14
|
+
@source = source
|
15
|
+
@targets = targets || []
|
16
|
+
@second_factor = second_factor
|
17
|
+
end
|
18
|
+
|
19
|
+
def create(environment, forced, custom_payload)
|
20
|
+
raise ArgumentError, "No target applications" if targets.empty?
|
21
|
+
@environment = environment
|
22
|
+
@forced = forced
|
23
|
+
@custom_payload = custom_payload
|
24
|
+
|
25
|
+
fill_promotion_target_urls
|
26
|
+
create_in_api
|
27
|
+
end
|
28
|
+
|
29
|
+
def create_in_api
|
30
|
+
promotion = Escobar::Heroku::PipelinePromotion.new(
|
31
|
+
client, pipeline, source, targets, second_factor
|
32
|
+
)
|
33
|
+
|
34
|
+
releases = promotion.create
|
35
|
+
handle_github_deployment_statuses_for(releases)
|
36
|
+
releases
|
37
|
+
end
|
38
|
+
|
39
|
+
def handle_github_deployment_statuses_for(releases)
|
40
|
+
releases.each do |release|
|
41
|
+
release.sha = release.ref
|
42
|
+
release.github_url = target_urls[release.app.id]
|
43
|
+
release.pipeline_name = pipeline.name
|
44
|
+
|
45
|
+
create_github_deployment_status(
|
46
|
+
release.github_url,
|
47
|
+
release.dashboard_build_output_url,
|
48
|
+
"pending",
|
49
|
+
"Promotion releasing.."
|
50
|
+
)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
private
|
55
|
+
|
56
|
+
def target_urls
|
57
|
+
@target_urls ||= {}
|
58
|
+
end
|
59
|
+
|
60
|
+
def fill_promotion_target_urls
|
61
|
+
targets.each do |target|
|
62
|
+
custom_payload_for_app = custom_payload.merge(
|
63
|
+
app_id: target.id, name: target.name
|
64
|
+
)
|
65
|
+
create_github_deployment(environment, custom_payload_for_app)
|
66
|
+
target_urls[target.id] = github_deployment_url
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def create_github_deployment_status(url, target_url, state, description)
|
71
|
+
payload = {
|
72
|
+
state: state,
|
73
|
+
target_url: target_url,
|
74
|
+
description: description
|
75
|
+
}
|
76
|
+
create_deployment_status(url, payload)
|
77
|
+
end
|
78
|
+
|
79
|
+
def create_deployment_status(url, payload)
|
80
|
+
github_client.create_deployment_status(url, payload)
|
81
|
+
end
|
82
|
+
|
83
|
+
def create_github_deployment(environment, custom_payload)
|
84
|
+
options = {
|
85
|
+
ref: source.current_release_ref,
|
86
|
+
task: "promote",
|
87
|
+
auto_merge: false,
|
88
|
+
payload: custom_payload.merge(custom_deployment_payload),
|
89
|
+
environment: environment,
|
90
|
+
required_contexts: required_commit_contexts
|
91
|
+
}
|
92
|
+
response = github_client.create_deployment(options)
|
93
|
+
handle_github_deployment_response(response)
|
94
|
+
end
|
95
|
+
|
96
|
+
def custom_deployment_payload
|
97
|
+
{
|
98
|
+
source: source.id,
|
99
|
+
pipeline: pipeline.to_hash,
|
100
|
+
provider: "slash-heroku"
|
101
|
+
}
|
102
|
+
end
|
103
|
+
|
104
|
+
def github_client
|
105
|
+
@github_client ||= Escobar::GitHub::Client.new(
|
106
|
+
client.github_token,
|
107
|
+
pipeline.github_repository
|
108
|
+
)
|
109
|
+
end
|
110
|
+
|
111
|
+
def required_commit_contexts
|
112
|
+
pipeline.required_commit_contexts(false)
|
113
|
+
end
|
114
|
+
|
115
|
+
def handle_github_deployment_response(response)
|
116
|
+
unless response["sha"]
|
117
|
+
handle_github_deployment_error(response)
|
118
|
+
end
|
119
|
+
|
120
|
+
@sha = response["sha"]
|
121
|
+
@github_deployment_url = response["url"]
|
122
|
+
response
|
123
|
+
end
|
124
|
+
|
125
|
+
class MissingContextsError < \
|
126
|
+
Escobar::Heroku::PipelinePromotion::MissingContextsError
|
127
|
+
end
|
128
|
+
|
129
|
+
def handle_github_deployment_error(response)
|
130
|
+
error = Escobar::GitHub::DeploymentError.new(
|
131
|
+
pipeline.github_repository, response, required_commit_contexts
|
132
|
+
)
|
133
|
+
raise error_for(error.default_message) unless error.missing_contexts?
|
134
|
+
raise MissingContextsError.new_from_build_request_and_error(self, error)
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
module Escobar
|
2
|
+
module Heroku
|
3
|
+
# Class reperesenting a Heroku Pipeline Promotion Targets
|
4
|
+
class PipelinePromotionTargets
|
5
|
+
attr_reader :client, :id, :name, :pipeline, :promotion
|
6
|
+
|
7
|
+
def initialize(pipeline, promotion)
|
8
|
+
@id = promotion["id"]
|
9
|
+
@name = pipeline.name
|
10
|
+
@client = pipeline.client
|
11
|
+
@pipeline = pipeline
|
12
|
+
@retries = 30
|
13
|
+
end
|
14
|
+
|
15
|
+
def release_id
|
16
|
+
promotion["source"]["release"]["id"]
|
17
|
+
end
|
18
|
+
|
19
|
+
def app_id
|
20
|
+
promotion["source"]["app"]["id"]
|
21
|
+
end
|
22
|
+
|
23
|
+
def source_release
|
24
|
+
@release ||= Escobar::Heroku::Release.new(
|
25
|
+
client, app_id, nil, release_id
|
26
|
+
)
|
27
|
+
end
|
28
|
+
|
29
|
+
def ref
|
30
|
+
@ref ||= source_release.ref
|
31
|
+
end
|
32
|
+
|
33
|
+
def targets_path
|
34
|
+
"/pipeline-promotions/#{id}/promotion-targets"
|
35
|
+
end
|
36
|
+
|
37
|
+
def info
|
38
|
+
@info ||= client.heroku.get(targets_path)
|
39
|
+
end
|
40
|
+
|
41
|
+
def releases
|
42
|
+
info.map do |target|
|
43
|
+
target_app_id = target["app"]["id"]
|
44
|
+
target_release_id = target["release"]["id"]
|
45
|
+
Escobar::Heroku::Release.new(
|
46
|
+
client, target_app_id, nil, target_release_id
|
47
|
+
)
|
48
|
+
end
|
49
|
+
rescue NoMethodError
|
50
|
+
raise(ArgumentError, info.to_json) unless retry?
|
51
|
+
sleep 0.5
|
52
|
+
@retries -= 1
|
53
|
+
@info = nil
|
54
|
+
retry
|
55
|
+
end
|
56
|
+
|
57
|
+
def retry?
|
58
|
+
@retries.positive?
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -28,6 +28,14 @@ module Escobar
|
|
28
28
|
@build ||= Escobar::Heroku::Build.new(client, app.id, build_id)
|
29
29
|
end
|
30
30
|
|
31
|
+
def slug
|
32
|
+
@slug ||= Escobar::Heroku::Slug.new(client, app.id, info["slug"]["id"])
|
33
|
+
end
|
34
|
+
|
35
|
+
def ref
|
36
|
+
slug && slug.ref
|
37
|
+
end
|
38
|
+
|
31
39
|
def dashboard_build_output_url
|
32
40
|
"https://dashboard.heroku.com/apps/#{app.name}/activity/builds/#{id}"
|
33
41
|
end
|
@@ -50,7 +58,7 @@ module Escobar
|
|
50
58
|
name: pipeline_name,
|
51
59
|
repo: repository,
|
52
60
|
app_id: app_id,
|
53
|
-
app_name:
|
61
|
+
app_name: app.name,
|
54
62
|
build_id: build_id,
|
55
63
|
release_id: id,
|
56
64
|
command_id: command_id,
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Escobar
|
2
|
+
module Heroku
|
3
|
+
# Class representing a heroku slug
|
4
|
+
class Slug
|
5
|
+
attr_reader :app_id, :app_name, :client, :id
|
6
|
+
|
7
|
+
attr_accessor :sha
|
8
|
+
|
9
|
+
def initialize(client, app_id, id)
|
10
|
+
@id = id
|
11
|
+
@app_id = app_id
|
12
|
+
@client = client
|
13
|
+
end
|
14
|
+
|
15
|
+
def info
|
16
|
+
@info ||= client.heroku.get("/apps/#{app_id}/slugs/#{id}")
|
17
|
+
end
|
18
|
+
|
19
|
+
def ref
|
20
|
+
info["commit"]
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
data/lib/escobar/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: escobar
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Corey Donohoe
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-
|
11
|
+
date: 2017-04-04 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: faraday
|
@@ -199,7 +199,11 @@ files:
|
|
199
199
|
- lib/escobar/heroku/coupling.rb
|
200
200
|
- lib/escobar/heroku/dynos.rb
|
201
201
|
- lib/escobar/heroku/pipeline.rb
|
202
|
+
- lib/escobar/heroku/pipeline_promotion.rb
|
203
|
+
- lib/escobar/heroku/pipeline_promotion_request.rb
|
204
|
+
- lib/escobar/heroku/pipeline_promotion_targets.rb
|
202
205
|
- lib/escobar/heroku/release.rb
|
206
|
+
- lib/escobar/heroku/slug.rb
|
203
207
|
- lib/escobar/version.rb
|
204
208
|
homepage: https://github.com/atmos/escobar
|
205
209
|
licenses:
|