Example #1
0
    def _AddAdditionalDetailsToBug(self, bug_id, alerts):
        """Adds additional data to the bug as a comment.

    Adds the link to /group_report and bug_id as well as the names of the bots
    that triggered the alerts, and a milestone label.

    Args:
      bug_id: Bug ID number.
      alerts: The Alert entities being associated with this bug.
    """
        base_url = '%s/group_report' % _GetServerURL()
        bug_page_url = '%s?bug_id=%s' % (base_url, bug_id)
        alerts_url = '%s?keys=%s' % (base_url, _UrlsafeKeys(alerts))
        comment = 'All graphs for this bug:\n  %s\n\n' % bug_page_url
        comment += 'Original alerts at time of bug-filing:\n  %s\n' % alerts_url

        bot_names = alert.GetBotNamesFromAlerts(alerts)
        if bot_names:
            comment += '\n\nBot(s) for this bug\'s original alert(s):\n\n'
            comment += '\n'.join(sorted(bot_names))
        else:
            comment += '\nCould not extract bot names from the list of alerts.'

        http = oauth2_decorator.decorator.http()
        service = issue_tracker_service.IssueTrackerService(http=http)
        service.AddBugComment(bug_id, comment)
Example #2
0
    def get(self):
        """The get handler method is called from a cron job.

    It expects no parameters and has no output. It checks all current bisect try
    jobs and send comments to an issue on the issue tracker if a bisect job has
    completed.
    """
        credentials = rietveld_service.Credentials(
            rietveld_service.GetDefaultRietveldConfig(),
            rietveld_service.PROJECTHOSTING_SCOPE)
        issue_tracker = issue_tracker_service.IssueTrackerService(
            additional_credentials=credentials)

        jobs_to_check = try_job.TryJob.query(
            try_job.TryJob.status == 'started').fetch()
        for job in jobs_to_check:
            try:
                if job.use_buildbucket:
                    logging.info('Checking job %s with Buildbucket job ID %s.',
                                 job.key.id(),
                                 getattr(job, 'buildbucket_job_id', None))
                else:
                    logging.info('Checking job %s with Rietveld issue ID %s.',
                                 job.key.id(),
                                 getattr(job, 'rietveld_issue_id', None))
                _CheckJob(job, issue_tracker)
            except Exception as e:  # pylint: disable=broad-except
                logging.error('Caught Exception %s: %s', type(e).__name__, e)
Example #3
0
 def _FetchBugs(self):
     http = oauth2_decorator.DECORATOR.http()
     issue_tracker = issue_tracker_service.IssueTrackerService(http=http)
     response = issue_tracker.List(q='opened-after:today-5',
                                   label='Type-Bug-Regression,Performance',
                                   sort='-id')
     return response.get('items', []) if response else []
    def get(self):
        """The get handler method is called from a cron job.

    It expects no parameters and has no output. It checks all current bisect try
    jobs and send comments to an issue on the issue tracker if a bisect job has
    completed.
    """
        credentials = utils.ServiceAccountCredentials()
        issue_tracker = issue_tracker_service.IssueTrackerService(
            additional_credentials=credentials)

        # Set privilege so we can also fetch internal try_job entities.
        datastore_hooks.SetPrivilegedRequest()

        jobs_to_check = try_job.TryJob.query(
            try_job.TryJob.status.IN(['started', 'pending'])).fetch()
        all_successful = True

        for job in jobs_to_check:
            try:
                _CheckJob(job, issue_tracker)
            except Exception as e:  # pylint: disable=broad-except
                logging.error('Caught Exception %s: %s\n%s',
                              type(e).__name__, e, traceback.format_exc())
                all_successful = False

        if all_successful:
            utils.TickMonitoringCustomMetric('UpdateBugWithResults')
Example #5
0
 def testNewBug_Success_NewBugReturnsId(self):
     service = issue_tracker_service.IssueTrackerService()
     service._ExecuteRequest = mock.Mock(return_value={'id': 333})
     bug_id = service.NewBug('Bug title',
                             'body',
                             owner='*****@*****.**')
     self.assertEqual(1, service._ExecuteRequest.call_count)
     self.assertEqual(333, bug_id)
Example #6
0
 def testNewBug_Failure_NewBugReturnsNone(self):
     service = issue_tracker_service.IssueTrackerService()
     service._ExecuteRequest = mock.Mock(return_value={})
     bug_id = service.NewBug('Bug title',
                             'body',
                             owner='*****@*****.**')
     self.assertEqual(1, service._ExecuteRequest.call_count)
     self.assertIsNone(bug_id)
Example #7
0
    def _CreateBug(self, summary, description, labels, components,
                   urlsafe_keys):
        """Creates a bug, associates it with the alerts, sends a HTML response.

    Args:
      summary: The new bug summary string.
      description: The new bug description string.
      labels: List of label strings for the new bug.
      components: List of component strings for the new bug.
      urlsafe_keys: Comma-separated alert keys in urlsafe format.
    """
        alert_keys = [ndb.Key(urlsafe=k) for k in urlsafe_keys.split(',')]
        alerts = ndb.get_multi(alert_keys)

        if not description:
            description = 'See the link to graphs below.'

        milestone_label = _MilestoneLabel(alerts)
        if milestone_label:
            labels.append(milestone_label)

        # Only project members (@chromium.org accounts) can be owners of bugs.
        owner = self.request.get('owner')
        if owner and not owner.endswith('@chromium.org'):
            self.RenderHtml(
                'bug_result.html',
                {'error': 'Owner email address must end with @chromium.org.'})
            return

        http = oauth2_decorator.DECORATOR.http()
        service = issue_tracker_service.IssueTrackerService(http=http)

        bug_id = service.NewBug(summary,
                                description,
                                labels=labels,
                                components=components,
                                owner=owner)
        if not bug_id:
            self.RenderHtml('bug_result.html',
                            {'error': 'Error creating bug!'})
            return

        bug_data.Bug(id=bug_id).put()
        for alert_entity in alerts:
            alert_entity.bug_id = bug_id
        ndb.put_multi(alerts)

        comment_body = _AdditionalDetails(bug_id, alerts)
        service.AddBugComment(bug_id, comment_body)

        template_params = {'bug_id': bug_id}
        if all(k.kind() == 'Anomaly' for k in alert_keys):
            bisect_result = auto_bisect.StartNewBisectForBug(bug_id)
            if 'error' in bisect_result:
                template_params['bisect_error'] = bisect_result['error']
            else:
                template_params.update(bisect_result)
        self.RenderHtml('bug_result.html', template_params)
Example #8
0
 def testAddBugComment_Basic(self):
     service = issue_tracker_service.IssueTrackerService()
     service._MakeCommentRequest = mock.Mock()
     self.assertTrue(service.AddBugComment(12345, 'The comment'))
     self.assertEqual(1, service._MakeCommentRequest.call_count)
     service._MakeCommentRequest.assert_called_with(12345, {
         'updates': {},
         'content': 'The comment'
     })
Example #9
0
    def _CommentOnRecoveredBug(cls, bug_id):
        """Adds a comment and close the bug on Issue tracker."""
        bug = ndb.Key('Bug', bug_id).get()
        if bug.status != bug_data.BUG_STATUS_OPENED:
            return
        bug.status = bug_data.BUG_STATUS_RECOVERED
        bug.put()
        comment = cls._RecoveredBugComment(bug_id)

        issue_tracker = issue_tracker_service.IssueTrackerService(
            additional_credentials=utils.ServiceAccountCredentials())
        issue_tracker.AddBugComment(bug_id, comment)
Example #10
0
 def testMakeCommentRequest_UserDoesNotExist_RetryMakeCommentRequest(self):
     service = issue_tracker_service.IssueTrackerService()
     error_content = {
         'error': {
             'message': 'The user does not exist',
             'code': 404
         }
     }
     service._ExecuteRequest = mock.Mock(side_effect=errors.HttpError(
         mock.Mock(
             return_value={'status': 404}), json.dumps(error_content)))
     service.AddBugComment(12345, 'The comment', owner='*****@*****.**')
     self.assertEqual(2, service._ExecuteRequest.call_count)
Example #11
0
 def testNewBug_UsesExpectedParams(self):
     service = issue_tracker_service.IssueTrackerService()
     service._MakeCreateRequest = mock.Mock()
     service.NewBug('Bug title', 'body', owner='*****@*****.**')
     service._MakeCreateRequest.assert_called_with({
         'title': 'Bug title',
         'summary': 'Bug title',
         'description': 'body',
         'labels': [],
         'status': 'Assigned',
         'owner': {
             'name': '*****@*****.**'
         },
     })
Example #12
0
 def testAddBugComment_MergeBug(self):
     service = issue_tracker_service.IssueTrackerService()
     service._MakeCommentRequest = mock.Mock()
     self.assertTrue(service.AddBugComment(12345, 'Dupe',
                                           merge_issue=54321))
     self.assertEqual(1, service._MakeCommentRequest.call_count)
     service._MakeCommentRequest.assert_called_with(
         12345, {
             'updates': {
                 'status': 'Duplicate',
                 'mergedInto': 54321,
             },
             'content': 'Dupe'
         })
Example #13
0
  def _CommentOnRecoveredBug(cls, bug_id):
    """Adds a comment and close the bug on Issue tracker."""
    bug = ndb.Key('Bug', bug_id).get()
    if bug.status != bug_data.BUG_STATUS_OPENED:
      return
    bug.status = bug_data.BUG_STATUS_RECOVERED
    bug.put()
    comment = cls._RecoveredBugComment(bug_id)

    credentials = rietveld_service.Credentials(
        rietveld_service.GetDefaultRietveldConfig(),
        rietveld_service.PROJECTHOSTING_SCOPE)
    issue_tracker = issue_tracker_service.IssueTrackerService(
        additional_credentials=credentials)
    issue_tracker.AddBugComment(bug_id, comment)
Example #14
0
 def testMakeCommentRequest_IssueDeleted_ReturnsTrue(self):
     service = issue_tracker_service.IssueTrackerService()
     error_content = {
         'error': {
             'message': 'User is not allowed to view this issue 12345',
             'code': 403
         }
     }
     service._ExecuteRequest = mock.Mock(side_effect=errors.HttpError(
         mock.Mock(
             return_value={'status': 403}), json.dumps(error_content)))
     comment_posted = service.AddBugComment(12345,
                                            'The comment',
                                            owner='*****@*****.**')
     self.assertEqual(1, service._ExecuteRequest.call_count)
     self.assertEqual(True, comment_posted)
Example #15
0
 def testAddBugComment_WithOptionalParameters(self):
     service = issue_tracker_service.IssueTrackerService()
     service._MakeCommentRequest = mock.Mock()
     self.assertTrue(
         service.AddBugComment(12345,
                               'Some other comment',
                               status='Fixed',
                               labels=['Foo'],
                               cc_list=['*****@*****.**']))
     self.assertEqual(1, service._MakeCommentRequest.call_count)
     service._MakeCommentRequest.assert_called_with(
         12345, {
             'updates': {
                 'status': 'Fixed',
                 'cc': ['*****@*****.**'],
                 'labels': ['Foo'],
             },
             'content': 'Some other comment'
         })
Example #16
0
def PerformBisect(bisect_job):
  """Starts the bisect job.

  This creates a patch, uploads it, then tells Rietveld to try the patch.

  TODO(qyearsley): If we want to use other tryservers sometimes in the future,
  then we need to have some way to decide which one to use. This could
  perhaps be passed as part of the bisect bot name, or guessed from the bisect
  bot name.

  Args:
    bisect_job: A TryJob entity.

  Returns:
    A dictionary containing the result; if successful, this dictionary contains
    the field "issue_id" and "issue_url", otherwise it contains "error".

  Raises:
    AssertionError: Bot or config not set as expected.
    request_handler.InvalidInputError: Some property of the bisect job
        is invalid.
  """
  assert bisect_job.bot and bisect_job.config
  if not bisect_job.key:
    bisect_job.put()

  if bisect_job.use_buildbucket:
    result = _PerformBuildbucketBisect(bisect_job)
  else:
    result = _PerformLegacyBisect(bisect_job)
  if 'error' in result:
    bisect_job.run_count += 1
    bisect_job.SetFailed()
    comment = 'Bisect job failed to kick off'
  elif result.get('issue_url'):
    comment = 'Started bisect job %s' % result['issue_url']
  else:
    comment = 'Started bisect job: %s' % result
  if bisect_job.bug_id:
    issue_tracker = issue_tracker_service.IssueTrackerService(
        additional_credentials=utils.ServiceAccountCredentials())
    issue_tracker.AddBugComment(bisect_job.bug_id, comment, send_email=False)
  return result
Example #17
0
    def get(self):
        """The get handler method is called from a cron job.

    It expects no parameters and has no output. It checks all current bisect try
    jobs and send comments to an issue on the issue tracker if a bisect job has
    completed.
    """
        credentials = rietveld_service.Credentials(
            rietveld_service.GetDefaultRietveldConfig(),
            rietveld_service.PROJECTHOSTING_SCOPE)
        issue_tracker = issue_tracker_service.IssueTrackerService(
            additional_credentials=credentials)

        # Set privilege so we can also fetch internal try_job entities.
        datastore_hooks.SetPrivilegedRequest()

        jobs_to_check = try_job.TryJob.query(
            try_job.TryJob.status == 'started').fetch()
        all_successful = True
        for job in jobs_to_check:
            try:
                if job.use_buildbucket:
                    logging.info('Checking job %s with Buildbucket job ID %s.',
                                 job.key.id(),
                                 getattr(job, 'buildbucket_job_id', None))
                else:
                    logging.info('Checking job %s with Rietveld issue ID %s.',
                                 job.key.id(),
                                 getattr(job, 'rietveld_issue_id', None))
                _CheckJob(job, issue_tracker)
            except Exception as e:  # pylint: disable=broad-except
                logging.error('Caught Exception %s: %s\n%s',
                              type(e).__name__, e, traceback.format_exc())
                all_successful = False
        if all_successful:
            utils.TickMonitoringCustomMetric('UpdateBugWithResults')
Example #18
0
 def testAddBugComment_WithNoBug_ReturnsFalse(self):
     service = issue_tracker_service.IssueTrackerService()
     service._MakeCommentRequest = mock.Mock()
     self.assertFalse(service.AddBugComment(None, 'Some comment'))
     self.assertFalse(service.AddBugComment(-1, 'Some comment'))
Example #19
0
 def testAddBugComment_Error(self, mock_logging_error):
     service = issue_tracker_service.IssueTrackerService()
     service._ExecuteRequest = mock.Mock(return_value=None)
     self.assertFalse(service.AddBugComment(12345, 'My bug comment'))
     self.assertEqual(1, service._ExecuteRequest.call_count)
     self.assertEqual(1, mock_logging_error.call_count)