def addNote(req, db, user): repository_id = req.getParameter("repository", filter=int) branch = req.getParameter("branch") upstream = req.getParameter("upstream") sha1 = req.getParameter("sha1") review_id = req.getParameter("review", None) text = req.read().strip() if review_id is not None: review = dbutils.Review.fromId(db, review_id) else: review = None cursor = db.cursor() cursor.execute("DELETE FROM checkbranchnotes WHERE repository=%s AND branch=%s AND upstream=%s AND sha1=%s", (repository_id, branch, upstream, sha1)) cursor.execute("INSERT INTO checkbranchnotes (repository, branch, upstream, sha1, uid, review, text) VALUES (%s, %s, %s, %s, %s, %s, %s)", (repository_id, branch, upstream, sha1, user.id, review_id, text or None)) db.commit() response = "ok" if review and review.repository.id == repository_id: repository = gitutils.Repository.fromId(db, repository_id) commit = gitutils.Commit.fromSHA1(db, repository, sha1) commitset = log.commitset.CommitSet(review.branch.getCommits(db)) upstreams = commitset.getFilteredTails(repository) if len(upstreams) == 1: upstream = upstreams.pop() if repository.mergebase([commit.sha1, upstream]) == upstream: response = "rebase" return response
def addNote(req, db, user): repository_id = req.getParameter("repository", filter=int) branch = req.getParameter("branch") upstream = req.getParameter("upstream") sha1 = req.getParameter("sha1") review_id = req.getParameter("review", None) text = req.read().strip() if review_id is not None: review = dbutils.Review.fromId(db, review_id) else: review = None cursor = db.cursor() cursor.execute("DELETE FROM checkbranchnotes WHERE repository=%s AND branch=%s AND upstream=%s AND sha1=%s", (repository_id, branch, upstream, sha1)) cursor.execute("INSERT INTO checkbranchnotes (repository, branch, upstream, sha1, uid, review, text) VALUES (%s, %s, %s, %s, %s, %s, %s)", (repository_id, branch, upstream, sha1, user.id, review_id, text or None)) db.commit() response = "ok" if review and review.repository.id == repository_id: repository = gitutils.Repository.fromId(db, repository_id) commit = gitutils.Commit.fromSHA1(db, repository, sha1) commitset = log.commitset.CommitSet(review.branch.commits) upstreams = commitset.getFilteredTails(repository) if len(upstreams) == 1: upstream = upstreams.pop() if repository.mergebase([commit.sha1, upstream]) == upstream: response = "rebase" return response
def process(self, db, user, review_id, new_head_sha1, new_upstream_sha1=None, branch=None, new_trackedbranch=None): review = dbutils.Review.fromId(db, review_id) new_head = gitutils.Commit.fromSHA1(db, review.repository, new_head_sha1) cursor = db.cursor() if review.state == 'closed': cursor.execute("SELECT closed_by FROM reviews WHERE id=%s", (review.id,)) closed_by = cursor.fetchone()[0] review.serial += 1 cursor.execute("UPDATE reviews SET state='open', serial=%s, closed_by=NULL WHERE id=%s", (review.serial, review.id)) else: closed_by = None trackedbranch = review.getTrackedBranch(db) if trackedbranch and not trackedbranch.disabled: cursor.execute("UPDATE trackedbranches SET disabled=TRUE WHERE id=%s", (trackedbranch.id,)) commitset = log.commitset.CommitSet(review.branch.commits) tails = commitset.getFilteredTails(review.branch.repository) if len(tails) == 1 and tails.pop() == new_upstream_sha1: # This appears to be a history rewrite. new_upstream_sha1 = None doPrepareRebase(db, user, review, new_upstream_sha1, branch) try: review.repository.run("update-ref", "refs/commit/%s" % new_head.sha1, new_head.sha1) with review.repository.relaycopy("RebaseReview") as relay: relay.run("fetch", "origin", "refs/commit/%s" % new_head.sha1) relay.run("push", "--force", "origin", "%s:refs/heads/%s" % (new_head.sha1, review.branch.name), env={ "REMOTE_USER": user.name }) if closed_by is not None: db.commit() state = review.getReviewState(db) if state.accepted: review.serial += 1 cursor.execute("UPDATE reviews SET state='closed', serial=%s, closed_by=%s WHERE id=%s", (review.serial, closed_by, review.id)) if trackedbranch and not trackedbranch.disabled: cursor.execute("UPDATE trackedbranches SET disabled=FALSE WHERE id=%s", (trackedbranch.id,)) if new_trackedbranch: cursor.execute("UPDATE trackedbranches SET remote_name=%s WHERE id=%s", (new_trackedbranch, trackedbranch.id)) db.commit() except: doCancelRebase(db, user, review) raise return OperationResult()
def process(self, db, user, review_id, new_head_sha1, new_upstream_sha1=None, branch=None, new_trackedbranch=None): review = dbutils.Review.fromId(db, review_id) new_head = gitutils.Commit.fromSHA1(db, review.repository, new_head_sha1) cursor = db.cursor() if review.state == 'closed': cursor.execute("SELECT closed_by FROM reviews WHERE id=%s", (review.id,)) closed_by = cursor.fetchone()[0] review.serial += 1 cursor.execute("UPDATE reviews SET state='open', serial=%s, closed_by=NULL WHERE id=%s", (review.serial, review.id)) else: closed_by = None trackedbranch = review.getTrackedBranch(db) if trackedbranch and not trackedbranch.disabled: cursor.execute("UPDATE trackedbranches SET disabled=TRUE WHERE id=%s", (trackedbranch.id,)) commitset = log.commitset.CommitSet(review.branch.commits) tails = commitset.getFilteredTails(review.branch.repository) if len(tails) == 1 and tails.pop() == new_upstream_sha1: # This appears to be a history rewrite. new_upstream_sha1 = None doPrepareRebase(db, user, review, new_upstream_sha1, branch) try: with review.repository.relaycopy("RebaseReview") as relay: with review.repository.temporaryref(new_head) as ref_name: relay.run("fetch", "origin", ref_name) relay.run("push", "--force", "origin", "%s:refs/heads/%s" % (new_head.sha1, review.branch.name), env={ "REMOTE_USER": user.name }) if closed_by is not None: db.commit() state = review.getReviewState(db) if state.accepted: review.serial += 1 cursor.execute("UPDATE reviews SET state='closed', serial=%s, closed_by=%s WHERE id=%s", (review.serial, closed_by, review.id)) if trackedbranch and not trackedbranch.disabled: cursor.execute("UPDATE trackedbranches SET disabled=FALSE WHERE id=%s", (trackedbranch.id,)) if new_trackedbranch: cursor.execute("UPDATE trackedbranches SET remote_name=%s WHERE id=%s", (new_trackedbranch, trackedbranch.id)) db.commit() except: doCancelRebase(db, user, review) raise return OperationResult()
def doPrepareRebase(db, user, review, new_upstream_arg=None, branch=None): commitset = log.commitset.CommitSet(review.branch.commits) tails = commitset.getFilteredTails(review.branch.repository) cursor = db.cursor() cursor.execute("SELECT uid FROM reviewrebases WHERE review=%s AND new_head IS NULL", (review.id,)) row = cursor.fetchone() if row: rebaser = dbutils.User.fromId(db, row[0]) raise OperationError("The review is already being rebased by %s <%s>." % (rebaser.fullname, rebaser.email)) head = commitset.getHeads().pop() head_id = head.getId(db) if new_upstream_arg is not None: if len(tails) > 1: raise OperationError("Rebase to new upstream commit not supported.") tail = gitutils.Commit.fromSHA1(db, review.branch.repository, tails.pop()) old_upstream_id = tail.getId(db) if new_upstream_arg == "0" * 40: new_upstream_id = None else: if not gitutils.re_sha1.match(new_upstream_arg): cursor.execute("SELECT sha1 FROM tags WHERE repository=%s AND name=%s", (review.branch.repository.id, new_upstream_arg)) row = cursor.fetchone() if row: new_upstream_arg = row[0] else: raise OperationError("Specified new upstream is invalid.") try: new_upstream = gitutils.Commit.fromSHA1(db, review.branch.repository, new_upstream_arg) except: raise OperationError("The specified new upstream commit does not exist in Critic's repository.") new_upstream_id = new_upstream.getId(db) else: old_upstream_id = None new_upstream_id = None cursor.execute("""INSERT INTO reviewrebases (review, old_head, new_head, old_upstream, new_upstream, uid, branch) VALUES (%s, %s, NULL, %s, %s, %s, %s)""", (review.id, head_id, old_upstream_id, new_upstream_id, user.id, branch)) review.incrementSerial(db) db.commit()
def getFilteredTails(self): import log.commitset commitset = log.commitset.CommitSet(self.branch.commits) return commitset.getFilteredTails(self.branch.repository)
def execute(db, user, review, all_commits, old_head, new_head, output): cursor = db.cursor() installs = Extension.getInstalls(db, user) data = None for extension_id, version_id, version_sha1, is_universal in installs: handlers = [] extension = Extension.fromId(db, extension_id) if version_id is not None: cursor.execute("""SELECT script, function FROM extensionroles JOIN extensionprocesscommitsroles ON (role=id) WHERE version=%s ORDER BY id ASC""", (version_id,)) handlers.extend(cursor) if not handlers: continue extension_path = getExtensionInstallPath(version_sha1) manifest = Manifest.load(extension_path) else: manifest = Manifest.load(extension.getPath()) for role in manifest.roles: if isinstance(role, ProcessCommitsRole): handlers.append((role.script, role.function)) if not handlers: continue if data is None: commitset = log.commitset.CommitSet(all_commits) assert old_head is None or old_head in commitset.getTails() assert new_head in commitset.getHeads() assert len(commitset.getHeads()) == 1 tails = commitset.getFilteredTails(review.repository) if len(tails) == 1: tail = gitutils.Commit.fromSHA1(db, review.repository, tails.pop()) changeset_id = changeset.utils.createChangeset( db, user, review.repository, from_commit=tail, to_commit=new_head)[0].id changeset_arg = "repository.getChangeset(%d)" % changeset_id else: changeset_arg = "null" commits_arg = "[%s]" % ",".join( [("repository.getCommit(%d)" % commit.getId(db)) for commit in all_commits]) data = { "review_id": review.id, "changeset": changeset_arg, "commits": commits_arg } for script, function in handlers: class Error(Exception): pass def print_header(): header = "%s::%s()" % (script, function) print >>output, ("\n[%s] %s\n[%s] %s" % (extension.getName(), header, extension.getName(), "=" * len(header))) try: argv = """ (function () { var review = new critic.Review(%(review_id)d); var repository = review.repository; var changeset = %(changeset)s; var commitset = new critic.CommitSet(%(commits)s); return [review, changeset, commitset]; })() """ % data argv = re.sub("[ \n]+", " ", argv.strip()) try: stdout_data = executeProcess( manifest, "processcommits", script, function, extension_id, user.id, argv, configuration.extensions.SHORT_TIMEOUT) except ProcessTimeout: raise Error("Timeout after %d seconds." % configuration.extensions.SHORT_TIMEOUT) except ProcessError as error: if error.returncode < 0: raise Error("Process terminated by signal %d." % -error.returncode) else: raise Error("Process returned %d.\n%s" % (error.returncode, error.stderr)) if stdout_data.strip(): print_header() for line in stdout_data.splitlines(): print >>output, "[%s] %s" % (extension.getName(), line) except Error as error: print_header() print >>output, "[%s] Extension error: %s" % (extension.getName(), error.message)
def execute(db, user, review, all_commits, old_head, new_head, output): cursor = db.cursor() installs = Extension.getInstalls(db, user) data = None for extension_id, version_id, version_sha1, is_universal in installs: handlers = [] extension = Extension.fromId(db, extension_id) if version_id is not None: cursor.execute( """SELECT script, function FROM extensionroles JOIN extensionprocesscommitsroles ON (role=id) WHERE version=%s ORDER BY id ASC""", (version_id, )) handlers.extend(cursor) if not handlers: continue extension_path = getExtensionInstallPath(version_sha1) manifest = Manifest.load(extension_path) else: manifest = Manifest.load(extension.getPath()) for role in manifest.roles: if isinstance(role, ProcessCommitsRole): handlers.append((role.script, role.function)) if not handlers: continue if data is None: commitset = log.commitset.CommitSet(all_commits) assert old_head is None or old_head in commitset.getTails() assert new_head in commitset.getHeads() assert len(commitset.getHeads()) == 1 tails = commitset.getFilteredTails(review.repository) if len(tails) == 1: tail = gitutils.Commit.fromSHA1(db, review.repository, tails.pop()) changeset_id = changeset.utils.createChangeset( db, user, review.repository, from_commit=tail, to_commit=new_head)[0].id changeset_arg = "repository.getChangeset(%d)" % changeset_id else: changeset_arg = "null" commits_arg = "[%s]" % ",".join( [("repository.getCommit(%d)" % commit.getId(db)) for commit in all_commits]) data = { "review_id": review.id, "changeset": changeset_arg, "commits": commits_arg } for script, function in handlers: class Error(Exception): pass def print_header(): header = "%s::%s()" % (script, function) print >> output, ("\n[%s] %s\n[%s] %s" % (extension.getName(), header, extension.getName(), "=" * len(header))) try: argv = """ (function () { var review = new critic.Review(%(review_id)d); var repository = review.repository; var changeset = %(changeset)s; var commitset = new critic.CommitSet(%(commits)s); return [review, changeset, commitset]; })() """ % data argv = re.sub("[ \n]+", " ", argv.strip()) try: stdout_data = executeProcess( manifest, "processcommits", script, function, extension_id, user.id, argv, configuration.extensions.SHORT_TIMEOUT) except ProcessTimeout: raise Error("Timeout after %d seconds." % configuration.extensions.SHORT_TIMEOUT) except ProcessError as error: if error.returncode < 0: raise Error("Process terminated by signal %d." % -error.returncode) else: raise Error("Process returned %d.\n%s" % (error.returncode, error.stderr)) if stdout_data.strip(): print_header() for line in stdout_data.splitlines(): print >> output, "[%s] %s" % (extension.getName(), line) except Error as error: print_header() print >> output, "[%s] Extension error: %s" % ( extension.getName(), error.message)
def getFilteredTails(self, db): import log.commitset commitset = log.commitset.CommitSet(self.branch.getCommits(db)) return commitset.getFilteredTails(self.branch.repository)
def execute(db, user, review, all_commits, old_head, new_head, output): cursor = db.cursor() cursor.execute("""SELECT extensions.id, extensions.author, extensions.name, extensionversions.sha1, roles.script, roles.function FROM extensions JOIN extensionversions ON (extensionversions.extension=extensions.id) JOIN extensionroles_processcommits AS roles ON (roles.version=extensionversions.id) WHERE uid=%s AND filter IS NULL""", (user.id,)) rows = cursor.fetchall() if rows: commitset = log.commitset.CommitSet(all_commits) assert old_head is None or old_head in commitset.getTails() assert new_head in commitset.getHeads() assert len(commitset.getHeads()) == 1 tails = commitset.getFilteredTails(review.repository) if len(tails) == 1: tail = gitutils.Commit.fromSHA1(db, review.repository, tails.pop()) changeset_id = changeset.utils.createChangeset(db, user, review.repository, from_commit=tail, to_commit=new_head)[0].id changeset_arg = "repository.getChangeset(%d)" % changeset_id db.commit() else: changeset_arg = "null" commits = "[%s]" % ",".join([("repository.getCommit(%d)" % commit.getId(db)) for commit in all_commits]) data = { "review_id": review.id, "changeset": changeset_arg, "commits": commits } for extension_id, author_id, extension_name, sha1, script, function in rows: author = dbutils.User.fromId(db, author_id) if sha1 is None: extension_path = getExtensionPath(author.name, extension_name) else: extension_path = getExtensionInstallPath(sha1) class Error(Exception): pass def print_header(): header = "%s::%s()" % (script, function) print >>output, "\n[%s] %s\n[%s] %s" % (extension_name, header, extension_name, "=" * len(header)) try: try: manifest = Manifest.load(extension_path) except ManifestError, error: raise Error("Invalid MANIFEST:\n%s" % error.message) for role in manifest.roles: if isinstance(role, ProcessCommitsRole) and role.script == script and role.function == function: break else: continue argv = """ (function () { var review = new critic.Review(%(review_id)d); var repository = review.repository; var changeset = %(changeset)s; var commitset = new critic.CommitSet(%(commits)s); return [review, changeset, commitset]; })() """ % data argv = re.sub("[ \n]+", " ", argv.strip()) try: stdout_data = executeProcess(manifest, role, extension_id, user.id, argv, configuration.extensions.SHORT_TIMEOUT) except ProcessTimeout: raise Error("Timeout after %d seconds." % configuration.extensions.SHORT_TIMEOUT) except ProcessError, error: if error.returncode < 0: if -error.returncode == signal.SIGXCPU: raise Error("CPU time limit (5 seconds) exceeded.") else: raise Error("Process terminated by signal %d." % -error.returncode) else: raise Error("Process returned %d.\n%s" % (error.returncode, error.stderr)) if stdout_data.strip(): print_header() for line in stdout_data.splitlines(): print >>output, "[%s] %s" % (extension_name, line) except Error, error: print_header() print >>output, "[%s] Extension error: %s" % (extension_name, error.message)