| # Copyright 2013 The Chromium Authors. All rights reserved. |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| |
| from recipe_engine import recipe_api |
| |
| class GerritApi(recipe_api.RecipeApi): |
| """Module for interact with gerrit endpoints""" |
| |
| def __init__(self, *args, **kwargs): |
| super(GerritApi, self).__init__(*args, **kwargs) |
| self._changes_target_branch_cache = {} |
| |
| def __call__(self, name, cmd, infra_step=True, **kwargs): |
| """Wrapper for easy calling of gerrit_utils steps.""" |
| assert isinstance(cmd, (list, tuple)) |
| prefix = 'gerrit ' |
| |
| env = self.m.context.env |
| env.setdefault('PATH', '%(PATH)s') |
| env['PATH'] = self.m.path.pathsep.join([ |
| env['PATH'], str(self.repo_resource())]) |
| |
| with self.m.context(env=env): |
| return self.m.python(prefix + name, |
| self.repo_resource('gerrit_client.py'), |
| cmd, |
| infra_step=infra_step, |
| **kwargs) |
| |
| def create_gerrit_branch(self, host, project, branch, commit, **kwargs): |
| """ |
| Create a new branch from given project and commit |
| |
| Returns: |
| the ref of the branch created |
| """ |
| args = [ |
| 'branch', |
| '--host', host, |
| '--project', project, |
| '--branch', branch, |
| '--commit', commit, |
| '--json_file', self.m.json.output() |
| ] |
| step_name = 'create_gerrit_branch (%s %s)' % (project, branch) |
| step_result = self(step_name, args, **kwargs) |
| ref = step_result.json.output.get('ref') |
| return ref |
| |
| # TODO(machenbach): Rename to get_revision? And maybe above to |
| # create_ref? |
| def get_gerrit_branch(self, host, project, branch, **kwargs): |
| """ |
| Get a branch from given project and commit |
| |
| Returns: |
| the revision of the branch |
| """ |
| args = [ |
| 'branchinfo', |
| '--host', host, |
| '--project', project, |
| '--branch', branch, |
| '--json_file', self.m.json.output() |
| ] |
| step_name = 'get_gerrit_branch (%s %s)' % (project, branch) |
| step_result = self(step_name, args, **kwargs) |
| revision = step_result.json.output.get('revision') |
| return revision |
| |
| def get_change_description(self, host, change, patchset): |
| """ |
| Get the description for a given CL and patchset. |
| |
| Args: |
| host: URL of Gerrit host to query. |
| change: The change number. |
| patchset: The patchset number. |
| |
| Returns: |
| The description corresponding to given CL and patchset. |
| """ |
| ri = self.get_revision_info(host, change, patchset) |
| return ri['commit']['message'] |
| |
| def get_revision_info(self, host, change, patchset): |
| """ |
| Returns the info for a given patchset of a given change. |
| |
| Args: |
| host: Gerrit host to query. |
| change: The change number. |
| patchset: The patchset number. |
| |
| Returns: |
| A dict for the target revision as documented here: |
| https://gerrit-review.googlesource.com/Documentation/rest-api-changes.html#list-changes |
| """ |
| assert int(change), change |
| assert int(patchset), patchset |
| cls = self.get_changes( |
| host, |
| query_params=[('change', str(change))], |
| o_params=['ALL_REVISIONS', 'ALL_COMMITS'], |
| limit=1) |
| cl = cls[0] if len(cls) == 1 else {'revisions': {}} |
| for ri in cl['revisions'].itervalues(): |
| # TODO(tandrii): add support for patchset=='current'. |
| if str(ri['_number']) == str(patchset): |
| return ri |
| |
| raise self.m.step.InfraFailure( |
| 'Error querying for CL description: host:%r change:%r; patchset:%r' % ( |
| host, change, patchset)) |
| |
| def get_changes(self, host, query_params, start=None, limit=None, |
| o_params=None, step_test_data=None, **kwargs): |
| """ |
| Query changes for the given host. |
| |
| Args: |
| host: URL of Gerrit host to query. |
| query_params: Query parameters as list of (key, value) tuples to form a |
| query as documented here: |
| https://gerrit-review.googlesource.com/Documentation/user-search.html#search-operators |
| start: How many changes to skip (starting with the most recent). |
| limit: Maximum number of results to return. |
| o_params: A list of additional output specifiers, as documented here: |
| https://gerrit-review.googlesource.com/Documentation/rest-api-changes.html#list-changes |
| step_test_data: Optional mock test data for the underlying gerrit client. |
| Returns: |
| A list of change dicts as documented here: |
| https://gerrit-review.googlesource.com/Documentation/rest-api-changes.html#list-changes |
| """ |
| args = [ |
| 'changes', |
| '--host', host, |
| '--json_file', self.m.json.output() |
| ] |
| if start: |
| args += ['--start', str(start)] |
| if limit: |
| args += ['--limit', str(limit)] |
| for k, v in query_params: |
| args += ['-p', '%s=%s' % (k, v)] |
| for v in (o_params or []): |
| args += ['-o', v] |
| if not step_test_data: |
| step_test_data = lambda: self.test_api.get_one_change_response_data() |
| |
| return self( |
| kwargs.pop('name', 'changes'), |
| args, |
| step_test_data=step_test_data, |
| **kwargs |
| ).json.output |
| |
| def abandon_change(self, host, change, message=None, name=None, |
| step_test_data=None): |
| args = [ |
| 'abandon', |
| '--host', host, |
| '--change', int(change), |
| '--json_file', self.m.json.output(), |
| ] |
| if message: |
| args.extend(['--message', message]) |
| if not step_test_data: |
| step_test_data = lambda: self.test_api.get_one_change_response_data( |
| status='ABANDONED', _number=str(change)) |
| |
| return self( |
| name or 'abandon', |
| args, |
| step_test_data=step_test_data, |
| ).json.output |