def createReview(db, user, repository, commits, branch_name, summary, description, from_branch_name=None, via_push=False, reviewfilters=None, applyfilters=True, applyparentfilters=False, recipientfilters=None): cursor = db.cursor() if via_push: applyparentfilters = bool(user.getPreference(db, 'review.applyUpstreamFilters')) branch = dbutils.Branch.fromName(db, repository, branch_name) if branch is not None: raise OperationFailure( code="branchexists", title="Invalid review branch name", message="""\ <p>There is already a branch named <code>%s</code> in the repository. You have to select a different name.</p> <p>If you believe the existing branch was created during an earlier (failed) attempt to create this review, you can try to delete it from the repository using the command<p> <pre> git push <remote> :%s</pre> <p>and then press the "Submit Review" button on this page again.""" % (htmlutils.htmlify(branch_name), htmlutils.htmlify(branch_name)), is_html=True) if not commits: raise OperationFailure( code="nocommits", title="No commits specified", message="You need at least one commit to create a review.") commitset = log_commitset.CommitSet(commits) heads = commitset.getHeads() if len(heads) != 1: # There is really no plausible way for this error to occur. raise OperationFailure( code="disconnectedtree", title="Disconnected tree", message=("The specified commits do do not form a single connected " "tree. Creating a review of them is not supported.")) head = heads.pop() if len(commitset.getTails()) != 1: tail_id = None else: tail_id = gitutils.Commit.fromSHA1(db, repository, commitset.getTails().pop()).getId(db) if not via_push: try: repository.createBranch(branch_name, head.sha1) except gitutils.GitCommandError as error: raise OperationFailure( code="branchfailed", title="Failed to create review branch", message=("<p><b>Output from git:</b></p>" "<code style='padding-left: 1em'>%s</code>" % htmlutils.htmlify(error.output)), is_html=True) try: cursor.execute("INSERT INTO branches (repository, name, head, tail, type) VALUES (%s, %s, %s, %s, 'review') RETURNING id", [repository.id, branch_name, head.getId(db), tail_id]) branch_id = cursor.fetchone()[0] reachable_values = [(branch_id, commit.getId(db)) for commit in commits] cursor.executemany("INSERT INTO reachable (branch, commit) VALUES (%s, %s)", reachable_values) cursor.execute("INSERT INTO reviews (type, branch, state, summary, description, applyfilters, applyparentfilters) VALUES ('official', %s, 'open', %s, %s, %s, %s) RETURNING id", (branch_id, summary, description, applyfilters, applyparentfilters)) review = dbutils.Review.fromId(db, cursor.fetchone()[0]) cursor.execute("INSERT INTO reviewusers (review, uid, owner) VALUES (%s, %s, TRUE)", (review.id, user.id)) if reviewfilters is not None: cursor.executemany("""INSERT INTO reviewfilters (review, uid, path, type, creator) VALUES (%s, %s, %s, %s, %s)""", [(review.id, filter_user_id, filter_path, filter_type, user.id) for filter_user_id, filter_path, filter_type, filter_delegate in reviewfilters]) is_opt_in = False if recipientfilters is not None: cursor.executemany("INSERT INTO reviewrecipientfilters (review, uid, include) VALUES (%s, %s, %s)", [(review.id, filter_user_id, filter_include) for filter_user_id, filter_include in recipientfilters]) for filter_user_id, filter_include in recipientfilters: if filter_user_id is None and not filter_include: is_opt_in = True addCommitsToReview(db, user, review, commits, new_review=True) if from_branch_name is not None: cursor.execute("UPDATE branches SET review=%s WHERE repository=%s AND name=%s", (review.id, repository.id, from_branch_name)) # Reload to get list of changesets added by addCommitsToReview(). review = dbutils.Review.fromId(db, review.id) pending_mails = [] recipients = review.getRecipients(db) for to_user in recipients: pending_mails.extend(mail.sendReviewCreated(db, user, to_user, recipients, review)) if not is_opt_in: recipient_by_id = dict((to_user.id, to_user) for to_user in recipients) cursor.execute("""SELECT userpreferences.uid, userpreferences.repository, userpreferences.filter, userpreferences.integer FROM userpreferences LEFT OUTER JOIN filters ON (filters.id=userpreferences.filter) WHERE userpreferences.item='review.defaultOptOut' AND userpreferences.uid=ANY (%s) AND (userpreferences.filter IS NULL OR filters.repository=%s) AND (userpreferences.repository IS NULL OR userpreferences.repository=%s)""", (recipient_by_id.keys(), repository.id, repository.id)) user_settings = {} has_filter_settings = False for user_id, repository_id, filter_id, integer in cursor: settings = user_settings.setdefault(user_id, [None, None, {}]) value = bool(integer) if repository_id is None and filter_id is None: settings[0] = value elif repository_id is not None: settings[1] = value else: settings[2][filter_id] = value has_filter_settings = True if has_filter_settings: filters = Filters() filters.setFiles(db, review=review) for user_id, (global_default, repository_default, filter_settings) in user_settings.items(): to_user = recipient_by_id[user_id] opt_out = None if repository_default is not None: opt_out = repository_default elif global_default is not None: opt_out = global_default if filter_settings: # Policy: # # If all of the user's filters that matched files in the # review have review.defaultOptOut enabled, then opt out. # When determining this, any review filters of the user's # that match files in the review count as filters that don't # have the review.defaultOptOut enabled. # # If any of the user's filters that matched files in the # review have review.defaultOptOut disabled, then don't opt # out. When determining this, review filters are ignored. # # Otherwise, ignore the filter settings, and go with either # the user's per-repository or global setting (as set # above.) filters.load(db, review=review, user=to_user) # A set of filter ids. If None is in the set, the user has # one or more review filters in the review. (These do not # have ids.) active_filters = filters.getActiveFilters(to_user) for filter_id in active_filters: if filter_id is None: continue elif filter_id in filter_settings: if not filter_settings[filter_id]: opt_out = False break else: break else: if None not in active_filters: opt_out = True if opt_out: cursor.execute("""INSERT INTO reviewrecipientfilters (review, uid, include) VALUES (%s, %s, FALSE)""", (review.id, to_user.id)) db.commit() mail.sendPendingMails(pending_mails) return review except: if not via_push: repository.run("branch", "-D", branch_name) raise
def createReview(db, user, repository, commits, branch_name, summary, description, from_branch_name=None, via_push=False, reviewfilters=None, applyfilters=True, applyparentfilters=False, recipientfilters=None): cursor = db.cursor() if via_push: applyparentfilters = bool(user.getPreference(db, 'review.applyUpstreamFilters')) branch = dbutils.Branch.fromName(db, repository, branch_name) if branch is not None: raise OperationFailure(code="branchexists", title="Invalid review branch name", message="""\ <p>There is already a branch named <code>%s</code> in the repository. You have to select a different name.</p> <p>If you believe the existing branch was created during an earlier (failed) attempt to create this review, you can try to delete it from the repository using the command<p> <pre> git push <remote> :%s</pre> <p>and then press the "Submit Review" button on this page again.""" % (htmlutils.htmlify(branch_name), htmlutils.htmlify(branch_name)), is_html=True) commitset = log_commitset.CommitSet(commits) if len(commitset.getHeads()) != 1: raise Exception, "invalid commit-set; multiple heads" head = commitset.getHeads().pop() if len(commitset.getTails()) != 1: tail_id = None else: tail_id = gitutils.Commit.fromSHA1(db, repository, commitset.getTails().pop()).getId(db) if not via_push: repository.branch(branch_name, head.sha1) try: cursor.execute("INSERT INTO branches (repository, name, head, tail, type) VALUES (%s, %s, %s, %s, 'review') RETURNING id", [repository.id, branch_name, head.getId(db), tail_id]) branch_id = cursor.fetchone()[0] reachable_values = [(branch_id, commit.getId(db)) for commit in commits] cursor.executemany("INSERT INTO reachable (branch, commit) VALUES (%s, %s)", reachable_values) cursor.execute("INSERT INTO reviews (type, branch, state, summary, description, applyfilters, applyparentfilters) VALUES ('official', %s, 'open', %s, %s, %s, %s) RETURNING id", (branch_id, summary, description, applyfilters, applyparentfilters)) review = dbutils.Review.fromId(db, cursor.fetchone()[0]) cursor.execute("INSERT INTO reviewusers (review, uid, owner) VALUES (%s, %s, TRUE)", (review.id, user.id)) if reviewfilters is not None: cursor.executemany("INSERT INTO reviewfilters (review, uid, directory, file, type, creator) VALUES (%s, %s, %s, %s, %s, %s)", [(review.id, filter_user_id, filter_directory_id, filter_file_id, filter_type, user.id) for filter_directory_id, filter_file_id, filter_type, filter_delegate, filter_user_id in reviewfilters]) if recipientfilters is not None: cursor.executemany("INSERT INTO reviewrecipientfilters (review, uid, include) VALUES (%s, %s, %s)", [(review.id, filter_user_id, filter_include) for filter_user_id, filter_include in recipientfilters]) addCommitsToReview(db, user, review, commits, new_review=True) if from_branch_name is not None: cursor.execute("UPDATE branches SET review=%s WHERE repository=%s AND name=%s", (review.id, repository.id, from_branch_name)) # Reload to get list of changesets added by addCommitsToReview(). review = dbutils.Review.fromId(db, review.id) pending_mails = [] recipients = review.getRecipients(db) for to_user in recipients: pending_mails.extend(mail.sendReviewCreated(db, user, to_user, recipients, review)) db.commit() mail.sendPendingMails(pending_mails) return review except: if not via_push: repository.run("branch", "-D", branch_name) raise
def createReview( db, user, repository, commits, branch_name, summary, description, from_branch_name=None, via_push=False, reviewfilters=None, applyfilters=True, applyparentfilters=False, recipientfilters=None, ): cursor = db.cursor() if via_push: applyparentfilters = bool(user.getPreference(db, "review.applyUpstreamFilters")) branch = dbutils.Branch.fromName(db, repository, branch_name) if branch is not None: raise OperationFailure( code="branchexists", title="Invalid review branch name", message="""\ <p>There is already a branch named <code>%s</code> in the repository. You have to select a different name.</p> <p>If you believe the existing branch was created during an earlier (failed) attempt to create this review, you can try to delete it from the repository using the command<p> <pre> git push <remote> :%s</pre> <p>and then press the "Submit Review" button on this page again.""" % (htmlutils.htmlify(branch_name), htmlutils.htmlify(branch_name)), is_html=True, ) if not commits: raise OperationFailure( code="nocommits", title="No commits specified", message="You need at least one commit to create a review." ) commitset = log_commitset.CommitSet(commits) heads = commitset.getHeads() if len(heads) != 1: # There is really no plausible way for this error to occur. raise OperationFailure( code="disconnectedtree", title="Disconnected tree", message=( "The specified commits do do not form a single connected " "tree. Creating a review of them is not supported." ), ) head = heads.pop() if len(commitset.getTails()) != 1: tail_id = None else: tail_id = gitutils.Commit.fromSHA1(db, repository, commitset.getTails().pop()).getId(db) if not via_push: try: repository.createBranch(branch_name, head.sha1) except gitutils.GitCommandError as error: raise OperationFailure( code="branchfailed", title="Failed to create review branch", message=( "<p><b>Output from git:</b></p>" "<code style='padding-left: 1em'>%s</code>" % htmlutils.htmlify(error.output) ), is_html=True, ) try: cursor.execute( "INSERT INTO branches (repository, name, head, tail, type) VALUES (%s, %s, %s, %s, 'review') RETURNING id", [repository.id, branch_name, head.getId(db), tail_id], ) branch_id = cursor.fetchone()[0] reachable_values = [(branch_id, commit.getId(db)) for commit in commits] cursor.executemany("INSERT INTO reachable (branch, commit) VALUES (%s, %s)", reachable_values) cursor.execute( "INSERT INTO reviews (type, branch, state, summary, description, applyfilters, applyparentfilters) VALUES ('official', %s, 'open', %s, %s, %s, %s) RETURNING id", (branch_id, summary, description, applyfilters, applyparentfilters), ) review = dbutils.Review.fromId(db, cursor.fetchone()[0]) cursor.execute("INSERT INTO reviewusers (review, uid, owner) VALUES (%s, %s, TRUE)", (review.id, user.id)) if reviewfilters is not None: cursor.executemany( """INSERT INTO reviewfilters (review, uid, path, type, creator) VALUES (%s, %s, %s, %s, %s)""", [ (review.id, filter_user_id, filter_path, filter_type, user.id) for filter_user_id, filter_path, filter_type, filter_delegate in reviewfilters ], ) is_opt_in = False if recipientfilters is not None: cursor.executemany( "INSERT INTO reviewrecipientfilters (review, uid, include) VALUES (%s, %s, %s)", [(review.id, filter_user_id, filter_include) for filter_user_id, filter_include in recipientfilters], ) for filter_user_id, filter_include in recipientfilters: if filter_user_id is None and not filter_include: is_opt_in = True addCommitsToReview(db, user, review, commits, new_review=True) if from_branch_name is not None: cursor.execute( "UPDATE branches SET review=%s WHERE repository=%s AND name=%s", (review.id, repository.id, from_branch_name), ) # Reload to get list of changesets added by addCommitsToReview(). review = dbutils.Review.fromId(db, review.id) pending_mails = [] recipients = review.getRecipients(db) for to_user in recipients: pending_mails.extend(mail.sendReviewCreated(db, user, to_user, recipients, review)) if not is_opt_in and to_user.getPreference(db, "review.defaultOptOut"): cursor.execute( "INSERT INTO reviewrecipientfilters (review, uid, include) VALUES (%s, %s, FALSE)", (review.id, to_user.id), ) db.commit() mail.sendPendingMails(pending_mails) return review except: if not via_push: repository.run("branch", "-D", branch_name) raise
def createReview(db, user, repository, commits, branch_name, summary, description, from_branch_name=None, via_push=False, reviewfilters=None, applyfilters=True, applyparentfilters=False, recipientfilters=None): cursor = db.cursor() if via_push: applyparentfilters = bool( user.getPreference(db, 'review.applyUpstreamFilters')) branch = dbutils.Branch.fromName(db, repository, branch_name) if branch is not None: raise OperationFailure( code="branchexists", title="Invalid review branch name", message="""\ <p>There is already a branch named <code>%s</code> in the repository. You have to select a different name.</p> <p>If you believe the existing branch was created during an earlier (failed) attempt to create this review, you can try to delete it from the repository using the command<p> <pre> git push <remote> :%s</pre> <p>and then press the "Submit Review" button on this page again.""" % (htmlutils.htmlify(branch_name), htmlutils.htmlify(branch_name)), is_html=True) if not commits: raise OperationFailure( code="nocommits", title="No commits specified", message="You need at least one commit to create a review.") commitset = log_commitset.CommitSet(commits) heads = commitset.getHeads() if len(heads) != 1: # There is really no plausible way for this error to occur. raise OperationFailure( code="disconnectedtree", title="Disconnected tree", message=("The specified commits do do not form a single connected " "tree. Creating a review of them is not supported.")) head = heads.pop() if len(commitset.getTails()) != 1: tail_id = None else: tail_id = gitutils.Commit.fromSHA1( db, repository, commitset.getTails().pop()).getId(db) if not via_push: try: repository.createBranch(branch_name, head.sha1) except gitutils.GitCommandError as error: raise OperationFailure( code="branchfailed", title="Failed to create review branch", message=("<p><b>Output from git:</b></p>" "<code style='padding-left: 1em'>%s</code>" % htmlutils.htmlify(error.output)), is_html=True) createChangesetsForCommits(db, commits) try: cursor.execute( "INSERT INTO branches (repository, name, head, tail, type) VALUES (%s, %s, %s, %s, 'review') RETURNING id", [repository.id, branch_name, head.getId(db), tail_id]) branch_id = cursor.fetchone()[0] reachable_values = [(branch_id, commit.getId(db)) for commit in commits] cursor.executemany( "INSERT INTO reachable (branch, commit) VALUES (%s, %s)", reachable_values) cursor.execute( "INSERT INTO reviews (type, branch, state, summary, description, applyfilters, applyparentfilters) VALUES ('official', %s, 'open', %s, %s, %s, %s) RETURNING id", (branch_id, summary, description, applyfilters, applyparentfilters)) review = dbutils.Review.fromId(db, cursor.fetchone()[0]) cursor.execute( "INSERT INTO reviewusers (review, uid, owner) VALUES (%s, %s, TRUE)", (review.id, user.id)) if reviewfilters is not None: cursor.executemany( """INSERT INTO reviewfilters (review, uid, path, type, creator) VALUES (%s, %s, %s, %s, %s)""", [(review.id, filter_user_id, filter_path, filter_type, user.id) for filter_user_id, filter_path, filter_type, filter_delegate in reviewfilters]) is_opt_in = False if recipientfilters is not None: cursor.executemany( "INSERT INTO reviewrecipientfilters (review, uid, include) VALUES (%s, %s, %s)", [(review.id, filter_user_id, filter_include) for filter_user_id, filter_include in recipientfilters]) for filter_user_id, filter_include in recipientfilters: if filter_user_id is None and not filter_include: is_opt_in = True addCommitsToReview(db, user, review, commits, new_review=True) if from_branch_name is not None: cursor.execute( "UPDATE branches SET review=%s WHERE repository=%s AND name=%s", (review.id, repository.id, from_branch_name)) # Reload to get list of changesets added by addCommitsToReview(). review = dbutils.Review.fromId(db, review.id) pending_mails = [] recipients = review.getRecipients(db) for to_user in recipients: pending_mails.extend( mail.sendReviewCreated(db, user, to_user, recipients, review)) if not is_opt_in: recipient_by_id = dict( (to_user.id, to_user) for to_user in recipients) cursor.execute( """SELECT userpreferences.uid, userpreferences.repository, userpreferences.filter, userpreferences.integer FROM userpreferences LEFT OUTER JOIN filters ON (filters.id=userpreferences.filter) WHERE userpreferences.item='review.defaultOptOut' AND userpreferences.uid=ANY (%s) AND (userpreferences.filter IS NULL OR filters.repository=%s) AND (userpreferences.repository IS NULL OR userpreferences.repository=%s)""", (recipient_by_id.keys(), repository.id, repository.id)) user_settings = {} has_filter_settings = False for user_id, repository_id, filter_id, integer in cursor: settings = user_settings.setdefault(user_id, [None, None, {}]) value = bool(integer) if repository_id is None and filter_id is None: settings[0] = value elif repository_id is not None: settings[1] = value else: settings[2][filter_id] = value has_filter_settings = True if has_filter_settings: filters = Filters() filters.setFiles(db, review=review) for user_id, (global_default, repository_default, filter_settings) in user_settings.items(): to_user = recipient_by_id[user_id] opt_out = None if repository_default is not None: opt_out = repository_default elif global_default is not None: opt_out = global_default if filter_settings: # Policy: # # If all of the user's filters that matched files in the # review have review.defaultOptOut enabled, then opt out. # When determining this, any review filters of the user's # that match files in the review count as filters that don't # have the review.defaultOptOut enabled. # # If any of the user's filters that matched files in the # review have review.defaultOptOut disabled, then don't opt # out. When determining this, review filters are ignored. # # Otherwise, ignore the filter settings, and go with either # the user's per-repository or global setting (as set # above.) filters.load(db, review=review, user=to_user) # A set of filter ids. If None is in the set, the user has # one or more review filters in the review. (These do not # have ids.) active_filters = filters.getActiveFilters(to_user) for filter_id in active_filters: if filter_id is None: continue elif filter_id in filter_settings: if not filter_settings[filter_id]: opt_out = False break else: break else: if None not in active_filters: opt_out = True if opt_out: cursor.execute( """INSERT INTO reviewrecipientfilters (review, uid, include) VALUES (%s, %s, FALSE)""", (review.id, to_user.id)) db.commit() mail.sendPendingMails(pending_mails) return review except: if not via_push: repository.run("branch", "-D", branch_name) raise
def createReview(db, user, repository, commits, branch_name, summary, description, from_branch_name=None, via_push=False, reviewfilters=None, applyfilters=True, applyparentfilters=False, recipientfilters=None): cursor = db.cursor() if via_push: applyparentfilters = bool( user.getPreference(db, 'review.applyUpstreamFilters')) branch = dbutils.Branch.fromName(db, repository, branch_name) if branch is not None: raise OperationFailure( code="branchexists", title="Invalid review branch name", message="""\ <p>There is already a branch named <code>%s</code> in the repository. You have to select a different name.</p> <p>If you believe the existing branch was created during an earlier (failed) attempt to create this review, you can try to delete it from the repository using the command<p> <pre> git push <remote> :%s</pre> <p>and then press the "Submit Review" button on this page again.""" % (htmlutils.htmlify(branch_name), htmlutils.htmlify(branch_name)), is_html=True) commitset = log_commitset.CommitSet(commits) if len(commitset.getHeads()) != 1: raise Exception, "invalid commit-set; multiple heads" head = commitset.getHeads().pop() if len(commitset.getTails()) != 1: tail_id = None else: tail_id = gitutils.Commit.fromSHA1( db, repository, commitset.getTails().pop()).getId(db) if not via_push: repository.branch(branch_name, head.sha1) try: cursor.execute( "INSERT INTO branches (repository, name, head, tail, type) VALUES (%s, %s, %s, %s, 'review') RETURNING id", [repository.id, branch_name, head.getId(db), tail_id]) branch_id = cursor.fetchone()[0] reachable_values = [(branch_id, commit.getId(db)) for commit in commits] cursor.executemany( "INSERT INTO reachable (branch, commit) VALUES (%s, %s)", reachable_values) cursor.execute( "INSERT INTO reviews (type, branch, state, summary, description, applyfilters, applyparentfilters) VALUES ('official', %s, 'open', %s, %s, %s, %s) RETURNING id", (branch_id, summary, description, applyfilters, applyparentfilters)) review = dbutils.Review.fromId(db, cursor.fetchone()[0]) cursor.execute( "INSERT INTO reviewusers (review, uid, owner) VALUES (%s, %s, TRUE)", (review.id, user.id)) if reviewfilters is not None: cursor.executemany( "INSERT INTO reviewfilters (review, uid, directory, file, type, creator) VALUES (%s, %s, %s, %s, %s, %s)", [(review.id, filter_user_id, filter_directory_id, filter_file_id, filter_type, user.id) for filter_directory_id, filter_file_id, filter_type, filter_delegate, filter_user_id in reviewfilters]) if recipientfilters is not None: cursor.executemany( "INSERT INTO reviewrecipientfilters (review, uid, include) VALUES (%s, %s, %s)", [(review.id, filter_user_id, filter_include) for filter_user_id, filter_include in recipientfilters]) addCommitsToReview(db, user, review, commits, new_review=True) if from_branch_name is not None: cursor.execute( "UPDATE branches SET review=%s WHERE repository=%s AND name=%s", (review.id, repository.id, from_branch_name)) # Reload to get list of changesets added by addCommitsToReview(). review = dbutils.Review.fromId(db, review.id) pending_mails = [] recipients = review.getRecipients(db) for to_user in recipients: pending_mails.extend( mail.sendReviewCreated(db, user, to_user, recipients, review)) db.commit() mail.sendPendingMails(pending_mails) return review except: if not via_push: repository.run("branch", "-D", branch_name) raise