@@ -181,40 +181,62 @@ def get_next_minor(prerelease_marker: str):
181
181
+ release_branch_match .group ('brname' ) + '"' )
182
182
return version_str
183
183
184
- def get_branch_tags (active_branch_name : str ):
184
+ def get_branch_tags (active_branch_name : str ) -> list [ str ] :
185
185
"""
186
- Returns the tag or tags (as a single string with newlines between tags)
187
- corresponding to the current branch, which must not be master. If the
188
- specified branch is a release branch then return all tags based on the
189
- major/minor X.Y release version. If the specified branch is neither master
190
- nor a release branch, then walk backwards in history until the first tag
191
- matching the glob '1.*' and return that tag.
186
+ Returns a list of tags corresponding to the current branch, which must not
187
+ be master. If the specified branch is a release branch then return all tags
188
+ based on the major/minor X.Y release version. If the specified branch is
189
+ neither master nor a release branch, then walk backwards in history until
190
+ the first tag matching the glob '1.*' and return that tag.
192
191
"""
193
192
194
193
if active_branch_name == 'master' :
195
194
raise Exception ('this method is not meant to be called while on "master"' )
196
- tags = ''
195
+
197
196
release_branch_match = RELEASE_BRANCH_RE .match (active_branch_name )
198
197
if release_branch_match :
199
198
# This is a release branch, so look for tags only on this branch
200
199
tag_glob = release_branch_match .group ('vermaj' ) + '.' \
201
200
+ release_branch_match .group ('vermin' ) + '.*'
202
- tags = check_output (['git' , 'tag' , '--list' , tag_glob ])
203
- else :
204
- # Not a release branch, so look for the most recent tag in history
205
- commits = check_output (['git' , 'log' , '--pretty=format:%H' ,
206
- '--no-merges' ])
207
- if len (commits ) > 0 :
208
- for commit in commits .splitlines ():
209
- tags = check_output (['git' , 'tag' , '--points-at' ,
210
- commit , '--list' , '1.*' ])
211
- if len (tags ) > 0 :
212
- # found a tag, we should be done
213
- break
214
-
215
- return tags
216
-
217
- def process_and_sort_tags (tags : str ):
201
+ return check_output (['git' , 'tag' , '--list' , tag_glob ]).splitlines ()
202
+
203
+ # Not a release branch, so look for the most recent tag in history
204
+ commits = check_output (['git' , 'log' , '--pretty=format:%H' , '--no-merges' ])
205
+ tags_by_obj = get_object_tags ()
206
+ for commit in commits .splitlines ():
207
+ got = tags_by_obj .get (commit )
208
+ if got :
209
+ return got
210
+ # No tags
211
+ return []
212
+
213
+
214
+ def iter_tag_lines ():
215
+ """
216
+ Generate a list of pairs of strings, where the first is a commit hash, and
217
+ the second is a tag that is associated with that commit. Duplicate commits
218
+ are possible.
219
+ """
220
+ output = check_output (['git' , 'tag' , '--list' , '1.*' , '--format=%(*objectname)|%(tag)' ])
221
+ lines = output .splitlines ()
222
+ for l in lines :
223
+ obj , tag = l .split ('|' , maxsplit = 1 )
224
+ if tag :
225
+ yield obj , tag
226
+
227
+
228
+ def get_object_tags () -> dict [str , list [str ]]:
229
+ """
230
+ Obtain a mapping between commit hashes and a list of tags that point to
231
+ that commit. Untagged commits will not be included in the resulting map.
232
+ """
233
+ ret : dict [str , list [str ]] = {}
234
+ for obj , tag in iter_tag_lines ():
235
+ ret .setdefault (obj , []).append (tag )
236
+ return ret
237
+
238
+
239
+ def process_and_sort_tags (tags : list [str ]):
218
240
"""
219
241
Given a string (as returned from get_branch_tags), return a sorted list of
220
242
zero or more tags (sorted based on the Version comparison) which meet
@@ -228,15 +250,14 @@ def process_and_sort_tags(tags: str):
228
250
if not tags or len (tags ) == 0 :
229
251
return processed_and_sorted_tags
230
252
231
- raw_tags = tags .splitlines ()
232
253
# find all the final release tags
233
- for tag in raw_tags :
254
+ for tag in tags :
234
255
release_tag_match = RELEASE_TAG_RE .match (tag )
235
256
if release_tag_match and not release_tag_match .group ('verpre' ):
236
257
processed_and_sorted_tags .append (tag )
237
258
# collect together final release tags and pre-release tags for
238
259
# versions that have not yet had a final release
239
- for tag in raw_tags :
260
+ for tag in tags :
240
261
tag_parts = tag .split ('-' )
241
262
if len (tag_parts ) >= 2 and tag_parts [0 ] not in processed_and_sorted_tags :
242
263
processed_and_sorted_tags .append (tag )
@@ -318,7 +339,7 @@ def previous(rel_ver: str):
318
339
version_parsed = parse_version (version_str )
319
340
rel_ver_str = rel_ver
320
341
rel_ver_parsed = parse_version (rel_ver_str )
321
- tags = check_output (['git' , 'tag' , '--list' , '1.*' ])
342
+ tags = check_output (['git' , 'tag' , '--list' , '1.*' ]). splitlines ()
322
343
processed_and_sorted_tags = process_and_sort_tags (tags )
323
344
for tag in processed_and_sorted_tags :
324
345
previous_tag_match = PREVIOUS_TAG_RE .match (tag )
0 commit comments