##// END OF EJS Templates
relnotes: enable extension when running releasenotes command...
Pulkit Goyal -
r39401:659e2bbd default
parent child Browse files
Show More
@@ -1,179 +1,181 b''
1 #!/usr/bin/env python3
1 #!/usr/bin/env python3
2 """Generate release notes from our commit log.
2 """Generate release notes from our commit log.
3
3
4 This uses the relnotes extension directives when they're available,
4 This uses the relnotes extension directives when they're available,
5 and falls back to our old pre-relnotes logic that used to live in the
5 and falls back to our old pre-relnotes logic that used to live in the
6 release-tools repo.
6 release-tools repo.
7 """
7 """
8 import argparse
8 import argparse
9 import re
9 import re
10 import subprocess
10 import subprocess
11
11
12 # Regenerate this list with
12 # Regenerate this list with
13 # hg export 'grep("\.\. [a-z]+::")' | grep '^\.\.' | \
13 # hg export 'grep("\.\. [a-z]+::")' | grep '^\.\.' | \
14 # sed 's/.. //;s/::.*//' | sort -u
14 # sed 's/.. //;s/::.*//' | sort -u
15 rnsections = ["api", "bc", "container", "feature", "fix", "note", "perf"]
15 rnsections = ["api", "bc", "container", "feature", "fix", "note", "perf"]
16
16
17 rules = {
17 rules = {
18 # keep
18 # keep
19 r"\(issue": 100,
19 r"\(issue": 100,
20 r"\(BC\)": 100,
20 r"\(BC\)": 100,
21 r"\(API\)": 100,
21 r"\(API\)": 100,
22 # core commands, bump up
22 # core commands, bump up
23 r"(commit|files|log|pull|push|patch|status|tag|summary)(|s|es):": 20,
23 r"(commit|files|log|pull|push|patch|status|tag|summary)(|s|es):": 20,
24 r"(annotate|alias|branch|bookmark|clone|graft|import|verify).*:": 20,
24 r"(annotate|alias|branch|bookmark|clone|graft|import|verify).*:": 20,
25 # extensions, bump up
25 # extensions, bump up
26 r"(mq|shelve|rebase):": 20,
26 r"(mq|shelve|rebase):": 20,
27 # newsy
27 # newsy
28 r": deprecate": 20,
28 r": deprecate": 20,
29 r"(option|feature|command|support)": 10,
29 r"(option|feature|command|support)": 10,
30 # bug-like?
30 # bug-like?
31 r"(fix|don't break|improve)": 7,
31 r"(fix|don't break|improve)": 7,
32 # boring stuff, bump down
32 # boring stuff, bump down
33 r"^contrib": -5,
33 r"^contrib": -5,
34 r"debug": -5,
34 r"debug": -5,
35 r"help": -5,
35 r"help": -5,
36 r"(doc|bundle2|obsolete|obsmarker|rpm|setup|debug\S+:)": -15,
36 r"(doc|bundle2|obsolete|obsmarker|rpm|setup|debug\S+:)": -15,
37 r"(check-code|check-commit|import-checker)": -20,
37 r"(check-code|check-commit|import-checker)": -20,
38 # cleanups and refactoring
38 # cleanups and refactoring
39 r"(cleanup|whitespace|nesting|indent|spelling|comment)": -20,
39 r"(cleanup|whitespace|nesting|indent|spelling|comment)": -20,
40 r"(typo|hint|note|style:|correct doc)": -20,
40 r"(typo|hint|note|style:|correct doc)": -20,
41 r"_": -10,
41 r"_": -10,
42 r"(argument|absolute_import|attribute|assignment|mutable)": -15,
42 r"(argument|absolute_import|attribute|assignment|mutable)": -15,
43 r"(unused|useless|unnecessary|duplicate|deprecated|scope|True|False)": -10,
43 r"(unused|useless|unnecessary|duplicate|deprecated|scope|True|False)": -10,
44 r"(redundant|pointless|confusing|uninitialized|meaningless|dead)": -10,
44 r"(redundant|pointless|confusing|uninitialized|meaningless|dead)": -10,
45 r": (drop|remove|inherit|rename|simplify|naming|inline)": -10,
45 r": (drop|remove|inherit|rename|simplify|naming|inline)": -10,
46 r"(docstring|document .* method)": -20,
46 r"(docstring|document .* method)": -20,
47 r"(factor|extract|prepare|split|replace| import)": -20,
47 r"(factor|extract|prepare|split|replace| import)": -20,
48 r": add.*(function|method|implementation|test|example)": -10,
48 r": add.*(function|method|implementation|test|example)": -10,
49 r": (move|extract) .* (to|into|from)": -20,
49 r": (move|extract) .* (to|into|from)": -20,
50 r": implement ": -5,
50 r": implement ": -5,
51 r": use .* implementation": -20,
51 r": use .* implementation": -20,
52 r"\S\S\S+\.\S\S\S\S+": -5,
52 r"\S\S\S+\.\S\S\S\S+": -5,
53 r": use .* instead of": -20,
53 r": use .* instead of": -20,
54 r"__": -5,
54 r"__": -5,
55 # dumb keywords
55 # dumb keywords
56 r"\S+/\S+:": -10,
56 r"\S+/\S+:": -10,
57 r"\S+\.\S+:": -10,
57 r"\S+\.\S+:": -10,
58 # drop
58 # drop
59 r"^i18n-": -50,
59 r"^i18n-": -50,
60 r"^i18n:.*(hint|comment)": -50,
60 r"^i18n:.*(hint|comment)": -50,
61 r"perf:": -50,
61 r"perf:": -50,
62 r"check-code:": -50,
62 r"check-code:": -50,
63 r"Added.*for changeset": -50,
63 r"Added.*for changeset": -50,
64 r"tests?:": -50,
64 r"tests?:": -50,
65 r"test-": -50,
65 r"test-": -50,
66 r"add.* tests": -50,
66 r"add.* tests": -50,
67 r"^_": -50,
67 r"^_": -50,
68 }
68 }
69
69
70 cutoff = 10
70 cutoff = 10
71 commits = []
71 commits = []
72
72
73 groupings = [
73 groupings = [
74 (r"util|parsers|repo|ctx|context|revlog|filelog|alias|cmdutil", "core"),
74 (r"util|parsers|repo|ctx|context|revlog|filelog|alias|cmdutil", "core"),
75 (r"revset|templater|ui|dirstate|hook|i18n|transaction|wire", "core"),
75 (r"revset|templater|ui|dirstate|hook|i18n|transaction|wire", "core"),
76 (r"color|pager", "core"),
76 (r"color|pager", "core"),
77 (r"hgweb|paper|coal|gitweb", "hgweb"),
77 (r"hgweb|paper|coal|gitweb", "hgweb"),
78 (r"pull|push|revert|resolve|annotate|bookmark|branch|clone", "commands"),
78 (r"pull|push|revert|resolve|annotate|bookmark|branch|clone", "commands"),
79 (r"commands|commit|config|files|graft|import|log|merge|patch", "commands"),
79 (r"commands|commit|config|files|graft|import|log|merge|patch", "commands"),
80 (r"phases|status|summary|amend|tag|help|verify", "commands"),
80 (r"phases|status|summary|amend|tag|help|verify", "commands"),
81 (r"rebase|mq|convert|eol|histedit|largefiles", "extensions"),
81 (r"rebase|mq|convert|eol|histedit|largefiles", "extensions"),
82 (r"shelve|unshelve", "extensions"),
82 (r"shelve|unshelve", "extensions"),
83 ]
83 ]
84
84
85 def main():
85 def main():
86 ap = argparse.ArgumentParser()
86 ap = argparse.ArgumentParser()
87 ap.add_argument(
87 ap.add_argument(
88 "startrev",
88 "startrev",
89 metavar="REV",
89 metavar="REV",
90 type=str,
90 type=str,
91 nargs=1,
91 nargs=1,
92 help=(
92 help=(
93 "Starting revision for the release notes. This revision "
93 "Starting revision for the release notes. This revision "
94 "won't be included, but later revisions will."
94 "won't be included, but later revisions will."
95 ),
95 ),
96 )
96 )
97 ap.add_argument(
97 ap.add_argument(
98 "--stoprev",
98 "--stoprev",
99 metavar="REV",
99 metavar="REV",
100 type=str,
100 type=str,
101 default="@",
101 default="@",
102 nargs=1,
102 nargs=1,
103 help=(
103 help=(
104 "Stop revision for release notes. This revision will be included,"
104 "Stop revision for release notes. This revision will be included,"
105 " but no later revisions will. This revision needs to be "
105 " but no later revisions will. This revision needs to be "
106 "a descendant of startrev."
106 "a descendant of startrev."
107 ),
107 ),
108 )
108 )
109 args = ap.parse_args()
109 args = ap.parse_args()
110 fromext = subprocess.check_output(
110 fromext = subprocess.check_output(
111 [
111 [
112 "hg",
112 "hg",
113 "--config",
114 "extensions.releasenotes=",
113 "releasenotes",
115 "releasenotes",
114 "-r",
116 "-r",
115 "%s::%s" % (args.startrev[0], args.stoprev[0]),
117 "%s::%s" % (args.startrev[0], args.stoprev[0]),
116 ]
118 ]
117 ).decode("utf-8")
119 ).decode("utf-8")
118 # Find all release notes from un-relnotes-flagged commits.
120 # Find all release notes from un-relnotes-flagged commits.
119 for entry in sorted(
121 for entry in sorted(
120 subprocess.check_output(
122 subprocess.check_output(
121 [
123 [
122 "hg",
124 "hg",
123 "log",
125 "log",
124 "-r",
126 "-r",
125 r'%s::%s - merge() - grep("\n\.\. (%s)::")'
127 r'%s::%s - merge() - grep("\n\.\. (%s)::")'
126 % (args.startrev[0], args.stoprev[0], "|".join(rnsections)),
128 % (args.startrev[0], args.stoprev[0], "|".join(rnsections)),
127 "-T",
129 "-T",
128 r"{desc|firstline}\n",
130 r"{desc|firstline}\n",
129 ]
131 ]
130 )
132 )
131 .decode("utf-8")
133 .decode("utf-8")
132 .splitlines()
134 .splitlines()
133 ):
135 ):
134 desc = entry.replace("`", "'")
136 desc = entry.replace("`", "'")
135
137
136 score = 0
138 score = 0
137 for rule, val in rules.items():
139 for rule, val in rules.items():
138 if re.search(rule, desc):
140 if re.search(rule, desc):
139 score += val
141 score += val
140
142
141 desc = desc.replace("(issue", "(Bts:issue")
143 desc = desc.replace("(issue", "(Bts:issue")
142
144
143 if score >= cutoff:
145 if score >= cutoff:
144 commits.append(desc)
146 commits.append(desc)
145 # Group unflagged notes.
147 # Group unflagged notes.
146 groups = {}
148 groups = {}
147 bcs = []
149 bcs = []
148 apis = []
150 apis = []
149
151
150 for d in commits:
152 for d in commits:
151 if "(BC)" in d:
153 if "(BC)" in d:
152 bcs.append(d)
154 bcs.append(d)
153 if "(API)" in d:
155 if "(API)" in d:
154 apis.append(d)
156 apis.append(d)
155 for rule, g in groupings:
157 for rule, g in groupings:
156 if re.match(rule, d):
158 if re.match(rule, d):
157 groups.setdefault(g, []).append(d)
159 groups.setdefault(g, []).append(d)
158 break
160 break
159 else:
161 else:
160 groups.setdefault("unsorted", []).append(d)
162 groups.setdefault("unsorted", []).append(d)
161 print(fromext)
163 print(fromext)
162 # print legacy release notes sections
164 # print legacy release notes sections
163 for g in sorted(groups):
165 for g in sorted(groups):
164 print("\n=== %s ===" % g)
166 print("\n=== %s ===" % g)
165 for d in sorted(groups[g]):
167 for d in sorted(groups[g]):
166 print(" * %s" % d)
168 print(" * %s" % d)
167
169
168 print("\n=== BC ===\n")
170 print("\n=== BC ===\n")
169
171
170 for d in sorted(bcs):
172 for d in sorted(bcs):
171 print(" * %s" % d)
173 print(" * %s" % d)
172
174
173 print("\n=== API Changes ===\n")
175 print("\n=== API Changes ===\n")
174
176
175 for d in sorted(apis):
177 for d in sorted(apis):
176 print(" * %s" % d)
178 print(" * %s" % d)
177
179
178 if __name__ == "__main__":
180 if __name__ == "__main__":
179 main()
181 main()
General Comments 0
You need to be logged in to leave comments. Login now