You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Determine bump type between two different versions #262
When using a staging branch, you can stack changes on the staging branch by bumping the prerelease number for every change pushed.
Determining whether to use a major, minor or patch bump on each push requires you check the whether the current prerelease version has had the appropriate bump with respect to the currently released version on master.
For example, pushing a minor change to staging when staging is at 1.0.1-rc.1 and master is at 1.0.1, the appropriate bump here would be bump_minor() since the staging version is not more recent than the master version.
Subsequently (when staging is at 1.1.0-rc.1 and master still at 1.0.1), a minor change or a patch change would not bump minor or patch, but instead bump the prerelease.
On the other hand, a major change would require a bump_major().
Hopefully the example illustrates where you would need to find the bump type needed to go from one version to another.
Situation
At the moment there is no simple explicit (or implicit) way to determine the diff bump between versions.
One must compare each part of the version to determine which is the bumped part.
This is trivial code that is prone to errors since it must be rewritten by anyone who wishes to achieve this task.
Proposition
Write a function maybe called diff that takes two VersionInfo objects and returns the differential bump (type: tbd).
At first, I was going to request that __sub__ be implemented for VersionInfo, but I figured out what I really wanted to do with this feature. I do think this would be a possible implicit way to achieve this goal, but there are simpler and better ways to do this explicitly, such as looping through the parts and returning the first one that is different.
Thanks @tlaferriere for your idea! Haven't thought of that, that's an interesting use case. 👍
I marked it for release 3 of semver as I think, this is a completely new functionality. Would prefer to implement this in a major release.
Not sure if I completely understood the details, therefor some questions:
Should the "diff" return the first part which could be found or all parts?
For example, the "diff" between 1.0.0 and 1.1.5 would be to raise the minor (1.0.0 -> 1.1.0) and then set the patch part (1.1.0 -> 1.1.5).
As you already noted, what type should be the "diff"?
That probably depends on how we consider point (1). It could be a string if we only want to know "major", "minor", "patch" etc. Or it could be a tuple/list if we allow more.
Are you trying to find the appropriate (bump) function or just the version part?
Do we allow a "diff" only from low to high?
What happens when you try to create a diff from 2.0.1 -> 1.0.5? There is no bump version which could do that (although there is .replace). Should we raise an exception?
Should the "diff" return the first part which could be found or all parts?
Because IMO the biggest use of the "diff" would in determining the relevance of a potential bump, I believe that only returning the first part raised would be enough for most uses. It would keep the complexity at a minimum, which is important for its maintainability.
There could exist uses for having all the different parts returned, but to be really useful, I believe it would also require knowing how many times each bump was applied. This is would then be more like a subtraction, and would probably warrant implementing __sub__ for VersionInfo. But that's out of scope for this issue (although I am curious to see if anyone has a use case for this).
As you already noted, what type should be the "diff"?
It could be a
string, which can be used as:
an argument to getattr in order to get the same part of another version
an argument to VersionInfo.next_version
int, which can be used as:
an index to get the same part of another version
Numerically, I'm leaning towards the str return type.
Are you trying to find the appropriate (bump) function or just the version part?
In my use case it would be simply the part, in order to know whether or not to apply the bump that I could apply. Thanks to VersionInfo.next_version, having the part as a string would allow us the obtain the appropriate bump function.
Do we allow a "diff" only from low to high?
Because of the unidirectionality of the bump functions, I think we can ignore the order in which the versions are passed in the function, just to KISS.
@tomschr I think we should disuss the location of this function.
As I mentioned here, it seems this project is on a trend of centralising functionality in the VersionInfo class.
Therefore I think this new function should be a method (with signature (self, other: VersionInfo) -> str) of VersionInfo.
Does this make sense?
I see this is still open from 2020 but wanted to come here to say something similar.
It's a significant pain that python3 -m semver bump prerelease 1.1.1 produces 1.1.1-rc1. This is a defect, in my view. bump should always increase the version number and 1.1.1-rc1 is a version less than 1.1.1. The correct output would be 1.1.2-rc1.
For a point of comparison, the semver nodejs package does this:
$ semver -i prerelease 1.1.1
1.1.2-0
I realise this is a different point to the one raised in this ticket but it is trying to address the same underlying problem: It is very difficult to produce a useable prerelease version from an existing released version number. You can't just bump both the patch and the prerelease versions unconditionally, because the patch version only needs to be bumped if there isn't already a prerelease tag in the version number.
@tomkcook Thanks for your comment! I'm also not happy, but changing it would introduce a backward incompatibility that could break existing code which rely on the current behavior.
I'm thinking about to change this and try to decide about these options:
Release semver 4 and change the behavior of it. Pro: Would fix the issue, existing code does not need to be changed. Con: Would leave all previous major releases with this flaw.
Introduce a new optional parameter in bump_prerelease which could switch between new and old behavior. Pro: Makes it easier to migrate. Con: Optional parameters can easily be forgotten, too confusing?
Introduce a new method (inc, bump etc.) which doesn't have this issue and deprecate all other bump_* methods. Pro: Better naming; internally it can still use the old code Con: Existing code needs to be maybe adjusted
Just fix the issue in version 3.1.0 and deal with the fallout later. Pro: Fixes the problem instantly Con: May break existing code if some rely on the current behavior.
Probably there are other options. I am currently considering what the best option would be. 🤔
@tomschr I agree those are the available options. Personally, I would go for option 3. Deprecation doesn't mean every piece of code needs to be updated immediately.
Thanks @tomschr for the detailed review of #493. Before revising it, I'd like to confirm the scope here:
Make Version.diff classify valid version pairs consistently with node-semver@7.7.2: ignore build metadata, return None for equal precedence, and support major, minor, patch, premajor, preminor, prepatch, and prerelease, including node's prerelease-to-release rules.
Accept Version, str, bytes, dict, tuple, and list inputs with Python-style conversion and explicit errors for invalid or unsupported inputs.
Update the tests, documentation, and changelog to match these semantics, using node-semver's diff cases as a reference.
I'd keep changes to next_version and the bump methods out of this PR. This classification alone would not resolve the staging-branch decision in the original example, so I would change #493 to reference #262 rather than automatically close it. Does this scope match what you have in mind? I'll wait for confirmation here before revising the implementation.
Make Version.diff classify valid version pairs consistently with node-semver@7.7.2: ignore build metadata, return None for equal precedence, and support major, minor, patch, premajor, preminor, prepatch, and prerelease, including node's prerelease-to-release rules.
If possible, yes.
Accept Version, str, bytes, dict, tuple, and list inputs with Python-style conversion and explicit errors for invalid or unsupported inputs.
Yes, please. I showed already a draft, untested suggestion in #493.
Update the tests, documentation, and changelog to match these semantics, using node-semver's diff cases as a reference.
Yes, please.
I'd keep changes to next_version and the bump methods out of this PR.
That's fine. 👍
This classification alone would not resolve the staging-branch decision in the original example, so I would change #493 to reference #262 rather than automatically close it. Does this scope match what you have in mind? I'll wait for confirmation here before revising the implementation.
Activity
tomschr commentedon Jun 11, 2020
Thanks @tlaferriere for your idea! Haven't thought of that, that's an interesting use case. 👍
I marked it for release 3 of semver as I think, this is a completely new functionality. Would prefer to implement this in a major release.
Not sure if I completely understood the details, therefor some questions:
For example, the "diff" between 1.0.0 and 1.1.5 would be to raise the minor (1.0.0 -> 1.1.0) and then set the patch part (1.1.0 -> 1.1.5).
That probably depends on how we consider point (1). It could be a string if we only want to know "major", "minor", "patch" etc. Or it could be a tuple/list if we allow more.
What happens when you try to create a diff from 2.0.1 -> 1.0.5? There is no bump version which could do that (although there is
.replace). Should we raise an exception?tlaferriere commentedon Jun 12, 2020
Because IMO the biggest use of the "diff" would in determining the relevance of a potential bump, I believe that only returning the first part raised would be enough for most uses. It would keep the complexity at a minimum, which is important for its maintainability.
There could exist uses for having all the different parts returned, but to be really useful, I believe it would also require knowing how many times each bump was applied. This is would then be more like a subtraction, and would probably warrant implementing
__sub__forVersionInfo. But that's out of scope for this issue (although I am curious to see if anyone has a use case for this).It could be a
getattrin order to get the same part of another versionVersionInfo.next_versionNumerically, I'm leaning towards the
strreturn type.In my use case it would be simply the part, in order to know whether or not to apply the bump that I could apply. Thanks to
VersionInfo.next_version, having the part as a string would allow us the obtain the appropriate bump function.Because of the unidirectionality of the bump functions, I think we can ignore the order in which the versions are passed in the function, just to KISS.
tlaferriere commentedon Jun 13, 2020
@tomschr I think we should disuss the location of this function.
As I mentioned here, it seems this project is on a trend of centralising functionality in the
VersionInfoclass.Therefore I think this new function should be a method (with signature
(self, other: VersionInfo) -> str) ofVersionInfo.Does this make sense?
tomschr commentedon Jun 13, 2020
@tlaferriere
Thanks for the detailed description. 👍 From what I've seen, it does make sense. Unless I've overlooked something important. 😉
tomkcook commentedon Feb 7, 2025
I see this is still open from 2020 but wanted to come here to say something similar.
It's a significant pain that
python3 -m semver bump prerelease 1.1.1produces1.1.1-rc1. This is a defect, in my view.bumpshould always increase the version number and1.1.1-rc1is a version less than1.1.1. The correct output would be1.1.2-rc1.For a point of comparison, the
semvernodejs package does this:I realise this is a different point to the one raised in this ticket but it is trying to address the same underlying problem: It is very difficult to produce a useable prerelease version from an existing released version number. You can't just bump both the patch and the prerelease versions unconditionally, because the patch version only needs to be bumped if there isn't already a prerelease tag in the version number.
tomschr commentedon Feb 11, 2025
@tomkcook Thanks for your comment! I'm also not happy, but changing it would introduce a backward incompatibility that could break existing code which rely on the current behavior.
I'm thinking about to change this and try to decide about these options:
Pro: Would fix the issue, existing code does not need to be changed.
Con: Would leave all previous major releases with this flaw.
bump_prereleasewhich could switch between new and old behavior.Pro: Makes it easier to migrate.
Con: Optional parameters can easily be forgotten, too confusing?
inc,bumpetc.) which doesn't have this issue and deprecate all otherbump_*methods.Pro: Better naming; internally it can still use the old code
Con: Existing code needs to be maybe adjusted
Pro: Fixes the problem instantly
Con: May break existing code if some rely on the current behavior.
Probably there are other options. I am currently considering what the best option would be. 🤔
Maybe you have an additional idea?
tomkcook commentedon Feb 12, 2025
@tomschr I agree those are the available options. Personally, I would go for option 3. Deprecation doesn't mean every piece of code needs to be updated immediately.
tomschr commentedon Feb 14, 2025
Thanks @tomkcook for your opinion. Just to let you know, I forgot to mention that recently I've merged PR #460 which could mitigate the issue.
masonjian commentedon Oct 11, 2026
Thanks @tomschr for the detailed review of #493. Before revising it, I'd like to confirm the scope here:
Version.diffclassify valid version pairs consistently withnode-semver@7.7.2: ignore build metadata, returnNonefor equal precedence, and supportmajor,minor,patch,premajor,preminor,prepatch, andprerelease, including node's prerelease-to-release rules.Version,str,bytes,dict,tuple, andlistinputs with Python-style conversion and explicit errors for invalid or unsupported inputs.I'd keep changes to
next_versionand the bump methods out of this PR. This classification alone would not resolve the staging-branch decision in the original example, so I would change #493 to reference #262 rather than automatically close it. Does this scope match what you have in mind? I'll wait for confirmation here before revising the implementation.tomschr commentedon Oct 11, 2026
Thank you!
If possible, yes.
Yes, please. I showed already a draft, untested suggestion in #493.
Yes, please.
That's fine. 👍
That would be great! 👍
Thank you very much! Please proceed, great job.