diff options
Diffstat (limited to 'git_contributors.py')
| -rw-r--r-- | git_contributors.py | 68 |
1 files changed, 68 insertions, 0 deletions
diff --git a/git_contributors.py b/git_contributors.py new file mode 100644 index 0000000..91a7f6a --- /dev/null +++ b/git_contributors.py @@ -0,0 +1,68 @@ +#!/usr/bin/python3 + +# List all contributors to a series of git commits. +# Copyright(C) 2022 Darrick J. Wong, All Rights Reserved. +# Licensed under GPL 2.0 or later + +import re +import subprocess +import io +import sys +import argparse + +DEBUG = False + +def backtick(args): + '''Generator function that yields lines of a program's stdout.''' + if DEBUG: + print(' '.join(args)) + p = subprocess.Popen(args, stdout = subprocess.PIPE) + for line in io.TextIOWrapper(p.stdout, encoding="utf-8"): + yield line.strip() + +def get_developers(revspec): + """Return the address list generated from signed-off-by and + acked-by lines in the message. + """ + addr_list = ['[email protected]', '[email protected]'] + tags = '%s|%s|%s|%s|%s|%s|%s|%s' % ( + 'signed-off-by', + 'acked-by', + 'cc', + 'reviewed-by', + 'reported-by', + 'tested-by', + 'suggested-by', + 'reported-and-tested-by') + regex1 = r'^(%s):\s+(.+)$' % tags + regex2 = r'^(%s):\s+.+<(.+)>$' % tags + + r1 = re.compile(regex1, re.I) + r2 = re.compile(regex2, re.I) + + for output in backtick(['git', 'log', '--pretty=medium', revspec]): + m = r2.match(output) + if m: + addr_list.append(m.expand(r'\g<2>')) + continue + m = r1.match(output) + if m: + addr_list.append(m.expand(r'\g<2>')) + + return set(addr_list) + +def main(): + parser = argparse.ArgumentParser(description = "List email addresses of contributors to a series of git commits.") + parser.add_argument("revisions", nargs = 1, \ + help = "git revisions to process.") + parser.add_argument("--delimiter", type = str, default = '\n', \ + help = "Separate each email address with this string.") + args = parser.parse_args() + + contributors = get_developers(args.revisions[0]) + + print(args.delimiter.join(sorted(contributors))) + return 0 + +if __name__ == '__main__': + sys.exit(main()) |
