@@ -74,6 +74,23 @@ def get_commit_tag(commit: GitCommit, tags: list[GitTag]) -> GitTag | None:
74
74
return next ((tag for tag in tags if tag .rev == commit .rev ), None )
75
75
76
76
77
+ def _get_release_info (
78
+ current_tag_name : str ,
79
+ current_tag_date : str ,
80
+ changes : dict [str | None , list ],
81
+ changelog_release_hook : ChangelogReleaseHook | None ,
82
+ commit_tag : GitTag | None ,
83
+ ) -> dict [str , Any ]:
84
+ release = {
85
+ "version" : current_tag_name ,
86
+ "date" : current_tag_date ,
87
+ "changes" : changes ,
88
+ }
89
+ if changelog_release_hook :
90
+ return changelog_release_hook (release , commit_tag )
91
+ return release
92
+
93
+
77
94
def generate_tree_from_commits (
78
95
commits : list [GitCommit ],
79
96
tags : list [GitTag ],
@@ -88,47 +105,47 @@ def generate_tree_from_commits(
88
105
pat = re .compile (changelog_pattern )
89
106
map_pat = re .compile (commit_parser , re .MULTILINE )
90
107
body_map_pat = re .compile (commit_parser , re .MULTILINE | re .DOTALL )
91
- current_tag : GitTag | None = None
92
108
rules = rules or TagRules ()
93
109
110
+ used_tag_names : set [str ] = set ()
111
+ current_tag_name = unreleased_version or "Unreleased"
112
+ current_tag_date = (
113
+ date .today ().isoformat () if unreleased_version is not None else ""
114
+ )
115
+
94
116
# Check if the latest commit is not tagged
95
- if commits :
96
- latest_commit = commits [0 ]
97
- current_tag = get_commit_tag (latest_commit , tags )
98
-
99
- current_tag_name : str = unreleased_version or "Unreleased"
100
- current_tag_date : str = ""
101
- if unreleased_version is not None :
102
- current_tag_date = date .today ().isoformat ()
103
- if current_tag is not None and current_tag .name :
104
- current_tag_name = current_tag .name
105
- current_tag_date = current_tag .date
106
-
107
- changes : dict = defaultdict (list )
108
- used_tags : list = [current_tag ]
117
+ current_tag = get_commit_tag (commits [0 ], tags ) if commits else None
118
+ if current_tag is not None :
119
+ used_tag_names .add (current_tag .name )
120
+ if current_tag .name :
121
+ current_tag_name = current_tag .name
122
+ current_tag_date = current_tag .date
123
+
124
+ changes : defaultdict [str | None , list ] = defaultdict (list )
125
+ commit_tag : GitTag | None = None
109
126
for commit in commits :
110
127
commit_tag = get_commit_tag (commit , tags )
111
128
112
129
if (
113
130
commit_tag
114
- and commit_tag not in used_tags
131
+ and commit_tag . name not in used_tag_names
115
132
and rules .include_in_changelog (commit_tag )
116
133
):
117
- used_tags .append (commit_tag )
118
- release = {
119
- "version" : current_tag_name ,
120
- "date" : current_tag_date ,
121
- "changes" : changes ,
122
- }
123
- if changelog_release_hook :
124
- release = changelog_release_hook (release , commit_tag )
125
- yield release
134
+ used_tag_names .add (commit_tag .name )
135
+
136
+ yield _get_release_info (
137
+ current_tag_name ,
138
+ current_tag_date ,
139
+ changes ,
140
+ changelog_release_hook ,
141
+ commit_tag ,
142
+ )
143
+
126
144
current_tag_name = commit_tag .name
127
145
current_tag_date = commit_tag .date
128
146
changes = defaultdict (list )
129
147
130
- matches = pat .match (commit .message )
131
- if not matches :
148
+ if not pat .match (commit .message ):
132
149
continue
133
150
134
151
# Process subject from commit message
@@ -153,14 +170,13 @@ def generate_tree_from_commits(
153
170
change_type_map ,
154
171
)
155
172
156
- release = {
157
- "version" : current_tag_name ,
158
- "date" : current_tag_date ,
159
- "changes" : changes ,
160
- }
161
- if changelog_release_hook :
162
- release = changelog_release_hook (release , commit_tag )
163
- yield release
173
+ yield _get_release_info (
174
+ current_tag_name ,
175
+ current_tag_date ,
176
+ changes ,
177
+ changelog_release_hook ,
178
+ commit_tag ,
179
+ )
164
180
165
181
166
182
def process_commit_message (
@@ -178,13 +194,15 @@ def process_commit_message(
178
194
** parsed .groupdict (),
179
195
}
180
196
181
- if processed := hook (message , commit ) if hook else message :
182
- messages = [processed ] if isinstance (processed , dict ) else processed
183
- for msg in messages :
184
- change_type = msg .pop ("change_type" , None )
185
- if change_type_map :
186
- change_type = change_type_map .get (change_type , change_type )
187
- changes [change_type ].append (msg )
197
+ if not (processed := hook (message , commit ) if hook else message ):
198
+ return
199
+
200
+ processed_messages = [processed ] if isinstance (processed , dict ) else processed
201
+ for msg in processed_messages :
202
+ change_type = msg .pop ("change_type" , None )
203
+ if change_type_map :
204
+ change_type = change_type_map .get (change_type , change_type )
205
+ changes [change_type ].append (msg )
188
206
189
207
190
208
def generate_ordered_changelog_tree (
@@ -228,8 +246,7 @@ def render_changelog(
228
246
** kwargs : Any ,
229
247
) -> str :
230
248
jinja_template = get_changelog_template (loader , template )
231
- changelog : str = jinja_template .render (tree = tree , ** kwargs )
232
- return changelog
249
+ return jinja_template .render (tree = tree , ** kwargs )
233
250
234
251
235
252
def incremental_build (
@@ -256,13 +273,12 @@ def incremental_build(
256
273
for index , line in enumerate (lines ):
257
274
if index == unreleased_start :
258
275
skip = True
259
- elif index == unreleased_end :
276
+ continue
277
+
278
+ if index == unreleased_end :
260
279
skip = False
261
- if (
262
- latest_version_position is None
263
- or isinstance (latest_version_position , int )
264
- and isinstance (unreleased_end , int )
265
- and latest_version_position > unreleased_end
280
+ if latest_version_position is None or (
281
+ unreleased_end is not None and latest_version_position > unreleased_end
266
282
):
267
283
continue
268
284
@@ -271,13 +287,15 @@ def incremental_build(
271
287
272
288
if index == latest_version_position :
273
289
output_lines .extend ([new_content , "\n " ])
274
-
275
290
output_lines .append (line )
276
- if not isinstance (latest_version_position , int ):
277
- if output_lines and output_lines [- 1 ].strip ():
278
- # Ensure at least one blank line between existing and new content.
279
- output_lines .append ("\n " )
280
- output_lines .append (new_content )
291
+
292
+ if latest_version_position is not None :
293
+ return output_lines
294
+
295
+ if output_lines and output_lines [- 1 ].strip ():
296
+ # Ensure at least one blank line between existing and new content.
297
+ output_lines .append ("\n " )
298
+ output_lines .append (new_content )
281
299
return output_lines
282
300
283
301
@@ -327,8 +345,7 @@ def get_oldest_and_newest_rev(
327
345
if not (newest_tag := rules .find_tag_for (tags , newest )):
328
346
raise NoCommitsFoundError ("Could not find a valid revision range." )
329
347
330
- oldest_tag = None
331
- oldest_tag_name = None
348
+ oldest_tag_name : str | None = None
332
349
if oldest :
333
350
if not (oldest_tag := rules .find_tag_for (tags , oldest )):
334
351
raise NoCommitsFoundError ("Could not find a valid revision range." )
@@ -340,17 +357,19 @@ def get_oldest_and_newest_rev(
340
357
if not tags_range :
341
358
raise NoCommitsFoundError ("Could not find a valid revision range." )
342
359
343
- oldest_rev : str | None = tags_range [- 1 ].name
344
360
newest_rev = newest_tag .name
345
361
346
- # check if it's the first tag created
347
- # and it's also being requested as part of the range
348
- if oldest_rev == tags [- 1 ].name and oldest_rev == oldest_tag_name :
349
- return None , newest_rev
350
-
351
- # when they are the same, and it's also the
352
- # first tag created
353
- if oldest_rev == newest_rev :
354
- return None , newest_rev
362
+ # Return None for oldest_rev if:
363
+ # 1. The oldest tag is the last tag in the list and matches the requested oldest tag, or
364
+ # 2. The oldest and newest tags are the same
365
+ oldest_rev : str | None = (
366
+ None
367
+ if (
368
+ tags_range [- 1 ].name == tags [- 1 ].name
369
+ and tags_range [- 1 ].name == oldest_tag_name
370
+ or tags_range [- 1 ].name == newest_rev
371
+ )
372
+ else tags_range [- 1 ].name
373
+ )
355
374
356
375
return oldest_rev , newest_rev
0 commit comments