@@ -371,6 +371,50 @@ def bump_build(self, token="build"):
371
371
build = cls ._increment_string (self ._build or (token or "build" ) + ".0" )
372
372
return cls (self ._major , self ._minor , self ._patch , self ._prerelease , build )
373
373
374
+ def next_version (self , part , prerelease_token = "rc" ):
375
+ """
376
+ Determines the next version, taking prereleases into account.
377
+
378
+ The "major", "minor", and "patch" raises the respective parts like
379
+ the ``bump_*`` functions. The real difference is using the
380
+ "preprelease" part. It gives you the next patch version of the prerelease,
381
+ for example:
382
+
383
+ >>> str(semver.VersionInfo.parse("0.1.4").next_version("prerelease"))
384
+ '0.1.5-rc.1'
385
+
386
+ :param part: One of "major", "minor", "patch", or "prerelease"
387
+ :param prerelease_token: prefix string of prerelease, defaults to 'rc'
388
+ :return:
389
+ """
390
+ validparts = {
391
+ "major" ,
392
+ "minor" ,
393
+ "patch" ,
394
+ "prerelease" ,
395
+ # "build", # currently not used
396
+ }
397
+ if part not in validparts :
398
+ raise ValueError (
399
+ "Invalid part. Expected one of {validparts}, but got {part!r}" .format (
400
+ validparts = validparts , part = part
401
+ )
402
+ )
403
+ version = self
404
+ if (version .prerelease or version .build ) and (
405
+ part == "patch"
406
+ or (part == "minor" and version .patch == 0 )
407
+ or (part == "major" and version .minor == version .patch == 0 )
408
+ ):
409
+ return version .replace (prerelease = None , build = None )
410
+
411
+ if part in ("major" , "minor" , "patch" ):
412
+ return str (getattr (version , "bump_" + part )())
413
+
414
+ if not version .prerelease :
415
+ version = version .bump_patch ()
416
+ return version .bump_prerelease (prerelease_token )
417
+
374
418
@comparator
375
419
def __eq__ (self , other ):
376
420
return _compare_by_keys (self .to_dict (), _to_dict (other )) == 0
@@ -851,6 +895,7 @@ def replace(version, **parts):
851
895
return str (VersionInfo .parse (version ).replace (** parts ))
852
896
853
897
898
+ # ---- CLI
854
899
def cmd_bump (args ):
855
900
"""
856
901
Subcommand: Bumps a version.
@@ -906,6 +951,19 @@ def cmd_compare(args):
906
951
return str (compare (args .version1 , args .version2 ))
907
952
908
953
954
+ def cmd_nextver (args ):
955
+ """
956
+ Subcommand: Determines the next version, taking prereleases into account.
957
+
958
+ Synopsis: nextver <VERSION> <PART>
959
+
960
+ :param args: The parsed arguments
961
+ :type args: :class:`argparse.Namespace`
962
+ """
963
+ version = VersionInfo .parse (args .version )
964
+ return str (version .next_version (args .part ))
965
+
966
+
909
967
def createparser ():
910
968
"""
911
969
Create an :class:`argparse.ArgumentParser` instance.
@@ -948,6 +1006,15 @@ def createparser():
948
1006
parser_check .set_defaults (func = cmd_check )
949
1007
parser_check .add_argument ("version" , help = "Version to check" )
950
1008
1009
+ # Create the nextver subcommand
1010
+ parser_nextver = s .add_parser (
1011
+ "nextver" , help = "Determines the next version, taking prereleases into account."
1012
+ )
1013
+ parser_nextver .set_defaults (func = cmd_nextver )
1014
+ parser_nextver .add_argument ("version" , help = "Version to raise" )
1015
+ parser_nextver .add_argument (
1016
+ "part" , help = "One of 'major', 'minor', 'patch', or 'prerelease'"
1017
+ )
951
1018
return parser
952
1019
953
1020
0 commit comments