#!/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 = ['linux-xfs@vger.kernel.org', 'linux-fsdevel@vger.kernel.org'] 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())