mirror of
https://github.com/semver/semver.git
synced 2026-07-11 06:53:03 -05:00
[GH-ISSUE #765] RFC: Forward-development or WIP (work-in-progress) support in Semantic Versioning #2242
Reference in New Issue
Block a user
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Originally created by @EvanCarroll on GitHub (Oct 28, 2021).
Original GitHub issue: https://github.com/semver/semver/issues/765
The spec assumes that pre-release is made on the final published version,
This assumes you know what
$VERSIONwill be as you progress with development and that your release is premediated. This is not ideal for modern agile development practices such as those espoused bysemantic-release. As such, code in a broken state or not ready to ship but needing testing, versioning, building, and deployment is not supported by semantic-version.Suggested Fix
Currently semantic-version supports the following to delineate non-version data,
-prefix for pre-release.+prefix for build metadata.By introducing a third unused character a forward-slash
/(mnemonic Forward-Progress), we can mark a build as not-released and internal, but more forward than the actual version. We can call this "Forward"Working Example
Let's say you decide to develop a new feature. The product your working on is currently at version 7.0.0 and your first commit is
0d0e0a1d8f. This version number could be automated to beLater, when you want to make available and release this functionality, you have some options
Ultimately you don't know where your commit (
0d0e0a1d8f) will land and most build systems that use semantic-versioning have no guidance on how to handle this unknown state (npm/cargo/semantic-release etc). The key here is that0d0e0a1d8fmay need to be QA'd, and it may need a build and currently the convention supported by pre-release requires people to guess whether or not the code that they've just written will ultimately be used toThese are easier to determine when you decide to release and when you've satisfied the quality gates then when you're developing.
This new convention provided by Forward allows you to replace release-forethought which is very often sentimental even if the numbering scheme isn't, with ignorance.
Ordering
I'm not sure how Forward should be ordered except to say that if available it should come after the final-release.
Not sure if the order should specify
/2coming after/1; or, if order should be simply undefined (which is not unprecedented the spec's build-metadata, denoted with a+prefix, is current undefined in ordering). Development is very often non-linear (happening in parallel) so it may be desirable to keep the ordering undefined.@jwdonahue commented on GitHub (Nov 29, 2021):
@EvanCarroll wrote:
I am unaware of any part of the spec that can be construed as making that assumption or requiring that in any way. The following history is perfectly legit SemVer:
The presence of a prerelease version in a package feed, in no way obligates anybody to ever issue any release version what-so-ever. Package feeds are littered with 0.y.z (prerelease) versions that can never morph into a release without a version change.
It seems that you are also trying to solve another pseudo problem w.r.t commits in a repository. You are assuming that it is a good or desired practice to commit version numbers to the source tree. Such a practice cannot scale well; to multiple developers, branches and build pipelines. Modifying the SemVer spec will not improve the prospects of such practices.
Instead, your developers should get in the habit of using semantic commit descriptions that clearly state whether the commit is a non-breaking fix, non-breaking feature addition, or breaking change. That is all that is required for a build system to determine what the next version number should be. While it may be convenient for the build system to tag the commit that it built the product from with the derived version, it is not necessary, if the commit hash is associated with that version number by other means (build meta, log or database).
You should also keep in mind that for a given commit hash, there can be multiple versions built, either as a product of the workflows or simply because multiple build machines produced output from the same commit hash at one time or another. Consider the case where one build agent is configured to produce instrumented output for the test lab telemetry system, while another constructs an RC candidate to be evaluated by security, legal, marketing or other teams. But this is not the venue for me to delve into these intricacies.
Given that there are few, if any, production build systems that are capable of building exactly the same bits twice in a row, even from exactly the same sources, and given that no two package content hashes should ever have the same name and version number on them, it is obvious that the version number should never come from the repo. Not even the commit hash is sufficient to uniquely version the output.
@EvanCarroll commented on GitHub (Dec 23, 2021):
@jwdonahue it's under the sorting rules,
And again,
It's even in the name pre- release, (not post- release).
The problem with this is that
-alphacomes before1.0.0, but what if1.0.0is released and you're developing on something that may be2.0.0or1.1.0or1.0.1. You're going to want a method for that to sort AFTER,1.0.0, otherwise how will you create tooling that allows you to grab the latest version? How will you draw the distinction about the versions that came before1.0.0and the ones that represent development after the release of1.0.0?The question is more of how do we want to represent this with a version spec. I've given you the problem description.
The rest of what you're saying about development practices is all personal conjecture. If I have a method of reprsenting unreleased development before a specific release and that's good development practice, I should have a method of representing unreleased development after a specific release.
@jwdonahue commented on GitHub (Dec 24, 2021):
@EvanCarroll
No prerelease ever sorts after a release version. It's not safe and a post release doesn't change that. You either have a release quality publication or you don't.
Your best option is to start with 1.0.1-alpha and work until you know where you landed in the (1.0.0, 2.y.z] range. As long as -alpha is attached, all changes are potentially breaking, so you're not going to harm anybody that isn't willing to take a little risk. You could have a history like this:
1.0.0-alpha
1.0.0
1.0.1-alpha // Technically a post 1.0.0 prerelease.
1.0.2-alpha
1.0.2 // Decided those bug fixes should be released.
1.0.3-alpha.0 // Alternate counting scheme.
1.0.3-alpha.1
2.0.0-alpha // You had to break it, but you're still in prerelease and no idea where you'll land.
1.0.3-beta // Bug fixes cherry picked from dev into release branch.
1.0.4
2.1.0-alpha // etc.
Precedence rules define sort order, not how consumers chose a version to pull. Most tools will let you pull the highest X.Y.Z-alpha* that is visible on the feed. In the above history, we have a choice to pull the latest release of 1.0.4 or the highest prerelease version available. We could even limit what we pull to the
[1.0.0-*, 2.0.0-*)range. With a good tool, you can chose between -beta or -alpha.@jwdonahue commented on GitHub (Dec 24, 2021):
@EvanCarroll
In fact, the prerelease tag is your ticket to make any kind of random changes you see fit to make:
In other words, you can publish any kind of WIP without even testing it if that is what you need to do. The presence of the prerelease tag literally means "consumer beware, this version might be dangerous".
I think this perennial issue regarding "post release" forms of versioning stems from the pre-DevOps era practice of marking up version controlled source or configuration files, with a version number. If you let go of that practice and generate version numbers at build, release/publication, you'll find that you can get by just fine with prerelease tags and a sound understanding of how to use your tools to filter/select versions from your feeds/file-shares.
My personal preference for WIP that is published to internal feeds, is to tag it with a build number, prerelease tag (not SemVer) and build meta consisting of the repo hash value, build cluster/machine and some clues what build options were applied (was it instrumented? etc.). Apply QA to those outputs and when you have an acceptable one, publish using SemVer or other acceptable versioning scheme. That last step usually being a manual operation requiring lots of sign-offs.
@EvanCarroll commented on GitHub (Dec 24, 2021):
You have a lot of words, but so many are unrelated to technical merits.
That's not true, what do you think this does in a
cargo.tomlorpackage.jsonfile,It picks the latest version that sorts greater major version 1 that is known to not have breaking changes. That should include things developed after 1.0.0 but compatible to it. The version
1.0.0-rc1would not get picked up, the proposed1.0.0/dev1would get picked up.@ljharb commented on GitHub (Dec 24, 2021):
The only way you could guarantee compatibility, is if you knew that the changes in the postrelease were patch or minor - in which case, you know which version it’s a prerelease for.
@jwdonahue commented on GitHub (Dec 24, 2021):
@EvanCarroll
That is a selector or version filter. How it behaves is not defined by SemVer.
You are free to issue a PR for whatever language you propose. I doubt you'll find much support for it. There's been plenty of earlier "post release" proposals made, some of them actually issued a PR. Fact is that any change to allow post-release semantics of any kind would be a breaking change to the spec, and it is highly unlikely to be supported by any of the maintainers.
@EvanCarroll commented on GitHub (Dec 24, 2021):
I'm not sure what you mean by compatability but if the following conditions are ensured,
Then 1.2.3/1 is not valid semver at all now. And making it a valid version would not change the ordering on systems that predated it.
@EvanCarroll commented on GitHub (Dec 24, 2021):
What are you even talking about? The whole purpose of semver is to establish version numbers so we know how one version relates to another version. It's pretty explicit (from the spec)
That precendence is what selectors depend on. It's what makes this project useful. This RFC allows you to have a corrolary to pre-release (which represents development before a release), but for after the actual release happens.
At this point I'm really having a hard time discerning any utility from your responses @jwdonahue.
@ljharb commented on GitHub (Dec 24, 2021):
I’m saying that if you know that 1.2.3/1 is compatible with 1.2.3, then you also have precisely enough information to know whether it (currently) would be a prerelease for 1.2.4 or 1.3.0 - so why not use the existing, well-understood facility of prereleases and publish one?
@jwdonahue commented on GitHub (Dec 24, 2021):
@EvanCarroll SemVer specifies precedence rules that say
V1 < V2. It does not define whether a consumer should selectMin(Versions)orMax(Versions)orPredicate[x](Versions). Those functions may sort Versions prior to choosing a specific version to pull, but not all F(Versions) are sensitive to sort order. The spec simply provides the minimal set of rules required to order a set of versions when order is important. Package managers and other tools, layer additional conventions on top of the SemVer rules to make them useful within specific development environments.Precisely what
foo = "1"means, is defined by the tool that reads that configuration statement. Perhaps it means "give me package named foo version 1", which is not a SemVer version string, or perhaps it means "give me package named foo in the range of [1.0.0, 2.0.0)"? The later isn't particularly useful if you don't also define the predicate that selects from the set of available versions in that range. Most tools have a default selector ofMinStable(r)orMax(r)in such cases.Simply taking the latest in the set of all publicly available
foois generally not what anybody wants to do. We usually limit the range of acceptable versions and then apply some heuristics to select the best from that set for our purposes. Some of us want preleases, some want only releases.Adding a "post-release" syntax will increase the complexity of SemVer compliant implementations without adding any apparent benefit. As you have proposed:
The "not-released and internal" implies it doesn't belong in the SemVer spec. You can use any versioning conventions you find useful in your internal processes. I've seen many uses of the 4 digit
<SemVer Triple>.<BuildNumber>format used in internal schemes. SemVer is for labelling that which will be published and is not generally useful for internal development.SemVer is unsuited for the kind of internal development where process actually matters, i.e.; multiple developers and development branches. Pure sort by date/timestamp, build number or any versioning scheme is virtually useless in a world where there are dozens of developers or teams working from different starting points in potentially different repos or branches in the code base and you have potentially thousands of build machines cranking away on those branches. No linear versioning scheme applies to such a messy, chaotic environment. The best you can hope for is to work towards a more manageable release cadence, heuristically selected from the bits that are ready to ship. You apply the appropriate SemVer version to the bits that you publish externally, not internally.
Many people have proposed similar breaking changes to the SemVer spec. There is a problem they want to solve and they think a change to the spec will automagically be taken up by the tool developers, or they are considering writing the tool themselves, but they think they'll have an easier time getting the required budget allocations if there is also movement in the psec. But that loop is slow compared to that which is implemented broadly and finds it's way into the spec.
Read the CONTRIBUTING.md file. Fork your favorite packaging tool and add your experimental feature. Then promote it, respond to feedback and when you think it's fully baked, write an RFC.
Good luck.
@EvanCarroll commented on GitHub (Dec 25, 2021):
@jwdonahue I would block you if I could, but I can't. It's not my intent to respond to you again. Not because you're bad guy, but I don't care about the non-technical objections. This isn't productive. You've got the last word on the matter. Thanks.
@EvanCarroll commented on GitHub (Dec 25, 2021):
@ljharb Ah, so you mean how would compatibilty be inferred between versions, rather than between between a version of semvar with and without such knowledge of forward-releases. I don't think it would work any different than pre-release currently does.
For example the spec says this,
Why is that this couldn't also be said,
The only thing you're trying to maintain here is the ordinal significance that this came after the released version. I'm not trying to make it more useful than something that signifies the same thing that comes before it.
@ljharb commented on GitHub (Dec 25, 2021):
Right - but “a prerelease for a version that comes after the released version” already conveys that information. Why do we need two ways to do so?
@jwdonahue commented on GitHub (Dec 25, 2021):
Well there's a first. I've never been accused of being non-technical before.
@EvanCarroll If I could silence everyone who disagrees with me, I'd be a happy camper too.
@jarphal commented on GitHub (Feb 25, 2022):
I need help
@jarphal commented on GitHub (Feb 25, 2022):
Please help me with