Skip to content

Instantly share code, notes, and snippets.

@stmobo
Last active December 9, 2019 14:46
Show Gist options
  • Save stmobo/9b96d4908bb53060e9f080eba4e8fd1b to your computer and use it in GitHub Desktop.
Save stmobo/9b96d4908bb53060e9f080eba4e8fd1b to your computer and use it in GitHub Desktop.
import subprocess as sp
import sys
import re
import dateutil.parser
from datetime import timezone
from pathlib import PurePath
git_log_format = [
"commit %H",
"refs: %D",
"author: %aN",
"committer: %cn",
"date: %aI",
"",
"%s"
]
log_match_re = r"commit ([0-9a-f]{40})\n((?:(?:[a-zA-Z]+):(?:[^\n]*)\n)+)\n([^\n]+)\n\n((?:[^\n]+\n(?!commit))*[^\n]+\n?)"
merge_request_namespace = 'upstream/merge-requests/'
def format_character_name(name):
if name == "saki_zls":
return "Saki (ZLS)"
elif name == "misty_hgss":
return "Misty (HGSS)"
elif name == "rarity_eg":
return "Rarity (EG)"
elif name == 'hk416':
return "HK416"
else:
name = name.replace('_', ' ')
name = re.sub(r"\w+", lambda m: m.group(0).capitalize(), name)
return name
def main():
if len(sys.argv) < 3:
sys.stderr.write("USAGE: {:s} [start commit] ['author'|'character']\n".format(sys.argv[0]))
sys.exit(1)
ret = sp.run(["git", "rev-parse", "--show-toplevel"], encoding="utf-8", capture_output=True)
if ret.returncode != 0:
sys.stderr.write("git fetch failed with error {:d}\n".format(ret.returncode))
sys.stderr.write(ret.stderr+"\n")
sys.exit(1)
repo_dir = ret.stdout.strip()
fetch_cmd = sp.run(["git", "fetch", "upstream"], cwd=repo_dir, stdout=sp.PIPE, stderr=sp.STDOUT, encoding="utf-8")
if fetch_cmd.returncode != 0:
sys.stderr.write("git fetch failed with error {:d}\n".format(fetch_cmd.returncode))
sys.stderr.write(fetch_cmd.stdout+"\n")
sys.exit(1)
log_data = sp.run(
[
"git", "log",
"--no-merges",
"--name-only",
"--format="+"%n".join(git_log_format),
sys.argv[1]+"..upstream/master"
],
cwd=repo_dir,
capture_output=True,
encoding="utf-8"
)
commits = []
for match in re.finditer(log_match_re, log_data.stdout):
commit_data = {
'sha': match[1],
'message': match[3].strip(),
'author': None,
'committer': (None, None),
'date': None,
'merge_requests': [],
'tags': [],
'topic': '',
'characters': []
}
opps = set()
for file in match[4].split('\n'):
p = PurePath(file)
try:
if p.parts[0] == 'opponents' and len(p.parts) > 2:
opps.add(p.parts[1].casefold())
except (IndexError, ValueError):
continue
commit_data['characters'] = list(opps)
for metadata in match[2].split('\n'):
kv = metadata.split(':', maxsplit=1)
key = kv[0].strip().lower()
try:
value = kv[1].strip()
except IndexError:
value = ''
if key == 'author':
commit_data['author'] = value
elif key == 'committer':
commit_data['committer'] = value
elif key == 'date':
commit_data['date'] = dateutil.parser.isoparse(value)
elif key == 'refs':
merge_requests = []
tags = []
for ref in value.split(','):
ref = ref.strip()
if ref.startswith(merge_request_namespace):
try:
mr_num = int(ref[len(merge_request_namespace):])
merge_requests.append(mr_num)
except ValueError:
continue
elif ref.startswith('tag: '):
tags.append(ref[5:])
commit_data['merge_requests'] = merge_requests
commit_data['tags'] = tags
if commit_data['committer'] == 'SPNATI Utilities Bot' and '#' in commit_data['author']:
# attempt to auto-detect discord usernames
author_name, author_tag = commit_data['author'].rsplit('#', maxsplit=1)
if len(author_tag) == 4 and author_tag.isdecimal():
commit_data['author'] = author_name
if ':' in commit_data['message']:
commit_data['topic'] = commit_data['message'].split(':', maxsplit=1)[0].casefold()
elif len(opps) > 0:
commit_data['topic'] = ', '.join(opps)
commits.append(commit_data)
groups = {}
# filter out version update commits:
commits = list(filter(lambda c: c['author'] != 'SPNATI Utilities Bot' or len(c['tags']) == 0, commits))
# organize commits:
for commit in commits:
commit_groups = []
if sys.argv[2] == 'author':
commit_groups = (commit['author'],)
elif sys.argv[2] == 'character':
commit_groups = commit['characters']
for group in commit_groups:
if group not in groups:
groups[group] = []
groups[group].append(commit)
for group_key, commit_set in sorted(groups.items(), key=lambda kv: kv[0]):
commit_set = sorted(commit_set, key=lambda c: c['date'], reverse=True)
commit_set = sorted(commit_set, key=lambda c: c['topic'])
if sys.argv[2] == 'character':
group_key = format_character_name(group_key)
sys.stdout.write("{:s} ({:d}):\n".format(group_key, len(commit_set)))
for commit in commit_set:
utc_date = commit['date'].astimezone(timezone.utc)
sys.stdout.write(" ")
sys.stdout.write(utc_date.strftime("[%d %b %Y] "))
sys.stdout.write(commit['message'])
if len(commit['merge_requests']) > 0:
sys.stdout.write(" ("+', '.join('!'+str(mr) for mr in commit['merge_requests'])+")")
sys.stdout.write("\n")
sys.stdout.write("\n")
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment