Merge "web: add /{tenant}/projects and /{tenant}/project/{project} routes"
This commit is contained in:
commit
ac3aa78bcb
|
@ -372,6 +372,144 @@ class TestWeb(BaseTestWeb):
|
|||
'voting': True
|
||||
}], data)
|
||||
|
||||
def test_web_project_list(self):
|
||||
# can we fetch the list of projects
|
||||
data = self.get_url('api/tenant/tenant-one/projects').json()
|
||||
|
||||
expected_list = [
|
||||
{'name': 'common-config', 'type': 'config'},
|
||||
{'name': 'org/project', 'type': 'untrusted'},
|
||||
{'name': 'org/project1', 'type': 'untrusted'},
|
||||
{'name': 'org/project2', 'type': 'untrusted'}
|
||||
]
|
||||
for p in expected_list:
|
||||
p["canonical_name"] = "review.example.com/%s" % p["name"]
|
||||
p["connection_name"] = "gerrit"
|
||||
self.assertEqual(expected_list, data)
|
||||
|
||||
def test_web_project_get(self):
|
||||
# can we fetch project details
|
||||
data = self.get_url(
|
||||
'api/tenant/tenant-one/project/org/project1').json()
|
||||
|
||||
jobs = [[{'abstract': False,
|
||||
'attempts': 3,
|
||||
'branches': [],
|
||||
'dependencies': [],
|
||||
'description': None,
|
||||
'files': [],
|
||||
'final': False,
|
||||
'implied_branch': None,
|
||||
'irrelevant_files': [],
|
||||
'name': 'project-merge',
|
||||
'parent': 'base',
|
||||
'post_review': None,
|
||||
'protected': None,
|
||||
'required_projects': [],
|
||||
'roles': [],
|
||||
'semaphore': None,
|
||||
'source_context': {
|
||||
'branch': 'master',
|
||||
'path': 'zuul.yaml',
|
||||
'project': 'common-config'},
|
||||
'timeout': None,
|
||||
'variables': {},
|
||||
'variant_description': '',
|
||||
'voting': True}],
|
||||
[{'abstract': False,
|
||||
'attempts': 3,
|
||||
'branches': [],
|
||||
'dependencies': ['project-merge'],
|
||||
'description': None,
|
||||
'files': [],
|
||||
'final': False,
|
||||
'implied_branch': None,
|
||||
'irrelevant_files': [],
|
||||
'name': 'project-test1',
|
||||
'parent': 'base',
|
||||
'post_review': None,
|
||||
'protected': None,
|
||||
'required_projects': [],
|
||||
'roles': [],
|
||||
'semaphore': None,
|
||||
'source_context': {
|
||||
'branch': 'master',
|
||||
'path': 'zuul.yaml',
|
||||
'project': 'common-config'},
|
||||
'timeout': None,
|
||||
'variables': {},
|
||||
'variant_description': '',
|
||||
'voting': True}],
|
||||
[{'abstract': False,
|
||||
'attempts': 3,
|
||||
'branches': [],
|
||||
'dependencies': ['project-merge'],
|
||||
'description': None,
|
||||
'files': [],
|
||||
'final': False,
|
||||
'implied_branch': None,
|
||||
'irrelevant_files': [],
|
||||
'name': 'project-test2',
|
||||
'parent': 'base',
|
||||
'post_review': None,
|
||||
'protected': None,
|
||||
'required_projects': [],
|
||||
'roles': [],
|
||||
'semaphore': None,
|
||||
'source_context': {
|
||||
'branch': 'master',
|
||||
'path': 'zuul.yaml',
|
||||
'project': 'common-config'},
|
||||
'timeout': None,
|
||||
'variables': {},
|
||||
'variant_description': '',
|
||||
'voting': True}],
|
||||
[{'abstract': False,
|
||||
'attempts': 3,
|
||||
'branches': [],
|
||||
'dependencies': ['project-merge'],
|
||||
'description': None,
|
||||
'files': [],
|
||||
'final': False,
|
||||
'implied_branch': None,
|
||||
'irrelevant_files': [],
|
||||
'name': 'project1-project2-integration',
|
||||
'parent': 'base',
|
||||
'post_review': None,
|
||||
'protected': None,
|
||||
'required_projects': [],
|
||||
'roles': [],
|
||||
'semaphore': None,
|
||||
'source_context': {
|
||||
'branch': 'master',
|
||||
'path': 'zuul.yaml',
|
||||
'project': 'common-config'},
|
||||
'timeout': None,
|
||||
'variables': {},
|
||||
'variant_description': '',
|
||||
'voting': True}]]
|
||||
|
||||
self.assertEqual(
|
||||
{
|
||||
'canonical_name': 'review.example.com/org/project1',
|
||||
'connection_name': 'gerrit',
|
||||
'name': 'org/project1',
|
||||
'configs': [{
|
||||
'templates': [],
|
||||
'default_branch': 'master',
|
||||
'merge_mode': 'merge-resolve',
|
||||
'pipelines': [{
|
||||
'name': 'check',
|
||||
'queue_name': None,
|
||||
'jobs': jobs,
|
||||
}, {
|
||||
'name': 'gate',
|
||||
'queue_name': 'integrated',
|
||||
'jobs': jobs,
|
||||
}]
|
||||
}]
|
||||
}, data)
|
||||
|
||||
def test_web_keys(self):
|
||||
with open(os.path.join(FIXTURE_DIR, 'public.pem'), 'rb') as f:
|
||||
public_pem = f.read()
|
||||
|
|
|
@ -2815,6 +2815,11 @@ class ProjectPipelineConfig(ConfigObject):
|
|||
# only come from templates.
|
||||
self.variables = Job._deepUpdate(self.variables, other)
|
||||
|
||||
def toDict(self):
|
||||
d = {}
|
||||
d['queue_name'] = self.queue_name
|
||||
return d
|
||||
|
||||
|
||||
class ProjectConfig(ConfigObject):
|
||||
# Represents a project configuration
|
||||
|
@ -2865,6 +2870,17 @@ class ProjectConfig(ConfigObject):
|
|||
return False
|
||||
return True
|
||||
|
||||
def toDict(self):
|
||||
d = {}
|
||||
d['default_branch'] = self.default_branch
|
||||
if self.merge_mode:
|
||||
d['merge_mode'] = list(filter(lambda x: x[1] == self.merge_mode,
|
||||
MERGER_MAP.items()))[0][0]
|
||||
else:
|
||||
d['merge_mode'] = None
|
||||
d['templates'] = self.templates
|
||||
return d
|
||||
|
||||
|
||||
class ProjectMetadata(object):
|
||||
"""Information about a Project
|
||||
|
|
|
@ -71,6 +71,8 @@ class RPCListener(object):
|
|||
self.worker.registerFunction("zuul:status_get")
|
||||
self.worker.registerFunction("zuul:job_get")
|
||||
self.worker.registerFunction("zuul:job_list")
|
||||
self.worker.registerFunction("zuul:project_get")
|
||||
self.worker.registerFunction("zuul:project_list")
|
||||
self.worker.registerFunction("zuul:key_get")
|
||||
self.worker.registerFunction("zuul:config_errors_list")
|
||||
|
||||
|
@ -390,6 +392,55 @@ class RPCListener(object):
|
|||
"description": desc})
|
||||
job.sendWorkComplete(json.dumps(output))
|
||||
|
||||
def handle_project_get(self, gear_job):
|
||||
args = json.loads(gear_job.arguments)
|
||||
tenant = self.sched.abide.tenants.get(args["tenant"])
|
||||
if not tenant:
|
||||
gear_job.sendWorkComplete(json.dumps(None))
|
||||
return
|
||||
trusted, project = tenant.getProject(args["project"])
|
||||
if not project:
|
||||
gear_job.sendWorkComplete(json.dumps({}))
|
||||
return
|
||||
result = project.toDict()
|
||||
result['configs'] = []
|
||||
configs = tenant.layout.getAllProjectConfigs(project.canonical_name)
|
||||
for config_obj in configs:
|
||||
config = config_obj.toDict()
|
||||
config['pipelines'] = []
|
||||
for pipeline_name, pipeline_config in sorted(
|
||||
config_obj.pipelines.items()):
|
||||
pipeline = pipeline_config.toDict()
|
||||
pipeline['name'] = pipeline_name
|
||||
pipeline['jobs'] = []
|
||||
for jobs in pipeline_config.job_list.jobs.values():
|
||||
job_list = []
|
||||
for job in jobs:
|
||||
job_list.append(job.toDict(tenant))
|
||||
pipeline['jobs'].append(job_list)
|
||||
config['pipelines'].append(pipeline)
|
||||
result['configs'].append(config)
|
||||
|
||||
gear_job.sendWorkComplete(json.dumps(result, cls=MappingProxyEncoder))
|
||||
|
||||
def handle_project_list(self, job):
|
||||
args = json.loads(job.arguments)
|
||||
tenant = self.sched.abide.tenants.get(args.get("tenant"))
|
||||
if not tenant:
|
||||
job.sendWorkComplete(json.dumps(None))
|
||||
return
|
||||
output = []
|
||||
for project in tenant.config_projects:
|
||||
pobj = project.toDict()
|
||||
pobj['type'] = "config"
|
||||
output.append(pobj)
|
||||
for project in tenant.untrusted_projects:
|
||||
pobj = project.toDict()
|
||||
pobj['type'] = "untrusted"
|
||||
output.append(pobj)
|
||||
job.sendWorkComplete(json.dumps(
|
||||
sorted(output, key=lambda project: project["name"])))
|
||||
|
||||
def handle_key_get(self, job):
|
||||
args = json.loads(job.arguments)
|
||||
tenant = self.sched.abide.tenants.get(args.get("tenant"))
|
||||
|
|
|
@ -304,6 +304,34 @@ class ZuulWebAPI(object):
|
|||
resp.headers['Access-Control-Allow-Origin'] = '*'
|
||||
return ret
|
||||
|
||||
@cherrypy.expose
|
||||
@cherrypy.tools.save_params()
|
||||
@cherrypy.tools.json_out(content_type='application/json; charset=utf-8')
|
||||
def projects(self, tenant):
|
||||
job = self.rpc.submitJob('zuul:project_list', {'tenant': tenant})
|
||||
ret = json.loads(job.data[0])
|
||||
if ret is None:
|
||||
raise cherrypy.HTTPError(404, 'Tenant %s does not exist.' % tenant)
|
||||
resp = cherrypy.response
|
||||
resp.headers['Access-Control-Allow-Origin'] = '*'
|
||||
return ret
|
||||
|
||||
@cherrypy.expose
|
||||
@cherrypy.tools.save_params()
|
||||
@cherrypy.tools.json_out(content_type='application/json; charset=utf-8')
|
||||
def project(self, tenant, project):
|
||||
job = self.rpc.submitJob(
|
||||
'zuul:project_get', {'tenant': tenant, 'project': project})
|
||||
ret = json.loads(job.data[0])
|
||||
if ret is None:
|
||||
raise cherrypy.HTTPError(404, 'Tenant %s does not exist.' % tenant)
|
||||
if not ret:
|
||||
raise cherrypy.HTTPError(
|
||||
404, 'Project %s does not exist.' % project)
|
||||
resp = cherrypy.response
|
||||
resp.headers['Access-Control-Allow-Origin'] = '*'
|
||||
return ret
|
||||
|
||||
@cherrypy.expose
|
||||
@cherrypy.tools.save_params()
|
||||
def key(self, tenant, project):
|
||||
|
@ -530,6 +558,10 @@ class ZuulWeb(object):
|
|||
controller=api, action='jobs')
|
||||
route_map.connect('api', '/api/tenant/{tenant}/job/{job_name}',
|
||||
controller=api, action='job')
|
||||
route_map.connect('api', '/api/tenant/{tenant}/projects',
|
||||
controller=api, action='projects')
|
||||
route_map.connect('api', '/api/tenant/{tenant}/project/{project:.*}',
|
||||
controller=api, action='project')
|
||||
route_map.connect('api', '/api/tenant/{tenant}/key/{project:.*}.pub',
|
||||
controller=api, action='key')
|
||||
route_map.connect('api', '/api/tenant/{tenant}/'
|
||||
|
|
Loading…
Reference in New Issue