oc-cdtapi 3.9.2__py2-none-any.whl → 3.9.4__py2-none-any.whl
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.
- oc_cdtapi/API.py +138 -42
- oc_cdtapi/DevPIAPI.py +30 -30
- oc_cdtapi/DmsAPI.py +120 -54
- oc_cdtapi/DmsGetverAPI.py +218 -155
- oc_cdtapi/ForemanAPI.py +495 -546
- oc_cdtapi/JenkinsAPI.py +171 -160
- oc_cdtapi/NexusAPI.py +1 -2
- {oc_cdtapi-3.9.2.dist-info → oc_cdtapi-3.9.4.dist-info}/METADATA +1 -1
- oc_cdtapi-3.9.4.dist-info/RECORD +15 -0
- oc_cdtapi-3.9.2.dist-info/RECORD +0 -15
- {oc_cdtapi-3.9.2.data → oc_cdtapi-3.9.4.data}/scripts/nexus.py +0 -0
- {oc_cdtapi-3.9.2.dist-info → oc_cdtapi-3.9.4.dist-info}/LICENSE +0 -0
- {oc_cdtapi-3.9.2.dist-info → oc_cdtapi-3.9.4.dist-info}/WHEEL +0 -0
- {oc_cdtapi-3.9.2.dist-info → oc_cdtapi-3.9.4.dist-info}/top_level.txt +0 -0
oc_cdtapi/JenkinsAPI.py
CHANGED
@@ -1,11 +1,12 @@
|
|
1
1
|
# requires python-requests rpm package
|
2
|
+
from enum import Enum
|
2
3
|
import requests
|
3
4
|
from .API import HttpAPI, HttpAPIError
|
4
5
|
from string import Template
|
5
6
|
import json
|
6
7
|
from collections import namedtuple, OrderedDict
|
7
8
|
import re
|
8
|
-
import xml.etree.ElementTree as ET
|
9
|
+
import xml.etree.ElementTree as ET
|
9
10
|
import posixpath
|
10
11
|
import sys
|
11
12
|
|
@@ -42,10 +43,11 @@ class Jenkins(HttpAPI):
|
|
42
43
|
_env_prefix = 'JENKINS'
|
43
44
|
|
44
45
|
def re(self, req):
|
45
|
-
if req and req
|
46
|
-
req = req
|
47
|
-
return posixpath.join(
|
48
|
-
|
46
|
+
if req and req.startswith('!'):
|
47
|
+
req = req.lstrip('!')
|
48
|
+
return posixpath.join(self.root, req)
|
49
|
+
|
50
|
+
return posixpath.join(self.root, req, 'api', 'json')
|
49
51
|
|
50
52
|
def post(self, req, *vargs, **kvargs):
|
51
53
|
# We need all post requests to be processed in a different way in re(),
|
@@ -57,127 +59,133 @@ class Jenkins(HttpAPI):
|
|
57
59
|
jobs = self.get('', params={'tree': 'jobs[name]'})
|
58
60
|
return filter(lambda x: (not prefix or x.startswith(prefix)) and (not suffix or x.endswith(suffix)),
|
59
61
|
map(lambda x: x['name'], jobs.json().get('jobs', [])))
|
62
|
+
|
60
63
|
def get_node(self, node):
|
61
64
|
"""Gets config.xml for specific slave"""
|
62
|
-
config = self.get(
|
65
|
+
config = self.get(posixpath.join('computer', node, 'config.xml'))
|
63
66
|
return config.text
|
64
67
|
|
65
68
|
def put_node(self, node, config):
|
66
69
|
"""Saves config.xml for a node (or creates new node)"""
|
67
|
-
request = posixpath.join(
|
70
|
+
request = posixpath.join('computer', node, 'config.xml')
|
68
71
|
params = None
|
69
|
-
headers = {'content-type'
|
72
|
+
headers = {'content-type': 'application/xml'}
|
70
73
|
|
71
74
|
try:
|
72
75
|
self.get_node(node)
|
73
76
|
except JenkinsError as e:
|
74
|
-
if e.code == 404:
|
77
|
+
if e.code == 404:
|
78
|
+
request = posixpath.join('computer', 'doCreateItem')
|
75
79
|
params = {'name': node}
|
76
80
|
|
77
|
-
if self.readonly:
|
81
|
+
if self.readonly:
|
82
|
+
return None
|
83
|
+
|
78
84
|
put = self.post(request, data=config, params=params, headers=headers)
|
79
85
|
return put
|
80
86
|
|
81
|
-
def delete_node(
|
87
|
+
def delete_node(self, node):
|
82
88
|
"""Deletes node from CI"""
|
83
|
-
if self.readonly:
|
84
|
-
|
89
|
+
if self.readonly:
|
90
|
+
return None
|
91
|
+
return self.post(posixpath.join('computer', node, 'doDelete'))
|
85
92
|
|
86
|
-
def get_node_label_from_config(
|
93
|
+
def get_node_label_from_config(self, config):
|
87
94
|
"""
|
88
95
|
Get the exact XML tag value with XPATH: label
|
89
96
|
:param self: self reference
|
90
97
|
:param config: xml string with a configuration of node
|
91
98
|
:return: <label> tag text
|
92
99
|
"""
|
93
|
-
obj_xml = ET.fromstring(
|
94
|
-
xml_tag = obj_xml.find(
|
100
|
+
obj_xml = ET.fromstring(config)
|
101
|
+
xml_tag = obj_xml.find('label')
|
95
102
|
|
96
|
-
if (
|
97
|
-
return ""
|
103
|
+
if (xml_tag is None) or (xml_tag.text is None) or (len(xml_tag.text.strip()) == 0):
|
104
|
+
return ""
|
98
105
|
|
99
|
-
return xml_tag.text
|
106
|
+
return xml_tag.text
|
100
107
|
|
101
108
|
def get_node_label(self, node, config=None):
|
102
|
-
if not config:
|
103
|
-
|
109
|
+
if not config:
|
110
|
+
config = self.get_node(node)
|
111
|
+
return self.get_node_label_from_config(config).split(' ')
|
104
112
|
|
105
|
-
def set_node_label_in_config(
|
113
|
+
def set_node_label_in_config(self, config, label):
|
106
114
|
"""
|
107
115
|
set <label> tag in XML config
|
108
116
|
:param self: self reference
|
109
117
|
:param config: string with XML node configuration
|
110
118
|
:return: string with edited 'config' with <lable> tag content set to 'label'
|
111
119
|
"""
|
112
|
-
obj_xml = ET.fromstring(
|
113
|
-
xml_tag = obj_xml.find(
|
120
|
+
obj_xml = ET.fromstring(config)
|
121
|
+
xml_tag = obj_xml.find('label')
|
114
122
|
|
115
|
-
if (
|
116
|
-
xml_tag = ET.SubElement(
|
123
|
+
if (xml_tag is None):
|
124
|
+
xml_tag = ET.SubElement(obj_xml, 'label')
|
117
125
|
|
118
|
-
xml_tag.text = label
|
126
|
+
xml_tag.text = label
|
119
127
|
|
120
|
-
return ET.tostring(
|
128
|
+
return ET.tostring(obj_xml, encoding='utf8')
|
121
129
|
|
122
130
|
def set_node_label(self, node, label):
|
123
131
|
config = self.get_node(node)
|
124
|
-
config = self.set_node_label_in_config(
|
132
|
+
config = self.set_node_label_in_config(config, ' '.join(label))
|
125
133
|
return self.put_node(node, config)
|
126
134
|
|
127
135
|
def enable_node(self, job):
|
128
|
-
if self.readonly:
|
129
|
-
|
136
|
+
if self.readonly:
|
137
|
+
return None
|
138
|
+
return self.post(posixpath.join('computer', job, 'enable'))
|
130
139
|
|
131
140
|
def disable_node(self, job):
|
132
|
-
if self.readonly:
|
133
|
-
|
141
|
+
if self.readonly:
|
142
|
+
return None
|
143
|
+
return self.post(posixpath.join('computer', job, 'disable'))
|
134
144
|
|
135
145
|
def is_node_idle(self, node):
|
136
146
|
"""Retrieve 'idle' attribute of a node via newer JSON API (may require Jenkins 2.x)."""
|
137
|
-
return json.
|
138
|
-
self.get("computer/{}/api/json".format(node)).content
|
139
|
-
)['idle']
|
147
|
+
return self.get(posixpath.join("computer", node, "api", "json")).json().get('idle')
|
140
148
|
|
141
|
-
def list_nodes(
|
149
|
+
def list_nodes(self):
|
142
150
|
"""
|
143
151
|
List all active nodes (except master one)
|
144
152
|
:return: List of strings with node names, possible empty
|
145
153
|
"""
|
146
|
-
raw_data = self.get(
|
154
|
+
raw_data = self.get("computer", params={"tree": "computer[displayName]"})
|
147
155
|
str_data = raw_data.text
|
148
156
|
|
149
157
|
# return map( lambda x: x[ "displayName" ], json.loads( self.get( "computer", params = { "tree" : "computer[displayName]" } ).text )[ "computer" ] );
|
150
|
-
return [x[
|
151
|
-
|
158
|
+
return [x["displayName"] for x in json.loads(str_data)["computer"]]
|
152
159
|
|
153
|
-
def job_xml_enable(
|
160
|
+
def job_xml_enable(self, config):
|
154
161
|
"""
|
155
162
|
Enables jenkins job by modifying XML tag (XPATH=) in the configuration
|
156
163
|
:param self: self reference
|
157
164
|
:param config: xml string from a config
|
158
165
|
:return: xml string with <disabled> tag value modified to 'true'
|
159
166
|
"""
|
160
|
-
obj_xml = ET.fromstring(
|
161
|
-
xml_tag = obj_xml.find(
|
167
|
+
obj_xml = ET.fromstring(config)
|
168
|
+
xml_tag = obj_xml.find('disabled')
|
162
169
|
|
163
170
|
if xml_tag is None:
|
164
|
-
return config
|
171
|
+
return config
|
165
172
|
|
166
|
-
xml_tag.text = "false"
|
173
|
+
xml_tag.text = "false"
|
167
174
|
|
168
|
-
return ET.tostring(
|
175
|
+
return ET.tostring(obj_xml, encoding='utf8')
|
169
176
|
|
170
177
|
def copy_job(self, config, j_name, parameters={}, enabled=True, use_template=False):
|
171
178
|
"""Create or update job by template"""
|
172
179
|
|
173
|
-
if config[0] != '<':
|
180
|
+
if config[0] != '<':
|
181
|
+
config = self.get_job(config)
|
174
182
|
parameters['name'] = j_name
|
175
183
|
if enabled:
|
176
|
-
config = self.job_xml_enable(
|
184
|
+
config = self.job_xml_enable(config)
|
177
185
|
|
178
|
-
cfg_type = str
|
186
|
+
cfg_type = str(type(config))
|
179
187
|
if cfg_type.find('byte') != -1:
|
180
|
-
config = str
|
188
|
+
config = str(config, 'UTF-8')
|
181
189
|
|
182
190
|
if use_template:
|
183
191
|
config = Template(config).safe_substitute(parameters)
|
@@ -190,142 +198,149 @@ class Jenkins(HttpAPI):
|
|
190
198
|
|
191
199
|
def get_job(self, job):
|
192
200
|
"""Gets config.xml for a job"""
|
193
|
-
config = self.get(
|
201
|
+
config = self.get(posixpath.join('job', job, 'config.xml'))
|
194
202
|
return config.text
|
195
203
|
|
196
204
|
def put_job(self, job, config):
|
197
205
|
"""Saves config.xml for a job (or creates new job)"""
|
198
|
-
request = posixpath.join(
|
206
|
+
request = posixpath.join('job', job, 'config.xml')
|
199
207
|
params = None
|
200
|
-
headers = {'content-type'
|
208
|
+
headers = {'content-type': 'application/xml'}
|
201
209
|
try:
|
202
210
|
self.get_job(job)
|
203
211
|
except JenkinsError as e:
|
204
|
-
if e.code == 404:
|
212
|
+
if e.code == 404:
|
213
|
+
request = 'createItem'
|
205
214
|
params = {'name': job}
|
206
215
|
|
207
|
-
if self.readonly:
|
216
|
+
if self.readonly:
|
217
|
+
return None
|
208
218
|
put = self.post(request, data=config, params=params, headers=headers)
|
209
219
|
return put
|
210
220
|
|
211
221
|
def enable_job(self, job):
|
212
|
-
if self.readonly:
|
213
|
-
|
222
|
+
if self.readonly:
|
223
|
+
return None
|
224
|
+
return self.post(posixpath.join('job', job, 'enable'))
|
214
225
|
|
215
226
|
def disable_job(self, job):
|
216
|
-
if self.readonly:
|
217
|
-
|
227
|
+
if self.readonly:
|
228
|
+
return None
|
229
|
+
return self.post(posixpath.join('job', job, 'disable'))
|
218
230
|
|
219
231
|
def delete_job(self, job):
|
220
|
-
if self.readonly:
|
221
|
-
|
232
|
+
if self.readonly:
|
233
|
+
return None
|
234
|
+
return self.post(posixpath.join('job', job, 'doDelete'))
|
222
235
|
|
223
236
|
def run_job(self, job, params=None):
|
224
|
-
if self.readonly:
|
237
|
+
if self.readonly:
|
238
|
+
return None
|
225
239
|
if params == None:
|
226
|
-
response=self.post(
|
240
|
+
response = self.post(posixpath.join('job', job, 'build'))
|
227
241
|
else:
|
228
|
-
response=self.post(
|
242
|
+
response = self.post(posixpath.join('job', job, 'buildWithParameters'), data=params)
|
229
243
|
|
230
|
-
queue_item=QueueItem.from_jenkins_response(response, self)
|
244
|
+
queue_item = QueueItem.from_jenkins_response(response, self)
|
231
245
|
return queue_item
|
232
246
|
|
233
|
-
def list_builds(
|
247
|
+
def list_builds(self, node=None):
|
234
248
|
"""
|
235
249
|
Get list of Builds which are currently build on the node given
|
236
250
|
:param node: list only jobs building on the node specified
|
237
251
|
:type node: string
|
238
252
|
:return: dictionary with node_names as a key and list of jobs dictionaries building on the node as { "job_name": ... , "build_number" : ... }, list may be None
|
239
253
|
"""
|
240
|
-
str_request = ""
|
241
|
-
dict_parms = {
|
254
|
+
str_request = ""
|
255
|
+
dict_parms = {"tree": "jobs[name,lastBuild[building,fullDisplayName,number,url,builtOn]]"}
|
242
256
|
|
243
257
|
if node is not None:
|
244
|
-
str_request = posixpath.join(
|
245
|
-
dict_parms[
|
258
|
+
str_request = posixpath.join("computer", node)
|
259
|
+
dict_parms["tree"] = "executors[idle,currentExecutable[idle,building,builtOn,number,fullDisplayName,url]]"
|
246
260
|
|
247
|
-
response = self.get(
|
248
|
-
dict_resp = json.loads(
|
261
|
+
response = self.get(str_request, params=dict_parms)
|
262
|
+
dict_resp = json.loads(response.text)
|
249
263
|
|
250
264
|
if node is not None:
|
251
|
-
if len(
|
252
|
-
return {
|
265
|
+
if len(dict_resp["executors"]) == 0:
|
266
|
+
return {node: list()}
|
253
267
|
|
254
|
-
ls_jobs = map(
|
255
|
-
|
256
|
-
else :
|
257
|
-
ls_jobs = dict_resp[ "jobs" ];
|
268
|
+
ls_jobs = map(lambda x: {"name": None, "lastBuild": (
|
269
|
+
None if x["idle"] else x["currentExecutable"])}, dict_resp["executors"])
|
258
270
|
|
271
|
+
else:
|
272
|
+
ls_jobs = dict_resp["jobs"]
|
259
273
|
|
260
|
-
dict_result = dict()
|
274
|
+
dict_result = dict()
|
261
275
|
|
262
276
|
for dict_job in ls_jobs:
|
263
|
-
if "lastBuild" not in dict_job or dict_job[
|
264
|
-
continue
|
277
|
+
if "lastBuild" not in dict_job or dict_job["lastBuild"] is None or not dict_job["lastBuild"]["building"]:
|
278
|
+
continue # inactive build, out of interes
|
265
279
|
|
266
|
-
str_job_name = dict_job[
|
280
|
+
str_job_name = dict_job["name"]
|
267
281
|
|
268
282
|
if not str_job_name:
|
269
|
-
str_job_name = dict_job[
|
283
|
+
str_job_name = dict_job["lastBuild"]["url"].split(
|
284
|
+
posixpath.sep + "job" + posixpath.sep, 1)[1].split(posixpath.sep, 1)[0]
|
270
285
|
|
271
|
-
str_builder_node = dict_job[
|
286
|
+
str_builder_node = dict_job["lastBuild"]["builtOn"]
|
272
287
|
|
273
288
|
if str_builder_node not in dict_result:
|
274
|
-
dict_result[
|
289
|
+
dict_result[str_builder_node] = list()
|
275
290
|
|
276
|
-
dict_result[
|
291
|
+
dict_result[str_builder_node].append(
|
292
|
+
{"job_name": str_job_name, "build_nubmer": dict_job["lastBuild"]["number"]})
|
277
293
|
|
278
|
-
return dict_result
|
294
|
+
return dict_result
|
279
295
|
|
280
|
-
def list_queue(
|
296
|
+
def list_queue(self):
|
281
297
|
"""
|
282
298
|
Get queue items, perhaps empty if no jobs queued
|
283
299
|
:return: list of QueueItems, possible empty
|
284
300
|
"""
|
285
|
-
ls_result = list()
|
286
|
-
obj_resp = self.get(
|
287
|
-
dict_resp = json.loads(
|
301
|
+
ls_result = list()
|
302
|
+
obj_resp = self.get("queue")
|
303
|
+
dict_resp = json.loads(obj_resp.text or {})
|
288
304
|
|
289
305
|
if not 'items' in dict_resp:
|
290
|
-
return ls_result
|
306
|
+
return ls_result
|
291
307
|
|
292
|
-
for dict_task in dict_resp[
|
308
|
+
for dict_task in dict_resp['items']:
|
293
309
|
if not 'task' in dict_task:
|
294
|
-
continue
|
310
|
+
continue
|
295
311
|
|
296
|
-
if not 'name' in dict_task[
|
297
|
-
continue
|
312
|
+
if not 'name' in dict_task['task']:
|
313
|
+
continue
|
298
314
|
|
299
315
|
if not 'id' in dict_task:
|
300
|
-
continue
|
316
|
+
continue
|
301
317
|
|
302
|
-
ls_result.append(
|
303
|
-
|
304
|
-
return ls_result
|
318
|
+
ls_result.append(QueueItem(dict_task['id'], self, dict_task))
|
319
|
+
|
320
|
+
return ls_result
|
305
321
|
|
306
|
-
def unqueue_item(
|
322
|
+
def unqueue_item(self, int_id):
|
307
323
|
"""
|
308
324
|
remove item with ID given from queue
|
309
325
|
:param int_id: id
|
310
326
|
:type int_id: integer
|
311
327
|
"""
|
312
|
-
if int_id is None or not isinstance(
|
313
|
-
raise TypeError(
|
328
|
+
if int_id is None or not isinstance(int_id, int):
|
329
|
+
raise TypeError("Wrong type of arguments: int_id is not integer")
|
314
330
|
|
315
331
|
try:
|
316
|
-
self.post(
|
332
|
+
self.post(posixpath.join('queue', 'cancelItem'), data={}, params={"id": int_id})
|
317
333
|
except:
|
318
|
-
pass
|
334
|
+
pass # since jenkins returns 404 code for this type of operation and it is normal
|
319
335
|
|
320
336
|
|
321
|
-
from enum import Enum
|
322
337
|
class BuildStatus(Enum):
|
323
|
-
BUILDING=0
|
324
|
-
SUCCESS=1
|
325
|
-
FAILURE=2
|
326
|
-
ABORTED=3
|
327
|
-
UNSTABLE=4
|
328
|
-
NOT_BUILD=5
|
338
|
+
BUILDING = 0
|
339
|
+
SUCCESS = 1
|
340
|
+
FAILURE = 2
|
341
|
+
ABORTED = 3
|
342
|
+
UNSTABLE = 4
|
343
|
+
NOT_BUILD = 5
|
329
344
|
|
330
345
|
|
331
346
|
class Build(object):
|
@@ -334,31 +349,31 @@ class Build(object):
|
|
334
349
|
"""
|
335
350
|
|
336
351
|
def __init__(self, job_name, build_number, jenkins_client):
|
337
|
-
self.job_name=job_name
|
338
|
-
self.build_number=build_number
|
339
|
-
self.jenkins_client=jenkins_client
|
340
|
-
self._build_status=BuildStatus.BUILDING
|
352
|
+
self.job_name = job_name
|
353
|
+
self.build_number = build_number
|
354
|
+
self.jenkins_client = jenkins_client
|
355
|
+
self._build_status = BuildStatus.BUILDING
|
341
356
|
|
342
357
|
def get_status(self):
|
343
358
|
self._update_build_status()
|
344
359
|
return self._build_status
|
345
360
|
|
346
361
|
def _update_build_status(self):
|
347
|
-
if self._build_status!=BuildStatus.BUILDING:
|
362
|
+
if self._build_status != BuildStatus.BUILDING:
|
348
363
|
return self._build_status
|
349
|
-
build_path = posixpath.join(
|
350
|
-
response=self.jenkins_client.get(build_path)
|
351
|
-
if response.status_code==404:
|
364
|
+
build_path = posixpath.join("job", self.job_name, str(self.build_number), 'api', 'json')
|
365
|
+
response = self.jenkins_client.get(build_path)
|
366
|
+
if response.status_code == 404:
|
352
367
|
raise JenkinsError("No build exist at %s" % build_path)
|
353
|
-
parsed_response=json.loads(response.text or "{}")
|
354
|
-
status_value=parsed_response["result"]
|
368
|
+
parsed_response = json.loads(response.text or "{}")
|
369
|
+
status_value = parsed_response["result"]
|
355
370
|
if not status_value:
|
356
|
-
self._build_status=BuildStatus.BUILDING
|
371
|
+
self._build_status = BuildStatus.BUILDING
|
357
372
|
else:
|
358
373
|
if sys.version_info.major == 2:
|
359
374
|
self._build_status = getattr(BuildStatus, status_value)
|
360
375
|
else:
|
361
|
-
self._build_status=BuildStatus[status_value]
|
376
|
+
self._build_status = BuildStatus[status_value]
|
362
377
|
|
363
378
|
|
364
379
|
class QueueItem(object):
|
@@ -369,55 +384,55 @@ class QueueItem(object):
|
|
369
384
|
|
370
385
|
@classmethod
|
371
386
|
def from_jenkins_response(cls, response, jenkins_client):
|
372
|
-
location_url=response.headers["Location"]
|
373
|
-
search_result=re.search(
|
374
|
-
queue_id=int(search_result.group("queue_id"))
|
387
|
+
location_url = response.headers["Location"]
|
388
|
+
search_result = re.search(r'' + posixpath.join("queue", "item", "(?P<queue_id>\d+)"), location_url)
|
389
|
+
queue_id = int(search_result.group("queue_id"))
|
375
390
|
return QueueItem(queue_id, jenkins_client)
|
376
|
-
|
377
|
-
def __init__(self, queue_id, jenkins_client, dict_details
|
391
|
+
|
392
|
+
def __init__(self, queue_id, jenkins_client, dict_details=None):
|
378
393
|
"""
|
379
394
|
:param resource: id in build queue (assigned at build launch request)
|
380
395
|
:param required: jenkins.Jenkins instance
|
381
396
|
"""
|
382
|
-
self.queue_id=queue_id
|
383
|
-
self.jenkins_client=jenkins_client
|
384
|
-
self._build=None
|
385
|
-
self._task=None
|
397
|
+
self.queue_id = queue_id
|
398
|
+
self.jenkins_client = jenkins_client
|
399
|
+
self._build = None
|
400
|
+
self._task = None
|
386
401
|
|
387
402
|
if not dict_details:
|
388
|
-
return
|
403
|
+
return
|
389
404
|
|
390
405
|
if "task" in dict_details:
|
391
|
-
self._task = dict_details[
|
406
|
+
self._task = dict_details["task"]
|
392
407
|
|
393
408
|
@property
|
394
|
-
def task(
|
409
|
+
def task(self):
|
395
410
|
"""
|
396
411
|
:return: dictionary with task parameters - job name, url, color - as it returned by Jenkins
|
397
412
|
"""
|
398
413
|
if not self._task:
|
399
|
-
self._try_update_queue_status()
|
400
|
-
return self._task
|
414
|
+
self._try_update_queue_status()
|
415
|
+
return self._task
|
401
416
|
|
402
417
|
@property
|
403
|
-
def job_name(
|
418
|
+
def job_name(self):
|
404
419
|
"""
|
405
420
|
:return: job name of the queue item
|
406
421
|
"""
|
407
422
|
|
408
423
|
if not self._task:
|
409
|
-
self._try_update_queue_status()
|
424
|
+
self._try_update_queue_status()
|
410
425
|
|
411
426
|
if not self._task:
|
412
|
-
return None
|
427
|
+
return None
|
413
428
|
|
414
429
|
if "url" not in self._task:
|
415
|
-
self._try_update_queue_status()
|
430
|
+
self._try_update_queue_status()
|
416
431
|
|
417
432
|
if "url" not in self._task:
|
418
|
-
return None
|
433
|
+
return None
|
419
434
|
|
420
|
-
return self._task[
|
435
|
+
return self._task["url"].split(posixpath.sep + "job" + posixpath.sep, 1).pop().split(posixpath.sep, 1).pop(0)
|
421
436
|
|
422
437
|
def is_running(self):
|
423
438
|
self._try_update_queue_status()
|
@@ -425,33 +440,29 @@ class QueueItem(object):
|
|
425
440
|
|
426
441
|
def get_build(self):
|
427
442
|
self._try_update_queue_status()
|
443
|
+
|
428
444
|
if self._build:
|
429
445
|
return self._build
|
430
|
-
|
431
|
-
|
446
|
+
|
447
|
+
raise BuildStatusException("Build is not started yet")
|
432
448
|
|
433
449
|
def _try_update_queue_status(self):
|
434
450
|
if self._build:
|
435
451
|
return
|
436
|
-
item_path= posixpath.join(
|
437
|
-
response=self.jenkins_client.get(item_path)
|
438
|
-
if response.status_code==404:
|
452
|
+
item_path = posixpath.join("queue", "item", str(self.queue_id), "api", "json")
|
453
|
+
response = self.jenkins_client.get(item_path)
|
454
|
+
if response.status_code == 404:
|
439
455
|
raise JenkinsError("No queue item exist at %s" % item_path)
|
440
|
-
parsed_response=json.loads(response.text or "{}")
|
456
|
+
parsed_response = json.loads(response.text or "{}")
|
441
457
|
if "executable" in parsed_response:
|
442
|
-
self._build=Build(parsed_response["task"]["name"],
|
443
|
-
|
444
|
-
|
458
|
+
self._build = Build(parsed_response["task"]["name"],
|
459
|
+
parsed_response["executable"]["number"],
|
460
|
+
self.jenkins_client)
|
445
461
|
|
446
462
|
if not self._task and "task" in parsed_response:
|
447
|
-
self._task = parsed_response[
|
448
|
-
|
463
|
+
self._task = parsed_response["task"]
|
464
|
+
|
449
465
|
|
450
466
|
class BuildStatusException(Exception):
|
451
467
|
pass
|
452
468
|
|
453
|
-
|
454
|
-
if __name__ == "__main__":
|
455
|
-
import doctest
|
456
|
-
|
457
|
-
doctest.testmod()
|
oc_cdtapi/NexusAPI.py
CHANGED
@@ -246,8 +246,7 @@ class NexusAPI(HttpAPI):
|
|
246
246
|
:param repo: repo
|
247
247
|
:type repo: str
|
248
248
|
"""
|
249
|
-
#
|
250
|
-
# but implemented ugly via 'posixpath' to get rid of extra dependencies
|
249
|
+
#urllib.urlparse.urljoin is not suitable for us since it joins only host part + relative part
|
251
250
|
if not gav:
|
252
251
|
raise ValueError("GAV is mandatory")
|
253
252
|
|
@@ -0,0 +1,15 @@
|
|
1
|
+
oc_cdtapi/API.py,SHA256=hpdnzyirYT_wISeznRmoqr-umYRT6uqKVwhmCXyj8Nk,12398
|
2
|
+
oc_cdtapi/DevPIAPI.py,SHA256=Nn63Ob0kA5XXuRZ3OIWG2rcnSsztKq9yPI6Lu2zX3Gk,1836
|
3
|
+
oc_cdtapi/DmsAPI.py,SHA256=j2Bx4Sryc4R1knyNjQmZshVuCePeD2q4W-fxv7zOMFc,9481
|
4
|
+
oc_cdtapi/DmsGetverAPI.py,SHA256=NIhWq2MDWaIBFLYJqkPCV9jZqM1HSZum6gIHquGHdQg,16085
|
5
|
+
oc_cdtapi/ForemanAPI.py,SHA256=FP_zeCgnSSYTPPck_xD0GsYH5BD0nLiOTiG1Qj4OkO8,39747
|
6
|
+
oc_cdtapi/JenkinsAPI.py,SHA256=lZ8pe3a4eb_6h53JE7QLuzOSlu7Sqatc9PQwWhio9Vg,15748
|
7
|
+
oc_cdtapi/NexusAPI.py,SHA256=uU12GtHvKlWorFaPAnFcQ5AGEc94MZ5SdmfM2Pw3F7A,26122
|
8
|
+
oc_cdtapi/TestServer.py,SHA256=HV97UWg2IK4gOYAp9yaMdwFUWsw9v66MxyZdI3qQctA,2715
|
9
|
+
oc_cdtapi/__init__.py,SHA256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
10
|
+
oc_cdtapi-3.9.4.data/scripts/nexus.py,SHA256=4teqZ_KtCSrwHDJVgA7lkreteod4Xt5XJFZNbwb7E6E,6858
|
11
|
+
oc_cdtapi-3.9.4.dist-info/LICENSE,SHA256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
12
|
+
oc_cdtapi-3.9.4.dist-info/METADATA,SHA256=mdcjdGDuh_sy8EI6-WzrW1CbF4-4i_L9ENeia0dk0O8,351
|
13
|
+
oc_cdtapi-3.9.4.dist-info/WHEEL,SHA256=1VPi6hfNQaRRNuEdK_3dv9o8COtLGnHWJghhj4CQ28k,92
|
14
|
+
oc_cdtapi-3.9.4.dist-info/top_level.txt,SHA256=d4-5-D-0CSeSXYuLCP7-nIFCpjkfmJr-Y_muzds8iVU,10
|
15
|
+
oc_cdtapi-3.9.4.dist-info/RECORD,,
|
oc_cdtapi-3.9.2.dist-info/RECORD
DELETED
@@ -1,15 +0,0 @@
|
|
1
|
-
oc_cdtapi/API.py,SHA256=ScjpCC6bdEzJBc1Qgp6ODH8bfxwccBr3hI9I96UYmQk,8680
|
2
|
-
oc_cdtapi/DevPIAPI.py,SHA256=SvQWSpsgZEsxJmm-edTPqZ25fi8KyvxQ0X27vjhU3cI,2054
|
3
|
-
oc_cdtapi/DmsAPI.py,SHA256=NzXfJ9k1srTOWZYCwOhxzLN1deNGnPtJoUy22qjiGmQ,7841
|
4
|
-
oc_cdtapi/DmsGetverAPI.py,SHA256=SOFLSl8DOCblR-swdHeufRLMPKahf1rDbILfz-4_zbk,13948
|
5
|
-
oc_cdtapi/ForemanAPI.py,SHA256=wGYPEPYgeNUSp2SATk_pZ4FRIwX9lmkcAgZyIzM47_4,39979
|
6
|
-
oc_cdtapi/JenkinsAPI.py,SHA256=ZBMDRmR4K7rlpGzqaWL7vPjlwweP4AGi2bom31v5T8s,15862
|
7
|
-
oc_cdtapi/NexusAPI.py,SHA256=PsE6Lzh3WcmZkqlIo0zqi_VvpHjYciUYvCLEQtH4bzw,26153
|
8
|
-
oc_cdtapi/TestServer.py,SHA256=HV97UWg2IK4gOYAp9yaMdwFUWsw9v66MxyZdI3qQctA,2715
|
9
|
-
oc_cdtapi/__init__.py,SHA256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
10
|
-
oc_cdtapi-3.9.2.data/scripts/nexus.py,SHA256=4teqZ_KtCSrwHDJVgA7lkreteod4Xt5XJFZNbwb7E6E,6858
|
11
|
-
oc_cdtapi-3.9.2.dist-info/LICENSE,SHA256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
12
|
-
oc_cdtapi-3.9.2.dist-info/METADATA,SHA256=xM5-EiF27G_0PGaH5sas5T5tCJI_1kLaKKBuvXGIKxc,351
|
13
|
-
oc_cdtapi-3.9.2.dist-info/WHEEL,SHA256=1VPi6hfNQaRRNuEdK_3dv9o8COtLGnHWJghhj4CQ28k,92
|
14
|
-
oc_cdtapi-3.9.2.dist-info/top_level.txt,SHA256=d4-5-D-0CSeSXYuLCP7-nIFCpjkfmJr-Y_muzds8iVU,10
|
15
|
-
oc_cdtapi-3.9.2.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|