22from typing import List , Optional
33
44import questionary
5- from packaging .version import Version
5+ from packaging .version import InvalidVersion , Version
66
77from commitizen import bump , cmd , factory , git , out
88from commitizen .commands .changelog import Changelog
1212 BumpTagFailedError ,
1313 DryRunExit ,
1414 ExpectedExit ,
15+ InvalidManualVersion ,
1516 NoCommitsFoundError ,
1617 NoneIncrementExit ,
1718 NoPatternMapError ,
1819 NotAGitProjectError ,
20+ NotAllowed ,
1921 NoVersionSpecifiedError ,
2022)
2123
@@ -102,10 +104,26 @@ def __call__(self): # noqa: C901
102104 dry_run : bool = self .arguments ["dry_run" ]
103105 is_yes : bool = self .arguments ["yes" ]
104106 increment : Optional [str ] = self .arguments ["increment" ]
105- prerelease : str = self .arguments ["prerelease" ]
107+ prerelease : Optional [ str ] = self .arguments ["prerelease" ]
106108 devrelease : Optional [int ] = self .arguments ["devrelease" ]
107109 is_files_only : Optional [bool ] = self .arguments ["files_only" ]
108110 is_local_version : Optional [bool ] = self .arguments ["local_version" ]
111+ manual_version = self .arguments ["manual_version" ]
112+
113+ if manual_version :
114+ if increment :
115+ raise NotAllowed ("--increment cannot be combined with MANUAL_VERSION" )
116+
117+ if prerelease :
118+ raise NotAllowed ("--prerelease cannot be combined with MANUAL_VERSION" )
119+
120+ if devrelease is not None :
121+ raise NotAllowed ("--devrelease cannot be combined with MANUAL_VERSION" )
122+
123+ if is_local_version :
124+ raise NotAllowed (
125+ "--local-version cannot be combined with MANUAL_VERSION"
126+ )
109127
110128 current_tag_version : str = bump .normalize_tag (
111129 current_version , tag_format = tag_format
@@ -127,46 +145,53 @@ def __call__(self): # noqa: C901
127145 if not commits and not current_version_instance .is_prerelease :
128146 raise NoCommitsFoundError ("[NO_COMMITS_FOUND]\n " "No new commits found." )
129147
130- if increment is None :
131- increment = self .find_increment (commits )
132-
133- # It may happen that there are commits, but they are not elegible
134- # for an increment, this generates a problem when using prerelease (#281)
135- if (
136- prerelease
137- and increment is None
138- and not current_version_instance .is_prerelease
139- ):
140- raise NoCommitsFoundError (
141- "[NO_COMMITS_FOUND]\n "
142- "No commits found to generate a pre-release.\n "
143- "To avoid this error, manually specify the type of increment with `--increment`"
144- )
145-
146- # Increment is removed when current and next version
147- # are expected to be prereleases.
148- if prerelease and current_version_instance .is_prerelease :
149- increment = None
148+ if manual_version :
149+ try :
150+ new_version = Version (manual_version )
151+ except InvalidVersion as exc :
152+ raise InvalidManualVersion (
153+ "[INVALID_MANUAL_VERSION]\n "
154+ f"Invalid manual version: '{ manual_version } '"
155+ ) from exc
156+ else :
157+ if increment is None :
158+ increment = self .find_increment (commits )
159+
160+ # It may happen that there are commits, but they are not eligible
161+ # for an increment, this generates a problem when using prerelease (#281)
162+ if (
163+ prerelease
164+ and increment is None
165+ and not current_version_instance .is_prerelease
166+ ):
167+ raise NoCommitsFoundError (
168+ "[NO_COMMITS_FOUND]\n "
169+ "No commits found to generate a pre-release.\n "
170+ "To avoid this error, manually specify the type of increment with `--increment`"
171+ )
150172
151- new_version = bump .generate_version (
152- current_version ,
153- increment ,
154- prerelease = prerelease ,
155- devrelease = devrelease ,
156- is_local_version = is_local_version ,
157- )
173+ # Increment is removed when current and next version
174+ # are expected to be prereleases.
175+ if prerelease and current_version_instance .is_prerelease :
176+ increment = None
177+
178+ new_version = bump .generate_version (
179+ current_version ,
180+ increment ,
181+ prerelease = prerelease ,
182+ devrelease = devrelease ,
183+ is_local_version = is_local_version ,
184+ )
158185
159186 new_tag_version = bump .normalize_tag (new_version , tag_format = tag_format )
160187 message = bump .create_commit_message (
161188 current_version , new_version , bump_commit_message
162189 )
163190
164191 # Report found information
165- information = (
166- f"{ message } \n "
167- f"tag to create: { new_tag_version } \n "
168- f"increment detected: { increment } \n "
169- )
192+ information = f"{ message } \n " f"tag to create: { new_tag_version } \n "
193+ if increment :
194+ information += f"increment detected: { increment } \n "
170195
171196 if self .changelog_to_stdout :
172197 # When the changelog goes to stdout, we want to send
@@ -179,7 +204,7 @@ def __call__(self): # noqa: C901
179204 if increment is None and new_tag_version == current_tag_version :
180205 raise NoneIncrementExit (
181206 "[NO_COMMITS_TO_BUMP]\n "
182- "The commits found are not elegible to be bumped"
207+ "The commits found are not eligible to be bumped"
183208 )
184209
185210 if self .changelog :
0 commit comments