From 85557a08f4918c65b5bc18868eaeb18e19800983 Mon Sep 17 00:00:00 2001 From: Marco Georgaklis Date: Thu, 3 Jun 2021 15:56:54 +0000 Subject: [PATCH] Implemented suppport for getrelatedchanges endpoint in gerrit module The endpoint documentation can be found here: https://gerrit-review.googlesource.com/Documentation/rest-api-changes.html#get-related-changes This involved adding support for the command in gerrit_client and gerrit_util and then incorporating functionality and testing into the gerrit recipe module. The reasoning for this is to be able to identify chained builds for improved accuracy of the new test identification for the FLake Endorser project. Bug:1204163 Change-Id: Ic60c733540a9afd7ff159408b0ea9ad7aac078e2 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/tools/depot_tools/+/2928016 Commit-Queue: Marco Georgaklis Reviewed-by: Josip Sokcevic --- gerrit_client.py | 16 ++++++ gerrit_util.py | 6 +++ recipes/README.recipes.md | 23 ++++++++- recipes/recipe_modules/gerrit/api.py | 36 +++++++++++++ .../gerrit/examples/full.expected/basic.json | 51 +++++++++++++++++++ .../recipe_modules/gerrit/examples/full.py | 6 +++ recipes/recipe_modules/gerrit/test_api.py | 31 +++++++++++ tests/gerrit_client_test.py | 10 ++++ 8 files changed, 177 insertions(+), 2 deletions(-) diff --git a/gerrit_client.py b/gerrit_client.py index 9e9082d25..0228d5ac0 100755 --- a/gerrit_client.py +++ b/gerrit_client.py @@ -153,6 +153,22 @@ def CMDchanges(parser, args): write_result(result, opt) +@subcommand.usage('[args ...]') +def CMDrelatedchanges(parser, args): + parser.add_option('-c', '--change', type=str, help='change id') + parser.add_option('-r', '--revision', type=str, help='revision id') + + (opt, args) = parser.parse_args(args) + + result = gerrit_util.GetRelatedChanges( + urlparse.urlparse(opt.host).netloc, + change=opt.change, + revision=opt.revision, + ) + logging.info(result) + write_result(result, opt) + + @subcommand.usage('[args ...]') def CMDcreatechange(parser, args): parser.add_option('-s', '--subject', help='subject for change') diff --git a/gerrit_util.py b/gerrit_util.py index 81d0f88d1..1f44a799e 100644 --- a/gerrit_util.py +++ b/gerrit_util.py @@ -703,6 +703,12 @@ def GetChangeRobotComments(host, change): return ReadHttpJsonResponse(CreateHttpConn(host, path)) +def GetRelatedChanges(host, change, revision='current'): + """Gets the related changes for a given change and revision.""" + path = 'changes/%s/revisions/%s/related' % (change, revision) + return ReadHttpJsonResponse(CreateHttpConn(host, path)) + + def AbandonChange(host, change, msg=''): """Abandons a Gerrit change.""" path = 'changes/%s/abandon' % change diff --git a/recipes/README.recipes.md b/recipes/README.recipes.md index 0ee202d58..141040eaf 100644 --- a/recipes/README.recipes.md +++ b/recipes/README.recipes.md @@ -361,7 +361,7 @@ Module for interact with Gerrit endpoints Wrapper for easy calling of gerrit_utils steps. -— **def [abandon\_change](/recipes/recipe_modules/gerrit/api.py#173)(self, host, change, message=None, name=None, step_test_data=None):** +— **def [abandon\_change](/recipes/recipe_modules/gerrit/api.py#209)(self, host, change, message=None, name=None, step_test_data=None):** — **def [create\_gerrit\_branch](/recipes/recipe_modules/gerrit/api.py#32)(self, host, project, branch, commit, \*\*kwargs):** @@ -408,6 +408,25 @@ Gets a branch from given project and commit Returns: The revision of the branch +— **def [get\_related\_changes](/recipes/recipe_modules/gerrit/api.py#173)(self, host, change, revision='current', step_test_data=None):** + +Queries related changes for a given host, change, and revision. + +Args: + * host: URL of Gerrit host to query. + * change: The change-id of the change to get related changes for as + documented here: + https://gerrit-review.googlesource.com/Documentation/rest-api-changes.html#change-id + * revision: The revision-id of the revision to get related changes for as + documented here: + https://gerrit-review.googlesource.com/Documentation/rest-api-changes.html#revision-id + This defaults to current, which names the most recent patch set. + * step_test_data: Optional mock test data for the underlying gerrit client. + +Returns: + A related changes dictionary as documented here: + https://gerrit-review.googlesource.com/Documentation/rest-api-changes.html#related-changes-info + — **def [get\_revision\_info](/recipes/recipe_modules/gerrit/api.py#90)(self, host, change, patchset, timeout=None, step_test_data=None):** Returns the info for a given patchset of a given change. @@ -421,7 +440,7 @@ Returns: A dict for the target revision as documented here: https://gerrit-review.googlesource.com/Documentation/rest-api-changes.html#list-changes -— **def [move\_changes](/recipes/recipe_modules/gerrit/api.py#193)(self, host, project, from_branch, to_branch, step_test_data=None):** +— **def [move\_changes](/recipes/recipe_modules/gerrit/api.py#229)(self, host, project, from_branch, to_branch, step_test_data=None):** ### *recipe_modules* / [git](/recipes/recipe_modules/git) [DEPS](/recipes/recipe_modules/git/__init__.py#1): [recipe\_engine/buildbucket][recipe_engine/recipe_modules/buildbucket], [recipe\_engine/context][recipe_engine/recipe_modules/context], [recipe\_engine/path][recipe_engine/recipe_modules/path], [recipe\_engine/platform][recipe_engine/recipe_modules/platform], [recipe\_engine/properties][recipe_engine/recipe_modules/properties], [recipe\_engine/python][recipe_engine/recipe_modules/python], [recipe\_engine/raw\_io][recipe_engine/recipe_modules/raw_io], [recipe\_engine/runtime][recipe_engine/recipe_modules/runtime], [recipe\_engine/step][recipe_engine/recipe_modules/step] diff --git a/recipes/recipe_modules/gerrit/api.py b/recipes/recipe_modules/gerrit/api.py index 0b6d3120a..4bb028d6e 100644 --- a/recipes/recipe_modules/gerrit/api.py +++ b/recipes/recipe_modules/gerrit/api.py @@ -170,6 +170,42 @@ class GerritApi(recipe_api.RecipeApi): **kwargs ).json.output + def get_related_changes(self, host, change, revision='current', step_test_data=None): + """Queries related changes for a given host, change, and revision. + + Args: + * host: URL of Gerrit host to query. + * change: The change-id of the change to get related changes for as + documented here: + https://gerrit-review.googlesource.com/Documentation/rest-api-changes.html#change-id + * revision: The revision-id of the revision to get related changes for as + documented here: + https://gerrit-review.googlesource.com/Documentation/rest-api-changes.html#revision-id + This defaults to current, which names the most recent patch set. + * step_test_data: Optional mock test data for the underlying gerrit client. + + Returns: + A related changes dictionary as documented here: + https://gerrit-review.googlesource.com/Documentation/rest-api-changes.html#related-changes-info + + """ + args = [ + 'relatedchanges', + '--host', + host, + '--change', + change, + '--revision', + revision, + '--json_file', + self.m.json.output(), + ] + if not step_test_data: + step_test_data = lambda: self.test_api.get_related_changes_response_data() + + return self('relatedchanges', args, + step_test_data=step_test_data).json.output + def abandon_change(self, host, change, message=None, name=None, step_test_data=None): args = [ diff --git a/recipes/recipe_modules/gerrit/examples/full.expected/basic.json b/recipes/recipe_modules/gerrit/examples/full.expected/basic.json index 15e509104..0a4be4c31 100644 --- a/recipes/recipe_modules/gerrit/examples/full.expected/basic.json +++ b/recipes/recipe_modules/gerrit/examples/full.expected/basic.json @@ -156,6 +156,57 @@ "@@@STEP_LOG_END@json.output@@@" ] }, + { + "cmd": [ + "vpython", + "-u", + "RECIPE_REPO[depot_tools]/gerrit_client.py", + "relatedchanges", + "--host", + "https://chromium-review.googlesource.com", + "--change", + "58478", + "--revision", + "2", + "--json_file", + "/path/to/tmp/json" + ], + "env": { + "PATH": ":RECIPE_REPO[depot_tools]" + }, + "infra_step": true, + "name": "gerrit relatedchanges", + "~followup_annotations": [ + "@@@STEP_LOG_LINE@json.output@{@@@", + "@@@STEP_LOG_LINE@json.output@ \"changes\": [@@@", + "@@@STEP_LOG_LINE@json.output@ {@@@", + "@@@STEP_LOG_LINE@json.output@ \"_change_number\": 58478, @@@", + "@@@STEP_LOG_LINE@json.output@ \"_current_revision_number\": 2, @@@", + "@@@STEP_LOG_LINE@json.output@ \"_revision_number\": 2, @@@", + "@@@STEP_LOG_LINE@json.output@ \"change_id\": \"Ic62ae3103fca2214904dbf2faf4c861b5f0ae9b5\", @@@", + "@@@STEP_LOG_LINE@json.output@ \"commit\": {@@@", + "@@@STEP_LOG_LINE@json.output@ \"author\": {@@@", + "@@@STEP_LOG_LINE@json.output@ \"date\": \"2014-07-12 15:04:24.000000000\", @@@", + "@@@STEP_LOG_LINE@json.output@ \"email\": \"example@example.com\", @@@", + "@@@STEP_LOG_LINE@json.output@ \"name\": \"Example Name\", @@@", + "@@@STEP_LOG_LINE@json.output@ \"tz\": 120@@@", + "@@@STEP_LOG_LINE@json.output@ }, @@@", + "@@@STEP_LOG_LINE@json.output@ \"commit\": \"78847477532e386f5a2185a4e8c90b2509e354e3\", @@@", + "@@@STEP_LOG_LINE@json.output@ \"parents\": [@@@", + "@@@STEP_LOG_LINE@json.output@ {@@@", + "@@@STEP_LOG_LINE@json.output@ \"commit\": \"bb499510bbcdbc9164d96b0dbabb4aa45f59a87e\"@@@", + "@@@STEP_LOG_LINE@json.output@ }@@@", + "@@@STEP_LOG_LINE@json.output@ ], @@@", + "@@@STEP_LOG_LINE@json.output@ \"subject\": \"Remove Solr\"@@@", + "@@@STEP_LOG_LINE@json.output@ }, @@@", + "@@@STEP_LOG_LINE@json.output@ \"project\": \"gerrit\", @@@", + "@@@STEP_LOG_LINE@json.output@ \"status\": \"NEW\"@@@", + "@@@STEP_LOG_LINE@json.output@ }@@@", + "@@@STEP_LOG_LINE@json.output@ ]@@@", + "@@@STEP_LOG_LINE@json.output@}@@@", + "@@@STEP_LOG_END@json.output@@@" + ] + }, { "cmd": [ "vpython", diff --git a/recipes/recipe_modules/gerrit/examples/full.py b/recipes/recipe_modules/gerrit/examples/full.py index dfd4e6b67..1a281771b 100644 --- a/recipes/recipe_modules/gerrit/examples/full.py +++ b/recipes/recipe_modules/gerrit/examples/full.py @@ -34,6 +34,10 @@ def RunSteps(api): start=1, limit=1, ) + related_changes = api.gerrit.get_related_changes(host, + change='58478', + revision='2') + assert len(related_changes["changes"]) == 1 # Query which returns no changes is still successful query. empty_list = api.gerrit.get_changes( @@ -69,5 +73,7 @@ def GenTests(api): api.gerrit.make_gerrit_get_branch_response_data()) + api.step_data('gerrit move changes', api.gerrit.get_move_change_response_data(branch='main')) + + api.step_data('gerrit relatedchanges', + api.gerrit.get_related_changes_response_data()) + api.step_data('gerrit changes empty query', api.gerrit.get_empty_changes_response_data())) diff --git a/recipes/recipe_modules/gerrit/test_api.py b/recipes/recipe_modules/gerrit/test_api.py index e7e031de9..27e73ba31 100644 --- a/recipes/recipe_modules/gerrit/test_api.py +++ b/recipes/recipe_modules/gerrit/test_api.py @@ -32,6 +32,34 @@ class GerritTestApi(recipe_test_api.RecipeTestApi): data.update(kwargs) return data + @staticmethod + def _related_changes_data(**kwargs): + data = { + "changes": [{ + "project": "gerrit", + "change_id": "Ic62ae3103fca2214904dbf2faf4c861b5f0ae9b5", + "commit": { + "commit": "78847477532e386f5a2185a4e8c90b2509e354e3", + "parents": [{ + "commit": "bb499510bbcdbc9164d96b0dbabb4aa45f59a87e" + }], + "author": { + "name": "Example Name", + "email": "example@example.com", + "date": "2014-07-12 15:04:24.000000000", + "tz": 120 + }, + "subject": "Remove Solr" + }, + "_change_number": 58478, + "_revision_number": 2, + "_current_revision_number": 2, + "status": "NEW" + }] + } + data.update(kwargs) + return data + def _make_gerrit_response_json(self, data): return self.m.json.output(data) @@ -56,3 +84,6 @@ class GerritTestApi(recipe_test_api.RecipeTestApi): def get_move_change_response_data(self, **kwargs): return self._make_gerrit_response_json([self._gerrit_change_data(**kwargs)]) + + def get_related_changes_response_data(self, **kwargs): + return self._make_gerrit_response_json(self._related_changes_data(**kwargs)) diff --git a/tests/gerrit_client_test.py b/tests/gerrit_client_test.py index d1a94440c..1520b9ea2 100755 --- a/tests/gerrit_client_test.py +++ b/tests/gerrit_client_test.py @@ -56,6 +56,16 @@ class TestGerritClient(unittest.TestCase): start=20, o_params=['op1', 'op2']) + @mock.patch('gerrit_util.GetRelatedChanges', return_value='') + def test_relatedchanges(self, util_mock): + gerrit_client.main([ + 'relatedchanges', '--host', 'https://example.org/foo', '--change', + 'foo-change-id', '--revision', 'foo-revision-id' + ]) + util_mock.assert_called_once_with('example.org', + change='foo-change-id', + revision='foo-revision-id') + @mock.patch('gerrit_util.CreateChange', return_value={}) def test_createchange(self, util_mock): gerrit_client.main([