summaryrefslogtreecommitdiff
path: root/git_contributors.py
blob: 91a7f6a5eeca458354b72857d0a8382be73e8b74 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
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())