automate_soup 0.1.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 +7 -0
- data/.gitignore +15 -0
- data/.rspec +2 -0
- data/.travis.yml +5 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +6 -0
- data/LICENSE.txt +21 -0
- data/README.md +128 -0
- data/Rakefile +10 -0
- data/automate_soup.gemspec +31 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/docs/AutomateSoup.html +2566 -0
- data/docs/AutomateSoup/API.html +1174 -0
- data/docs/AutomateSoup/Change.html +892 -0
- data/docs/AutomateSoup/Credentials.html +452 -0
- data/docs/AutomateSoup/Rest.html +321 -0
- data/docs/AutomateSoup/Stage.html +428 -0
- data/docs/AutomateSoup/Topic.html +530 -0
- data/docs/_index.html +166 -0
- data/docs/class_list.html +51 -0
- data/docs/coverage/.last_run.json +5 -0
- data/docs/coverage/.resultset.json +145 -0
- data/docs/coverage/.resultset.json.lock +0 -0
- data/docs/coverage/assets/0.10.2/application.css +799 -0
- data/docs/coverage/assets/0.10.2/application.js +1707 -0
- data/docs/coverage/assets/0.10.2/colorbox/border.png +0 -0
- data/docs/coverage/assets/0.10.2/colorbox/controls.png +0 -0
- data/docs/coverage/assets/0.10.2/colorbox/loading.gif +0 -0
- data/docs/coverage/assets/0.10.2/colorbox/loading_background.png +0 -0
- data/docs/coverage/assets/0.10.2/favicon_green.png +0 -0
- data/docs/coverage/assets/0.10.2/favicon_red.png +0 -0
- data/docs/coverage/assets/0.10.2/favicon_yellow.png +0 -0
- data/docs/coverage/assets/0.10.2/loading.gif +0 -0
- data/docs/coverage/assets/0.10.2/magnify.png +0 -0
- data/docs/coverage/assets/0.10.2/smoothness/images/ui-bg_flat_0_aaaaaa_40x100.png +0 -0
- data/docs/coverage/assets/0.10.2/smoothness/images/ui-bg_flat_75_ffffff_40x100.png +0 -0
- data/docs/coverage/assets/0.10.2/smoothness/images/ui-bg_glass_55_fbf9ee_1x400.png +0 -0
- data/docs/coverage/assets/0.10.2/smoothness/images/ui-bg_glass_65_ffffff_1x400.png +0 -0
- data/docs/coverage/assets/0.10.2/smoothness/images/ui-bg_glass_75_dadada_1x400.png +0 -0
- data/docs/coverage/assets/0.10.2/smoothness/images/ui-bg_glass_75_e6e6e6_1x400.png +0 -0
- data/docs/coverage/assets/0.10.2/smoothness/images/ui-bg_glass_95_fef1ec_1x400.png +0 -0
- data/docs/coverage/assets/0.10.2/smoothness/images/ui-bg_highlight-soft_75_cccccc_1x100.png +0 -0
- data/docs/coverage/assets/0.10.2/smoothness/images/ui-icons_222222_256x240.png +0 -0
- data/docs/coverage/assets/0.10.2/smoothness/images/ui-icons_2e83ff_256x240.png +0 -0
- data/docs/coverage/assets/0.10.2/smoothness/images/ui-icons_454545_256x240.png +0 -0
- data/docs/coverage/assets/0.10.2/smoothness/images/ui-icons_888888_256x240.png +0 -0
- data/docs/coverage/assets/0.10.2/smoothness/images/ui-icons_cd0a0a_256x240.png +0 -0
- data/docs/coverage/index.html +968 -0
- data/docs/css/common.css +1 -0
- data/docs/css/full_list.css +58 -0
- data/docs/css/style.css +492 -0
- data/docs/file.README.html +211 -0
- data/docs/file_list.html +56 -0
- data/docs/frames.html +17 -0
- data/docs/index.html +211 -0
- data/docs/js/app.js +248 -0
- data/docs/js/full_list.js +216 -0
- data/docs/js/jquery.js +4 -0
- data/docs/method_list.html +395 -0
- data/docs/top-level-namespace.html +110 -0
- data/lib/automate_soup.rb +264 -0
- data/lib/automate_soup/api.rb +112 -0
- data/lib/automate_soup/change.rb +105 -0
- data/lib/automate_soup/credentials.rb +16 -0
- data/lib/automate_soup/rest.rb +40 -0
- data/lib/automate_soup/stage.rb +25 -0
- data/lib/automate_soup/version.rb +3 -0
- metadata +195 -0
@@ -0,0 +1,264 @@
|
|
1
|
+
require 'automate_soup/api'
|
2
|
+
require 'automate_soup/credentials'
|
3
|
+
require 'automate_soup/rest'
|
4
|
+
require 'automate_soup/stage'
|
5
|
+
require 'automate_soup/change'
|
6
|
+
require 'automate_soup/version'
|
7
|
+
require 'ostruct'
|
8
|
+
|
9
|
+
##
|
10
|
+
# Top level module
|
11
|
+
#
|
12
|
+
module AutomateSoup
|
13
|
+
class << self
|
14
|
+
attr_accessor :url, :credentials, :api, :enterprise, :organization, :project, :pipeline
|
15
|
+
|
16
|
+
##
|
17
|
+
# Setup Automate Soup client.
|
18
|
+
#
|
19
|
+
# @option url [String] The Chef Automate URL.
|
20
|
+
# @option username [String] The Chef Automate username.
|
21
|
+
# @option token [String] The Chef Automate user token.
|
22
|
+
# @option password [String] The Chef Automate user password.
|
23
|
+
#
|
24
|
+
def setup(
|
25
|
+
url: nil,
|
26
|
+
username: nil,
|
27
|
+
token: nil,
|
28
|
+
password: nil,
|
29
|
+
enterprise: 'default',
|
30
|
+
organization: nil,
|
31
|
+
project: nil,
|
32
|
+
pipeline: nil
|
33
|
+
)
|
34
|
+
@url = url
|
35
|
+
@credentials = if token
|
36
|
+
token_credentials(username, token)
|
37
|
+
else
|
38
|
+
password_credentials(username, password)
|
39
|
+
end
|
40
|
+
@api = AutomateSoup::API.new(self)
|
41
|
+
@enterprise = enterprise
|
42
|
+
@organization = organization
|
43
|
+
@project = project
|
44
|
+
@pipeline = pipeline
|
45
|
+
self
|
46
|
+
end
|
47
|
+
|
48
|
+
##
|
49
|
+
# Check the status of Automate
|
50
|
+
#
|
51
|
+
def status
|
52
|
+
o = @api.status
|
53
|
+
OpenStruct.new o
|
54
|
+
end
|
55
|
+
|
56
|
+
##
|
57
|
+
# Fetch all organizations under an enterprise
|
58
|
+
#
|
59
|
+
def orgs(enterprise = 'default')
|
60
|
+
@api.orgs enterprise
|
61
|
+
end
|
62
|
+
|
63
|
+
##
|
64
|
+
# Fetch all projects under an enterprise, organization pair
|
65
|
+
#
|
66
|
+
def projects(enterprise: 'default', organization: nil)
|
67
|
+
@api.projects(enterprise: enterprise, organization: organization)
|
68
|
+
end
|
69
|
+
|
70
|
+
##
|
71
|
+
# Fetch all pipelines of a project under an enterprise, organization pair
|
72
|
+
#
|
73
|
+
def pipelines(enterprise: 'default', organization: nil, project: nil)
|
74
|
+
@api.pipelines(enterprise: enterprise, organization: organization, project: project)
|
75
|
+
end
|
76
|
+
|
77
|
+
##
|
78
|
+
# Fetch a pipeline of a project under an enterprise, organization pair.
|
79
|
+
#
|
80
|
+
def pipeline(enterprise: 'default', organization: nil, project: nil, pipeline: nil)
|
81
|
+
arr = []
|
82
|
+
@api.pipeline(enterprise: enterprise, organization: organization, project: project, pipeline: pipeline).each do |o|
|
83
|
+
arr << OpenStruct.new(o)
|
84
|
+
end
|
85
|
+
arr
|
86
|
+
end
|
87
|
+
|
88
|
+
##
|
89
|
+
# Filters out the topics from the pipelines changes .
|
90
|
+
#
|
91
|
+
# @option enterprise [String] the enterprise to fetch org from, defaults to
|
92
|
+
# default.
|
93
|
+
# @option organization [String] the organization to fetch from.
|
94
|
+
# @option project [String] the project to fetch from.
|
95
|
+
# @option pipeline [String] the pipeline to fetch from.
|
96
|
+
#
|
97
|
+
def pipeline_topics(enterprise: 'default', organization: nil, project: nil, pipeline: nil)
|
98
|
+
self.pipeline(
|
99
|
+
enterprise: enterprise,
|
100
|
+
organization: organization,
|
101
|
+
project: project,
|
102
|
+
pipeline: pipeline
|
103
|
+
).map { |p| p.topic }
|
104
|
+
end
|
105
|
+
|
106
|
+
##
|
107
|
+
# Find a change by topic.
|
108
|
+
#
|
109
|
+
# @option enterprise [String] the enterprise to fetch org from, defaults to
|
110
|
+
# default.
|
111
|
+
# @option organization [String] the organization to fetch from.
|
112
|
+
# @option project [String] the project to fetch from.
|
113
|
+
# @option pipeline [String] the pipeline to fetch from.
|
114
|
+
# @option topic [String] the topic to fetch a change from.
|
115
|
+
#
|
116
|
+
def change_by_topic(enterprise: @enterprise, organization: @organization, project: @project, pipeline: @pipeline, topic: nil)
|
117
|
+
o = self.pipeline(
|
118
|
+
enterprise: enterprise,
|
119
|
+
organization: organization,
|
120
|
+
project: project,
|
121
|
+
pipeline: pipeline
|
122
|
+
).select { |p| p.topic.eql?(topic) }.first
|
123
|
+
AutomateSoup::Change.new o
|
124
|
+
end
|
125
|
+
|
126
|
+
##
|
127
|
+
# Approve a change by change topic.
|
128
|
+
#
|
129
|
+
# @option enterprise [String] the enterprise to fetch org from, defaults to
|
130
|
+
# default.
|
131
|
+
# @option organization [String] the organization to fetch from.
|
132
|
+
# @option project [String] the project to fetch from.
|
133
|
+
# @option pipeline [String] the pipeline to fetch from.
|
134
|
+
# @option topic [String] the change topic to approve
|
135
|
+
# @option wait [Boolean] to wait for the approval stages to complete.
|
136
|
+
# @option timeout [Integer] the time in seconds to wait between requests defaults
|
137
|
+
# to 10
|
138
|
+
# @option retries [Integer] the amount of retries to make, defaults to 5
|
139
|
+
#
|
140
|
+
def approve_change(enterprise: @enterprise, organization: @organization, project: @project, pipeline: @pipeline, topic: nil, wait: false, timeout: 10, retries: 5)
|
141
|
+
o = self.change_by_topic(
|
142
|
+
enterprise: enterprise,
|
143
|
+
organization: organization,
|
144
|
+
project: project,
|
145
|
+
pipeline: pipeline,
|
146
|
+
topic: topic
|
147
|
+
)
|
148
|
+
if wait && !o.approvable? && !o.deliverable?
|
149
|
+
times = 1
|
150
|
+
while times <= retries
|
151
|
+
o = self.change_by_topic(
|
152
|
+
enterprise: enterprise,
|
153
|
+
organization: organization,
|
154
|
+
project: project,
|
155
|
+
pipeline: pipeline,
|
156
|
+
topic: topic
|
157
|
+
)
|
158
|
+
break if o.approvable?
|
159
|
+
return false if o.current_stage.failed?
|
160
|
+
puts "Stage #{o.current_stage.stage}: #{o.current_stage.status} retries #{times}/#{retries}"
|
161
|
+
sleep timeout
|
162
|
+
times += 1
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
o.approve
|
167
|
+
return true if !wait && o.deliverable?
|
168
|
+
times = 1
|
169
|
+
while times <= retries
|
170
|
+
o = self.change_by_topic(
|
171
|
+
enterprise: enterprise,
|
172
|
+
organization: organization,
|
173
|
+
project: project,
|
174
|
+
pipeline: pipeline,
|
175
|
+
topic: topic
|
176
|
+
)
|
177
|
+
break if o.deliverable?
|
178
|
+
return false if o.current_stage.failed?
|
179
|
+
puts "Stage #{o.current_stage.stage}: #{o.current_stage.status} retries #{times}/#{retries}"
|
180
|
+
times += 1
|
181
|
+
sleep timeout
|
182
|
+
end
|
183
|
+
true
|
184
|
+
end
|
185
|
+
|
186
|
+
|
187
|
+
##
|
188
|
+
# Delivery a change by a topic
|
189
|
+
#
|
190
|
+
# @option enterprise [String] the enterprise to fetch org from, defaults to
|
191
|
+
# default.
|
192
|
+
# @option organization [String] the organization to fetch from.
|
193
|
+
# @option project [String] the project to fetch from.
|
194
|
+
# @option pipeline [String] the pipeline to fetch from.
|
195
|
+
# @option topic [String] the change topic to approve
|
196
|
+
# @option wait [Boolean] to wait for the approval stages to complete.
|
197
|
+
# @option timeout [Integer] the time in seconds to wait between requests defaults
|
198
|
+
# to 10
|
199
|
+
# @option retries [Integer] the amount of retries to make, defaults to 5
|
200
|
+
#
|
201
|
+
def deliver_change(enterprise: @enterprise, organization: @organization, project: @project, pipeline: @pipeline, topic: nil, wait: false, timeout: 10, retries: 5)
|
202
|
+
o = self.change_by_topic(
|
203
|
+
enterprise: enterprise,
|
204
|
+
organization: organization,
|
205
|
+
project: project,
|
206
|
+
pipeline: pipeline,
|
207
|
+
topic: topic
|
208
|
+
)
|
209
|
+
return false if !o.deliverable?
|
210
|
+
if wait && !o.deliverable?
|
211
|
+
times = 1
|
212
|
+
while times <= retries
|
213
|
+
o = self.change_by_topic(
|
214
|
+
enterprise: enterprise,
|
215
|
+
organization: organization,
|
216
|
+
project: project,
|
217
|
+
pipeline: pipeline,
|
218
|
+
topic: topic
|
219
|
+
)
|
220
|
+
break if o.deliverable?
|
221
|
+
return false if o.current_stage.failed?
|
222
|
+
puts "Stage #{o.current_stage.stage}: #{o.current_stage.status} retries #{times}/#{retries}"
|
223
|
+
sleep timeout
|
224
|
+
times += 1
|
225
|
+
end
|
226
|
+
end
|
227
|
+
|
228
|
+
o.deliver
|
229
|
+
return true if !wait && o.delivered?
|
230
|
+
times = 1
|
231
|
+
while times <= retries
|
232
|
+
o = self.change_by_topic(
|
233
|
+
enterprise: enterprise,
|
234
|
+
organization: organization,
|
235
|
+
project: project,
|
236
|
+
pipeline: pipeline,
|
237
|
+
topic: topic
|
238
|
+
)
|
239
|
+
break if o.delivered?
|
240
|
+
return false if o.current_stage.failed?
|
241
|
+
puts "Stage #{o.current_stage.stage}: #{o.current_stage.status} retries #{times}/#{retries}"
|
242
|
+
times += 1
|
243
|
+
sleep timeout
|
244
|
+
end
|
245
|
+
true
|
246
|
+
end
|
247
|
+
|
248
|
+
private
|
249
|
+
|
250
|
+
def password_credentials(username, password)
|
251
|
+
AutomateSoup::Credentials.new(
|
252
|
+
username: username,
|
253
|
+
password: password
|
254
|
+
)
|
255
|
+
end
|
256
|
+
|
257
|
+
def token_credentials(username, token)
|
258
|
+
AutomateSoup::Credentials.new(
|
259
|
+
username: username,
|
260
|
+
token: token
|
261
|
+
)
|
262
|
+
end
|
263
|
+
end
|
264
|
+
end
|
@@ -0,0 +1,112 @@
|
|
1
|
+
module AutomateSoup
|
2
|
+
##
|
3
|
+
# API class to interact with chef automate
|
4
|
+
class API
|
5
|
+
def initialize(soup)
|
6
|
+
@soup = soup
|
7
|
+
end
|
8
|
+
|
9
|
+
##
|
10
|
+
# Get the status of the Automate API
|
11
|
+
#
|
12
|
+
def status
|
13
|
+
AutomateSoup::Rest.get(
|
14
|
+
url: "#{@soup.url}/api/_status",
|
15
|
+
username: @soup.credentials.username,
|
16
|
+
token: @soup.credentials.token
|
17
|
+
)
|
18
|
+
end
|
19
|
+
|
20
|
+
##
|
21
|
+
# Get the organizations given the enterprise.
|
22
|
+
#
|
23
|
+
# @param enterprise [String] the enterprise to fetch orgs from, defaults to
|
24
|
+
# default.
|
25
|
+
#
|
26
|
+
def orgs(enterprise = 'default')
|
27
|
+
@hash = AutomateSoup::Rest.get(
|
28
|
+
url: "#{@soup.url}/api/v0/e/#{enterprise}/orgs",
|
29
|
+
username: @soup.credentials.username,
|
30
|
+
token: @soup.credentials.token
|
31
|
+
)
|
32
|
+
raise "Failed to fetch orgs under enterprise #{enterprise}" unless @hash['orgs']
|
33
|
+
@hash['orgs']
|
34
|
+
end
|
35
|
+
|
36
|
+
##
|
37
|
+
# Get the projects under and organization given the enterprise.
|
38
|
+
#
|
39
|
+
# @option enterprise [String] the enterprise to fetch org from, defaults to
|
40
|
+
# default.
|
41
|
+
# @option organization [String] the organization to fetch projects from.
|
42
|
+
#
|
43
|
+
def projects(enterprise: 'default', organization: nil)
|
44
|
+
@hash = AutomateSoup::Rest.get(
|
45
|
+
url: "#{@soup.url}/api/v0/e/#{enterprise}/orgs/#{organization}/projects",
|
46
|
+
username: @soup.credentials.username,
|
47
|
+
token: @soup.credentials.token
|
48
|
+
)
|
49
|
+
|
50
|
+
rescue JSON::ParserError
|
51
|
+
raise "Failed to fetch projects under organization #{organization} enterprise #{enterprise}"
|
52
|
+
end
|
53
|
+
|
54
|
+
##
|
55
|
+
# Fetch a project under an enterprise, organization pair
|
56
|
+
#
|
57
|
+
# @option enterprise [String] the enterprise to fetch org from, defaults to
|
58
|
+
# default.
|
59
|
+
# @option organization [String] the organization to fetch projects from.
|
60
|
+
# @option project [String] the organization to fetch projects from.
|
61
|
+
#
|
62
|
+
def project(enterprise: 'default', organization: nil, project: nil)
|
63
|
+
@hash = AutomateSoup::Rest.get(
|
64
|
+
url: "#{@soup.url}/api/v0/e/#{enterprise}/orgs/#{organization}/projects/#{project}/pipelines",
|
65
|
+
username: @soup.credentials.username,
|
66
|
+
token: @soup.credentials.token
|
67
|
+
)
|
68
|
+
|
69
|
+
rescue JSON::ParserError
|
70
|
+
raise "Failed to fetch projects under organization #{organization} enterprise #{enterprise}"
|
71
|
+
end
|
72
|
+
|
73
|
+
##
|
74
|
+
# Fetch all project pipelines under an enterprise, organization pair
|
75
|
+
#
|
76
|
+
# @option enterprise [String] the enterprise to fetch org from, defaults to
|
77
|
+
# default.
|
78
|
+
# @option organization [String] the organization to fetch pipelines from.
|
79
|
+
# @option project [String] the project to fetch pipelines from.
|
80
|
+
#
|
81
|
+
def pipelines(enterprise: 'default', organization: nil, project: nil)
|
82
|
+
@hash = AutomateSoup::Rest.get(
|
83
|
+
url: "#{@soup.url}/api/v0/e/#{enterprise}/orgs/#{organization}/projects/#{project}/pipelines",
|
84
|
+
username: @soup.credentials.username,
|
85
|
+
token: @soup.credentials.token
|
86
|
+
)
|
87
|
+
@hash['pipelines']
|
88
|
+
|
89
|
+
rescue JSON::ParserError
|
90
|
+
raise "Failed to fetch pipelines under organization #{organization} enterprise #{enterprise}"
|
91
|
+
end
|
92
|
+
|
93
|
+
##
|
94
|
+
# Fetch a projects pipeline under an enterprise, organization pair
|
95
|
+
#
|
96
|
+
# @option enterprise [String] the enterprise to fetch org from, defaults to
|
97
|
+
# default.
|
98
|
+
# @option organization [String] the organization to fetch from.
|
99
|
+
# @option project [String] the project to fetch from.
|
100
|
+
# @option pipeline [String] the pipeline to fetch from.
|
101
|
+
#
|
102
|
+
def pipeline(enterprise: 'default', organization: nil, project: nil, pipeline: nil)
|
103
|
+
@hash = AutomateSoup::Rest.get(
|
104
|
+
url: "#{@soup.url}/api/v0/e/#{enterprise}/orgs/#{organization}/projects/#{project}/changes?pipeline=#{pipeline}&limit=25",
|
105
|
+
username: @soup.credentials.username,
|
106
|
+
token: @soup.credentials.token
|
107
|
+
)
|
108
|
+
rescue JSON::ParserError
|
109
|
+
raise "Failed to fetch pipelines under organization #{organization} enterprise #{enterprise}"
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
@@ -0,0 +1,105 @@
|
|
1
|
+
require 'ostruct'
|
2
|
+
|
3
|
+
module AutomateSoup
|
4
|
+
##
|
5
|
+
# Class to represent operations on a change.
|
6
|
+
#
|
7
|
+
class Change
|
8
|
+
def initialize(hash)
|
9
|
+
@source = OpenStruct.new hash
|
10
|
+
end
|
11
|
+
|
12
|
+
##
|
13
|
+
# Delegate method missing to the underlying OpenStruct
|
14
|
+
#
|
15
|
+
def method_missing(method, *args, &block)
|
16
|
+
@source.send(method, *args, &block)
|
17
|
+
end
|
18
|
+
|
19
|
+
##
|
20
|
+
# Determing the current stage of the change.
|
21
|
+
# @return [AutomateSoup::Stage] the current stage.
|
22
|
+
def current_stage
|
23
|
+
Stage.new @source.stages.last
|
24
|
+
end
|
25
|
+
|
26
|
+
##
|
27
|
+
# Wrapper for the _links property on the struct
|
28
|
+
#
|
29
|
+
def links
|
30
|
+
@source._links
|
31
|
+
end
|
32
|
+
|
33
|
+
##
|
34
|
+
# Determine if the change has been delivered successfully.
|
35
|
+
#
|
36
|
+
# @return [Boolean] if this change is delivered
|
37
|
+
def delivered?
|
38
|
+
(current_stage.stage.eql?('delivered') &&
|
39
|
+
current_stage.status.eql?('passed') &&
|
40
|
+
!AutomateSoup.url.nil? &&
|
41
|
+
!AutomateSoup.credentials.nil?)
|
42
|
+
end
|
43
|
+
|
44
|
+
##
|
45
|
+
# Determine if the change is deliverable.
|
46
|
+
#
|
47
|
+
# @return [Boolean] if this change is deliverable
|
48
|
+
def deliverable?
|
49
|
+
(current_stage.stage.eql?('acceptance') &&
|
50
|
+
current_stage.status.eql?('passed') &&
|
51
|
+
!AutomateSoup.url.nil? &&
|
52
|
+
!AutomateSoup.credentials.nil? &&
|
53
|
+
!links.nil? &&
|
54
|
+
!links['deliver'].nil? &&
|
55
|
+
!links['deliver']['href'].nil?)
|
56
|
+
end
|
57
|
+
|
58
|
+
##
|
59
|
+
# Determine if the change is approvable.
|
60
|
+
#
|
61
|
+
# @return [Boolean] if this change is approvable
|
62
|
+
def approvable?
|
63
|
+
(current_stage.stage.eql?('verify') &&
|
64
|
+
current_stage.status.eql?('passed') &&
|
65
|
+
!AutomateSoup.url.nil? &&
|
66
|
+
!AutomateSoup.credentials.nil? &&
|
67
|
+
!links.nil? &&
|
68
|
+
!links['approve'].nil? &&
|
69
|
+
!links['approve']['href'].nil?)
|
70
|
+
end
|
71
|
+
|
72
|
+
##
|
73
|
+
# Approve this change.
|
74
|
+
def approve
|
75
|
+
return nil if current_stage.stage != 'verify'
|
76
|
+
raise 'Must run AutomateSoup.setup first' if AutomateSoup.url.nil? || AutomateSoup.credentials.nil?
|
77
|
+
raise 'Approve link not available' if links.nil? || links['approve'].nil? || links['approve']['href'].nil?
|
78
|
+
url = "#{AutomateSoup.url}#{links['approve']['href']}"
|
79
|
+
res = AutomateSoup::Rest.post(
|
80
|
+
url: url,
|
81
|
+
username: AutomateSoup.credentials.username,
|
82
|
+
token: AutomateSoup.credentials.token
|
83
|
+
)
|
84
|
+
raise "Failed to approve change: #{res.code}" if res.code != '204'
|
85
|
+
true
|
86
|
+
end
|
87
|
+
|
88
|
+
##
|
89
|
+
# Deliver this change.
|
90
|
+
def deliver
|
91
|
+
raise 'Must approve change first' if current_stage.stage.eql? 'verify'
|
92
|
+
return nil if current_stage.stage != 'acceptance'
|
93
|
+
raise 'Must run AutomateSoup.setup first' if AutomateSoup.url.nil? || AutomateSoup.credentials.nil?
|
94
|
+
raise 'Deliver link not available' if links.nil? || links['deliver'].nil? || links['deliver']['href'].nil?
|
95
|
+
url = "#{AutomateSoup.url}#{links['deliver']['href']}"
|
96
|
+
res = AutomateSoup::Rest.post(
|
97
|
+
url: url,
|
98
|
+
username: AutomateSoup.credentials.username,
|
99
|
+
token: AutomateSoup.credentials.token
|
100
|
+
)
|
101
|
+
raise "Failed to deliver change: #{res.code}" if res.code != '204'
|
102
|
+
true
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|