Add freeze-job subcommand
This adds support for the freeze-job endpoint and displays information about a job as it would run in a pipeline. Because there is so much data, the text formatter only displays a high-level summary of the most interesting parts of a job. The JSON formatter returns everything. Change-Id: Ia3e00bf10eae0d569aa49773e81bc8bab1584ba7
This commit is contained in:
parent
f999949aed
commit
f96ddd00fc
@ -164,6 +164,27 @@ Note that zero values for ``oldrev`` and ``newrev`` can indicate
|
||||
branch creation and deletion; the source code of Zuul is the best reference
|
||||
for these more advanced operations.
|
||||
|
||||
Freeze-job
|
||||
^^^^^^^^^^
|
||||
|
||||
Display information about a job as it would be run in a particular
|
||||
project's pipeline. This causes Zuul to combine all of the matching
|
||||
jobs and variants that would be used to form the final version of a
|
||||
job that would be executed for a change or ref as enqueued into the
|
||||
specified pipeline. This includes job attributes, playbook paths,
|
||||
nodesets, variables, etc. Secret names may be included but the values
|
||||
are redacted.
|
||||
|
||||
The default text output shows an abbreviated summary of only the most
|
||||
pertinent information. The JSON output reports all available
|
||||
information.
|
||||
|
||||
.. program-output:: zuul-client freeze-job --help
|
||||
|
||||
Example::
|
||||
|
||||
zuul-client freeze-job --tenant mytenant --pipeline check --project org/project --branch master --job tox
|
||||
|
||||
Job-graph
|
||||
^^^^^^^^^
|
||||
|
||||
|
5
releasenotes/notes/freeze-job-8b2e86292952291e.yaml
Normal file
5
releasenotes/notes/freeze-job-8b2e86292952291e.yaml
Normal file
@ -0,0 +1,5 @@
|
||||
---
|
||||
features:
|
||||
- |
|
||||
Add freeze-job subcommand to display information about jobs as they would
|
||||
be run in a project's pipeline.
|
@ -488,3 +488,25 @@ GuS6/ewjS+arA1Iyeg/IxmECAwEAAQ==
|
||||
'https://fake.zuul/api/tenant/tenant1/pipeline/check/'
|
||||
'project/project1/branch/master/freeze-jobs')
|
||||
self.assertEqual(fakejson, graph)
|
||||
|
||||
def test_freeze_job(self):
|
||||
"""Test freeze-job endpoint"""
|
||||
client = ZuulRESTClient(url='https://fake.zuul/')
|
||||
# test status checks
|
||||
self._test_status_check(
|
||||
client, 'get', client.freeze_jobs,
|
||||
'tenant1', 'check', 'project1', 'master')
|
||||
|
||||
fakejson = {
|
||||
"job": "testjob",
|
||||
"ansible_version": "5",
|
||||
}
|
||||
req = FakeRequestResponse(200, fakejson)
|
||||
client.session.get = MagicMock(return_value=req)
|
||||
client.info_ = {}
|
||||
job = client.freeze_job('tenant1', 'check', 'project1', 'master',
|
||||
'testjob')
|
||||
client.session.get.assert_any_call(
|
||||
'https://fake.zuul/api/tenant/tenant1/pipeline/check/'
|
||||
'project/project1/branch/master/freeze-job/testjob')
|
||||
self.assertEqual(fakejson, job)
|
||||
|
@ -649,3 +649,45 @@ verify_ssl=True"""
|
||||
'project/project1/branch/master/freeze-jobs',
|
||||
)
|
||||
self.assertEqual(0, exit_code)
|
||||
|
||||
def test_freeze_job(self):
|
||||
"""Test freeze-job subcommand"""
|
||||
ZC = ZuulClient()
|
||||
with patch('requests.Session') as mock_sesh:
|
||||
session = mock_sesh.return_value
|
||||
fakejson = {
|
||||
"job": "testjob",
|
||||
"ansible_version": "5",
|
||||
"nodeset": {
|
||||
"groups": [],
|
||||
"name": "ubuntu-jammy",
|
||||
},
|
||||
"vars": {},
|
||||
"pre_playbooks": [
|
||||
{
|
||||
"branch": "master",
|
||||
"connection": "gerrit",
|
||||
"path": "playbooks/base/pre.yaml",
|
||||
"project": "opendev/base-jobs",
|
||||
"roles": [],
|
||||
"trusted": True,
|
||||
},
|
||||
]
|
||||
}
|
||||
session.get = MagicMock(
|
||||
side_effect=mock_get(
|
||||
MagicMock(return_value=FakeRequestResponse(200, fakejson))
|
||||
)
|
||||
)
|
||||
exit_code = ZC._main(
|
||||
['--zuul-url', 'https://fake.zuul', 'freeze-job',
|
||||
'--tenant', 'tenant1',
|
||||
'--pipeline', 'check',
|
||||
'--project', 'project1',
|
||||
'--branch', 'master',
|
||||
'--job', 'testjob'])
|
||||
session.get.assert_any_call(
|
||||
'https://fake.zuul/api/tenant/tenant1/pipeline/check/'
|
||||
'project/project1/branch/master/freeze-job/testjob',
|
||||
)
|
||||
self.assertEqual(0, exit_code)
|
||||
|
@ -305,3 +305,15 @@ class ZuulRESTClient(object):
|
||||
req = self.session.get(url)
|
||||
self._check_request_status(req)
|
||||
return req.json()
|
||||
|
||||
def freeze_job(self, tenant, pipeline, project, branch, job):
|
||||
suffix = (f'pipeline/{pipeline}/project/{project}/'
|
||||
f'branch/{branch}/freeze-job/{job}')
|
||||
if self.info.get("tenant"):
|
||||
self._check_scope(tenant)
|
||||
else:
|
||||
suffix = f'tenant/{tenant}/{suffix}'
|
||||
url = urllib.parse.urljoin(self.base_url, suffix)
|
||||
req = self.session.get(url)
|
||||
self._check_request_status(req)
|
||||
return req.json()
|
||||
|
@ -109,6 +109,7 @@ class ZuulClient():
|
||||
self.add_builds_list_subparser(subparsers)
|
||||
self.add_build_info_subparser(subparsers)
|
||||
self.add_job_graph_subparser(subparsers)
|
||||
self.add_freeze_job_subparser(subparsers)
|
||||
|
||||
return subparsers
|
||||
|
||||
@ -814,6 +815,32 @@ class ZuulClient():
|
||||
print(formatted_result)
|
||||
return True
|
||||
|
||||
def add_freeze_job_subparser(self, subparsers):
|
||||
cmd_freeze_job = subparsers.add_parser(
|
||||
'freeze-job', help='Freeze and display a job')
|
||||
cmd_freeze_job.add_argument(
|
||||
'--tenant', help='tenant name', required=False, default='')
|
||||
cmd_freeze_job.add_argument('--pipeline', help='pipeline name',
|
||||
required=True)
|
||||
cmd_freeze_job.add_argument('--project', help='project name',
|
||||
required=True)
|
||||
cmd_freeze_job.add_argument('--branch', help='branch name',
|
||||
required=True)
|
||||
cmd_freeze_job.add_argument('--job', help='job name',
|
||||
required=True)
|
||||
cmd_freeze_job.set_defaults(func=self.freeze_job)
|
||||
self.cmd_freeze_job = cmd_freeze_job
|
||||
|
||||
def freeze_job(self):
|
||||
client = self.get_client()
|
||||
self._check_tenant_scope(client)
|
||||
job = client.freeze_job(self.tenant(), self.args.pipeline,
|
||||
self.args.project, self.args.branch,
|
||||
self.args.job)
|
||||
formatted_result = self.formatter('FreezeJob')(job)
|
||||
print(formatted_result)
|
||||
return True
|
||||
|
||||
|
||||
def main():
|
||||
ZuulClient().main()
|
||||
|
@ -15,6 +15,7 @@
|
||||
|
||||
import time
|
||||
from dateutil.parser import isoparse
|
||||
import pprint
|
||||
|
||||
import prettytable
|
||||
import json
|
||||
@ -66,6 +67,9 @@ class BaseFormatter:
|
||||
def formatJobGraph(self, data):
|
||||
raise NotImplementedError
|
||||
|
||||
def formatFreezeJob(self, data):
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
class JSONFormatter(BaseFormatter):
|
||||
def __call__(self, data) -> str:
|
||||
@ -285,6 +289,41 @@ class PrettyTableFormatter(BaseFormatter):
|
||||
])
|
||||
return str(table)
|
||||
|
||||
def formatFreezeJob(self, data) -> str:
|
||||
printer = pprint.PrettyPrinter(indent=2)
|
||||
ret = ''
|
||||
for label, key in [
|
||||
('Job', 'job'),
|
||||
('Branch', 'branch'),
|
||||
('Ansible Version', 'ansible_version'),
|
||||
('Timeout', 'timeout'),
|
||||
('Post Timeout', 'post_timeout'),
|
||||
('Workspace Scheme', 'workspace_scheme'),
|
||||
('Override Checkout', 'override_checkout'),
|
||||
]:
|
||||
value = data.get(key)
|
||||
if value is not None:
|
||||
ret += f'{label}: {value}\n'
|
||||
if data['nodeset']['name']:
|
||||
ret += f"Nodeset: {data['nodeset']['name']}\n"
|
||||
for label, key in [
|
||||
('Pre-run Playbooks', 'pre_playbooks'),
|
||||
('Run Playbooks', 'playbooks'),
|
||||
('Post-run Playbooks', 'post_playbooks'),
|
||||
('Cleanup Playbooks', 'cleanup_playbooks'),
|
||||
]:
|
||||
pbs = data.get(key)
|
||||
if not pbs:
|
||||
continue
|
||||
ret += f"{label}:\n"
|
||||
for pb in pbs:
|
||||
trusted = ' [trusted]' if pb['trusted'] else ''
|
||||
ret += (f" {pb['connection']}:{pb['project']}:"
|
||||
f"{pb['path']}@{pb['branch']}{trusted}\n")
|
||||
ret += 'Vars:\n'
|
||||
ret += printer.pformat(data['vars'])
|
||||
return ret
|
||||
|
||||
|
||||
class DotFormatter(BaseFormatter):
|
||||
"""Format for graphviz"""
|
||||
|
Loading…
Reference in New Issue
Block a user