escobar 0.3.22 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 331accfe3f9ff2cca530fa1037f115088e806288
4
- data.tar.gz: 7557209c606e88607b5e9e43ca04eae53563bccd
3
+ metadata.gz: 9319e5ced60dbfb825a5d97d8c39ddc69a847d7a
4
+ data.tar.gz: 5fa1d246746ad8385b7ec4d07dff3615f1f5e09c
5
5
  SHA512:
6
- metadata.gz: 20b094047b014575d3749ffb4f51715462f10954e2c8df1852a8b4259ff4e0033ce9cddf7bd158090c4243f3018fe1fb1e98fa2e48e78b15f4b9b933fb95c410
7
- data.tar.gz: 1d6598813bfeabcc5d1ef95b263fadce6bbcc4316eb3843cc2657e4eac735723bcc4ff2328399a2b4defa45a058d081bf867f1e9997a8b70c69b7f461737b474
6
+ metadata.gz: 807b6c257647c7841612393639816fefb4805a73fa86453dd52fb00afc260de468057e9b078be6022a85340e2fecc6f72793e4c2a31d91aa162f79a328952ba0
7
+ data.tar.gz: 61c0411e0c87a88153c3024ffbb3eecff890452f862f04444fec51057b5d0c96cacce459c8991c682071530fe6df5d580de72542ba8854463f0617db93c17f3b
@@ -1,4 +1,5 @@
1
1
  # coding: utf-8
2
+
2
3
  lib = File.expand_path("../lib", __FILE__)
3
4
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
5
  require "escobar/version"
@@ -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] || {},
@@ -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
- !client.heroku.put("/apps/#{id}/pre-authorizations", second_factor).any?
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
- github_client.required_contexts.map do |context|
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: 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
@@ -1,3 +1,3 @@
1
1
  module Escobar
2
- VERSION = "0.3.22".freeze
2
+ VERSION = "0.4.0".freeze
3
3
  end
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.3.22
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-03-23 00:00:00.000000000 Z
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: