tools/review-tools/cherry-checker

162 lines
4.3 KiB
Python
Executable File

#!/usr/bin/env python3
import argparse
import subprocess
import re
import sys
left = "master"
right = "OpenSSL_1_1_1-stable"
def parse_arguments():
parser = argparse.ArgumentParser(
description = """Shows the commits in '{left}...{right}'
which are eligible for cherry-picking. A commit is considered
cherry-picked, if there is another commit on the "other side"
which introduces an equivalent patch.
For details, see the documentation of the '--cherry-mark' option
in the git-log(1) manpage.
""".format(left=left, right=right))
parser.add_argument(
'-a', '--all',
action = 'store_true',
help = "Show all commits, also those which have been cherry-picked."\
)
parser.add_argument(
'-s', '--sort',
action = 'store_true',
help = "Sort commits w.r.t. pull request number and author date."\
)
parser.add_argument(
'-r', '--remote',
action = 'store_true',
help = "Compare the remote branches instead of the local ones."\
)
args = parser.parse_args()
return args
def check_openssl_git_repo():
"""Checks whether we're inside a openssl.git downstrem repository"""
try:
if "/openssl.git" in subprocess.check_output(
["git", "remote", "-v"]
).decode():
return True;
except:
pass
return False
def get_remote():
try:
return subprocess.check_output(
["git", "config", "branch.master.remote"]
).decode().trim()
except:
return "origin"
def pick_cherries(left, right, all = False):
"""Lists all commits from the symmetric difference of left and right
By default, all commits are omitted which have an 'equivalent' commit
on the other side, unless 'all' == True.
"""
git_command = [
"git", "log", "--oneline", "--cherry-mark", "--left-right",
left + "..." + right, "--pretty=%at;%m;%h;%s"
]
prnum_regex = re.compile("|".join([
# The standard pull request annotation
"\(Merged from https://github.com/openssl/openssl/pull/([0-9]+)\)",
# @kroeck's special pull request annotation ;-)
"GH: #([0-9]+)"
]))
fixes_regex = re.compile(
"Fixes[:]?\s+(#|https://github.com/openssl/openssl/pull/)([0-9]+)")
for line in subprocess.check_output(git_command).decode().splitlines():
timestamp, branch, commit, subject = line.split(";", maxsplit=3)
if branch == '=' and not all:
continue
# shorten overlong subject lines
if len(subject) > 70:
subject = subject[:70] + "..."
# search commit message for pull request number
message = subprocess.check_output(
["git", "show", "--no-patch", commit]
).decode()
match = prnum_regex.search(message)
if match:
if match.group(1):
prnum = match.group(1)
else:
prnum = match.group(2)
else:
prnum = "????"
match = fixes_regex.search(message)
if match:
fixes = "#" + match.group(2)
else:
fixes = ""
yield prnum, fixes, timestamp, branch, commit, subject
if __name__ == '__main__':
args = parse_arguments()
if not check_openssl_git_repo():
print("cherry-checker: Not inside an openssl git repository.", file=sys.stderr)
sys.exit(1)
if args.remote:
remote = get_remote()
left = remote+"/"+left
right = remote+"/"+right
commits = pick_cherries(left, right, args.all)
if args.sort:
commits = sorted(commits, reverse=True)
print("""These cherries are hanging on the git-tree:
<- {left}
-> {right}
== both
prnum | fixes | br | commit | subject
------- | ------ | -- | ---------- | -------------------------------------------""".format(
left = left,
right = right))
branch_marker = { '<': '<-', '>': '->', '=' : '==' }
try:
for prnum, fixes, _, branch, commit, subject in commits:
print(' {:>6} | {:>6} | {} | {} | {} '.format(
'#'+prnum, fixes, branch_marker[branch], commit, subject
))
except subprocess.CalledProcessError as e:
print(e, file=sys.stderr)