-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathgit-mig-auto-msg
executable file
·116 lines (92 loc) · 3.37 KB
/
git-mig-auto-msg
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
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
#!/usr/bin/env python3
"""
Usage:
# basic usage
git mig-auto-msg "some changes" | git commit -F-
# if you specify coauthors, you need to preserve the verbatim generated message to avoid
# removing double empty lines (needed to be correctly parsed by github)
git mig-auto-msg -c nse "odoo.com specific" | git commit -F- --cleanup=verbatim
# when amending commit, the `--amend` flag has to be used to determine all files touched by
# then commit
git mig-auto-msg --amend | git commit -F- --amend
"""
from collections import defaultdict
from email.utils import parseaddr, formataddr
from functools import reduce
import operator
from subprocess import check_output
import click
remote = check_output(['git', 'remote', 'get-url', 'origin']).decode().strip()
assert remote in {"[email protected]:odoo/upgrade.git", "[email protected]:odoo/saas-migration.git"}
def rs(s):
assert s
if len(s) == 1:
return list(s)[0]
return '{' + ','.join(sorted(s)) + '}'
def format_coauthor(coauthor):
p = parseaddr(coauthor)
if p[0]:
return formataddr(p)
# no formated correctly, search author
commit = check_output(["git", "rev-list", "--all", "-i", "-n1", "--author", coauthor]).decode().strip()
if not commit:
return coauthor
author = check_output(["git", "show", "--no-patch", "--format=%an%n%ae", commit]).decode().strip()
return formataddr(author.split("\n"))
@click.command()
@click.option('-A', 'tag', flag_value='[ADD]')
@click.option('-F', 'tag', flag_value='[FIX]')
@click.option('-c', 'coauthors', type=str, multiple=True)
@click.option('--amend', is_flag=True)
@click.argument('message', required=False)
def main(tag=None, message=None, coauthors=(), amend=False):
status = check_output(['git', 'status', '--porcelain']).decode()
if amend:
status += "\n"
status += check_output(['git', 'show', '--format=', '--name-status', 'HEAD']).decode()
mods = defaultdict(set)
util = False
guess_tag = '[ADD]'
for l in status.splitlines():
if not l or l[0] not in 'AM':
continue
if l[0] == 'M':
guess_tag = '[FIX]'
f = l[2:].strip()
if f.startswith("migrations/util/"):
util = True
continue
try:
_, module, version, *_ = f.split('/')
except ValueError:
# Not an upgrade script?
continue
version = '.'.join(version.split('.')[:2]) if version != '0.0.0' else '0.0.0'
mods[module].add(version)
agg = []
if util:
agg = ['util']
while mods:
common_versions = reduce(operator.and_, mods.values())
agg_mod = {k for k, v in mods.items() if v == common_versions}
if not agg_mod:
break
agg.append('{}/{}'.format(rs(agg_mod), rs(common_versions)))
new_mods = defaultdict(set)
for m in mods:
v = mods[m] - common_versions
if v:
new_mods[m] = v
mods = new_mods
for m, v in mods.items():
agg.append('{}/{}'.format(m, rs(v)))
if tag is None:
tag = guess_tag
output = '{} {}'.format(tag, ','.join(agg))
if message:
output += ': ' + message
if coauthors:
output += "\n\n\n" + "\n".join("Co-authored-by: %s" % format_coauthor(ca) for ca in coauthors)
print(output)
if __name__ == '__main__':
main()