11import os
2+ import re
23from pathlib import Path
34from typing import NamedTuple , Optional
45
@@ -12,6 +13,52 @@ class GitDescribeVersion(NamedTuple):
1213 hash : Optional [str ] = None
1314
1415
16+ def determine_version_bump (repo_path = "." ):
17+ try :
18+
19+ repo = Repo (repo_path )
20+ if repo .bare :
21+ raise ValueError ("Not a valid Git repository." )
22+
23+ tags = sorted (repo .tags , key = lambda t : t .commit .committed_date , reverse = True )
24+ version_tags = [tag for tag in tags if tag .name .startswith ("v" )]
25+ if not version_tags :
26+ raise ValueError ("No version tags found." )
27+
28+ last_tag = version_tags [0 ]
29+ commits = repo .iter_commits (f"{ last_tag .name } ..HEAD" )
30+
31+ ignored_types = ["chore" , "style" , "refactor" , "test" ]
32+ patch_types = ["fix" , "docs" , "perf" ]
33+
34+ minor_change = False
35+ patch_change = False
36+
37+ for commit in commits :
38+ message = commit .message .strip ()
39+
40+ if any (re .match (rf"^{ ignored_type } (\([^\)]+\))?:" , message ) for ignored_type in ignored_types ):
41+ continue
42+
43+ if "BREAKING CHANGE:" in message or re .match (r"^feat(\([^\)]+\))?!:" , message ):
44+ return "major"
45+
46+ if re .match (r"^feat(\([^\)]+\))?:" , message ):
47+ minor_change = True
48+
49+ if any (re .match (rf"^{ patch_types } (\([^\)]+\))?:" , message ) for ignored_type in ignored_types ):
50+ patch_change = True
51+
52+ if minor_change :
53+ return "minor"
54+ if patch_change :
55+ return "patch"
56+ return None
57+
58+ except Exception as e :
59+ raise RuntimeError (f"Error: { e } " )
60+
61+
1562def get_current_version_from_git () -> Version :
1663 repo = Repo (Path .cwd ())
1764
@@ -21,7 +68,13 @@ def get_current_version_from_git() -> Version:
2168
2269 version = Version (git_version .version [1 :])
2370 if git_version .commits is not None and git_version .commits != "0" :
24- version = version .next_patch ()
71+ next_version = determine_version_bump ()
72+ if next_version == "major" :
73+ version = version .next_major ()
74+ elif next_version == "minor" :
75+ version = version .next_minor ()
76+ elif next_version == "patch" :
77+ version = version .next_patch ()
2578 version .prerelease = ("dev" , git_version .commits )
2679
2780 return version
@@ -34,3 +87,7 @@ def get_version() -> Version:
3487 return Version (os .environ ["CZ_PRE_NEW_VERSION" ])
3588
3689 return get_current_version_from_git ()
90+
91+
92+ if __name__ == "__main__" :
93+ print (get_version ())
0 commit comments