20
20
from github import Github
21
21
import os
22
22
import re
23
-
23
+ import subprocess
24
24
25
25
def print_pulls (repo_name , title , pulls ):
26
- if len (pulls ) > 0 :
26
+ if len (pulls ) > 0 :
27
27
print ("**{}:**" .format (title ))
28
28
print ()
29
- for pull , commit in pulls :
29
+ for ( pull , commit ) in pulls :
30
30
url = "https://github.com/{}/pull/{}" .format (repo_name , pull .number )
31
- print (
32
- "- {} [#{}]({}) ({})" .format (
33
- pull .title , pull .number , url , commit .author .login
34
- )
35
- )
31
+ print ("- {} [#{}]({}) ({})" .format (pull .title , pull .number , url , commit .author .login ))
36
32
print ()
37
33
38
34
39
- def generate_changelog (repo , repo_name , tag1 , tag2 ):
35
+ def generate_changelog (repo , repo_name , tag1 , tag2 , version ):
36
+
40
37
# get a list of commits between two tags
41
38
print (f"Fetching list of commits between { tag1 } and { tag2 } " , file = sys .stderr )
42
39
comparison = repo .compare (tag1 , tag2 )
@@ -55,65 +52,113 @@ def generate_changelog(repo, repo_name, tag1, tag2):
55
52
all_pulls .append ((pull , commit ))
56
53
57
54
# we split the pulls into categories
58
- # TODO: make categories configurable
59
55
breaking = []
60
56
bugs = []
61
57
docs = []
62
58
enhancements = []
59
+ performance = []
60
+ other = []
63
61
64
62
# categorize the pull requests based on GitHub labels
65
63
print ("Categorizing pull requests" , file = sys .stderr )
66
- for pull , commit in all_pulls :
64
+ for (pull , commit ) in all_pulls :
65
+
67
66
# see if PR title uses Conventional Commits
68
- cc_type = ""
69
- # cc_scope = ''
70
- cc_breaking = ""
71
- parts = re .findall (r" ^([a-z]+)(\([a-z]+\))?(!)?:" , pull .title )
67
+ cc_type = ''
68
+ cc_scope = ''
69
+ cc_breaking = ''
70
+ parts = re .findall (r' ^([a-z]+)(\([a-z]+\))?(!)?:' , pull .title )
72
71
if len (parts ) == 1 :
73
72
parts_tuple = parts [0 ]
74
- cc_type = parts_tuple [0 ] # fix, feat, docs, chore
75
- # cc_scope = parts_tuple[1] # component within project
76
- cc_breaking = parts_tuple [2 ] == "!"
73
+ cc_type = parts_tuple [0 ] # fix, feat, docs, chore
74
+ cc_scope = parts_tuple [1 ] # component within project
75
+ cc_breaking = parts_tuple [2 ] == '!'
77
76
78
77
labels = [label .name for label in pull .labels ]
79
- # print(pull.number, labels, parts, file=sys.stderr)
80
- if "api change" in labels or cc_breaking :
78
+ if 'api change' in labels or cc_breaking :
81
79
breaking .append ((pull , commit ))
82
- elif " bug" in labels or cc_type == " fix" :
80
+ elif ' bug' in labels or cc_type == ' fix' :
83
81
bugs .append ((pull , commit ))
84
- elif "enhancement" in labels or cc_type == "feat" :
82
+ elif 'performance' in labels or cc_type == 'perf' :
83
+ performance .append ((pull , commit ))
84
+ elif 'enhancement' in labels or cc_type == 'feat' :
85
85
enhancements .append ((pull , commit ))
86
- elif " documentation" in labels or cc_type == " docs" :
86
+ elif ' documentation' in labels or cc_type == ' docs' or cc_type == 'doc' :
87
87
docs .append ((pull , commit ))
88
+ else :
89
+ other .append ((pull , commit ))
88
90
89
91
# produce the changelog content
90
92
print ("Generating changelog content" , file = sys .stderr )
93
+
94
+ # ASF header
95
+ print ("""<!--
96
+ Licensed to the Apache Software Foundation (ASF) under one
97
+ or more contributor license agreements. See the NOTICE file
98
+ distributed with this work for additional information
99
+ regarding copyright ownership. The ASF licenses this file
100
+ to you under the Apache License, Version 2.0 (the
101
+ "License"); you may not use this file except in compliance
102
+ with the License. You may obtain a copy of the License at
103
+
104
+ http://www.apache.org/licenses/LICENSE-2.0
105
+
106
+ Unless required by applicable law or agreed to in writing,
107
+ software distributed under the License is distributed on an
108
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
109
+ KIND, either express or implied. See the License for the
110
+ specific language governing permissions and limitations
111
+ under the License.
112
+ -->\n """ )
113
+
114
+ print (f"# Apache DataFusion Python { version } Changelog\n " )
115
+
116
+ # get the number of commits
117
+ commit_count = subprocess .check_output (f"git log --pretty=oneline { tag1 } ..{ tag2 } | wc -l" , shell = True , text = True ).strip ()
118
+
119
+ # get number of contributors
120
+ contributor_count = subprocess .check_output (f"git shortlog -sn { tag1 } ..{ tag2 } | wc -l" , shell = True , text = True ).strip ()
121
+
122
+ print (f"This release consists of { commit_count } commits from { contributor_count } contributors. "
123
+ f"See credits at the end of this changelog for more information.\n " )
124
+
91
125
print_pulls (repo_name , "Breaking changes" , breaking )
126
+ print_pulls (repo_name , "Performance related" , performance )
92
127
print_pulls (repo_name , "Implemented enhancements" , enhancements )
93
128
print_pulls (repo_name , "Fixed bugs" , bugs )
94
129
print_pulls (repo_name , "Documentation updates" , docs )
95
- print_pulls (repo_name , "Merged pull requests " , all_pulls )
130
+ print_pulls (repo_name , "Other " , other )
96
131
132
+ # show code contributions
133
+ credits = subprocess .check_output (f"git shortlog -sn { tag1 } ..{ tag2 } " , shell = True , text = True ).rstrip ()
134
+
135
+ print ("## Credits\n " )
136
+ print ("Thank you to everyone who contributed to this release. Here is a breakdown of commits (PRs merged) "
137
+ "per contributor.\n " )
138
+ print ("```" )
139
+ print (credits )
140
+ print ("```\n " )
141
+
142
+ print ("Thank you also to everyone who contributed in other ways such as filing issues, reviewing "
143
+ "PRs, and providing feedback on this release.\n " )
97
144
98
145
def cli (args = None ):
99
146
"""Process command line arguments."""
100
147
if not args :
101
148
args = sys .argv [1 :]
102
149
103
150
parser = argparse .ArgumentParser ()
104
- parser .add_argument (
105
- "project" , help = "The project name e.g. apache/datafusion-python"
106
- )
107
- parser .add_argument ("tag1" , help = "The previous release tag" )
108
- parser .add_argument ("tag2" , help = "The current release tag" )
151
+ parser .add_argument ("tag1" , help = "The previous commit or tag (e.g. 0.1.0)" )
152
+ parser .add_argument ("tag2" , help = "The current commit or tag (e.g. HEAD)" )
153
+ parser .add_argument ("version" , help = "The version number to include in the changelog" )
109
154
args = parser .parse_args ()
110
155
111
156
token = os .getenv ("GITHUB_TOKEN" )
157
+ project = "apache/datafusion-python"
112
158
113
159
g = Github (token )
114
- repo = g .get_repo (args .project )
115
- generate_changelog (repo , args .project , args .tag1 , args .tag2 )
116
-
160
+ repo = g .get_repo (project )
161
+ generate_changelog (repo , project , args .tag1 , args .tag2 , args .version )
117
162
118
163
if __name__ == "__main__" :
119
- cli ()
164
+ cli ()
0 commit comments