コード例 #1
0
  def Run(self, cnxn, services, allow_edit=True):
    """Updates an issue based on the parsed commands."""
    try:
      issue = services.issue.GetIssueByLocalID(
          cnxn, self.project.project_id, self.local_id)
    except exceptions.NoSuchIssueException:
      return  # Issue does not exist, so do nothing

    old_owner_id = issue.owner_id
    new_summary = self.parser.summary or issue.summary

    if self.parser.status is None:
      new_status = issue.status
    else:
      new_status = self.parser.status

    if self.parser.owner_id is None:
      new_owner_id = issue.owner_id
    else:
      new_owner_id = self.parser.owner_id

    new_cc_ids = [cc for cc in list(issue.cc_ids) + list(self.parser.cc_add)
                  if cc not in self.parser.cc_remove]
    (new_labels, _update_add, _update_remove) = framework_bizobj.MergeLabels(
         issue.labels, self.parser.labels_add,
         self.parser.labels_remove, self.config)

    new_field_values = issue.field_values  # TODO(jrobbins): edit custom ones

    if not allow_edit:
      # If user can't edit, then only consider the plain-text comment,
      # and set all other fields back to their original values.
      logging.info('Processed reply from user who can not edit issue')
      new_summary = issue.summary
      new_status = issue.status
      new_owner_id = issue.owner_id
      new_cc_ids = issue.cc_ids
      new_labels = issue.labels
      new_field_values = issue.field_values

    amendments, comment_pb = services.issue.ApplyIssueComment(
        cnxn, services, self.commenter_id,
        self.project.project_id, issue.local_id, new_summary, new_status,
        new_owner_id, new_cc_ids, new_labels, new_field_values,
        issue.component_ids, issue.blocked_on_iids, issue.blocking_iids,
        issue.dangling_blocked_on_refs, issue.dangling_blocking_refs,
        issue.merged_into, comment=self.description,
        inbound_message=self.inbound_message)

    logging.info('Updated issue %s:%s w/ amendments %r',
                 self.project.project_name, issue.local_id, amendments)

    if amendments or self.description:  # Avoid completely empty comments.
      send_notifications.PrepareAndSendIssueChangeNotification(
          issue.issue_id, self.hostport, self.commenter_id,
          old_owner_id=old_owner_id, comment_id=comment_pb.id)
コード例 #2
0
  def testMergeLabels_SingleValuedEnums(self):
    self.config.field_defs.append(tracker_pb2.FieldDef(
        field_id=1, field_name='Size',
        field_type=tracker_pb2.FieldTypes.ENUM_TYPE,
        is_multivalued=False))
    self.config.field_defs.append(tracker_pb2.FieldDef(
        field_id=1, field_name='Branch-Name',
        field_type=tracker_pb2.FieldTypes.ENUM_TYPE,
        is_multivalued=False))

    # We can add a label for a single-valued enum.
    (merged_labels, update_add, update_remove) = framework_bizobj.MergeLabels(
        ['Priority-Medium', 'OpSys-OSX'], ['Size-L'], [], self.config)
    self.assertEquals(merged_labels, ['Priority-Medium', 'OpSys-OSX', 'Size-L'])
    self.assertEquals(update_add, ['Size-L'])
    self.assertEquals(update_remove, [])

    # Adding and removing the same label adds it.
    (merged_labels, update_add, update_remove) = framework_bizobj.MergeLabels(
        ['Priority-Medium'], ['Size-M'], ['Size-M'], self.config)
    self.assertEquals(merged_labels, ['Priority-Medium', 'Size-M'])
    self.assertEquals(update_add, ['Size-M'])
    self.assertEquals(update_remove, [])

    # Adding Size-L replaces Size-M.
    (merged_labels, update_add, update_remove) = framework_bizobj.MergeLabels(
        ['Priority-Medium', 'Size-M'], ['Size-L', 'OpSys-Win'], [],
        self.config)
    self.assertEquals(merged_labels,
                      ['Priority-Medium', 'Size-L', 'OpSys-Win'])
    self.assertEquals(update_add, ['Size-L', 'OpSys-Win'])
    self.assertEquals(update_remove, [])

    # Adding Size-L and Size-XL replaces with L only.
    (merged_labels, update_add, update_remove) = framework_bizobj.MergeLabels(
        ['Size-M', 'OpSys-OSX'], ['Size-L', 'Size-XL'], [], self.config)
    self.assertEquals(merged_labels, ['OpSys-OSX', 'Size-L'])
    self.assertEquals(update_add, ['Size-L'])
    self.assertEquals(update_remove, [])

    # Multi-part labels work as expected.
    (merged_labels, update_add, update_remove) = framework_bizobj.MergeLabels(
        ['Size-M', 'OpSys-OSX'], ['Size-M-USA'], [], self.config)
    self.assertEquals(
        merged_labels, ['OpSys-OSX', 'Size-M-USA'])
    self.assertEquals(update_add, ['Size-M-USA'])
    self.assertEquals(update_remove, [])

    # Multi-part enum names only filter labels that match whole name.
    (merged_labels, update_add, update_remove) = framework_bizobj.MergeLabels(
        ['Branch-Name-Master'],
        ['Branch-Prediction', 'Branch-Name-Beta'], [], self.config)
    self.assertEquals(
        merged_labels, ['Branch-Prediction', 'Branch-Name-Beta'])
    self.assertEquals(update_add, ['Branch-Prediction', 'Branch-Name-Beta'])
    self.assertEquals(update_remove, [])
コード例 #3
0
    def testMergeLabels(self):
        (merged_labels, update_add,
         update_remove) = framework_bizobj.MergeLabels([], [], [], [])
        self.assertEquals(merged_labels, [])
        self.assertEquals(update_add, [])
        self.assertEquals(update_remove, [])

        (merged_labels, update_add,
         update_remove) = framework_bizobj.MergeLabels(['a', 'b'], [], [], [])
        self.assertEquals(merged_labels, ['a', 'b'])
        self.assertEquals(update_add, [])
        self.assertEquals(update_remove, [])

        (merged_labels, update_add,
         update_remove) = framework_bizobj.MergeLabels(['a', 'b', 'd'], ['c'],
                                                       ['d'], [])
        self.assertEquals(merged_labels, ['a', 'b', 'c'])
        self.assertEquals(update_add, ['c'])
        self.assertEquals(update_remove, ['d'])

        (merged_labels, update_add,
         update_remove) = framework_bizobj.MergeLabels(['a', 'b', 'd'], ['d'],
                                                       ['e'], [])
        self.assertEquals(merged_labels, ['a', 'b', 'd'])
        self.assertEquals(update_add, [])  # d was already there.
        self.assertEquals(update_remove, [])  # there was no e.

        (merged_labels, update_add,
         update_remove) = framework_bizobj.MergeLabels(
             ['Priority-Medium', 'OpSys-OSX'], ['Hot'], ['OpSys-OSX'],
             ['Priority'])
        self.assertEquals(merged_labels, ['Priority-Medium', 'Hot'])
        self.assertEquals(update_add, ['Hot'])
        self.assertEquals(update_remove, ['OpSys-OSX'])

        (merged_labels, update_add,
         update_remove) = framework_bizobj.MergeLabels(
             ['Priority-Medium', 'OpSys-OSX'], ['Priority-High', 'OpSys-Win'],
             [], ['Priority'])
        self.assertEquals(merged_labels,
                          ['OpSys-OSX', 'Priority-High', 'OpSys-Win'])
        self.assertEquals(update_add, ['Priority-High', 'OpSys-Win'])
        self.assertEquals(update_remove, [])

        (merged_labels, update_add,
         update_remove) = framework_bizobj.MergeLabels(
             ['Priority-Medium', 'OpSys-OSX'], [],
             ['Priority-Medium', 'OpSys-Win'], ['Priority'])
        self.assertEquals(merged_labels, ['OpSys-OSX'])
        self.assertEquals(update_add, [])
        self.assertEquals(update_remove, ['Priority-Medium'])
コード例 #4
0
ファイル: commands.py プロジェクト: asdfghjjklllllaaa/infra
def ParseQuickEditCommand(cnxn, cmd, issue, config, logged_in_user_id,
                          services):
    """Parse a quick edit command into assignments and labels."""
    parts = _BreakCommandIntoParts(cmd)
    parser = AssignmentParser(None, easier_kv_labels=True)

    for key, value in parts:
        if key:  # A key=value assignment.
            valid_assignment = parser.ParseAssignment(cnxn, key, value, config,
                                                      services,
                                                      logged_in_user_id)
            if not valid_assignment:
                logging.info('ignoring assignment: %r, %r', key, value)

        elif value.startswith('-'):  # Removing a label.
            parser.labels_remove.append(_StandardizeLabel(value[1:], config))

        else:  # Adding a label.
            value = value.strip('+')
            parser.labels_add.append(_StandardizeLabel(value, config))

    new_summary = parser.summary or issue.summary

    if parser.status is None:
        new_status = issue.status
    else:
        new_status = parser.status

    if parser.owner_id is None:
        new_owner_id = issue.owner_id
    else:
        new_owner_id = parser.owner_id

    new_cc_ids = [
        cc for cc in list(issue.cc_ids) + list(parser.cc_add)
        if cc not in parser.cc_remove
    ]
    (new_labels, _update_add, _update_remove) = framework_bizobj.MergeLabels(
        issue.labels, parser.labels_add, parser.labels_remove, config)

    return new_summary, new_status, new_owner_id, new_cc_ids, new_labels
コード例 #5
0
ファイル: commands.py プロジェクト: mcgreevy/chromium-infra
  def ParseAssignment(self, cnxn, key, value, config, services, user_id):
    """Parse command-style text entered by the user to update an issue.

    E.g., The user may want to set the issue status to "reviewed", or
    set the owner to "me".

    Args:
      cnxn: connection to SQL database.
      key: string name of the field to set.
      value: string value to be interpreted.
      config: Projects' issue tracker configuration PB.
      services: connections to backends.
      user_id: int user ID of the user making the change.

    Returns:
      True if the line could be parsed as an assigment, False otherwise.
      Also, as a side-effect, the assigned values are built up in the instance
      variables of the parser.
    """
    valid_line = True

    if key == 'owner':
      if framework_constants.NO_VALUE_RE.match(value):
        self.owner_id = framework_constants.NO_USER_SPECIFIED
      else:
        try:
          self.owner_id = _LookupMeOrUsername(cnxn, value, services, user_id)
        except user_svc.NoSuchUserException:
          logging.warning('bad owner: %r when committing to project_id %r',
                          value, config.project_id)
          valid_line = False

    elif key == 'cc':
      try:
        add, remove = _ParsePlusMinusList(value)
        self.cc_add = [_LookupMeOrUsername(cnxn, cc, services, user_id)
                       for cc in add]
        self.cc_remove = [_LookupMeOrUsername(cnxn, cc, services, user_id)
                          for cc in remove]
        for user_id in self.cc_add:
          if user_id not in self.cc_list:
            self.cc_list.append(user_id)
        self.cc_list = [user_id for user_id in self.cc_list
                        if user_id not in self.cc_remove]
      except user_svc.NoSuchUserException:
        logging.warning('bad cc: %r when committing to project_id %r',
                        value, config.project_id)
        valid_line = False

    elif key == 'summary':
      self.summary = value

    elif key == 'status':
      if framework_constants.NO_VALUE_RE.match(value):
        self.status = ''
      else:
        self.status = _StandardizeStatus(value, config)

    elif key == 'label' or key == 'labels':
      self.labels_add, self.labels_remove = _ParsePlusMinusList(value)
      self.labels_add = [_StandardizeLabel(lab, config)
                         for lab in self.labels_add]
      self.labels_remove = [_StandardizeLabel(lab, config)
                            for lab in self.labels_remove]
      (self.labels_list, _update_add,
       _update_remove) = framework_bizobj.MergeLabels(
           self.labels_list, self.labels_add, self.labels_remove,
           config.exclusive_label_prefixes)

    elif (self.easier_kv_labels and
          key not in tracker_constants.RESERVED_PREFIXES and
          key and value):
      if key.startswith('-'):
        self.labels_remove.append(_StandardizeLabel(
            '%s-%s' % (key[1:], value), config))
      else:
        self.labels_add.append(_StandardizeLabel(
            '%s-%s' % (key, value), config))

    else:
      valid_line = False

    return valid_line
コード例 #6
0
  def testMergeLabels_Labels(self):
    # Empty case.
    (merged_labels, update_add, update_remove) = framework_bizobj.MergeLabels(
        [], [], [], self.config)
    self.assertEquals(merged_labels, [])
    self.assertEquals(update_add, [])
    self.assertEquals(update_remove, [])

    # No-op case.
    (merged_labels, update_add, update_remove) = framework_bizobj.MergeLabels(
        ['a', 'b'], [], [], self.config)
    self.assertEquals(merged_labels, ['a', 'b'])
    self.assertEquals(update_add, [])
    self.assertEquals(update_remove, [])

    # Adding and removing at the same time.
    (merged_labels, update_add, update_remove) = framework_bizobj.MergeLabels(
        ['a', 'b', 'd'], ['c'], ['d'], self.config)
    self.assertEquals(merged_labels, ['a', 'b', 'c'])
    self.assertEquals(update_add, ['c'])
    self.assertEquals(update_remove, ['d'])

    # Removing a non-matching label has no effect.
    (merged_labels, update_add, update_remove) = framework_bizobj.MergeLabels(
        ['a', 'b', 'd'], ['d'], ['e'], self.config)
    self.assertEquals(merged_labels, ['a', 'b', 'd'])
    self.assertEquals(update_add, [])     # d was already there.
    self.assertEquals(update_remove, [])  # there was no e.

    # We can add and remove at the same time.
    (merged_labels, update_add, update_remove) = framework_bizobj.MergeLabels(
        ['Priority-Medium', 'OpSys-OSX'], ['Hot'], ['OpSys-OSX'], self.config)
    self.assertEquals(merged_labels, ['Priority-Medium', 'Hot'])
    self.assertEquals(update_add, ['Hot'])
    self.assertEquals(update_remove, ['OpSys-OSX'])

    # Adding Priority-High replaces Priority-Medium.
    (merged_labels, update_add, update_remove) = framework_bizobj.MergeLabels(
        ['Priority-Medium', 'OpSys-OSX'], ['Priority-High', 'OpSys-Win'], [],
        self.config)
    self.assertEquals(merged_labels,
                      ['OpSys-OSX', 'Priority-High', 'OpSys-Win'])
    self.assertEquals(update_add, ['Priority-High', 'OpSys-Win'])
    self.assertEquals(update_remove, [])

    # Adding Priority-High and Priority-Low replaces with High only.
    (merged_labels, update_add, update_remove) = framework_bizobj.MergeLabels(
        ['Priority-Medium', 'OpSys-OSX'],
        ['Priority-High', 'Priority-Low'], [], self.config)
    self.assertEquals(merged_labels,
                      ['OpSys-OSX', 'Priority-High'])
    self.assertEquals(update_add, ['Priority-High'])
    self.assertEquals(update_remove, [])

    # Removing a mix of matching and non-matching labels only does matching.
    (merged_labels, update_add, update_remove) = framework_bizobj.MergeLabels(
        ['Priority-Medium', 'OpSys-OSX'], [], ['Priority-Medium', 'OpSys-Win'],
        self.config)
    self.assertEquals(merged_labels, ['OpSys-OSX'])
    self.assertEquals(update_add, [])
    self.assertEquals(update_remove, ['Priority-Medium'])

    # Multi-part labels work as expected.
    (merged_labels, update_add, update_remove) = framework_bizobj.MergeLabels(
        ['Priority-Medium', 'OpSys-OSX-11'],
        ['Priority-Medium-Rare', 'OpSys-OSX-13'], [], self.config)
    self.assertEquals(
        merged_labels, ['OpSys-OSX-11', 'Priority-Medium-Rare', 'OpSys-OSX-13'])
    self.assertEquals(update_add, ['Priority-Medium-Rare', 'OpSys-OSX-13'])
    self.assertEquals(update_remove, [])

    # Multi-part exclusive prefixes only filter labels that match whole prefix.
    self.config.exclusive_label_prefixes.append('Branch-Name')
    (merged_labels, update_add, update_remove) = framework_bizobj.MergeLabels(
        ['Branch-Name-Master'],
        ['Branch-Prediction', 'Branch-Name-Beta'], [], self.config)
    self.assertEquals(
        merged_labels, ['Branch-Prediction', 'Branch-Name-Beta'])
    self.assertEquals(update_add, ['Branch-Prediction', 'Branch-Name-Beta'])
    self.assertEquals(update_remove, [])
コード例 #7
0
  def testMergeLabels_MultiValuedEnums(self):
    self.config.field_defs.append(tracker_pb2.FieldDef(
        field_id=1, field_name='OpSys',
        field_type=tracker_pb2.FieldTypes.ENUM_TYPE,
        is_multivalued=True))
    self.config.field_defs.append(tracker_pb2.FieldDef(
        field_id=1, field_name='Branch-Name',
        field_type=tracker_pb2.FieldTypes.ENUM_TYPE,
        is_multivalued=True))

    # We can add a label for a multi-valued enum.
    (merged_labels, update_add, update_remove) = framework_bizobj.MergeLabels(
        ['Priority-Medium'], ['OpSys-Win'], [], self.config)
    self.assertEquals(merged_labels, ['Priority-Medium', 'OpSys-Win'])
    self.assertEquals(update_add, ['OpSys-Win'])
    self.assertEquals(update_remove, [])

    # We can remove a matching label for a multi-valued enum.
    (merged_labels, update_add, update_remove) = framework_bizobj.MergeLabels(
        ['Priority-Medium', 'OpSys-Win'], [], ['OpSys-Win'], self.config)
    self.assertEquals(merged_labels, ['Priority-Medium'])
    self.assertEquals(update_add, [])
    self.assertEquals(update_remove, ['OpSys-Win'])

    # We can remove a non-matching label and it is a no-op.
    (merged_labels, update_add, update_remove) = framework_bizobj.MergeLabels(
        ['Priority-Medium', 'OpSys-OSX'], [], ['OpSys-Win'], self.config)
    self.assertEquals(merged_labels, ['Priority-Medium', 'OpSys-OSX'])
    self.assertEquals(update_add, [])
    self.assertEquals(update_remove, [])

    # Adding and removing the same label adds it.
    (merged_labels, update_add, update_remove) = framework_bizobj.MergeLabels(
        ['Priority-Medium'], ['OpSys-Win'], ['OpSys-Win'], self.config)
    self.assertEquals(merged_labels, ['Priority-Medium', 'OpSys-Win'])
    self.assertEquals(update_add, ['OpSys-Win'])
    self.assertEquals(update_remove, [])

    # We can add a label for a multi-valued enum, even if matching exists.
    (merged_labels, update_add, update_remove) = framework_bizobj.MergeLabels(
        ['Priority-Medium', 'OpSys-OSX'], ['OpSys-Win'], [], self.config)
    self.assertEquals(
        merged_labels, ['Priority-Medium', 'OpSys-OSX', 'OpSys-Win'])
    self.assertEquals(update_add, ['OpSys-Win'])
    self.assertEquals(update_remove, [])

    # Adding two at the same time is fine.
    (merged_labels, update_add, update_remove) = framework_bizobj.MergeLabels(
        ['Size-M', 'OpSys-OSX'], ['OpSys-Win', 'OpSys-Vax'], [], self.config)
    self.assertEquals(
        merged_labels, ['Size-M', 'OpSys-OSX', 'OpSys-Win', 'OpSys-Vax'])
    self.assertEquals(update_add, ['OpSys-Win', 'OpSys-Vax'])
    self.assertEquals(update_remove, [])

    # Multi-part labels work as expected.
    (merged_labels, update_add, update_remove) = framework_bizobj.MergeLabels(
        ['Size-M', 'OpSys-OSX'], ['OpSys-Win-10'], [], self.config)
    self.assertEquals(
        merged_labels, ['Size-M', 'OpSys-OSX', 'OpSys-Win-10'])
    self.assertEquals(update_add, ['OpSys-Win-10'])
    self.assertEquals(update_remove, [])

    # Multi-part enum names don't mess up anything.
    (merged_labels, update_add, update_remove) = framework_bizobj.MergeLabels(
        ['Branch-Name-Master'],
        ['Branch-Prediction', 'Branch-Name-Beta'], [], self.config)
    self.assertEquals(
        merged_labels,
        ['Branch-Name-Master', 'Branch-Prediction', 'Branch-Name-Beta'])
    self.assertEquals(update_add, ['Branch-Prediction', 'Branch-Name-Beta'])
    self.assertEquals(update_remove, [])