summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZuul <zuul@review.openstack.org>2019-03-07 21:50:13 +0000
committerGerrit Code Review <review@openstack.org>2019-03-07 21:50:13 +0000
commit875bb953631e9a384f35cac8f9ffe254b357b1d0 (patch)
tree9055cf0f407b5d4d30950861389184d8ca90e587
parente9900ca1d4570908592491d7eb7cbb1fc1da9ba4 (diff)
parent48959d6e5388c0628905703c8cd8d250cdd722a0 (diff)
Merge "web: add /{tenant}/buildset/{uuid} route"
-rwxr-xr-xtests/unit/test_web.py46
-rw-r--r--zuul/driver/sql/sqlconnection.py31
-rwxr-xr-xzuul/web/__init__.py50
3 files changed, 112 insertions, 15 deletions
diff --git a/tests/unit/test_web.py b/tests/unit/test_web.py
index f2e33c6..fe080cd 100755
--- a/tests/unit/test_web.py
+++ b/tests/unit/test_web.py
@@ -815,6 +815,23 @@ class TestBuildInfo(ZuulDBTestCase, BaseTestWeb):
815 815
816 buildsets = self.get_url("api/tenant/tenant-one/buildsets").json() 816 buildsets = self.get_url("api/tenant/tenant-one/buildsets").json()
817 self.assertEqual(2, len(buildsets)) 817 self.assertEqual(2, len(buildsets))
818 project_bs = [x for x in buildsets if x["project"] == "org/project"][0]
819
820 buildset = self.get_url(
821 "api/tenant/tenant-one/buildset/%s" % project_bs['uuid']).json()
822 self.assertEqual(3, len(buildset["builds"]))
823
824 project_test1_build = [x for x in buildset["builds"]
825 if x["job_name"] == "project-test1"][0]
826 self.assertEqual('SUCCESS', project_test1_build['result'])
827
828 project_test2_build = [x for x in buildset["builds"]
829 if x["job_name"] == "project-test2"][0]
830 self.assertEqual('SUCCESS', project_test2_build['result'])
831
832 project_merge_build = [x for x in buildset["builds"]
833 if x["job_name"] == "project-merge"][0]
834 self.assertEqual('SUCCESS', project_merge_build['result'])
818 835
819 836
820class TestArtifacts(ZuulDBTestCase, BaseTestWeb, AnsibleZuulTestCase): 837class TestArtifacts(ZuulDBTestCase, BaseTestWeb, AnsibleZuulTestCase):
@@ -844,3 +861,32 @@ class TestArtifacts(ZuulDBTestCase, BaseTestWeb, AnsibleZuulTestCase):
844 {'url': 'http://example.com/tarball', 861 {'url': 'http://example.com/tarball',
845 'name': 'tarball'}, 862 'name': 'tarball'},
846 ]) 863 ])
864
865 def test_buildset_artifacts(self):
866 self.add_base_changes()
867 self.executor_server.hold_jobs_in_build = False
868 self.executor_server.release()
869 self.waitUntilSettled()
870
871 buildsets = self.get_url("api/tenant/tenant-one/buildsets").json()
872 project_bs = [x for x in buildsets if x["project"] == "org/project"][0]
873 buildset = self.get_url(
874 "api/tenant/tenant-one/buildset/%s" % project_bs['uuid']).json()
875 print("X" * 120)
876 print(buildset)
877 print("Y" * 120)
878 self.assertEqual(3, len(buildset["builds"]))
879
880 test1_build = [x for x in buildset["builds"]
881 if x["job_name"] == "project-test1"][0]
882 arts = test1_build['artifacts']
883 arts.sort(key=lambda x: x['name'])
884 self.assertEqual([
885 {'url': 'http://example.com/docs',
886 'name': 'docs'},
887 {'url': 'http://logs.example.com/build/relative/docs',
888 'name': 'relative',
889 'metadata': {'foo': 'bar'}},
890 {'url': 'http://example.com/tarball',
891 'name': 'tarball'},
892 ], test1_build['artifacts'])
diff --git a/zuul/driver/sql/sqlconnection.py b/zuul/driver/sql/sqlconnection.py
index 8652e46..c99187f 100644
--- a/zuul/driver/sql/sqlconnection.py
+++ b/zuul/driver/sql/sqlconnection.py
@@ -31,6 +31,9 @@ PROVIDES_TABLE = 'zuul_provides'
31 31
32 32
33class DatabaseSession(object): 33class DatabaseSession(object):
34
35 log = logging.getLogger("zuul.DatabaseSession")
36
34 def __init__(self, connection): 37 def __init__(self, connection):
35 self.connection = connection 38 self.connection = connection
36 self.session = connection.session 39 self.session = connection.session
@@ -134,6 +137,29 @@ class DatabaseSession(object):
134 except sqlalchemy.orm.exc.NoResultFound: 137 except sqlalchemy.orm.exc.NoResultFound:
135 return [] 138 return []
136 139
140 def getBuildset(self, tenant, uuid):
141 """Get one buildset with its builds"""
142
143 buildset_table = self.connection.zuul_buildset_table
144
145 q = self.session().query(self.connection.buildSetModel).\
146 options(orm.joinedload(self.connection.buildSetModel.builds).
147 subqueryload(self.connection.buildModel.artifacts)).\
148 options(orm.joinedload(self.connection.buildSetModel.builds).
149 subqueryload(self.connection.buildModel.provides)).\
150 with_hint(buildset_table, 'USE INDEX (PRIMARY)', 'mysql')
151
152 q = self.listFilter(q, buildset_table.c.tenant, tenant)
153 q = self.listFilter(q, buildset_table.c.uuid, uuid)
154
155 try:
156 return q.one()
157 except sqlalchemy.orm.exc.NoResultFound:
158 return None
159 except sqlalchemy.orm.exc.MultipleResultsFound:
160 self.log.error("Multiple buildset found with uuid %s", uuid)
161 return None
162
137 163
138class SQLConnection(BaseConnection): 164class SQLConnection(BaseConnection):
139 driver_name = 'sql' 165 driver_name = 'sql'
@@ -319,3 +345,8 @@ class SQLConnection(BaseConnection):
319 """Return a list of BuildSet objects""" 345 """Return a list of BuildSet objects"""
320 with self.getSession() as db: 346 with self.getSession() as db:
321 return db.getBuildsets(*args, **kw) 347 return db.getBuildsets(*args, **kw)
348
349 def getBuildset(self, *args, **kw):
350 """Return a BuildSet objects"""
351 with self.getSession() as db:
352 return db.getBuildset(*args, **kw)
diff --git a/zuul/web/__init__.py b/zuul/web/__init__.py
index 8684e1c..cd58603 100755
--- a/zuul/web/__init__.py
+++ b/zuul/web/__init__.py
@@ -431,6 +431,8 @@ class ZuulWebAPI(object):
431 'voting': build.voting, 431 'voting': build.voting,
432 'log_url': build.log_url, 432 'log_url': build.log_url,
433 'node_name': build.node_name, 433 'node_name': build.node_name,
434 'artifacts': [],
435 'provides': [],
434 } 436 }
435 437
436 if buildset: 438 if buildset:
@@ -443,22 +445,20 @@ class ZuulWebAPI(object):
443 'ref': buildset.ref, 445 'ref': buildset.ref,
444 'newrev': buildset.newrev, 446 'newrev': buildset.newrev,
445 'ref_url': buildset.ref_url, 447 'ref_url': buildset.ref_url,
446 'artifacts': [],
447 'provides': [],
448 }) 448 })
449 449
450 for artifact in build.artifacts: 450 for artifact in build.artifacts:
451 art = { 451 art = {
452 'name': artifact.name, 452 'name': artifact.name,
453 'url': artifact.url, 453 'url': artifact.url,
454 } 454 }
455 if artifact.meta: 455 if artifact.meta:
456 art['metadata'] = json.loads(artifact.meta) 456 art['metadata'] = json.loads(artifact.meta)
457 ret['artifacts'].append(art) 457 ret['artifacts'].append(art)
458 for provides in build.provides: 458 for provides in build.provides:
459 ret['provides'].append({ 459 ret['provides'].append({
460 'name': provides.name, 460 'name': provides.name,
461 }) 461 })
462 return ret 462 return ret
463 463
464 def _get_connection(self, tenant): 464 def _get_connection(self, tenant):
@@ -505,7 +505,7 @@ class ZuulWebAPI(object):
505 resp.headers['Access-Control-Allow-Origin'] = '*' 505 resp.headers['Access-Control-Allow-Origin'] = '*'
506 return data 506 return data
507 507
508 def buildsetToDict(self, buildset): 508 def buildsetToDict(self, buildset, builds=[]):
509 ret = { 509 ret = {
510 'uuid': buildset.uuid, 510 'uuid': buildset.uuid,
511 'result': buildset.result, 511 'result': buildset.result,
@@ -519,6 +519,10 @@ class ZuulWebAPI(object):
519 'newrev': buildset.newrev, 519 'newrev': buildset.newrev,
520 'ref_url': buildset.ref_url, 520 'ref_url': buildset.ref_url,
521 } 521 }
522 if builds:
523 ret['builds'] = []
524 for build in builds:
525 ret['builds'].append(self.buildToDict(build))
522 return ret 526 return ret
523 527
524 @cherrypy.expose 528 @cherrypy.expose
@@ -541,6 +545,20 @@ class ZuulWebAPI(object):
541 545
542 @cherrypy.expose 546 @cherrypy.expose
543 @cherrypy.tools.save_params() 547 @cherrypy.tools.save_params()
548 @cherrypy.tools.json_out(content_type='application/json; charset=utf-8')
549 def buildset(self, tenant, uuid):
550 connection = self._get_connection(tenant)
551
552 data = connection.getBuildset(tenant, uuid)
553 if not data:
554 raise cherrypy.HTTPError(404, "Buildset not found")
555 data = self.buildsetToDict(data, data.builds)
556 resp = cherrypy.response
557 resp.headers['Access-Control-Allow-Origin'] = '*'
558 return data
559
560 @cherrypy.expose
561 @cherrypy.tools.save_params()
544 @cherrypy.tools.websocket(handler_cls=LogStreamHandler) 562 @cherrypy.tools.websocket(handler_cls=LogStreamHandler)
545 def console_stream(self, tenant): 563 def console_stream(self, tenant):
546 cherrypy.request.ws_handler.zuulweb = self.zuulweb 564 cherrypy.request.ws_handler.zuulweb = self.zuulweb
@@ -697,6 +715,8 @@ class ZuulWeb(object):
697 controller=api, action='build') 715 controller=api, action='build')
698 route_map.connect('api', '/api/tenant/{tenant}/buildsets', 716 route_map.connect('api', '/api/tenant/{tenant}/buildsets',
699 controller=api, action='buildsets') 717 controller=api, action='buildsets')
718 route_map.connect('api', '/api/tenant/{tenant}/buildset/{uuid}',
719 controller=api, action='buildset')
700 route_map.connect('api', '/api/tenant/{tenant}/config-errors', 720 route_map.connect('api', '/api/tenant/{tenant}/config-errors',
701 controller=api, action='config_errors') 721 controller=api, action='config_errors')
702 722