def _main(): myauth = HTTPDigestAuth('account', 'password') rest = GerritRestAPI(url='http://code...', auth=myauth) try: """ conditions """ query = ["status:open"] query += ["owner:leon5209"] query += ["age:1week"] changes = rest.get("/changes/?q=%s" % "%20".join(query)) logging.debug("there are %d changes", len(changes)) """ abandon """ for change in changes: logging.debug("subject : %s ", change['subject']) logging.debug("change id : %s ", change['change_id']) # we don't kill draft if change['status'] == "DRAFT": logging.debug("skip, we dont abandon draft") else: logging.debug("commit out of date , abandon!") rest.post("/changes/" + change['change_id'] + "/abandon", json={ "message": "This Commit is out of date, auto abandon! " }) except RequestException as err: logging.error("Error: %s", str(err))
def _main(): parser = optparse.OptionParser() parser.add_option('-g', '--gerrit-url', dest='gerrit_url', metavar='URL', default=None, help='gerrit server URL') parser.add_option('-b', '--basic-auth', dest='basic_auth', action='store_true', help='(deprecated) use HTTP basic authentication instead' ' of digest') parser.add_option('-d', '--digest-auth', dest='digest_auth', action='store_true', help='use HTTP digest authentication instead of basic') parser.add_option('-n', '--dry-run', dest='dry_run', action='store_true', help='enable dry-run mode: show stale changes but do ' 'not abandon them') parser.add_option('-a', '--age', dest='age', metavar='AGE', default="6months", help='age of change since last update ' '(default: %default)') parser.add_option('-m', '--message', dest='message', metavar='STRING', default=None, help='Custom message to append to abandon message') parser.add_option('--branch', dest='branches', metavar='BRANCH_NAME', default=[], action='append', help='Abandon changes only on the given branch') parser.add_option('--exclude-branch', dest='exclude_branches', metavar='BRANCH_NAME', default=[], action='append', help='Do not abandon changes on given branch') parser.add_option('--project', dest='projects', metavar='PROJECT_NAME', default=[], action='append', help='Abandon changes only on the given project') parser.add_option('--exclude-project', dest='exclude_projects', metavar='PROJECT_NAME', default=[], action='append', help='Do not abandon changes on given project') parser.add_option('--owner', dest='owner', metavar='USERNAME', default=None, action='store', help='Only abandon changes owned by the given user') parser.add_option('-v', '--verbose', dest='verbose', action='store_true', help='enable verbose (debug) logging') (options, _args) = parser.parse_args() level = logging.DEBUG if options.verbose else logging.INFO logging.basicConfig(format='%(asctime)s %(levelname)s %(message)s', level=level) if not options.gerrit_url: logging.error("Gerrit URL is required") return 1 pattern = re.compile(r"^([\d]+)(month[s]?|year[s]?|week[s]?)") match = pattern.match(options.age) if not match: logging.error("Invalid age: %s", options.age) return 1 message = "Abandoning after %s %s or more of inactivity." % \ (match.group(1), match.group(2)) if options.digest_auth: auth_type = HTTPDigestAuthFromNetrc else: auth_type = HTTPBasicAuthFromNetrc try: auth = auth_type(url=options.gerrit_url) gerrit = GerritRestAPI(url=options.gerrit_url, auth=auth) except Exception as e: logging.error(e) return 1 logging.info(message) try: stale_changes = [] offset = 0 step = 500 query_terms = ["status:new", "age:%s" % options.age] if options.branches: query_terms += ["branch:%s" % b for b in options.branches] elif options.exclude_branches: query_terms += ["-branch:%s" % b for b in options.exclude_branches] if options.projects: query_terms += ["project:%s" % p for p in options.projects] elif options.exclude_projects: query_terms = ["-project:%s" % p for p in options.exclude_projects] if options.owner: query_terms += ["owner:%s" % options.owner] query = "%20".join(query_terms) while True: q = query + "&n=%d&S=%d" % (step, offset) logging.debug("Query: %s", q) url = "/changes/?q=" + q result = gerrit.get(url) logging.debug("%d changes", len(result)) if not result: break stale_changes += result last = result[-1] if "_more_changes" in last: logging.debug("More...") offset += step else: break except Exception as e: logging.error(e) return 1 abandoned = 0 errors = 0 abandon_message = message if options.message: abandon_message += "\n\n" + options.message for change in stale_changes: number = change["_number"] try: owner = change["owner"]["name"] except: owner = "Unknown" subject = change["subject"] if len(subject) > 70: subject = subject[:65] + " [...]" change_id = change["id"] logging.info("%s (%s): %s", number, owner, subject) if options.dry_run: continue try: gerrit.post("/changes/" + change_id + "/abandon", data='{"message" : "%s"}' % abandon_message) abandoned += 1 except Exception as e: errors += 1 logging.error(e) logging.info("Total %d stale open changes", len(stale_changes)) if not options.dry_run: logging.info("Abandoned %d changes. %d errors.", abandoned, errors)
def _main(): parser = optparse.OptionParser() parser.add_option('-g', '--gerrit-url', dest='gerrit_url', metavar='URL', default=None, help='gerrit server URL') parser.add_option('-b', '--basic-auth', dest='basic_auth', action='store_true', help='use HTTP basic authentication instead of digest') parser.add_option('-n', '--dry-run', dest='dry_run', action='store_true', help='enable dry-run mode: show stale changes but do ' 'not abandon them') parser.add_option('-a', '--age', dest='age', metavar='AGE', default="6months", help='age of change since last update ' '(default: %default)') parser.add_option('-m', '--message', dest='message', metavar='STRING', default=None, help='Custom message to append to abandon message') parser.add_option('--branch', dest='branches', metavar='BRANCH_NAME', default=[], action='append', help='Abandon changes only on the given branch') parser.add_option('--exclude-branch', dest='exclude_branches', metavar='BRANCH_NAME', default=[], action='append', help='Do not abandon changes on given branch') parser.add_option('--project', dest='projects', metavar='PROJECT_NAME', default=[], action='append', help='Abandon changes only on the given project') parser.add_option('--exclude-project', dest='exclude_projects', metavar='PROJECT_NAME', default=[], action='append', help='Do not abandon changes on given project') parser.add_option('--owner', dest='owner', metavar='USERNAME', default=None, action='store', help='Only abandon changes owned by the given user') parser.add_option('-v', '--verbose', dest='verbose', action='store_true', help='enable verbose (debug) logging') (options, _args) = parser.parse_args() level = logging.DEBUG if options.verbose else logging.INFO logging.basicConfig(format='%(asctime)s %(levelname)s %(message)s', level=level) if not options.gerrit_url: logging.error("Gerrit URL is required") return 1 pattern = re.compile(r"^([\d]+)(month[s]?|year[s]?|week[s]?)") match = pattern.match(options.age) if not match: logging.error("Invalid age: %s", options.age) return 1 message = "Abandoning after %s %s or more of inactivity." % \ (match.group(1), match.group(2)) if options.basic_auth: auth_type = HTTPBasicAuthFromNetrc else: auth_type = HTTPDigestAuthFromNetrc try: auth = auth_type(url=options.gerrit_url) gerrit = GerritRestAPI(url=options.gerrit_url, auth=auth) except Exception as e: logging.error(e) return 1 logging.info(message) try: stale_changes = [] offset = 0 step = 500 query_terms = ["status:new", "age:%s" % options.age] if options.branches: query_terms += ["branch:%s" % b for b in options.branches] elif options.exclude_branches: query_terms += ["-branch:%s" % b for b in options.exclude_branches] if options.projects: query_terms += ["project:%s" % p for p in options.projects] elif options.exclude_projects: query_terms = ["-project:%s" % p for p in options.exclude_projects] if options.owner: query_terms += ["owner:%s" % options.owner] query = "%20".join(query_terms) while True: q = query + "&n=%d&S=%d" % (step, offset) logging.debug("Query: %s", q) url = "/changes/?q=" + q result = gerrit.get(url) logging.debug("%d changes", len(result)) if not result: break stale_changes += result last = result[-1] if "_more_changes" in last: logging.debug("More...") offset += step else: break except Exception as e: logging.error(e) return 1 abandoned = 0 errors = 0 abandon_message = message if options.message: abandon_message += "\n\n" + options.message for change in stale_changes: number = change["_number"] try: owner = change["owner"]["name"] except: owner = "Unknown" subject = change["subject"] if len(subject) > 70: subject = subject[:65] + " [...]" change_id = change["id"] logging.info("%s (%s): %s", number, owner, subject) if options.dry_run: continue try: gerrit.post("/changes/" + change_id + "/abandon", data='{"message" : "%s"}' % abandon_message) abandoned += 1 except Exception as e: errors += 1 logging.error(e) logging.info("Total %d stale open changes", len(stale_changes)) if not options.dry_run: logging.info("Abandoned %d changes. %d errors.", abandoned, errors)
def _main(): descr = "Perform bulk operations on Gerrit" parser = argparse.ArgumentParser( description=descr, formatter_class=argparse.ArgumentDefaultsHelpFormatter ) parser.add_argument( "-u", "--gerrit-url", dest="url", required=False, default="https://gerrit-review.googlesource.com", help="Gerrit URL", ) parser.add_argument( "-q", "--query", dest="query", required=True, action="store", help="query" ) parser.add_argument( "-o", "--option", dest="options", required=False, action="append", help="query options", ) parser.add_argument( "-c", "--commands", dest="commands", required=False, action="store_true", help="how to fetch changes; appends -o " + REVISION + " -o " + COMMANDS, ) parser.add_argument( "-a", "--approve", dest="approve", required=False, action="store_true", help="apply Code-Review+2 to changes", ) parser.add_argument( "-v", "--verify", dest="verify", required=False, action="store_true", help="apply Verified+1 to changes", ) parser.add_argument( "-s", "--submit", dest="submit", required=False, action="store_true", help="submit changes", ) parser.add_argument( "-f", "--filter", dest="filter", required=False, help="filter changes by project prefix", ) parser.add_argument( "-fs", "--subject", dest="subject", required=False, help="filter changes by subject prefix", ) parser.add_argument( "--abandon", dest="abandon", required=False, action="store_true", help="abandon changes", ) parser.add_argument( "--hashtag", dest="hashtags", required=False, action="append", help="add hashtags", ) parser.add_argument( "-r", "--reviewer", dest="reviewers", required=False, action="append", help="add reviewers", ) options = parser.parse_args() api = GerritRestAPI(url=options.url) query_terms = options.query.replace(" ", "%20") uri = "/changes/?q=" + query_terms query_options = [o.upper() for o in options.options] if options.options else [] if options.commands: if REVISION not in query_options: query_options.append(REVISION) if COMMANDS not in query_options: query_options.append(COMMANDS) if query_options: uri += "".join(["&o=%s" % o for o in query_options]) changes = api.get(uri) changes_count = len(changes) print("Found %d changes" % changes_count) if options.filter: changes = [c for c in changes if c["project"].startswith(options.filter)] if options.subject: changes = [c for c in changes if c["subject"].startswith(options.subject)] filtered_count = len(changes) if filtered_count < changes_count: print("Filtered out %d changes" % (changes_count - filtered_count)) labels = {} review = {} if options.reviewers: review["reviewers"] = [{"reviewer": r} for r in options.reviewers] if options.verify: labels["Verified"] = 1 if options.approve: labels["Code-Review"] = 2 if labels: review["labels"] = labels for change in changes: print("%s : %s" % (change["project"], change["subject"])) try: if options.hashtags: hashtags = {"add": options.hashtags} api.post("/changes/%s/hashtags" % change["id"], json=hashtags) if options.abandon: api.post("/changes/%s/abandon" % change["id"]) continue if review: api.post( "/changes/%s/revisions/current/review" % change["id"], json=review ) if options.submit: api.post("/changes/%s/submit" % change["id"]) except Exception as e: print("Operation failed: %s" % e, file=sys.stderr) if options.commands: for change in changes: repo = change["project"].split("/")[-1] command = next(iter(change["revisions"].values()))["fetch"]["http"][ "commands" ]["Checkout"] print("cd %s && %s && cd -" % (repo, command))
def _main(): parser = optparse.OptionParser() parser.add_option( "-g", "--gerrit-url", dest="gerrit_url", metavar="URL", default=None, help="gerrit server URL", ) parser.add_option( "-b", "--basic-auth", dest="basic_auth", action="store_true", help="(deprecated) use HTTP basic authentication instead of digest", ) parser.add_option( "-d", "--digest-auth", dest="digest_auth", action="store_true", help="use HTTP digest authentication instead of basic", ) parser.add_option( "-n", "--dry-run", dest="dry_run", action="store_true", help="enable dry-run mode: show stale changes but do not abandon them", ) parser.add_option( "-t", "--test", dest="testmode", action="store_true", help="test mode: query changes with the `test-abandon` " "topic and ignore age option", ) parser.add_option( "-a", "--age", dest="age", metavar="AGE", default="6months", help="age of change since last update in days, months" " or years (default: %default)", ) parser.add_option( "-m", "--message", dest="message", metavar="STRING", default=None, help="custom message to append to abandon message", ) parser.add_option( "--branch", dest="branches", metavar="BRANCH_NAME", default=[], action="append", help="abandon changes only on the given branch", ) parser.add_option( "--exclude-branch", dest="exclude_branches", metavar="BRANCH_NAME", default=[], action="append", help="do not abandon changes on given branch", ) parser.add_option( "--project", dest="projects", metavar="PROJECT_NAME", default=[], action="append", help="abandon changes only on the given project", ) parser.add_option( "--exclude-project", dest="exclude_projects", metavar="PROJECT_NAME", default=[], action="append", help="do not abandon changes on given project", ) parser.add_option( "--owner", dest="owner", metavar="USERNAME", default=None, action="store", help="only abandon changes owned by the given user", ) parser.add_option( "--exclude-wip", dest="exclude_wip", action="store_true", help="Exclude changes that are Work-in-Progress", ) parser.add_option( "-v", "--verbose", dest="verbose", action="store_true", help="enable verbose (debug) logging", ) (options, _args) = parser.parse_args() level = logging.DEBUG if options.verbose else logging.INFO logging.basicConfig(format="%(asctime)s %(levelname)s %(message)s", level=level) if not options.gerrit_url: logging.error("Gerrit URL is required") return 1 if options.testmode: message = "Abandoning in test mode" else: pattern = re.compile(r"^([\d]+)(month[s]?|year[s]?|week[s]?)") match = pattern.match(options.age) if not match: logging.error("Invalid age: %s", options.age) return 1 message = "Abandoning after %s %s or more of inactivity." % ( match.group(1), match.group(2), ) if options.digest_auth: auth_type = HTTPDigestAuthFromNetrc else: auth_type = HTTPBasicAuthFromNetrc try: auth = auth_type(url=options.gerrit_url) gerrit = GerritRestAPI(url=options.gerrit_url, auth=auth) except Exception as e: logging.error(e) return 1 logging.info(message) try: stale_changes = [] offset = 0 step = 500 if options.testmode: query_terms = ["status:new", "owner:self", "topic:test-abandon"] else: query_terms = ["status:new", "age:%s" % options.age] if options.exclude_wip: query_terms += ["-is:wip"] if options.branches: query_terms += ["branch:%s" % b for b in options.branches] elif options.exclude_branches: query_terms += ["-branch:%s" % b for b in options.exclude_branches] if options.projects: query_terms += ["project:%s" % p for p in options.projects] elif options.exclude_projects: query_terms = ["-project:%s" % p for p in options.exclude_projects] if options.owner and not options.testmode: query_terms += ["owner:%s" % options.owner] query = "%20".join(query_terms) while True: q = query + "&o=DETAILED_ACCOUNTS&n=%d&S=%d" % (step, offset) logging.debug("Query: %s", q) url = "/changes/?q=" + q result = gerrit.get(url) logging.debug("%d changes", len(result)) if not result: break stale_changes += result last = result[-1] if "_more_changes" in last: logging.debug("More...") offset += step else: break except Exception as e: logging.error(e) return 1 abandoned = 0 errors = 0 abandon_message = message if options.message: abandon_message += "\n\n" + options.message for change in stale_changes: number = change["_number"] project = "" if len(options.projects) != 1: project = "%s: " % change["project"] owner = "" if options.verbose: try: o = change["owner"]["name"] except KeyError: o = "Unknown" owner = " (%s)" % o subject = change["subject"] if len(subject) > 70: subject = subject[:65] + " [...]" change_id = change["id"] logging.info("%s%s: %s%s", number, owner, project, subject) if options.dry_run: continue try: gerrit.post( "/changes/" + change_id + "/abandon", json={"message": "%s" % abandon_message}, ) abandoned += 1 except Exception as e: errors += 1 logging.error(e) logging.info("Total %d stale open changes", len(stale_changes)) if not options.dry_run: logging.info("Abandoned %d changes. %d errors.", abandoned, errors)