-
Notifications
You must be signed in to change notification settings - Fork 702
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Allow infinite (n) optional version segments #242
Comments
@isaacs: Would love your thoughts and feedback, too. |
Personally, I'm much more a fan of using a different syntax for these cases so that we wouldn't end up in a world with Instead of just appending numbers I'd rather suggest to introduce a post-release section that hi-jacks the current The use cases I can imagine:
Because there are many things to consider with the second problem (e.g. integrate a lib that depends on another lib already and bases its version on that) I have not yet been able to find a good solution for this problem as post-releases will remain abusable in that regard. The same thing applies to your suggestion however. Examples: Note that this is a breaking change and would require SemVer 3.0.0. |
I struggle to express just how strongly opposed to this I am. It is completely unclear whether What you are describing is not SemVer, it's a completely different thing. Use the prerelease and/or build tagging features. If the dependency version isn't something that you're going to select on, then use build metadata, because that's what that is for, and does not require Yet Another magic character. Furthermore, how would one express, as a dependency, that you require version Let's back up several steps here and identify the problem that we're trying to solve. Then, let's evaluate whether we actually need to solve that problem, or if in fact we need to: (a) evangelize the use of SemVer, (b) factor dependencies in a more modular fashion, (c) tie public APIs less tightly to internal dependencies, (d) become more comfortable with the idea that SemVer only expresses semantics about public API and not about internal implementation details, or (e) do something else entirely. |
@isaacs exactly. From: isaacsmailto:notifications@github.com I struggle to express just how strongly opposed to this I am. It is completely unclear whether What you are describing is not SemVer, it's a completely different thing. Use the prerelease and/or build tagging features. If the dependency version isn't something that you're going to select on, then use build metadata, because that's what that is for, and does not require Yet Another magic character. Furthermore, how would one express, as a dependency, that you require version Let's back up several steps here and identify the problem that we're trying to solve. Then, let's evaluate whether we actually need to solve that problem, or if in fact we need to: (a) evangelize the use of SemVer, (b) factor dependencies in a more modular fashion, (c) tie public APIs less tightly to internal dependencies, (d) become more comfortable with the idea that SemVer only expresses semantics about public API and not about internal implementation details, or (e) do something else entirely. Reply to this email directly or view it on GitHub: |
Some great points among those (though I disagree with a few), guys. Thanks! To clarify my particular use case:
So, thinking through this my needs further, I think I must conclude that SemVer--in pretty much any theoretical future state--is not really capable of supporting this situation because I essentially need to represent 2 public API versions simultaneously. As such, I believe my only remaining option as far as SemVer + the NPM tooling goes is to publish a different module for each external version (e.g. Disappointing... but I feel like I have a better understanding of the situation's depth after talking through it, so thanks for the outlet. |
@JamesMGreene Certainly putting the version number in the name is an option. That's why we have, for example, https://www.npmjs.com/package/unicode-3.0.0 which is version 0.1.5. On the other hand, you could just make your wrapper even lighter, and just go ahead and tie your version number to the flex-sdk's version. But it means that you can never update the wrapper code. You can also put maybe just the major version or major.minor in the package name, and say that you accept patch updates to the internal dep. Since flex is likely to update only very rarely, maybe that's fine. There's a lot of ways around this. But SemVer on your module version should refer to its external API surface, and nothing else. |
That's exactly how I started... and then I needed to update my wrapper code to normalize inconsistent line endings that snuck into a few versions (apparently Adobe sometimes packaged it on Windows, and sometimes on Linux/Mac (or always on Windows and forgot to normalize it sometimes)). And so, I was quickly put back a few steps, especially after discovering that NPM no longer allow republishing anymore (not exactly fortuitous timing 😢), and then ended up resorting to the pre-release versioning strategy. That worked alright until NPM moved to its node-semver version 4 range semantics that handicapped consumers of modules using a pre-release versioning strategy like mine. I understand the rationale behind the change but that was a major bummer for me. |
I would have rather seen that in SemVer At this point, I would worry that changing the meaning of the |
And, even if we did change the meaning of the So, let's say I have versions Now, going a little outside of the scope of SemVer proper and into the world of querying/selecting/matching/etc. version ranges, I would then expect my consumers would want to install such a versioned module by running Similarly outside of the scope of SemVer proper, the NPM registry would need to start accepting modules with |
@JamesMGreene For your use case I actually intended the examples This is probably a bit confusing though so if you hit any problems, feel free to ask. |
SemVer is there to express the version of your code, and your code alone. It is the job of the package managers to manage dependent packages. This is the use case for build metadata, so that you can easily and fully express with words these ideas, without making the version precedence rules insane. You could easily introduce a breaking change in your wrapper API, and as a consumer I want to know this. Also, I'm not going to choose a wrapper because I am already using some specific framework; for me it works the other way around. |
@FichteFoll: OK, interesting, that gives me a better feel for what you're talking about. Using After that, though, NPM's client and registry would also need to be updated to stop stripped build metadata and allow multiple versions of the same package version to be published with different build metadata. Would also need to add the appropriate corresponding selectors into node-semver, of course, but I'm personally less worried about happening successfully than the former concern with publishing. |
Build metadata is a human friendly note, and nothing more. Two packages with the same version and different metadata (and differing content) would be 😿 all over the place. |
I think it can serve a much better role than it does—at least in NPM—today. SemVer §10 states:
This means that build metadata differences do NOT alter the version "level". For example, the versions It does NOT mean that versions with the same version level but differing build metadata are identical/equal versions/content. NPM makes this faulty interpretation today by always stripping the build metadata off the version number during prepublish/publish, which thus disallows publishing another "parallel" version with different build metadata. For example, let me describe a sequence of events:
Yes... but that is not inherently incorrect unless the publisher makes it such. If the APIs (and [known] bug statuses) are in sync, then this is actually perfectly correct usage. I also think that the package manager can make the call on the default behavior of publishing versions with build metadata. For example, I think it is fine if NPM continues to exclude the build metadata from the version by default so long as it provides a mechanism to include the build metadata in the version (e.g. adding a |
Yes, that's exactly what I'm thinking of build metadata. However: The current semver spec doesn't exactly allow this use with multiple parallel releases that share the version number but have differing metadata, but this is pretty much the only viable use case for metadata that I have found so far. On the flip side, this would probably be better implemented as a prefix since semantically the metadata is more important than the major number and would separate channels respectively (so For the dependency example, that would mean include the dependency version in your name and then provide your own version number after that. Going back to @isaacs's point: I'm not actually sure if semver needs to (or even can) solve this use case since it is likely to behave different for different platforms. The closest proposal I can think of right now would be the |
Sorry, apparently I am back-tracking to respond to @EddieGarmon's comments in reverse order:
Agreed.
At least for my particular use case, that is definitely not the norm. Consumers come seeking the specific version [ranges] of the external library to ensure they can compile to their desired target level... they don't really care about my wrapper beyond knowing the basic API hasn't been broken (major version upgrade) as it truly as paper thin. |
I would disagree. As I mentioned earlier, SemVer states that build metadata should be ignored for the sake of version precedence (which only means for sorting order), not that it should be ignored altogether for version equality checking.
Agreed. I see no point to having the metadata extension even be specified if you can't publish a version that includes it... but perhaps that is a problem limited to NPM's interpretation of the SemVer spec? Not sure if other package managers suffer from the same interpretation.
If it's not part of SemVer, then it will not end up well-supported... in which case, changing the package name rather than the version still makes more sense to achieve better cross-cutting support. |
The troubling part is that now this has me thinking through how to basically abuse NPM package names and dependencies in order to fake double-versioned SemVer.... For example: Top Level:
Low Level:
|
"Top Level Convenience Aliases" is where things start getting dirty. |
Agreed. They're also really not necessary since they are achievable via actual SemVer-based selectors:
So I should [happily] just drop those so long as I continue having a faux-SemVer top level package like |
Yet another option would be to create a package that is able to install any version of the Flex SDK by specifying that version in the code rather than in the package version. For example: var flexSdk = require('flex-sdk-wrapper')('4.6.0'); That would give you the flexibility to release (wrapper) package updates as you see fit, and support newer Flex SDKs in newer versions of your package. In a way, that makes a lot more sense to me. And you could still support semver in the argument that you pass to the function. Of course, the downside would be that you replicate some of npm's logic in your package's source. Also, your Flex SDK version number would no longer be in |
@timdp: Valid idea but not something I would want to provide or use, personally. Additionally, that means that all installation variations necessary must be handled within a single version of the module, rather than being able to handle those on a per-version basis. |
@JamesMGreene Is the installation logic that complicated? I'd be willing to have a stab at creating such a package, but if you say that you had a lot of issues with yours, I'll probably bail. Sorry to kinda go off topic here. |
For what it's worth, I built:
James, it's nowhere near as versatile as your approach, but all the configuration logic could theoretically be backported if need be. Since it covers my scenario, I'm not going to bother with that for now though. I'll shut up about the Flex SDK-specific case now. |
@timdp: More power to you. 👍 Unfortunately for me, I haven't any free time to really work on my open source projects since like Christmas time, so everything has been a it stale/neglected, and this particular issue is not at the top of my list. 😢 |
[Japanese] Fix Japanese translation for slightly better expression
The Problem
Among the other reasons mentioned in various issues both opened and closed in this repo (#213, #241, #200, etc.), being confined to only a 3-segment version number for public releases is especially bothersome for downstream wrappers (e.g. bootstrap-sass, the Node.js module wrapper for PhantomJS, the Node.js wrapper for Adobe/Apache Flex SDK, etc.) that would benefit greatly from being able to maintain some semblance of being aligned with the upstream library's version number.
For example, with JamesMGreene/node-flex-sdk, I've wrapped the Adobe/Apache Flex SDK for consumption (i.e. build automation) in Node.js. The actual Adobe/Apache Flex SDK releases have a 3-segment version number, e.g.
3.0.1
. Ideally, my corresponding version numbers would be identical, plus a wrapper-specific post-build number, so that consumers don't need to learn much about the wrapper itself in order to install the correctly desired version of the upstream library. I was excited when SemVer2.0.0-rc1
was posted because it allowed for this exact desire using+
to indicate the start of a post-build number... but then SemVer2.0.0-rc2
/2.0.0
changed+
to indicate the start of "build metadata" and suggested that it "should" be ignored when determining version precedence. So... back to square one! ⬛Today, I am choosing to use the pre-release version part for tracking my wrapper's post-build number but, alas, that is incredibly _un_semantic, as it would suggest that my wrapper is not on par with the associated upstream version. The result is that someone trying to install
4.6.0
of my Node.js module will end up not getting anything installed at all when they run something likenpm install flex-sdk@4.6.0
. They must instead run something less intuitive likenpm install flex-sdk@^4.6.0-0
.And please don't just shout "that's a tooling problem!" at this point... NPM is just trying its best to actually adhere to supporting the SemVer 2.0.0 spec correctly for its package ecosystem.
Proposed Solution
After looking at #213, which proposes adding a 4th segment to the "core version", my big fear is that we might add a 4th segment in the next major version of the spec (which I am mostly in favor of) but then that would become the new standard for some upstream libraries, and subsequent the downstream wrappers would need a 5th segment, etc. etc. (or a proper post-build versioning scheme that MUST be considered when determining version precedence).
In light of that fear, my more generic proposal is to allow an infinite (
n
) optional.{number}
segments [after the required 3-segment "core" version] for additional version comparison. Associated tools would just need to iterate through them, which they are already required to do in order to support pre-release version segments correctly. The only big difference is that the "core" version requires (a) [a minimum of] 3 segments, and (b) that all of its segments be strictly numerical and without any leading zeroes.Supporting this idea in the spec would require only a few changes, though I'd gladly welcome help on coming up with the correct wording (changes in bold):
0
OR DROPPED when any of the major, minor, and patch version segments are incremented.versionsidentifiers are always compared numerically.0
. Examples: 1.0.0 == 1.0.0.0 == 1.0.0.0.0 < 1.0.0.0.1 < 1.0.0.1 == 1.0.0.1.0 < 1.0.1 == 1.0.1.0.0 < 1.1.0 < 2.0.0, etc.fieldsidentifiers has a higher precedence than a smaller set, if all of the preceding identifiers are equal UNLESS all of the following identifiers are specifically equal to0
. If both versions have pre-release sets BUT one version's pre-release set includes more identifiers than the other version's pre-release set, then any corresponding missing identifiers MUST be treated as0
. Example: 1.0.0-alpha == 1.0.0-alpha.0 < 1.0.0-alpha.1 < 1.0.0-alpha.beta < 1.0.0-beta < 1.0.0-beta.2 < 1.0.0-beta.11 < 1.0.0-rc.1** == 1.0.0-rc1.0** < 1.0.0.Example Partial Implementation
I wrote an example partial implementation of this idea in JavaScript (modeled as a subset of the npm/node-semver API) with a fair number of particularly pertinent version precedence unit tests, you can take a peek at it here:
http://jsbin.com/sekuxo/5/edit
It's pretty simple, IMHO.
Feedback
Feedback, please!
The text was updated successfully, but these errors were encountered: