def on_review_request_publishing(user, review_request_draft, **kwargs): # There have been strange cases (all local, and during development), where # when attempting to publish a review request, this handler will fail # because the draft does not exist. This is a really strange case, and not # one we expect to happen in production. However, since we've seen it # locally, we handle it here, and log. if not review_request_draft: logger.error('Strangely, there was no review request draft on the ' 'review request we were attempting to publish.') return # If the review request draft has a new DiffSet we will only allow # publishing if that DiffSet has been verified. It is important to # do this for every review request, not just pushed ones, because # we can't trust the storage mechanism which indicates it was pushed. # TODO: This will be fixed when we transition away from extra_data. if review_request_draft.diffset: try: DiffSetVerification.objects.get( diffset=review_request_draft.diffset) except DiffSetVerification.DoesNotExist: logger.error( 'An attempt was made by User %s to publish an unverified ' 'DiffSet with id %s', user.id, review_request_draft.diffset.id) raise PublishError( 'This review request draft contained a manually uploaded ' 'diff, which is prohibited. Please push to the review server ' 'to create review requests. If you believe you received this ' 'message in error, please file a bug.') review_request = review_request_draft.get_review_request() commit_data = fetch_commit_data(review_request) # skip review requests that were not pushed if not is_pushed(review_request, commit_data=commit_data): return if not is_parent(review_request, commit_data): # Send a signal asking for approval to publish this review request. # We only want to publish this commit request if we are in the middle # of publishing the parent. If the parent is publishing it will be # listening for this signal to approve it. approvals = commit_request_publishing.send_robust( sender=review_request, user=user, review_request_draft=review_request_draft) for receiver, approved in approvals: if approved: break else: # This publish is not approved by the parent review request. raise CommitPublishProhibited() # The reviewid passed through p2rb is, for Mozilla's instance anyway, # bz://<bug id>/<irc nick>. reviewid = commit_data.draft_extra_data.get(IDENTIFIER_KEY, None) m = REVIEWID_RE.match(reviewid) if not m: raise InvalidBugIdError('<unknown>') bug_id = m.group(1) try: bug_id = int(bug_id) except (TypeError, ValueError): raise InvalidBugIdError(bug_id) siteconfig = SiteConfiguration.objects.get_current() using_bugzilla = (siteconfig.settings.get("auth_backend", "builtin") == "bugzilla") if using_bugzilla: commit_data = fetch_commit_data(review_request_draft) publish_as_id = commit_data.draft_extra_data.get(PUBLISH_AS_KEY) if publish_as_id: u = User.objects.get(id=publish_as_id) b = Bugzilla(get_bugzilla_api_key(u)) else: b = Bugzilla(get_bugzilla_api_key(user)) try: if b.is_bug_confidential(bug_id): raise ConfidentialBugError except BugzillaError as e: # Special cases: # 100: Invalid Bug Alias # 101: Bug does not exist if e.fault_code and (e.fault_code == 100 or e.fault_code == 101): raise InvalidBugIdError(bug_id) raise # Note that the bug ID has already been set when the review was created. # If this is a squashed/parent review request, automatically publish all # relevant children. if is_parent(review_request, commit_data): unpublished_rids = map( int, json.loads(commit_data.extra_data[UNPUBLISHED_KEY])) discard_on_publish_rids = map( int, json.loads(commit_data.extra_data[DISCARD_ON_PUBLISH_KEY])) child_rrs = list(gen_child_rrs(review_request_draft)) # Create or update Bugzilla attachments for each draft commit. This # is done before the children are published to ensure that MozReview # doesn't get into a strange state if communication with Bugzilla is # broken or attachment creation otherwise fails. The Bugzilla # attachments will then, of course, be in a weird state, but that # should be fixed by the next successful publish. if using_bugzilla: children_to_post = [] children_to_obsolete = [] for child in child_rrs: child_draft = child.get_draft(user=user) if child_draft: if child.id in discard_on_publish_rids: children_to_obsolete.append(child) children_to_post.append((child_draft, child)) if children_to_post or children_to_obsolete: update_bugzilla_attachments(b, bug_id, children_to_post, children_to_obsolete) # Publish draft commits. This will already include items that are in # unpublished_rids, so we'll remove anything we publish out of # unpublished_rids. for child in child_rrs: if child.get_draft(user=user) or not child.public: def approve_publish(sender, user, review_request_draft, **kwargs): return child is sender # Setup the parent signal handler to approve the publish # and then publish the child. commit_request_publishing.connect(approve_publish, sender=child, weak=False) try: child.publish(user=user) except NotModifiedError: # As we create empty drafts as part of allowing reviewer # delegation, delete these empty drafts instead of # throwing an error. child.get_draft(user=user).delete() finally: commit_request_publishing.disconnect( receiver=approve_publish, sender=child, weak=False) if child.id in unpublished_rids: unpublished_rids.remove(child.id) # The remaining unpubished_rids need to be closed as discarded because # they have never been published, and they will appear in the user's # dashboard unless closed. for child in gen_rrs_by_rids(unpublished_rids): child.close(ReviewRequest.DISCARDED, user=user, description=NEVER_USED_DESCRIPTION) # We also close the discard_on_publish review requests because, well, # we don't need them anymore. We use a slightly different message # though. for child in gen_rrs_by_rids(discard_on_publish_rids): child.close(ReviewRequest.DISCARDED, user=user, description=OBSOLETE_DESCRIPTION) commit_data.extra_data[UNPUBLISHED_KEY] = '[]' commit_data.extra_data[DISCARD_ON_PUBLISH_KEY] = '[]' # Copy any drafted CommitData from draft_extra_data to extra_data. for key in DRAFTED_COMMIT_DATA_KEYS: if key in commit_data.draft_extra_data: commit_data.extra_data[key] = commit_data.draft_extra_data[key] commit_data.save(update_fields=['extra_data']) review_request.save()
def on_review_request_publishing(user, review_request_draft, **kwargs): # There have been strange cases (all local, and during development), where # when attempting to publish a review request, this handler will fail # because the draft does not exist. This is a really strange case, and not # one we expect to happen in production. However, since we've seen it # locally, we handle it here, and log. if not review_request_draft: logging.error('Strangely, there was no review request draft on the ' 'review request we were attempting to publish.') return review_request = review_request_draft.get_review_request() # skip review requests that were not pushed if not is_review_request_pushed(review_request): return if not is_parent(review_request): # Send a signal asking for approval to publish this review request. # We only want to publish this commit request if we are in the middle # of publishing the parent. If the parent is publishing it will be # listening for this signal to approve it. approvals = commit_request_publishing.send_robust( sender=review_request, user=user, review_request_draft=review_request_draft) for receiver, approved in approvals: if approved: break else: # This publish is not approved by the parent review request. raise CommitPublishProhibited() # The reviewid passed through p2rb is, for Mozilla's instance anyway, # bz://<bug id>/<irc nick>. reviewid = review_request_draft.extra_data.get('p2rb.identifier', None) m = REVIEWID_RE.match(reviewid) if not m: raise InvalidBugIdError('<unknown>') bug_id = m.group(1) using_bugzilla = we_are_using_bugzilla() try: bug_id = int(bug_id) except (TypeError, ValueError): raise InvalidBugIdError(bug_id) if using_bugzilla: b = Bugzilla(get_bugzilla_api_key(user)) try: if b.is_bug_confidential(bug_id): raise ConfidentialBugError except BugzillaError as e: # Special cases: # 100: Invalid Bug Alias # 101: Bug does not exist if e.fault_code and (e.fault_code == 100 or e.fault_code == 101): raise InvalidBugIdError(bug_id) raise # Note that the bug ID has already been set when the review was created. # If this is a squashed/parent review request, automatically publish all # relevant children. if is_review_request_squashed(review_request): unpublished_rids = map(int, json.loads( review_request.extra_data['p2rb.unpublished_rids'])) discard_on_publish_rids = map(int, json.loads( review_request.extra_data['p2rb.discard_on_publish_rids'])) child_rrs = list(gen_child_rrs(review_request_draft)) # Create or update Bugzilla attachments for each draft commit. This # is done before the children are published to ensure that MozReview # doesn't get into a strange state if communication with Bugzilla is # broken or attachment creation otherwise fails. The Bugzilla # attachments will then, of course, be in a weird state, but that # should be fixed by the next successful publish. if using_bugzilla: for child in child_rrs: child_draft = child.get_draft(user=user) if child_draft: if child.id in discard_on_publish_rids: b.obsolete_review_attachments( bug_id, get_obj_url(child)) post_bugzilla_attachment(b, bug_id, child_draft, child) # Publish draft commits. This will already include items that are in # unpublished_rids, so we'll remove anything we publish out of # unpublished_rids. for child in child_rrs: if child.get_draft(user=user) or not child.public: def approve_publish(sender, user, review_request_draft, **kwargs): return child is sender # Setup the parent signal handler to approve the publish # and then publish the child. commit_request_publishing.connect(approve_publish, sender=child, weak=False) try: child.publish(user=user) finally: commit_request_publishing.disconnect( receiver=approve_publish, sender=child, weak=False) if child.id in unpublished_rids: unpublished_rids.remove(child.id) # The remaining unpubished_rids need to be closed as discarded because # they have never been published, and they will appear in the user's # dashboard unless closed. for child in gen_rrs_by_rids(unpublished_rids): child.close(ReviewRequest.DISCARDED, user=user, description=NEVER_USED_DESCRIPTION) # We also close the discard_on_publish review requests because, well, # we don't need them anymore. We use a slightly different message # though. for child in gen_rrs_by_rids(discard_on_publish_rids): child.close(ReviewRequest.DISCARDED, user=user, description=OBSOLETE_DESCRIPTION) review_request.extra_data['p2rb.unpublished_rids'] = '[]' review_request.extra_data['p2rb.discard_on_publish_rids'] = '[]' # Copy p2rb extra data from the draft, overwriting the current # values on the review request. draft_extra_data = review_request_draft.extra_data for key in DRAFTED_EXTRA_DATA_KEYS: if key in draft_extra_data: review_request.extra_data[key] = draft_extra_data[key] review_request.save()
def on_review_request_publishing(user, review_request_draft, **kwargs): # There have been strange cases (all local, and during development), where # when attempting to publish a review request, this handler will fail # because the draft does not exist. This is a really strange case, and not # one we expect to happen in production. However, since we've seen it # locally, we handle it here, and log. if not review_request_draft: logger.error('Strangely, there was no review request draft on the ' 'review request we were attempting to publish.') return # If the review request draft has a new DiffSet we will only allow # publishing if that DiffSet has been verified. It is important to # do this for every review request, not just pushed ones, because # we can't trust the storage mechanism which indicates it was pushed. # TODO: This will be fixed when we transition away from extra_data. if review_request_draft.diffset: try: DiffSetVerification.objects.get( diffset=review_request_draft.diffset) except DiffSetVerification.DoesNotExist: logger.error( 'An attempt was made by User %s to publish an unverified ' 'DiffSet with id %s', user.id, review_request_draft.diffset.id) raise PublishError( 'This review request draft contained a manually uploaded ' 'diff, which is prohibited. Please push to the review server ' 'to create review requests. If you believe you received this ' 'message in error, please file a bug.') review_request = review_request_draft.get_review_request() commit_data = fetch_commit_data(review_request) # skip review requests that were not pushed if not is_pushed(review_request, commit_data=commit_data): return if not is_parent(review_request, commit_data): # Send a signal asking for approval to publish this review request. # We only want to publish this commit request if we are in the middle # of publishing the parent. If the parent is publishing it will be # listening for this signal to approve it. approvals = commit_request_publishing.send_robust( sender=review_request, user=user, review_request_draft=review_request_draft) for receiver, approved in approvals: if approved: break else: # This publish is not approved by the parent review request. raise CommitPublishProhibited() # The reviewid passed through p2rb is, for Mozilla's instance anyway, # bz://<bug id>/<irc nick>. reviewid = commit_data.draft_extra_data.get(IDENTIFIER_KEY, None) m = REVIEWID_RE.match(reviewid) if not m: raise InvalidBugIdError('<unknown>') bug_id = m.group(1) try: bug_id = int(bug_id) except (TypeError, ValueError): raise InvalidBugIdError(bug_id) siteconfig = SiteConfiguration.objects.get_current() using_bugzilla = ( siteconfig.settings.get("auth_backend", "builtin") == "bugzilla") if using_bugzilla: b = Bugzilla(get_bugzilla_api_key(user)) try: if b.is_bug_confidential(bug_id): raise ConfidentialBugError except BugzillaError as e: # Special cases: # 100: Invalid Bug Alias # 101: Bug does not exist if e.fault_code and (e.fault_code == 100 or e.fault_code == 101): raise InvalidBugIdError(bug_id) raise # Note that the bug ID has already been set when the review was created. # If this is a squashed/parent review request, automatically publish all # relevant children. if is_parent(review_request, commit_data): unpublished_rids = map(int, json.loads( commit_data.extra_data[UNPUBLISHED_KEY])) discard_on_publish_rids = map(int, json.loads( commit_data.extra_data[DISCARD_ON_PUBLISH_KEY])) child_rrs = list(gen_child_rrs(review_request_draft)) # Create or update Bugzilla attachments for each draft commit. This # is done before the children are published to ensure that MozReview # doesn't get into a strange state if communication with Bugzilla is # broken or attachment creation otherwise fails. The Bugzilla # attachments will then, of course, be in a weird state, but that # should be fixed by the next successful publish. if using_bugzilla: for child in child_rrs: child_draft = child.get_draft(user=user) if child_draft: if child.id in discard_on_publish_rids: b.obsolete_review_attachments( bug_id, get_obj_url(child)) post_bugzilla_attachment(b, bug_id, child_draft, child) # Publish draft commits. This will already include items that are in # unpublished_rids, so we'll remove anything we publish out of # unpublished_rids. for child in child_rrs: if child.get_draft(user=user) or not child.public: def approve_publish(sender, user, review_request_draft, **kwargs): return child is sender # Setup the parent signal handler to approve the publish # and then publish the child. commit_request_publishing.connect(approve_publish, sender=child, weak=False) try: child.publish(user=user) finally: commit_request_publishing.disconnect( receiver=approve_publish, sender=child, weak=False) if child.id in unpublished_rids: unpublished_rids.remove(child.id) # The remaining unpubished_rids need to be closed as discarded because # they have never been published, and they will appear in the user's # dashboard unless closed. for child in gen_rrs_by_rids(unpublished_rids): child.close(ReviewRequest.DISCARDED, user=user, description=NEVER_USED_DESCRIPTION) # We also close the discard_on_publish review requests because, well, # we don't need them anymore. We use a slightly different message # though. for child in gen_rrs_by_rids(discard_on_publish_rids): child.close(ReviewRequest.DISCARDED, user=user, description=OBSOLETE_DESCRIPTION) commit_data.extra_data[UNPUBLISHED_KEY] = '[]' commit_data.extra_data[DISCARD_ON_PUBLISH_KEY] = '[]' # Copy any drafted CommitData from draft_extra_data to extra_data. for key in DRAFTED_COMMIT_DATA_KEYS: if key in commit_data.draft_extra_data: commit_data.extra_data[key] = commit_data.draft_extra_data[key] commit_data.save(update_fields=['extra_data']) review_request.save()