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']])
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')
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')
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, }