web: add /{tenant}/buildset/{uuid} route

This change adds a /buildset/{uuid} route to return a single buildset.

Change-Id: Id703d337caa68278dfed25aa0ff07371d0e81a1b
This commit is contained in:
Tristan Cacqueray 2019-02-21 03:32:27 +00:00
parent 84fefd146d
commit 48959d6e53
3 changed files with 112 additions and 15 deletions

View File

@ -725,6 +725,23 @@ class TestBuildInfo(ZuulDBTestCase, BaseTestWeb):
buildsets = self.get_url("api/tenant/tenant-one/buildsets").json()
self.assertEqual(2, len(buildsets))
project_bs = [x for x in buildsets if x["project"] == "org/project"][0]
buildset = self.get_url(
"api/tenant/tenant-one/buildset/%s" % project_bs['uuid']).json()
self.assertEqual(3, len(buildset["builds"]))
project_test1_build = [x for x in buildset["builds"]
if x["job_name"] == "project-test1"][0]
self.assertEqual('SUCCESS', project_test1_build['result'])
project_test2_build = [x for x in buildset["builds"]
if x["job_name"] == "project-test2"][0]
self.assertEqual('SUCCESS', project_test2_build['result'])
project_merge_build = [x for x in buildset["builds"]
if x["job_name"] == "project-merge"][0]
self.assertEqual('SUCCESS', project_merge_build['result'])
class TestArtifacts(ZuulDBTestCase, BaseTestWeb, AnsibleZuulTestCase):
@ -754,3 +771,32 @@ class TestArtifacts(ZuulDBTestCase, BaseTestWeb, AnsibleZuulTestCase):
{'url': 'http://example.com/tarball',
'name': 'tarball'},
])
def test_buildset_artifacts(self):
self.add_base_changes()
self.executor_server.hold_jobs_in_build = False
self.executor_server.release()
self.waitUntilSettled()
buildsets = self.get_url("api/tenant/tenant-one/buildsets").json()
project_bs = [x for x in buildsets if x["project"] == "org/project"][0]
buildset = self.get_url(
"api/tenant/tenant-one/buildset/%s" % project_bs['uuid']).json()
print("X" * 120)
print(buildset)
print("Y" * 120)
self.assertEqual(3, len(buildset["builds"]))
test1_build = [x for x in buildset["builds"]
if x["job_name"] == "project-test1"][0]
arts = test1_build['artifacts']
arts.sort(key=lambda x: x['name'])
self.assertEqual([
{'url': 'http://example.com/docs',
'name': 'docs'},
{'url': 'http://logs.example.com/build/relative/docs',
'name': 'relative',
'metadata': {'foo': 'bar'}},
{'url': 'http://example.com/tarball',
'name': 'tarball'},
], test1_build['artifacts'])

View File

@ -31,6 +31,9 @@ PROVIDES_TABLE = 'zuul_provides'
class DatabaseSession(object):
log = logging.getLogger("zuul.DatabaseSession")
def __init__(self, connection):
self.connection = connection
self.session = connection.session
@ -134,6 +137,29 @@ class DatabaseSession(object):
except sqlalchemy.orm.exc.NoResultFound:
return []
def getBuildset(self, tenant, uuid):
"""Get one buildset with its builds"""
buildset_table = self.connection.zuul_buildset_table
q = self.session().query(self.connection.buildSetModel).\
options(orm.joinedload(self.connection.buildSetModel.builds).
subqueryload(self.connection.buildModel.artifacts)).\
options(orm.joinedload(self.connection.buildSetModel.builds).
subqueryload(self.connection.buildModel.provides)).\
with_hint(buildset_table, 'USE INDEX (PRIMARY)', 'mysql')
q = self.listFilter(q, buildset_table.c.tenant, tenant)
q = self.listFilter(q, buildset_table.c.uuid, uuid)
try:
return q.one()
except sqlalchemy.orm.exc.NoResultFound:
return None
except sqlalchemy.orm.exc.MultipleResultsFound:
self.log.error("Multiple buildset found with uuid %s", uuid)
return None
class SQLConnection(BaseConnection):
driver_name = 'sql'
@ -319,3 +345,8 @@ class SQLConnection(BaseConnection):
"""Return a list of BuildSet objects"""
with self.getSession() as db:
return db.getBuildsets(*args, **kw)
def getBuildset(self, *args, **kw):
"""Return a BuildSet objects"""
with self.getSession() as db:
return db.getBuildset(*args, **kw)

View File

@ -431,6 +431,8 @@ class ZuulWebAPI(object):
'voting': build.voting,
'log_url': build.log_url,
'node_name': build.node_name,
'artifacts': [],
'provides': [],
}
if buildset:
@ -443,22 +445,20 @@ class ZuulWebAPI(object):
'ref': buildset.ref,
'newrev': buildset.newrev,
'ref_url': buildset.ref_url,
'artifacts': [],
'provides': [],
})
for artifact in build.artifacts:
art = {
'name': artifact.name,
'url': artifact.url,
}
if artifact.meta:
art['metadata'] = json.loads(artifact.meta)
ret['artifacts'].append(art)
for provides in build.provides:
ret['provides'].append({
'name': provides.name,
})
for artifact in build.artifacts:
art = {
'name': artifact.name,
'url': artifact.url,
}
if artifact.meta:
art['metadata'] = json.loads(artifact.meta)
ret['artifacts'].append(art)
for provides in build.provides:
ret['provides'].append({
'name': provides.name,
})
return ret
def _get_connection(self, tenant):
@ -505,7 +505,7 @@ class ZuulWebAPI(object):
resp.headers['Access-Control-Allow-Origin'] = '*'
return data
def buildsetToDict(self, buildset):
def buildsetToDict(self, buildset, builds=[]):
ret = {
'uuid': buildset.uuid,
'result': buildset.result,
@ -519,6 +519,10 @@ class ZuulWebAPI(object):
'newrev': buildset.newrev,
'ref_url': buildset.ref_url,
}
if builds:
ret['builds'] = []
for build in builds:
ret['builds'].append(self.buildToDict(build))
return ret
@cherrypy.expose
@ -539,6 +543,20 @@ class ZuulWebAPI(object):
resp.headers['Access-Control-Allow-Origin'] = '*'
return [self.buildsetToDict(b) for b in buildsets]
@cherrypy.expose
@cherrypy.tools.save_params()
@cherrypy.tools.json_out(content_type='application/json; charset=utf-8')
def buildset(self, tenant, uuid):
connection = self._get_connection(tenant)
data = connection.getBuildset(tenant, uuid)
if not data:
raise cherrypy.HTTPError(404, "Buildset not found")
data = self.buildsetToDict(data, data.builds)
resp = cherrypy.response
resp.headers['Access-Control-Allow-Origin'] = '*'
return data
@cherrypy.expose
@cherrypy.tools.save_params()
@cherrypy.tools.websocket(handler_cls=LogStreamHandler)
@ -697,6 +715,8 @@ class ZuulWeb(object):
controller=api, action='build')
route_map.connect('api', '/api/tenant/{tenant}/buildsets',
controller=api, action='buildsets')
route_map.connect('api', '/api/tenant/{tenant}/buildset/{uuid}',
controller=api, action='buildset')
route_map.connect('api', '/api/tenant/{tenant}/config-errors',
controller=api, action='config_errors')