Exemplo n.º 1
0
    def _ProcessDeps(cl, deps, required):
        """Yields matching dependencies for a patch"""
        # We need to query the change to guarantee that we have a .gerrit_number
        for dep in deps:
            if not dep.remote in opts.gerrit:
                opts.gerrit[dep.remote] = gerrit.GetGerritHelper(
                    remote=dep.remote, print_cmd=opts.debug)
            helper = opts.gerrit[dep.remote]

            # TODO(phobbs) this should maybe catch network errors.
            changes = _QueryChange(dep.ToGerritQueryText(), helper=helper)

            # Handle empty results.  If we found a commit that was pushed directly
            # (e.g. a bot commit), then gerrit won't know about it.
            if not changes:
                if required:
                    logging.error('CL %s depends on %s which cannot be found',
                                  cl, dep.ToGerritQueryText())
                continue

            # Our query might have matched more than one result.  This can come up
            # when CQ-DEPEND uses a Gerrit Change-Id, but that Change-Id shows up
            # across multiple repos/branches.  We blindly check all of them in the
            # hopes that all open ones are what the user wants, but then again the
            # CQ-DEPEND syntax itself is unable to differeniate.  *shrug*
            if len(changes) > 1:
                logging.warning('CL %s has an ambiguous CQ dependency %s', cl,
                                dep.ToGerritQueryText())
            for change in changes:
                if change.status == 'NEW':
                    yield change
Exemplo n.º 2
0
def GetGerrit(opts, cl=None):
    """Auto pick the right gerrit instance based on the |cl|

  Args:
    opts: The general options object.
    cl: A CL taking one of the forms: 1234 *1234 chromium:1234

  Returns:
    A tuple of a gerrit object and a sanitized CL #.
  """
    gob = opts.gob
    if cl is not None:
        if cl.startswith('*') or cl.startswith('chrome-internal:'):
            gob = config_lib.GetSiteParams().INTERNAL_GOB_INSTANCE
            if cl.startswith('*'):
                cl = cl[1:]
            else:
                cl = cl[16:]
        elif ':' in cl:
            gob, cl = cl.split(':', 1)

    if not gob in opts.gerrit:
        opts.gerrit[gob] = gerrit.GetGerritHelper(gob=gob,
                                                  print_cmd=opts.debug)

    return (opts.gerrit[gob], cl)
Exemplo n.º 3
0
    def SimpleCreate(cls, cros_internal=True, cros=True):
        """Classmethod helper for creating a HelperPool from boolean options.

    Args:
      cros_internal: If True, allow access to a GerritHelper for internal.
      cros: If True, allow access to a GerritHelper for external.

    Returns:
      An appropriately configured HelperPool instance.
    """
        site_params = config_lib.GetSiteParams()
        if cros:
            cros = gerrit.GetGerritHelper(site_params.EXTERNAL_REMOTE)
        else:
            cros = None

        if cros_internal:
            cros_internal = gerrit.GetGerritHelper(site_params.INTERNAL_REMOTE)
        else:
            cros_internal = None

        return cls(cros_internal=cros_internal, cros=cros)
Exemplo n.º 4
0
 def _GetHelper(self, remote=config_lib.GetSiteParams().EXTERNAL_REMOTE):
     return gerrit.GetGerritHelper(remote)
Exemplo n.º 5
0
 def _GetHelper(self, remote=site_config.params.EXTERNAL_REMOTE):
     return gerrit.GetGerritHelper(remote)
Exemplo n.º 6
0
def main(argv):
  # Locate actions that are exposed to the user.  All functions that start
  # with "UserAct" are fair game.
  act_pfx = 'UserAct'
  actions = [x for x in globals() if x.startswith(act_pfx)]

  usage = """%prog [options] <action> [action args]

There is no support for doing line-by-line code review via the command line.
This helps you manage various bits and CL status.

Example:
  $ gerrit todo             # List all the CLs that await your review.
  $ gerrit mine             # List all of your open CLs.
  $ gerrit inspect 28123    # Inspect CL 28123 on the public gerrit.
  $ gerrit inspect *28123   # Inspect CL 28123 on the internal gerrit.
  $ gerrit verify 28123 1   # Mark CL 28123 as verified (+1).

Actions:"""
  indent = max([len(x) - len(act_pfx) for x in actions])
  for a in sorted(actions):
    usage += '\n  %-*s: %s' % (indent, a[len(act_pfx):].lower(),
                               globals()[a].__doc__)

  parser = commandline.OptionParser(usage=usage)
  parser.add_option('-i', '--internal', default=None, action='store_true',
                    help='Query gerrit-int')
  parser.add_option('-e', '--external', dest='internal', action='store_false',
                    help='Query gerrit (default)')
  parser.add_option('--sort', default='number', help='Key to sort on '
                                                     '(number, project)')
  parser.add_option('-v', '--verbose', default=False, action='store_true',
                    help='Be more verbose in output')
  opts, args = parser.parse_args(argv)
  if not args:
    parser.error('missing action')

  # pylint: disable=W0603
  global COLOR
  COLOR = terminal.Color(enabled=opts.color)

  # TODO: This sucks.  We assume that all actions which take an argument are
  # a CL #.  Or at least, there's no other reason for it to start with a *.
  # We do this to automatically select internal vs external gerrit as this
  # convention is encoded in much of our system.  However, the rest of this
  # script doesn't expect (or want) the leading *.
  if len(args) > 1:
    if args[1][0] == '*':
      if opts.internal is None:
        opts.internal = True
      args[1] = args[1][1:]

  opts.gerrit = gerrit.GetGerritHelper(
      constants.INTERNAL_REMOTE if opts.internal else constants.EXTERNAL_REMOTE,
      print_cmd=opts.debug)

  # Now look up the requested user action and run it.
  cmd = args[0].lower()
  args = args[1:]
  functor = globals().get(act_pfx + cmd.capitalize())
  if functor:
    argspec = inspect.getargspec(functor)
    if argspec.varargs:
      if len(args) < len(argspec.args):
        parser.error('incorrect number of args: %s expects at least %s' %
                     (cmd, len(argspec.args)))
    elif len(argspec.args) - 1 != len(args):
      parser.error('incorrect number of args: %s expects %s' %
                   (cmd, len(argspec.args) - 1))
    try:
      functor(opts, *args)
    except (cros_build_lib.RunCommandError, gerrit.GerritException) as e:
      cros_build_lib.Die(e.message)
  else:
    parser.error('unknown action: %s' % (cmd,))
Exemplo n.º 7
0
def main(argv):
    parser = optparse.OptionParser(
        usage="usage: prog [--internal|--external] [--query|--age] "
        "[email_addresses|usernames]")
    parser.add_option("-i",
                      "--internal",
                      default=False,
                      action="store_true",
                      help="Query gerrit-int.")
    parser.add_option("-e",
                      "--external",
                      dest="internal",
                      action="store_false",
                      help="Query gerrit.  Note this is the default.")
    parser.add_option(
        "--age",
        default="6mon",
        help="Limit results to within this gerrit age query.  See "
        "http://goo.gl/AdJy3 for the age form; to see the last 3 "
        "months, it would be '3mon'.  Defaults to the last 6 "
        "months.")
    parser.add_option(
        "--query",
        default=None,
        help="Freeform gerrit query.  If specified, it overrides "
        "the normal querying behaviour.  Use only if you know "
        "what you're doing.")

    opts, args = parser.parse_args(argv)
    if not args and not opts.query:
        parser.error("no querying parameters given.")

    logging.getLogger().setLevel(logging.WARNING)
    query = []

    helper = gerrit.GetGerritHelper(constants.INTERNAL_REMOTE if opts.
                                    internal else constants.EXTERNAL_REMOTE)
    recomposed_args = []
    for arg in args:
        if "@" not in arg:
            recomposed_args.extend(find_user(helper, arg))
        else:
            recomposed_args.append(arg)

    args = set(recomposed_args)
    addresses = [x.replace(":", "\:") for x in args]
    owners = ["owner:%s" % x for x in addresses]
    reviewers = ["reviewer:%s" % x for x in addresses]

    if opts.query:
        query.append(opts.query)
    elif args:
        query.append("( %s )" % " OR ".join(owners))
        query.append("-age:%s" % opts.age)

    query = " AND ".join(query)

    results = helper.Query(query, current_patch=False, sort="lastUpdated")
    targets = frozenset(args)

    if not args:
        print "query resulted in %i owned CLs." % len(results)
        print "no email addresses given so unable to do scoring stats"
        return 0

    print "Owner stats: %i CLs." % len(results)
    stats = {}
    for x in results:
        status = x["status"].lower()
        stats[status] = stats.get(status, 0) + 1
    if "new" in stats:
        stats["open"] = stats.pop("new")
    for status, value in sorted(stats.iteritems(), key=lambda x: x[0]):
        print "  %s: %i" % (status, value)

    # Get approval stats.
    requested = helper.Query(
        "( %s  AND NOT ( %s ) ) AND -age:%s" %
        (" OR ".join(reviewers), " OR ".join(owners), opts.age),
        current_patch=False,
        options=("--all-approvals", ))

    total_scored_patchsets = scoring = 0
    lgtms = 0
    for cl in requested:
        touched_it = False
        lgtmed = False
        for patchset in cl.get("patchSets", ()):
            for approval in patchset.get("approvals", ()):
                if targets.intersection([approval["by"].get("email")]):
                    touched_it = True
                    if (("CRVW", 2) == (approval.get("type"),
                                        int(approval.get("value", 0)))):
                        lgtmed = True
                    total_scored_patchsets += 1
        if touched_it:
            scoring += 1
        if lgtmed:
            lgtms += 1

    # Find comments; gerrit doesn't give that information in --all-approvals
    # unfortunately.
    comments = helper.Query(
        "( %s AND NOT ( %s ) ) AND -age:%s" %
        (" OR ".join(reviewers), " OR ".join(owners), opts.age),
        options=("--comments", "--patch-sets"),
        raw=True,
        current_patch=False)
    requested_review = len(comments)

    commented_changes = total_comments = 0
    for change in comments:
        touched = False
        for comment in change.get("comments", ()):
            if comment["reviewer"].get("email", None) in targets:
                total_comments += 1
                touched = True
        if touched:
            commented_changes += 1

    print(
        "Requested as a reviewer for %i changes, commented on %i, "
        "%i comments total; lgtm'd %i changes" %
        (requested_review, commented_changes, total_comments, lgtms))
    ratio = float(
        total_scored_patchsets) / scoring if total_scored_patchsets else 0
    print(
        "Review stats: %i Changes scored; %i individual patchsets scored "
        "(for a %2.2fx scoring/change rate)" %
        (scoring, total_scored_patchsets, ratio))