diff --git a/git_cl.py b/git_cl.py index a1f58c856..dc6f4cdd9 100755 --- a/git_cl.py +++ b/git_cl.py @@ -398,7 +398,7 @@ def trigger_try_jobs(auth_config, changelist, options, masters, category): def fetch_try_jobs(auth_config, changelist, options): """Fetches try jobs from buildbucket. - Returns a map from build id to build info as json dictionary. + Returns a map from build id to build info as a dictionary. """ rietveld_url = settings.GetDefaultServerUrl() rietveld_host = urlparse.urlparse(rietveld_url).hostname @@ -533,6 +533,31 @@ def print_try_jobs(options, builds): print('Total: %d try jobs' % total) +def write_try_results_json(output_file, builds): + """Writes a subset of the data from fetch_try_jobs to a file as JSON. + + The input |builds| dict is assumed to be generated by Buildbucket. + Buildbucket documentation: http://goo.gl/G0s101 + """ + + def convert_build_dict(build): + return { + 'buildbucket_id': build.get('id'), + 'status': build.get('status'), + 'result': build.get('result'), + 'bucket': build.get('bucket'), + 'builder_name': json.loads( + build.get('parameters_json', '{}')).get('builder_name'), + 'failure_reason': build.get('failure_reason'), + 'url': build.get('url'), + } + + converted = [] + for _, build in sorted(builds.items()): + converted.append(convert_build_dict(build)) + write_json(output_file, converted) + + def MatchSvnGlob(url, base_url, glob_spec, allow_wildcards): """Return the corresponding git ref if |base_url| together with |glob_spec| matches the full |url|. @@ -4755,6 +4780,8 @@ def CMDtry_results(parser, args): group.add_option( "--buildbucket-host", default='cr-buildbucket.appspot.com', help="Host of buildbucket. The default host is %default.") + group.add_option( + '--json', help='Path of JSON output file to write try job results to.') parser.add_option_group(group) auth.add_auth_options(parser) options, args = parser.parse_args(args) @@ -4783,7 +4810,10 @@ def CMDtry_results(parser, args): print('ERROR: Exception when trying to fetch try jobs: %s\n%s' % (e, stacktrace)) return 1 - print_try_jobs(options, jobs) + if options.json: + write_try_results_json(options.json, jobs) + else: + print_try_jobs(options, jobs) return 0 diff --git a/tests/git_cl_test.py b/tests/git_cl_test.py index 9796b2bcb..961801ed8 100755 --- a/tests/git_cl_test.py +++ b/tests/git_cl_test.py @@ -1484,7 +1484,7 @@ class TestGitCl(TestCase): }) self.calls.append( ((['ask_for_data', 'If you know what you are doing, ' - 'press Enter to continue, Ctrl+C to abort.'],), '')) + 'press Enter to continue, Ctrl+C to abort.'],), '')) self.assertIsNone(cl.EnsureAuthenticated(force=False)) def test_gerrit_ensure_authenticated_ok(self): @@ -1850,6 +1850,54 @@ class TestGitCl(TestCase): out.getvalue(), 'scheduled CQ Dry Run on https://codereview.chromium.org/123\n') + def test_write_try_results_json(self): + builds = { + '9000': { + 'id': '9000', + 'status': 'STARTED', + 'url': 'http://build.cr.org/p/x.y/builders/my-builder/builds/2', + 'result_details_json': '{"properties": {}}', + 'bucket': 'master.x.y', + 'created_by': 'user:someone@chromium.org', + 'created_ts': '147200002222000', + 'parameters_json': '{"builder_name": "my-builder", "category": ""}', + }, + '8000': { + 'id': '8000', + 'status': 'COMPLETED', + 'result': 'FAILURE', + 'failure_reason': 'BUILD_FAILURE', + 'url': 'http://build.cr.org/p/x.y/builders/my-builder/builds/1', + 'result_details_json': '{"properties": {}}', + 'bucket': 'master.x.y', + 'created_by': 'user:someone@chromium.org', + 'created_ts': '147200001111000', + 'parameters_json': '{"builder_name": "my-builder", "category": ""}', + }, + } + expected_output = [ + { + 'buildbucket_id': '8000', + 'bucket': 'master.x.y', + 'builder_name': 'my-builder', + 'status': 'COMPLETED', + 'result': 'FAILURE', + 'failure_reason': 'BUILD_FAILURE', + 'url': 'http://build.cr.org/p/x.y/builders/my-builder/builds/1', + }, + { + 'buildbucket_id': '9000', + 'bucket': 'master.x.y', + 'builder_name': 'my-builder', + 'status': 'STARTED', + 'result': None, + 'failure_reason': None, + 'url': 'http://build.cr.org/p/x.y/builders/my-builder/builds/2', + } + ] + self.calls = [(('write_json', 'output.json', expected_output), '')] + git_cl.write_try_results_json('output.json', builds) + def _common_GerritCommitMsgHookCheck(self): self.mock(git_cl.sys, 'stdout', StringIO.StringIO()) self.mock(git_cl.os.path, 'abspath',