@@ -422,6 +422,53 @@ def compare(self, other):
422
422
423
423
return rccmp
424
424
425
+ def next_version (self , part , prerelease_token = "rc" ):
426
+ """
427
+ Determines next version, preserving natural order.
428
+
429
+ .. versionadded:: 2.10.0
430
+
431
+ This function is taking prereleases into account.
432
+ The "major", "minor", and "patch" raises the respective parts like
433
+ the ``bump_*`` functions. The real difference is using the
434
+ "preprelease" part. It gives you the next patch version of the prerelease,
435
+ for example:
436
+
437
+ >>> str(semver.VersionInfo.parse("0.1.4").next_version("prerelease"))
438
+ '0.1.5-rc.1'
439
+
440
+ :param part: One of "major", "minor", "patch", or "prerelease"
441
+ :param prerelease_token: prefix string of prerelease, defaults to 'rc'
442
+ :return:
443
+ """
444
+ validparts = {
445
+ "major" ,
446
+ "minor" ,
447
+ "patch" ,
448
+ "prerelease" ,
449
+ # "build", # currently not used
450
+ }
451
+ if part not in validparts :
452
+ raise ValueError (
453
+ "Invalid part. Expected one of {validparts}, but got {part!r}" .format (
454
+ validparts = validparts , part = part
455
+ )
456
+ )
457
+ version = self
458
+ if (version .prerelease or version .build ) and (
459
+ part == "patch"
460
+ or (part == "minor" and version .patch == 0 )
461
+ or (part == "major" and version .minor == version .patch == 0 )
462
+ ):
463
+ return version .replace (prerelease = None , build = None )
464
+
465
+ if part in ("major" , "minor" , "patch" ):
466
+ return str (getattr (version , "bump_" + part )())
467
+
468
+ if not version .prerelease :
469
+ version = version .bump_patch ()
470
+ return version .bump_prerelease (prerelease_token )
471
+
425
472
@comparator
426
473
def __eq__ (self , other ):
427
474
return self .compare (other ) == 0
@@ -709,7 +756,10 @@ def max_ver(ver1, ver2):
709
756
>>> semver.max_ver("1.0.0", "2.0.0")
710
757
'2.0.0'
711
758
"""
712
- ver1 = VersionInfo .parse (ver1 )
759
+ if isinstance (ver1 , str ):
760
+ ver1 = VersionInfo .parse (ver1 )
761
+ elif not isinstance (ver1 , VersionInfo ):
762
+ raise TypeError ()
713
763
cmp_res = ver1 .compare (ver2 )
714
764
if cmp_res >= 0 :
715
765
return str (ver1 )
@@ -898,6 +948,7 @@ def replace(version, **parts):
898
948
return str (VersionInfo .parse (version ).replace (** parts ))
899
949
900
950
951
+ # ---- CLI
901
952
def cmd_bump (args ):
902
953
"""
903
954
Subcommand: Bumps a version.
@@ -953,6 +1004,19 @@ def cmd_compare(args):
953
1004
return str (compare (args .version1 , args .version2 ))
954
1005
955
1006
1007
+ def cmd_nextver (args ):
1008
+ """
1009
+ Subcommand: Determines the next version, taking prereleases into account.
1010
+
1011
+ Synopsis: nextver <VERSION> <PART>
1012
+
1013
+ :param args: The parsed arguments
1014
+ :type args: :class:`argparse.Namespace`
1015
+ """
1016
+ version = VersionInfo .parse (args .version )
1017
+ return str (version .next_version (args .part ))
1018
+
1019
+
956
1020
def createparser ():
957
1021
"""
958
1022
Create an :class:`argparse.ArgumentParser` instance.
@@ -995,6 +1059,15 @@ def createparser():
995
1059
parser_check .set_defaults (func = cmd_check )
996
1060
parser_check .add_argument ("version" , help = "Version to check" )
997
1061
1062
+ # Create the nextver subcommand
1063
+ parser_nextver = s .add_parser (
1064
+ "nextver" , help = "Determines the next version, taking prereleases into account."
1065
+ )
1066
+ parser_nextver .set_defaults (func = cmd_nextver )
1067
+ parser_nextver .add_argument ("version" , help = "Version to raise" )
1068
+ parser_nextver .add_argument (
1069
+ "part" , help = "One of 'major', 'minor', 'patch', or 'prerelease'"
1070
+ )
998
1071
return parser
999
1072
1000
1073
0 commit comments