contributors.py Python3 refactor
This commit is contained in:
189
contrib/contributors.py
Executable file → Normal file
189
contrib/contributors.py
Executable file → Normal file
@@ -1,4 +1,4 @@
|
|||||||
#!/usr/bin/python2
|
#!/usr/bin/python3
|
||||||
"""Update the contributor list
|
"""Update the contributor list
|
||||||
|
|
||||||
Alias handling is done by git with .mailmap
|
Alias handling is done by git with .mailmap
|
||||||
@@ -6,110 +6,133 @@ New contributors are merged in the short-term list.
|
|||||||
Moving them to a "higher" list should be a manual process.
|
Moving them to a "higher" list should be a manual process.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import fileinput
|
import re
|
||||||
from subprocess import Popen, PIPE
|
from pathlib import Path
|
||||||
|
import subprocess
|
||||||
|
|
||||||
|
CONTRIB_FILE_CONTRIBUTOR_RE = re.compile(r'\* (.+) (<.+>)')
|
||||||
|
|
||||||
|
|
||||||
def format_contributor(contributor):
|
def format_contributor(contributor):
|
||||||
return " * {0} {1}".format(
|
return " * {0} {1}".format(contributor["name"], contributor["email"])
|
||||||
" ".join(contributor["name"]),
|
|
||||||
contributor["email"])
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def get_contributors():
|
||||||
# generate list of contributors
|
""" Parse all contributors from output of git shortlog -se
|
||||||
|
"""
|
||||||
contributors = []
|
contributors = []
|
||||||
p_git = Popen(["git", "shortlog", "-se"], stdout=PIPE)
|
p_git = subprocess.run(["git", "shortlog", "-se"], stdout=subprocess.PIPE)
|
||||||
for line in p_git.stdout:
|
for line in p_git.stdout.decode('utf-8').split('\n'):
|
||||||
contributors.append({
|
m = re.search(r"(\d+)\t(.+) (<.+>)", line)
|
||||||
'count': int(line.split("\t")[0].strip()),
|
if m:
|
||||||
'name': line.split("\t")[1].split()[0:-1],
|
contributors.append({
|
||||||
'email': line.split("\t")[1].split()[-1]
|
"count": int(m.group(1)),
|
||||||
|
"name": m.group(2),
|
||||||
|
"email": m.group(3)
|
||||||
})
|
})
|
||||||
|
return contributors
|
||||||
|
|
||||||
# cache listed contributors
|
|
||||||
|
def get_old_contributors(contrib_file_lines):
|
||||||
|
""" Parse existing contributors from CONTRIBUTORS.rst
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
(list) Contributors as {"name", "email"} dicts
|
||||||
|
"""
|
||||||
old_contributors = []
|
old_contributors = []
|
||||||
with open("CONTRIBUTORS.rst", "r") as contrib_file:
|
for line in contrib_file_lines:
|
||||||
for line in contrib_file:
|
m = CONTRIB_FILE_CONTRIBUTOR_RE.search(line)
|
||||||
if "@" in line:
|
if m:
|
||||||
old_contributors.append({
|
old_contributors.append({"name": m.group(1), "email": m.group(2)})
|
||||||
'name': line.split()[1:-1],
|
return old_contributors
|
||||||
'email': line.split()[-1]
|
|
||||||
})
|
|
||||||
|
|
||||||
old = map(lambda x: (x['name'], x['email']), old_contributors)
|
|
||||||
old_emails = map(lambda x: x['email'], old_contributors)
|
|
||||||
old_names = map(lambda x: x['name'], old_contributors)
|
|
||||||
|
|
||||||
# check which contributors are new
|
def get_new_contributors(contributors, old_contributors):
|
||||||
|
""" Find new contributors and any possible alias or email changes
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
(tuple) list of new contributors,
|
||||||
|
list of new aliases as (contributor, existing_name),
|
||||||
|
list of new emails as (contributor, existing_email)
|
||||||
|
"""
|
||||||
|
old_email_names = {c['email']: c['name'] for c in old_contributors}
|
||||||
|
old_name_emails = {c['name']: c['email'] for c in old_contributors}
|
||||||
new_contributors = []
|
new_contributors = []
|
||||||
update_mailmap = False
|
new_alias = []
|
||||||
|
new_email = []
|
||||||
for contributor in contributors:
|
for contributor in contributors:
|
||||||
if (contributor['name'], contributor['email']) in old:
|
name, email = contributor['name'], contributor['email']
|
||||||
# this exact combination already in the list
|
existing_name, existing_email = old_email_names.get(email), old_name_emails.get(name)
|
||||||
|
|
||||||
|
if existing_name == name and existing_email == email:
|
||||||
|
# exact combination already in list
|
||||||
pass
|
pass
|
||||||
elif (contributor['email'] not in old_emails
|
elif existing_name is None and existing_email is None:
|
||||||
and contributor['name'] not in old_names):
|
|
||||||
# name AND email are not in the list
|
|
||||||
new_contributors.append(contributor)
|
new_contributors.append(contributor)
|
||||||
elif contributor['email'] in old_emails:
|
elif existing_name is not None:
|
||||||
# email is listed, but with another name
|
new_alias.append((contributor, existing_name))
|
||||||
old_name = filter(lambda x: x['email'] == contributor['email'],
|
elif existing_email is not None:
|
||||||
old_contributors)[0]['name']
|
new_email.append((contributor, existing_email))
|
||||||
print "new alias %s for %s %s ?" % (
|
return (
|
||||||
" ".join(contributor['name']),
|
sorted(new_contributors, key=lambda x: x['name'].split()[-1].lower()),
|
||||||
" ".join(old_name),
|
new_alias,
|
||||||
contributor['email'])
|
new_email
|
||||||
update_mailmap = True
|
)
|
||||||
elif contributor['name'] in old_names:
|
|
||||||
# probably a new email for a previous contributor
|
|
||||||
other_mail = filter(lambda x: x['name'] == contributor['name'],
|
|
||||||
old_contributors)[0]['email']
|
|
||||||
print "new email %s for %s %s ?" % (
|
|
||||||
contributor['email'],
|
|
||||||
" ".join(contributor['name']),
|
|
||||||
other_mail)
|
|
||||||
update_mailmap = True
|
|
||||||
if update_mailmap:
|
|
||||||
print "Please update .mailmap"
|
|
||||||
|
|
||||||
# sort on the last word of the name
|
|
||||||
new_contributors = sorted(new_contributors,
|
|
||||||
key=lambda x: x['name'][-1].lower())
|
|
||||||
|
|
||||||
# show new contributors to be merged to the list
|
def merge_short_term_contributors(contrib_file_lines, new_contributors):
|
||||||
if new_contributors:
|
""" Merge new contributors into Short-term Contributions section in
|
||||||
print "inserting:"
|
alphabetical order.
|
||||||
for contributor in new_contributors:
|
|
||||||
print format_contributor(contributor)
|
|
||||||
|
|
||||||
# merge with alphabetical (by last part of name) contributor list
|
Returns:
|
||||||
i = 0
|
(list) Lines including new contributors for writing to CONTRIBUTORS.rst
|
||||||
|
"""
|
||||||
short_term_found = False
|
short_term_found = False
|
||||||
for line in fileinput.input("CONTRIBUTORS.rst", inplace=1):
|
for (i, line) in enumerate(contrib_file_lines):
|
||||||
if not short_term_found:
|
if not short_term_found:
|
||||||
print line,
|
|
||||||
if "Short-term" in line:
|
if "Short-term" in line:
|
||||||
short_term_found = True
|
short_term_found = True
|
||||||
else:
|
else:
|
||||||
if i >= len(new_contributors) or "@" not in line:
|
if CONTRIB_FILE_CONTRIBUTOR_RE.search(line):
|
||||||
print line,
|
break
|
||||||
else:
|
|
||||||
listed_name = line.split()[-2].lower()
|
short_term_contributor_lines = [l for l in contrib_file_lines[i:] if l] + \
|
||||||
contributor = new_contributors[i]
|
[format_contributor(c) + "\n" for c in new_contributors]
|
||||||
# insert all new contributors that fit here
|
|
||||||
while listed_name > contributor["name"][-1].lower():
|
def last_name_sort(contrib_line):
|
||||||
print format_contributor(contributor)
|
m = CONTRIB_FILE_CONTRIBUTOR_RE.search(contrib_line)
|
||||||
i += 1
|
return m.group(1).split()[-1].lower()
|
||||||
if i < len(new_contributors):
|
|
||||||
contributor = new_contributors[i]
|
return contrib_file_lines[:i] + sorted(short_term_contributor_lines, key=last_name_sort)
|
||||||
else:
|
|
||||||
break
|
|
||||||
print line,
|
def main():
|
||||||
# append remaining contributors
|
contrib_file = Path("CONTRIBUTORS.rst")
|
||||||
with open("CONTRIBUTORS.rst", "a") as contrib_file:
|
with contrib_file.open() as f:
|
||||||
while i < len(new_contributors):
|
contrib_file_lines = f.readlines()
|
||||||
contrib_file.write(format_contributor(new_contributors[i]) + "\n")
|
|
||||||
i += 1
|
old_contributors = get_old_contributors(contrib_file_lines)
|
||||||
|
|
||||||
|
contributors = get_contributors()
|
||||||
|
new_contributors, new_alias, new_email = get_new_contributors(contributors, old_contributors)
|
||||||
|
|
||||||
|
for contributor, old_name in new_alias:
|
||||||
|
print("new alias {0} for {1} {2} ?".format(
|
||||||
|
contributor['name'], old_name, contributor['email']))
|
||||||
|
|
||||||
|
for contributor, old_email in new_email:
|
||||||
|
print("new email {0} for {1} {2} ?".format(
|
||||||
|
contributor['email'], contributor['name'], old_email))
|
||||||
|
|
||||||
|
if new_alias or new_email:
|
||||||
|
print("Please update .mailmap")
|
||||||
|
|
||||||
|
if new_contributors:
|
||||||
|
print("inserting:")
|
||||||
|
print("\n".join([format_contributor(c) for c in new_contributors]))
|
||||||
|
|
||||||
|
with contrib_file.open("w") as f:
|
||||||
|
f.writelines(merge_short_term_contributors(contrib_file_lines, new_contributors))
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|||||||
Reference in New Issue
Block a user