27
27
28
28
import os
29
29
import re
30
+ import sys
31
+ import typing
30
32
from collections import OrderedDict , defaultdict
31
33
from datetime import date
32
- from typing import Callable , Dict , Iterable , List , Optional , Tuple
34
+ from typing import Callable , Dict , Iterable , List , Optional , Tuple , Type
33
35
34
36
from jinja2 import Environment , PackageLoader
37
+ from packaging .version import InvalidVersion , Version
35
38
36
39
from commitizen import defaults
37
40
from commitizen .bump import normalize_tag
38
41
from commitizen .exceptions import InvalidConfigurationError , NoCommitsFoundError
39
42
from commitizen .git import GitCommit , GitTag
40
43
44
+ if sys .version_info >= (3 , 8 ):
45
+ from commitizen .version_types import VersionProtocol
46
+ else :
47
+ # workaround mypy issue for 3.7 python
48
+ VersionProtocol = typing .Any
49
+
41
50
42
51
def get_commit_tag (commit : GitCommit , tags : List [GitTag ]) -> Optional [GitTag ]:
43
52
return next ((tag for tag in tags if tag .rev == commit .rev ), None )
44
53
45
54
55
+ def get_version (tag : GitTag ) -> Optional [Version ]:
56
+ version = None
57
+ try :
58
+ version = Version (tag .name )
59
+ except InvalidVersion :
60
+ pass
61
+ return version
62
+
63
+
64
+ def tag_included_in_changelog (
65
+ tag : GitTag , used_tags : List , merge_prerelease : bool
66
+ ) -> bool :
67
+ if tag in used_tags :
68
+ return False
69
+
70
+ version = get_version (tag )
71
+ if version is None :
72
+ return False
73
+
74
+ if merge_prerelease and version .is_prerelease :
75
+ return False
76
+
77
+ return True
78
+
79
+
46
80
def generate_tree_from_commits (
47
81
commits : List [GitCommit ],
48
82
tags : List [GitTag ],
@@ -51,6 +85,7 @@ def generate_tree_from_commits(
51
85
unreleased_version : Optional [str ] = None ,
52
86
change_type_map : Optional [Dict [str , str ]] = None ,
53
87
changelog_message_builder_hook : Optional [Callable ] = None ,
88
+ merge_prerelease : bool = False ,
54
89
) -> Iterable [Dict ]:
55
90
pat = re .compile (changelog_pattern )
56
91
map_pat = re .compile (commit_parser , re .MULTILINE )
@@ -73,15 +108,15 @@ def generate_tree_from_commits(
73
108
for commit in commits :
74
109
commit_tag = get_commit_tag (commit , tags )
75
110
76
- if commit_tag is not None and commit_tag not in used_tags :
111
+ if commit_tag is not None and tag_included_in_changelog (
112
+ commit_tag , used_tags , merge_prerelease
113
+ ):
77
114
used_tags .append (commit_tag )
78
115
yield {
79
116
"version" : current_tag_name ,
80
117
"date" : current_tag_date ,
81
118
"changes" : changes ,
82
119
}
83
- # TODO: Check if tag matches the version pattern, otherwise skip it.
84
- # This in order to prevent tags that are not versions.
85
120
current_tag_name = commit_tag .name
86
121
current_tag_date = commit_tag .date
87
122
changes = defaultdict (list )
@@ -286,7 +321,10 @@ def get_smart_tag_range(
286
321
287
322
288
323
def get_oldest_and_newest_rev (
289
- tags : List [GitTag ], version : str , tag_format : str
324
+ tags : List [GitTag ],
325
+ version : str ,
326
+ tag_format : str ,
327
+ version_type_cls : Optional [Type [VersionProtocol ]] = None ,
290
328
) -> Tuple [Optional [str ], Optional [str ]]:
291
329
"""Find the tags for the given version.
292
330
@@ -301,11 +339,15 @@ def get_oldest_and_newest_rev(
301
339
except ValueError :
302
340
newest = version
303
341
304
- newest_tag = normalize_tag (newest , tag_format = tag_format )
342
+ newest_tag = normalize_tag (
343
+ newest , tag_format = tag_format , version_type_cls = version_type_cls
344
+ )
305
345
306
346
oldest_tag = None
307
347
if oldest :
308
- oldest_tag = normalize_tag (oldest , tag_format = tag_format )
348
+ oldest_tag = normalize_tag (
349
+ oldest , tag_format = tag_format , version_type_cls = version_type_cls
350
+ )
309
351
310
352
tags_range = get_smart_tag_range (tags , newest = newest_tag , oldest = oldest_tag )
311
353
if not tags_range :
0 commit comments