def generate(self): needFiles = False if len(self.files) > 0: needFiles = True query = OperationQuery(self.client, { "project": self.projects, "status": [ OperationQuery.STATUS_OPEN ], "branch": self.branches, "topic": self.topics, "reviewer": self.reviewers, }, patches=OperationQuery.PATCHES_ALL, approvals=True, files=needFiles) def match_files(change): if len(self.files) == 0: return True for filere in self.files: for patch in change.patches: for file in patch.files: if re.search(filere, file.path): return True return False table = self.new_table("Changes To Do List") def querycb(change): if self.filter(change) and match_files(change): table.add_row(change) query.run(querycb) return table
def generate(self): # We could query all projects at once, but if we do them # individually it means we get better hit rate against the # cache if the report is re-run for many different project # combinations reviewers = {} now = time.time() for project in self.projects: query = OperationQuery(self.client, { "project": [project], }, patches=OperationQuery.PATCHES_ALL, approvals=True) def querycb(change): for patch in change.patches: for approval in patch.approvals: if approval.action == ModelApproval.ACTION_VERIFIED: continue user = approval.user if user is None or user.username is None: continue username = user.username if username not in reviewers: reviewers[username] = { "total": 0} agesecs = approval.get_age(now) ageweeks = int(agesecs / (60 * 60 * 24 * 7)) + 1 key = "week%d" % ageweeks if key not in reviewers[username]: reviewers[username][key] = 0 reviewers[username][key] = reviewers[username][key] + 1 if ageweeks <= 52: reviewers[username]["total"] = reviewers[username]["total"] + 1 query.run(querycb) table = self.new_table("Daily review rates per week") for reviewer in reviewers.keys(): userteam = "" for team in self.teams.keys(): if reviewer in self.teams[team]: userteam = team table.add_row([reviewer, userteam, reviewers[reviewer]]) return table
def run(self, config, client, options): change = options.change query = OperationQuery( client, {"change": [change]}, patches=OperationQuery.PATCHES_ALL, approvals=True, files=True, comments=True ) if options.all: bots = [] else: bots = config.get_organization_bots() def mycb(change): self.format_change(change, bots, options.color, options.current, int(options.patch)) query.run(mycb, limit=1)
def generate(self): query = OperationQuery(self.client, { "project": self.projects, "status": [ OperationQuery.STATUS_OPEN ], "reviewer": self.reviewers, }, patches=OperationQuery.PATCHES_ALL, approvals=True) table = self.new_table("Changes To Do List") def querycb(change): if self.filter(change): table.add_row(change) query.run(querycb) return table
def generate(self): query = OperationQuery(self.client, { "project": self.projects, "status": [OperationQuery.STATUS_OPEN], "reviewer": self.reviewers, }, patches=OperationQuery.PATCHES_ALL, approvals=True) table = self.new_table("Changes To Do List") def querycb(change): if self.filter(change): table.add_row(change) query.run(querycb) return table
def run(self, config, client, options): change = options.change query = OperationQuery(client, { "change": [ change ], }, patches=OperationQuery.PATCHES_ALL, approvals=True, files=True, comments=True) if options.all: bots = [] else: bots = config.get_organization_bots() def mycb(change): self.format_change(change, bots, options.color, options.current, int(options.patch)) query.run(mycb, limit=1)
def generate(self): needFiles = False if len(self.files) > 0: needFiles = True query = OperationQuery(self.client, { "project": self.projects, "owner": self.owners, "message": self.messages, "branch": self.branches, "topic": self.topics, "status": self.status, "reviewer": self.reviewers, }, rawquery=self.rawquery, patches=OperationQuery.PATCHES_CURRENT, approvals=True, files=needFiles) def match_files(change): if len(self.files) == 0: return True for filere in self.files: for patch in change.patches: for file in patch.files: if re.search(filere, file.path): return True return False table = self.new_table("Changes") def querycb(change): if match_files(change): table.add_row(change) query.run(querycb) return table
def generate(self): needFiles = False if len(self.files) > 0: needFiles = True query = OperationQuery(self.client, { "project": self.projects, "owner": self.owners, "message": self.messages, "branch": self.branches, "status": self.status, "reviewer": self.reviewers, }, rawquery=self.rawquery, patches=OperationQuery.PATCHES_CURRENT, approvals=True, files=needFiles) def match_files(change): if len(self.files) == 0: return True for filere in self.files: for patch in change.patches: for file in patch.files: if re.search(filere, file.path): return True return False table = self.new_table("Changes") def querycb(change): if match_files(change): table.add_row(change) query.run(querycb) return table
def generate(self): # We could query all projects at once, but if we do them # individually it means we get better hit rate against the # cache if the report is re-run for many different project # combinations reviews = [] cutoff = time.time() - (self.maxagedays * 24 * 60 * 60) for project in self.projects: query = OperationQuery(self.client, { "project": [project], }, patches=OperationQuery.PATCHES_ALL, approvals=True) def querycb(change): for patch in change.patches: for approval in patch.approvals: if approval.is_newer_than(cutoff): reviews.append(approval) query.run(querycb) reviewers = {} for review in reviews: if review.action != ModelApproval.ACTION_REVIEWED or review.user is None: continue reviewer = review.user.username if reviewer is None: reviewer = review.user.name if reviewer is None: continue if reviewer.lower() in ["jenkins", "smokestack"]: continue reviewers.setdefault(reviewer, { 'votes': {'flag-m2': 0, 'flag-m1': 0, 'flag-p1': 0, 'flag-p2': 0}, 'total': 0, }) reviewers[reviewer]['total'] = reviewers[reviewer]['total'] + 1 votes = { "-2" : "flag-m2", "-1" : "flag-m1", "1" : "flag-p1", "2" : "flag-p2" } cur = reviewers[reviewer]['votes'][votes[str(review.value)]] reviewers[reviewer]['votes'][votes[str(review.value)]] = cur + 1 compound = ReportOutputCompound() table = self.new_table("Review statistics") compound.add_report(table) for user, votes in reviewers.items(): userteam = "" for team in self.teams.keys(): if user in self.teams[team]: userteam = team table.add_row([user, votes, userteam]) summary = ReportOutputList([ ReportOutputColumn("nreviews", "Total reviews", format="%d", mapfunc=lambda rep, col, row: row[0]), ReportOutputColumn("nreviewers", "Total rviewers", format="%d", mapfunc=lambda rep, col, row: row[1]) ], title="Review summary") summary.set_row([len(reviews), len(reviewers.keys())]) compound.add_report(summary) return compound
def generate(self): # We could query all projects at once, but if we do them # individually it means we get better hit rate against the # cache if the report is re-run for many different project # combinations agecurrent = {} agefirst = {} agenonnacked = {} wait_reviewer = [] wait_submitter = [] changes = {} for project in self.projects: query = OperationQuery(self.client, { "project": [project], "status": [OperationQuery.STATUS_OPEN], "branch": [self.branch], "topic": [self.topic], }, patches=OperationQuery.PATCHES_ALL, approvals=True) def querycb(change): if change.status != "NEW": return now = time.time() current = change.get_current_patch() first = change.get_first_patch() nonnacked = change.get_reviewer_not_nacked_patch() changes[change.id] = change if current.is_nacked(): wait_submitter.append(change.id) else: wait_reviewer.append(change.id) agecurrent[change.id] = current.get_age(now) agefirst[change.id] = first.get_age(now) if nonnacked: agenonnacked[change.id] = nonnacked.get_age(now) else: agenonnacked[change.id] = 0 query.run(querycb) compound = ReportOutputCompound() summary = ReportOutputList([ ReportOutputColumn("nreviews", "Total open reviews", format="%d", mapfunc=lambda rep, col, row: row[0] + row [1]), ReportOutputColumn("waitsubmitter", "Waiting on submitter", format="%d", mapfunc=lambda rep, col, row: row[0]), ReportOutputColumn("waitreviewer", "Waiting on reviewer", format="%d", mapfunc=lambda rep, col, row: row[1]), ], title="Review summary") summary.set_row([len(wait_submitter), len(wait_reviewer)]) compound.add_report(summary) lastrev = ReportOutputList([ ReportOutputColumn("average", "Average wait time", mapfunc=lambda rep, col, row: row[0]), ReportOutputColumn("median", "Median wait time", mapfunc=lambda rep, col, row: row[1]), ReportOutputColumn("stale", "Older than %d days" % self.days, format="%d", mapfunc=lambda rep, col, row: row[2]), ], title="Summary since current revision") lastrev.set_row([self.average_age(wait_reviewer, agecurrent), self.median_age(wait_reviewer, agecurrent), self.older_than(wait_reviewer, agecurrent, self.days)]) compound.add_report(lastrev) firstrev = ReportOutputList([ ReportOutputColumn("average", "Average wait time", mapfunc=lambda rep, col, row: row[0]), ReportOutputColumn("median", "Median wait time", mapfunc=lambda rep, col, row: row[1]), ], title="Summary since first revision") firstrev.set_row([self.average_age(wait_reviewer, agefirst), self.median_age(wait_reviewer, agefirst)]) compound.add_report(firstrev) nonnackedrev = ReportOutputList([ ReportOutputColumn("average", "Average wait time", mapfunc=lambda rep, col, row: row[0]), ReportOutputColumn("median", "Median wait time", mapfunc=lambda rep, col, row: row[1]), ], title="Summary since last revision without -1/-2 from reviewer") nonnackedrev.set_row([self.average_age(wait_reviewer, agenonnacked), self.median_age(wait_reviewer, agenonnacked)]) compound.add_report(nonnackedrev) def waitlastmap(rep, col, row): return format_delta(row.get_current_age()) def waitlastsort(rep, col, row): return row.get_current_age() waitlastrev = self.new_table("Longest waiting since current revision") waitlastrev.add_column(ReportOutputColumn("age", "Age", sortfunc=waitlastsort, mapfunc=waitlastmap)) waitlastrev.sortcol = "age" waitlastrev.reverse = True for change in self.get_longest_changes(wait_reviewer, changes, agecurrent, 5): waitlastrev.add_row(change) compound.add_report(waitlastrev) def waitfirstmap(rep, col, row): return format_delta(row.get_first_age()) def waitfirstsort(rep, col, row): return row.get_first_age() waitfirstrev = self.new_table("Longest waiting since first revision") waitfirstrev.add_column(ReportOutputColumn("age", "Age", sortfunc=waitfirstsort, mapfunc=waitfirstmap)) waitfirstrev.sortcol = "age" waitfirstrev.reverse = True for change in self.get_longest_changes(wait_reviewer, changes, agefirst, 5): waitfirstrev.add_row(change) compound.add_report(waitfirstrev) def waitnonnackedmap(rep, col, row): return format_delta(row.get_reviewer_not_nacked_age()) def waitnonnackedsort(rep, col, row): return row.get_reviewer_not_nacked_age() waitnonnackedrev = self.new_table("Longest waiting since last revision without -1/-2 from reviewer") waitnonnackedrev.add_column(ReportOutputColumn("age", "Age", sortfunc=waitnonnackedsort, mapfunc=waitnonnackedmap)) waitnonnackedrev.sortcol = "age" waitnonnackedrev.reverse = True for change in self.get_longest_changes(wait_reviewer, changes, agenonnacked, 5): waitnonnackedrev.add_row(change) compound.add_report(waitnonnackedrev) return compound
def generate(self): # We could query all projects at once, but if we do them # individually it means we get better hit rate against the # cache if the report is re-run for many different project # combinations agecurrent = {} agefirst = {} agenonnacked = {} wait_reviewer = [] wait_submitter = [] changes = {} for project in self.projects: query = OperationQuery(self.client, { "project": [project], "status": [OperationQuery.STATUS_OPEN], "branch": [self.branch], }, patches=OperationQuery.PATCHES_ALL, approvals=True) def querycb(change): if change.status != "NEW": return now = time.time() current = change.get_current_patch() first = change.get_first_patch() nonnacked = change.get_reviewer_not_nacked_patch() changes[change.id] = change if current.is_nacked(): wait_submitter.append(change.id) else: wait_reviewer.append(change.id) agecurrent[change.id] = current.get_age(now) agefirst[change.id] = first.get_age(now) if nonnacked: agenonnacked[change.id] = nonnacked.get_age(now) else: agenonnacked[change.id] = 0 query.run(querycb) compound = ReportOutputCompound() summary = ReportOutputList([ ReportOutputColumn("nreviews", "Total open reviews", format="%d", mapfunc=lambda rep, col, row: row[0] + row[1]), ReportOutputColumn("waitsubmitter", "Waiting on submitter", format="%d", mapfunc=lambda rep, col, row: row[0]), ReportOutputColumn("waitreviewer", "Waiting on reviewer", format="%d", mapfunc=lambda rep, col, row: row[1]), ], title="Review summary") summary.set_row([len(wait_submitter), len(wait_reviewer)]) compound.add_report(summary) lastrev = ReportOutputList([ ReportOutputColumn("average", "Average wait time", mapfunc=lambda rep, col, row: row[0]), ReportOutputColumn("median", "Median wait time", mapfunc=lambda rep, col, row: row[1]), ReportOutputColumn("stale", "Older than %d days" % self.days, format="%d", mapfunc=lambda rep, col, row: row[2]), ], title="Summary since current revision") lastrev.set_row([ self.average_age(wait_reviewer, agecurrent), self.median_age(wait_reviewer, agecurrent), self.older_than(wait_reviewer, agecurrent, self.days) ]) compound.add_report(lastrev) firstrev = ReportOutputList([ ReportOutputColumn("average", "Average wait time", mapfunc=lambda rep, col, row: row[0]), ReportOutputColumn("median", "Median wait time", mapfunc=lambda rep, col, row: row[1]), ], title="Summary since first revision") firstrev.set_row([ self.average_age(wait_reviewer, agefirst), self.median_age(wait_reviewer, agefirst) ]) compound.add_report(firstrev) nonnackedrev = ReportOutputList( [ ReportOutputColumn("average", "Average wait time", mapfunc=lambda rep, col, row: row[0]), ReportOutputColumn("median", "Median wait time", mapfunc=lambda rep, col, row: row[1]), ], title="Summary since last revision without -1/-2 from reviewer") nonnackedrev.set_row([ self.average_age(wait_reviewer, agenonnacked), self.median_age(wait_reviewer, agenonnacked) ]) compound.add_report(nonnackedrev) def waitlastmap(rep, col, row): return format_delta(row.get_current_age()) def waitlastsort(rep, col, row): return row.get_current_age() waitlastrev = self.new_table("Longest waiting since current revision") waitlastrev.add_column( ReportOutputColumn("age", "Age", sortfunc=waitlastsort, mapfunc=waitlastmap)) waitlastrev.sortcol = "age" waitlastrev.reverse = True for change in self.get_longest_changes(wait_reviewer, changes, agecurrent, 5): waitlastrev.add_row(change) compound.add_report(waitlastrev) def waitfirstmap(rep, col, row): return format_delta(row.get_first_age()) def waitfirstsort(rep, col, row): return row.get_first_age() waitfirstrev = self.new_table("Longest waiting since first revision") waitfirstrev.add_column( ReportOutputColumn("age", "Age", sortfunc=waitfirstsort, mapfunc=waitfirstmap)) waitfirstrev.sortcol = "age" waitfirstrev.reverse = True for change in self.get_longest_changes(wait_reviewer, changes, agefirst, 5): waitfirstrev.add_row(change) compound.add_report(waitfirstrev) def waitnonnackedmap(rep, col, row): return format_delta(row.get_reviewer_not_nacked_age()) def waitnonnackedsort(rep, col, row): return row.get_reviewer_not_nacked_age() waitnonnackedrev = self.new_table( "Longest waiting since last revision without -1/-2 from reviewer") waitnonnackedrev.add_column( ReportOutputColumn("age", "Age", sortfunc=waitnonnackedsort, mapfunc=waitnonnackedmap)) waitnonnackedrev.sortcol = "age" waitnonnackedrev.reverse = True for change in self.get_longest_changes(wait_reviewer, changes, agenonnacked, 5): waitnonnackedrev.add_row(change) compound.add_report(waitnonnackedrev) return compound
def generate(self): # We could query all projects at once, but if we do them # individually it means we get better hit rate against the # cache if the report is re-run for many different project # combinations reviews = [] cutoff = time.time() - (self.maxagedays * 24 * 60 * 60) for project in self.projects: query = OperationQuery(self.client, { "project": [project], }, patches=OperationQuery.PATCHES_ALL, approvals=True) def querycb(change): for patch in change.patches: for approval in patch.approvals: if approval.is_newer_than(cutoff): reviews.append(approval) query.run(querycb) reviewers = {} for review in reviews: if review.action != ModelApproval.ACTION_REVIEWED or review.user is None: continue reviewer = review.user.username if reviewer is None: reviewer = review.user.name if reviewer is None: continue if reviewer.lower() in ["jenkins", "smokestack"]: continue reviewers.setdefault( reviewer, { 'votes': { 'flag-m2': 0, 'flag-m1': 0, 'flag-p1': 0, 'flag-p2': 0 }, 'total': 0, }) reviewers[reviewer]['total'] = reviewers[reviewer]['total'] + 1 votes = { "-2": "flag-m2", "-1": "flag-m1", "1": "flag-p1", "2": "flag-p2" } cur = reviewers[reviewer]['votes'][votes[str(review.value)]] reviewers[reviewer]['votes'][votes[str(review.value)]] = cur + 1 compound = ReportOutputCompound() table = self.new_table("Review statistics") compound.add_report(table) for user, votes in reviewers.items(): userteam = "" for team in self.teams.keys(): if user in self.teams[team]: userteam = team table.add_row([user, votes, userteam]) summary = ReportOutputList([ ReportOutputColumn("nreviews", "Total reviews", format="%d", mapfunc=lambda rep, col, row: row[0]), ReportOutputColumn("nreviewers", "Total rviewers", format="%d", mapfunc=lambda rep, col, row: row[1]) ], title="Review summary") summary.set_row([len(reviews), len(reviewers.keys())]) compound.add_report(summary) return compound