[GH-ISSUE #29] Change "must reset" to "should reset" patch numbers #1756

Closed
opened 2026-04-20 09:19:20 -05:00 by GiteaMirror · 6 comments
Owner

Originally created by @jamesarosen on GitHub (May 30, 2012).
Original GitHub issue: https://github.com/semver/semver/issues/29

This article on continuous deployment of gems suggests a mechanism that uses the build number (which is non-decreasing) as the patch. That violates the semver statement (3) that, "When a minor version number is incremented, the patch version MUST be reset to zero." It seems to me that using the build number here both obeys the spirit of semver and the letter of all but this one statement. Most notably, it does not break the meaning of ~> x.y.z.

Originally created by @jamesarosen on GitHub (May 30, 2012). Original GitHub issue: https://github.com/semver/semver/issues/29 [This article](http://hackers.mylookout.com/2012/05/continuous-deployment-for-gems/) on continuous deployment of gems suggests a mechanism that uses the build number (which is non-decreasing) as the patch. That violates the semver statement (3) that, "When a minor version number is incremented, the patch version MUST be reset to zero." It seems to me that using the build number here both obeys the spirit of semver _and_ the letter of all but this one statement. Most notably, it does _not_ break the meaning of `~> x.y.z`.
Author
Owner

@audigex commented on GitHub (Jul 16, 2012):

Does that mean problems, however, that if you have multiple concurrent versions (ie 2.0.z is the current main version but 1.4.z is still being maintained)?

ie 1.4.z is up to version 1.4.5 when 2.0.6 is released (this is where I might be misunderstanding the article) - carrying the patch number over
2.0.7 is subsequently released, then 2.0.8, to fix bugs.
I then release a new patch for 1.4.z to fix a bug - which would be numbered 1.4.9 (again, I may be missing the point here)

This means that the version numbers could be non-consecutive for each minor version.
1.4.5 jumps to 1.4.9
2.0.6 goes to 2.0.7, 2.0.8 then 2.0.10

This doesn't seem like desired behaviour to me. It would seem to work perfectly when development of each version is stopped as soon as the next version is released, but then the numbering would be logical anyway. I'd rather keep track of revision separately to version number - versions are for external users to check compatibility, revisions are for developers to find where bugs and problems were introduced, or for internal reference.

<!-- gh-comment-id:7008260 --> @audigex commented on GitHub (Jul 16, 2012): Does that mean problems, however, that if you have multiple concurrent versions (ie 2.0.z is the current main version but 1.4.z is still being maintained)? ie 1.4.z is up to version 1.4.5 when 2.0.6 is released (this is where I might be misunderstanding the article) - carrying the patch number over 2.0.7 is subsequently released, then 2.0.8, to fix bugs. I then release a new patch for 1.4.z to fix a bug - which would be numbered 1.4.9 (again, I may be missing the point here) This means that the version numbers could be non-consecutive for each minor version. 1.4.5 jumps to 1.4.9 2.0.6 goes to 2.0.7, 2.0.8 then 2.0.10 This doesn't seem like desired behaviour to me. It would seem to work perfectly when development of each version is stopped as soon as the next version is released, but then the numbering would be logical anyway. I'd rather keep track of revision separately to version number - versions are for external users to check compatibility, revisions are for developers to find where bugs and problems were introduced, or for internal reference.
Author
Owner

@jamesarosen commented on GitHub (Jul 16, 2012):

The jump from 1.4.5 to 1.4.9 might be a little confusing to humans at first glance, but it doesn't seem wrong to me. It obeys the contract of ~>. Indeed, you would have this same gap if the author built and released, then yanked 1.4.6, 1.4.7, and 1.4.8.

<!-- gh-comment-id:7011458 --> @jamesarosen commented on GitHub (Jul 16, 2012): The jump from `1.4.5` to `1.4.9` might be a little confusing to humans at first glance, but it doesn't seem _wrong_ to me. It obeys the contract of `~>`. Indeed, you would have this same gap if the author built and released, then yanked `1.4.6`, `1.4.7`, and `1.4.8`.
Author
Owner

@TheRealEdwardCullen commented on GitHub (Jul 27, 2012):

I strongly disagree; SemVer is about external version numbering. The 'build number' is an implementation detail, for example, let's say that we build 1.2.3 and deploy it onto some test infrastructure, now let's say that something goes wrong and we end up losing the build artefacts for this first build, so we re-build exactly the same code.

Semantically, there is no difference, but under the proposed scheme you would get different version numbers; the conversation that ensues:

Manager: "How is 1.2.4 different to 1.2.3?"
Developer: "It isn't."
Manager: "Why does it have a different number then?"
Developer: "We rebuilt it."
Manager: "Does that make it different."
Developer: "Functionally, no."
Manager: "So it is different then, so we need to repeat ALL our testing?"
Developer: "Well, no, it is different, but it's functionally the same."
Manager: "So we don't need to repeat all our testing?"
Developer: "It passed the smoke test, so there's no reason to think there's any difference."
Manager: "So why does it have a different version number."
Developer: "Because it's a different build."
Manager: "But you just said it's the same, so we don't need to redo all our testing."
Developer: "That's right."
Manager: "But you can't be sure?"
Developer: - Enters long discussion about meta-physical uncertainty... -

I think you get the idea... :)

<!-- gh-comment-id:7302672 --> @TheRealEdwardCullen commented on GitHub (Jul 27, 2012): I **strongly** disagree; SemVer is about _external_ version numbering. The 'build number' is an implementation detail, for example, let's say that we build 1.2.3 and deploy it onto some test infrastructure, now let's say that something goes wrong and we end up losing the build artefacts for this first build, so we re-build exactly the same code. Semantically, there is no difference, but under the proposed scheme you would get different version numbers; the conversation that ensues: Manager: "How is 1.2.4 different to 1.2.3?" Developer: "It isn't." Manager: "Why does it have a different number then?" Developer: "We rebuilt it." Manager: "Does that make it different." Developer: "Functionally, no." Manager: "So it is different then, so we need to repeat ALL our testing?" Developer: "Well, no, it is different, but it's functionally the same." Manager: "So we don't need to repeat all our testing?" Developer: "It passed the smoke test, so there's no reason to think there's any difference." Manager: "So why does it have a different version number." Developer: "Because it's a different build." Manager: "But you just said it's the same, so we don't need to redo all our testing." Developer: "That's right." Manager: "But you can't be sure?" Developer: - Enters long discussion about meta-physical uncertainty... - I think you get the idea... :)
Author
Owner

@jamesarosen commented on GitHub (Jul 27, 2012):

I will take first the morality play you so vividly present, then separately the argument in the first graph.

The interaction between Manager and Developer is indeed a perilous one, but alas! It is neither prevented in the current scheme, nor exacerbated by my proposal to relax the reset-to-0 constraint. The closest rule I can find is that the "Patch version Z (x.y.Z | x > 0) MUST be incremented if only backwards compatible bug fixes are introduced." The careful eye will observe the "if" with only one "f." That is, the specification does not state that the patch version may be incremented only concurrent with backwards-compatible bug fixes. The conscientious developer might release a patch version consisting of only refactorings or performance improvements -- all backwards-compatible, of course.

You suggest lost build artifacts as a possible antecedent to the exchange between Manager and Developer. (Indeed, you mention no others, so perhaps "the cause" is a better phrase.) But why, if the build artifacts were lost, would the build system publish a corresponding version? Would not the outward behavior be simply that the version number be skipped?

Let us now examine your concern over the exposing of the implementation detail. I put to you that releasing versions 1.1.54 and 1.2.55 but no versions of 1.2.x below 55 exposes no information that was not already available, for the [http://rubygems.org](RubyGems server) displays the timestamp of each release. All you have told the world is that 1.2.55 was released at some point in time after 1.1.54, but you have already told the world this by the timing of your releases. The same equivalence is equally true if you were to release 1.2.54 and later 1.1.55.

<!-- gh-comment-id:7310265 --> @jamesarosen commented on GitHub (Jul 27, 2012): I will take first the morality play you so vividly present, then separately the argument in the first graph. The interaction between Manager and Developer is indeed a perilous one, but alas! It is neither prevented in the current scheme, nor exacerbated by my proposal to relax the reset-to-0 constraint. The closest rule I can find is that the "Patch version Z (x.y.Z | x > 0) MUST be incremented if only backwards compatible bug fixes are introduced." The careful eye will observe the "if" with only one "f." That is, the specification does not state that the patch version may be incremented _only_ concurrent with backwards-compatible bug fixes. The conscientious developer might release a patch version consisting of only refactorings or performance improvements -- all backwards-compatible, of course. You suggest lost build artifacts as a possible antecedent to the exchange between Manager and Developer. (Indeed, you mention no others, so perhaps "_the_ cause" is a better phrase.) But why, if the build artifacts were lost, would the build system publish a corresponding version? Would not the outward behavior be simply that the version number be skipped? Let us now examine your concern over the exposing of the implementation detail. I put to you that releasing versions 1.1.54 and 1.2.55 but no versions of 1.2.x below 55 exposes no information that was not already available, for the [http://rubygems.org](RubyGems server) displays the timestamp of each release. All you have told the world is that 1.2.55 was released at some point in time after 1.1.54, but you have already told the world this by the timing of your releases. The same equivalence is equally true if you were to release 1.2.54 and later 1.1.55.
Author
Owner

@haacked commented on GitHub (Oct 2, 2012):

Sorry for the late follow-up, but the latest version of SemVer does include a provision for build numbers specifically for scenarios like this. This should hopefully remove the need to make the patch have dual meaning and be affected by continuous integration builds.

<!-- gh-comment-id:9081377 --> @haacked commented on GitHub (Oct 2, 2012): Sorry for the late follow-up, but the latest version of SemVer does include a provision for build numbers specifically for scenarios like this. This should hopefully remove the need to make the patch have dual meaning and be affected by continuous integration builds.
Author
Owner

@jamesarosen commented on GitHub (Oct 2, 2012):

Brilliant! I have no specific desire to corrupt the meaning of "patch" :)

<!-- gh-comment-id:9082411 --> @jamesarosen commented on GitHub (Oct 2, 2012): Brilliant! I have no _specific_ desire to corrupt the meaning of "patch" :)
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/semver#1756