Example #1
0
 def test_schedule(self):
   put_builds_response = {
     'results': [
       {
         'build': {'id': '1'},
       },
       {
         'build': {'id': '1'},
       },
     ]
   }
   self.fake_responses = [
     {'delegation_token': 'deltok', 'validity_duration': 1000},
     put_builds_response,
   ]
   issue = models.Issue(
       id='123',
       project='chromium',
       owner=users.User(email='*****@*****.**'),
   )
   builds = buildbucket.schedule(issue, '1', [
       ('tryserver.chromium.linux', 'linux_rel'),
       ('tryserver.chromium.linux', 'win_rel'),
   ])
   self.assertEqual(
       builds, [r['build'] for r in put_builds_response['results']])
Example #2
0
 def test_schedule(self):
   put_builds_response = {
     'results': [
       {
         'build': {'id': '1'},
       },
       {
         'build': {'id': '1'},
       },
     ]
   }
   self.fake_responses = [
     {'token': 'deltok', 'delegationSubtoken': {'validityDuration': 18000}},
     put_builds_response,
   ]
   issue = models.Issue(
       id='123',
       project='chromium',
       owner=users.User(email='*****@*****.**'),
   )
   builds = buildbucket.schedule(issue, '1', [
       {'bucket': 'master.tryserver.chromium.linux', 'builder': 'linux_rel'},
       {'bucket': 'master.tryserver.chromium.linux', 'builder': 'linux_debug'},
   ])
   self.assertEqual(
       builds, [r['build'] for r in put_builds_response['results']])
def try_patchset(request):
  """/<issue>/try/<patchset> - Add a try job for the given patchset."""
  # Only allow trying the last patchset of an issue.
  last_patchset_key = models.PatchSet.query(ancestor=request.issue.key).order(
    -models.PatchSet.created).get(keys_only=True)
  if last_patchset_key != request.patchset.key:
    content = (
        'Patchset %d/%d invalid: Can only try the last patchset of an issue.' %
        (request.issue.key.id(), request.patchset.key.id()))
    logging.info(content)
    return HttpResponseBadRequest(content, content_type='text/plain')

  form = TryPatchSetForm(request.POST)
  if not form.is_valid():
    return HttpResponseBadRequest('Invalid POST arguments',
                                  content_type='text/plain')
  reason = form.cleaned_data['reason']
  revision = form.cleaned_data['revision']
  clobber = form.cleaned_data['clobber']
  master = form.cleaned_data['master']
  category = form.cleaned_data.get('category', 'cq')

  try:
    builders = json.loads(form.cleaned_data['builders'])
  except json.JSONDecodeError:
    content = 'Invalid json for builder spec: ' + form.cleaned_data['builders']
    logging.error(content)
    return HttpResponseBadRequest(content, content_type='text/plain')

  if not isinstance(builders, dict):
    content = 'Invalid builder spec: ' + form.cleaned_data['builders']
    logging.error(content)
    return HttpResponseBadRequest(content, content_type='text/plain')

  logging.debug(
      'clobber=%s\nrevision=%s\nreason=%s\nmaster=%s\nbuilders=%s\category=%s',
      clobber, revision, reason, master, builders, category)

  builds = []
  for builder, tests in builders.iteritems():
    props = {
      'reason': reason,
      'testfilter': tests,
    }
    if clobber:
      # clobber property is checked for presence. Its value is ignored.
      props['clobber'] = True
    builds.append({
      'bucket': 'master.%s' % master,
      'builder': builder,
      'category': category,
      'properties': props,
      'revision': revision,
    })

  scheduled_builds = buildbucket.schedule(
      request.issue, request.patchset.key.id(), builds)
  logging.info('Started %d jobs: %r', len(scheduled_builds), scheduled_builds)
  return {
    'jobs': scheduled_builds,
  }
def edit_flags(request):
  """/<issue>/edit_flags - Edit issue's flags."""
  last_patchset = models.PatchSet.query(ancestor=request.issue.key).order(
    -models.PatchSet.created).get()
  if not last_patchset:
    return HttpResponseForbidden('Can only modify flags on last patchset',
        content_type='text/plain')
  if request.issue.closed:
    return HttpResponseForbidden('Can not modify flags for a closed issue',
        content_type='text/plain')

  if request.method == 'GET':
    # TODO(maruel): Have it set per project.
    initial_builders = 'win_rel, mac_rel, linux_rel'
    form = EditFlagsForm(initial={
        'last_patchset': last_patchset.key.id(),
        'commit': request.issue.commit,
        'builders': initial_builders})

    return responses.respond(request,
                         'edit_flags.html',
                         {'issue': request.issue, 'form': form})

  form = EditFlagsForm(request.POST)
  if not form.is_valid():
    return HttpResponseBadRequest('Invalid POST arguments',
        content_type='text/plain')
  if (form.cleaned_data['last_patchset'] != last_patchset.key.id()):
    return HttpResponseForbidden('Can only modify flags on last patchset',
        content_type='text/plain')

  if 'commit' in request.POST:
    if request.issue.private and form.cleaned_data['commit'] :
      return HttpResponseBadRequest(
        'Cannot set commit on private issues', content_type='text/plain')
    if not request.issue.is_cq_available and form.cleaned_data['commit']:
      return HttpResponseBadRequest(
        'Cannot set commit on an issue that does not have a commit queue',
        content_type='text/plain')
    request.issue.commit = form.cleaned_data['commit']
    request.issue.cq_dry_run = form.cleaned_data['cq_dry_run']
    user_email = request.user.email().lower()
    if user_email == views.CQ_SERVICE_ACCOUNT:
      user_email = views.CQ_COMMIT_BOT_EMAIL
    if (request.issue.commit and  # Add as reviewer if setting, not clearing.
        user_email != request.issue.owner.email() and
        user_email not in request.issue.reviewers and
        user_email not in request.issue.collaborator_emails()):
      request.issue.reviewers.append(request.user.email())
    # Update the issue with the checking/unchecking of the CQ box but reduce
    # spam by not emailing users.
    action = 'checked' if request.issue.commit else 'unchecked'
    commit_checked_msg = 'The CQ bit was %s by %s' % (action, user_email)
    if request.issue.cq_dry_run:
      commit_checked_msg += ' to run a CQ dry run'
      request.issue.cq_dry_run_last_triggered_by = user_email
      logging.info('CQ dry run has been triggered by %s for %d/%d', user_email,
                   request.issue.key.id(), last_patchset.key.id())
    # Mail just the owner and only if the CQ bit was unchecked by someone other
    # than the owner or CQ itself. More details in
    # https://code.google.com/p/skia/issues/detail?id=3093
    send_mail = (user_email != request.issue.owner.email() and
                 user_email != views.CQ_COMMIT_BOT_EMAIL and
                 not request.issue.commit)
    views.make_message(request, request.issue, commit_checked_msg,
                       send_mail=send_mail, auto_generated=True,
                       email_to=[request.issue.owner.email()]).put()
    request.issue.put()
    if request.issue.commit and not request.issue.cq_dry_run:
      views.notify_approvers_of_new_patchsets(request, request.issue)

  if 'builders' in request.POST:
    new_builders = filter(None, map(unicode.strip,
                                    form.cleaned_data['builders'].split(',')))
    if request.issue.private and new_builders:
      return HttpResponseBadRequest(
        'Cannot add trybots on private issues', content_type='text/plain')

    builds = []
    for b in new_builders:
      bucket, builder = b.split(':', 1)
      builds.append({
        'bucket': bucket,
        'builder': builder,
      })
    buildbucket.schedule(request.issue, last_patchset.key.id(), builds)
  return HttpResponse('OK', content_type='text/plain')
Example #5
0
def edit_flags(request):
  """/<issue>/edit_flags - Edit issue's flags."""
  last_patchset = models.PatchSet.query(ancestor=request.issue.key).order(
    -models.PatchSet.created).get()
  if not last_patchset:
    return HttpResponseForbidden('Can only modify flags on last patchset',
        content_type='text/plain')
  if request.issue.closed:
    return HttpResponseForbidden('Can not modify flags for a closed issue',
        content_type='text/plain')

  if request.method == 'GET':
    # TODO(maruel): Have it set per project.
    initial_builders = 'win_rel, mac_rel, linux_rel'
    form = EditFlagsForm(initial={
        'last_patchset': last_patchset.key.id(),
        'commit': request.issue.commit,
        'builders': initial_builders})

    return responses.respond(request,
                         'edit_flags.html',
                         {'issue': request.issue, 'form': form})

  form = EditFlagsForm(request.POST)
  if not form.is_valid():
    return HttpResponseBadRequest('Invalid POST arguments',
        content_type='text/plain')
  if (form.cleaned_data['last_patchset'] != last_patchset.key.id()):
    return HttpResponseForbidden('Can only modify flags on last patchset',
        content_type='text/plain')

  if 'commit' in request.POST:
    if request.issue.private and form.cleaned_data['commit'] :
      return HttpResponseBadRequest(
        'Cannot set commit on private issues', content_type='text/plain')
    request.issue.commit = form.cleaned_data['commit']
    request.issue.cq_dry_run = form.cleaned_data['cq_dry_run']
    user_email = request.user.email().lower()
    if user_email == views.CQ_SERVICE_ACCOUNT:
      user_email = views.CQ_COMMIT_BOT_EMAIL
    if (request.issue.commit and  # Add as reviewer if setting, not clearing.
        user_email != request.issue.owner.email() and
        user_email not in request.issue.reviewers and
        user_email not in request.issue.collaborator_emails()):
      request.issue.reviewers.append(request.user.email())
    # Update the issue with the checking/unchecking of the CQ box but reduce
    # spam by not emailing users.
    action = 'checked' if request.issue.commit else 'unchecked'
    commit_checked_msg = 'The CQ bit was %s by %s' % (action, user_email)
    if request.issue.cq_dry_run:
      commit_checked_msg += ' to run a CQ dry run'
      request.issue.cq_dry_run_last_triggered_by = user_email
      logging.info('CQ dry run has been triggered by %s for %d/%d', user_email,
                   request.issue.key.id(), last_patchset.key.id())
    # Mail just the owner if the CQ bit was unchecked by someone other than the
    # owner. More details in
    # https://code.google.com/p/skia/issues/detail?id=3093
    unchecked_by_non_owner = (user_email != request.issue.owner.email() and
                              not request.issue.commit)
    views.make_message(request, request.issue, commit_checked_msg,
                       send_mail=unchecked_by_non_owner, auto_generated=True,
                       email_to=[request.issue.owner.email()]).put()
    request.issue.put()
    if request.issue.commit and not request.issue.cq_dry_run:
      views.notify_approvers_of_new_patchsets(request, request.issue)

  if 'builders' in request.POST:
    new_builders = filter(None, map(unicode.strip,
                                    form.cleaned_data['builders'].split(',')))
    if request.issue.private and new_builders:
      return HttpResponseBadRequest(
        'Cannot add trybots on private issues', content_type='text/plain')

  buildbucket.schedule(
      request.issue,
      last_patchset.key.id(),
      [b.split(':', 1) for b in new_builders])

  return HttpResponse('OK', content_type='text/plain')
Example #6
0
def try_patchset(request):
  """/<issue>/try/<patchset> - Add a try job for the given patchset."""
  # Only allow trying the last patchset of an issue.
  last_patchset_key = models.PatchSet.query(ancestor=request.issue.key).order(
    -models.PatchSet.created).get(keys_only=True)
  if last_patchset_key != request.patchset.key:
    content = (
        'Patchset %d/%d invalid: Can only try the last patchset of an issue.' %
        (request.issue.key.id(), request.patchset.key.id()))
    logging.info(content)
    return HttpResponseBadRequest(content, content_type='text/plain')

  form = TryPatchSetForm(request.POST)
  if not form.is_valid():
    return HttpResponseBadRequest('Invalid POST arguments',
                                  content_type='text/plain')
  reason = form.cleaned_data['reason']
  revision = form.cleaned_data['revision']
  clobber = form.cleaned_data['clobber']
  master = form.cleaned_data['master']
  category = form.cleaned_data.get('category', 'cq')

  try:
    builders = json.loads(form.cleaned_data['builders'])
  except json.JSONDecodeError:
    content = 'Invalid json for builder spec: ' + form.cleaned_data['builders']
    logging.error(content)
    return HttpResponseBadRequest(content, content_type='text/plain')

  if not isinstance(builders, dict):
    content = 'Invalid builder spec: ' + form.cleaned_data['builders']
    logging.error(content)
    return HttpResponseBadRequest(content, content_type='text/plain')

  logging.debug(
      'clobber=%s\nrevision=%s\nreason=%s\nmaster=%s\nbuilders=%s\category=%s',
      clobber, revision, reason, master, builders, category)

  builds = []
  for builder, tests in builders.iteritems():
    props = {
      'reason': reason,
      'testfilter': tests,
    }
    if clobber:
      # clobber property is checked for presence. Its value is ignored.
      props['clobber'] = True
    builds.append({
      'builder': builder,
      'category': category,
      'master': master,
      'properties': props,
      'revision': revision,
    })

  scheduled_builds = buildbucket.schedule(
      request.issue, request.patchset.key.id(), builds)
  logging.info('Started %d jobs: %r', len(scheduled_builds), scheduled_builds)
  return {
    'jobs': scheduled_builds,
  }