Home: NuGet pack ignores nuspec versions [unwanted version normalization?]

Created on 27 Jun 2016  ·  100Comments  ·  Source: NuGet/Home

Hello,

It seems latest NuGet pack ignores the version set in the nuspec (or via the -Version override flag) and the dependencies' versions, by normalising them, even if nobody asked for it :(

It seems this was "fixed" for this https://github.com/NuGet/Home/issues/2039, but to me this seems a super counter-intuitive change, that breaks (at least for us) the daily workflows.

For the meantime, we had to do a workaround to "fix" the versions in the generated nupkg. I'm hoping that this can be fixed either by removing this weird logic, or allowing the nuget pack command to generate nuget package which contains the _same_ versions as in the nuspec.

I'm using NuGet Version: 3.4.4.1321.

With this nuspec:

<?xml version="1.0" encoding="UTF-8"?><package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
  <metadata>
    <authors>author</authors>
    <version>1.9.0.0-SNAPSHOT</version>
    <id>mylib</id>
    <dependencies>
      <dependency id="dependency" version="3.16.0.0"/>
    </dependencies>
    <description>mylib</description>
  </metadata>
</package>

executing nuget pack mylib.nuspec -Version 1.9.0.0-SNAPSHOT generates this .nuspec:

<?xml version="1.0" encoding="utf-8"?>
<package xmlns="http://schemas.microsoft.com/packaging/2013/05/nuspec.xsd">
  <metadata>
    <id>mylib</id>
    <version>1.9.0-SNAPSHOT</version>
    <authors>author</authors>
    <owners>author</owners>
    <requireLicenseAcceptance>false</requireLicenseAcceptance>
    <description>mylib</description>
    <dependencies>
      <dependency id="dependency" version="3.16.0" />
    </dependencies>
  </metadata>
</package>

As we can see:

  • Version is 1.9.0-SNAPSHOT instead of 1.9.0.0-SNAPSHOT (even if we specifically overrode it via the command line) - same happens with a non-SNAPSHOT version
  • Even worse, the dependency version is 3.16.0 instead of 3.16.0.0
  • Funnily enough, the filename has the full version: mylib.1.9.0.0-SNAPSHOT.nupkg
Quality Week Pack Backlog 2 DCR help wanted

Most helpful comment

I agree with @slaneyrw, there needs to be a -verbatim option (or similar) to the NuGet pack command that retains the originally authored nuspec file _exactly as authored_.

All 100 comments

@timotei would you share more about your scenarios here? Are you expecting the version string to be an exact match as part of other scripts or tools?

Well, we have _a ton_ of internal libraries that are used throughout the end products (private NuGet repo based on Artifactory). Some scripts/tools generate them directly via the nuget pack, others are using some more legacy build systems and we managed to make some bridge between them (not possible/feasible to migrate them to the newer NuGet-based process).

The issue comes from the fact that newer NuGet _automatically_ normalizes the version, making the interop between the two types of projects hard to almost impossible. Basically, we have interop between Java and .NET libraries (via IKVM), and thus we have a specific format for the versions, which we must respect.

That's why, it's very important (for us and I think in general) that tools that generate stuff, do it in a expected way, based on the .nuspec, because that impacts the entire dependency tree. So, I'd expect the nuget pack step not to change anything that's already set in the nuspec. Or, at least, provide a way to skip that behavior.

I'd like to understand how this is working, are your scripts resolving nuget dependencies without nuget? Does IKVM consume nupkgs directly? Which parts of your build process read the nupkgs without nuget?

Yeah, up until NuGet 3.4, we had in place a simple mechanism which would translate 1-to-1 from Gradle dependencies, to NuGet packages (which are basically IKVM-compiled assemblies - Java to .NET). We were able to create the packages.config file with the mapped dependencies + versions, then do a nuget restore, use the restored deps in a custom processing step which does the final .NET compilation.

Once NuGet 3.4+ went in, we found the issue that the versions wouldn't be mapped properly, all depending on whether the restored NuGet packages were created with NuGet 3.4+ or not. The thing is, nuget places the restored packages in folder with the full version, not the normalized one, which means, if a package was created with NuGet prior to 3.4 it will have 1.0.0.0, while with NuGet 3.4+, it will be 1.0.0. This means there's suddenly no reliable/deterministic rule for the location of the packages. This issue comes from the fact that nuget pack will normalize the generated version.

The thing is, nuget places the restored packages in folder with the full version, not the normalized one

This has been fixed in 3.5.0, you can find it here: https://dist.nuget.org/win-x86-commandline/v3.5.0-beta2/NuGet.exe

there's suddenly no reliable/deterministic rule for the location of the packages

With normalization there is only one possible string, making this deterministic now. Paths can be determined upfront without opening every nupkg to check if it is the expected version.

Here is how it works:

  1. Versions have three parts to match SemVer
  2. If the version contains a 4th non-zero digit, then it is also added since NuGet allowed 4 part versions at the start.
  3. Leading zeros are always removed

Examples:
1.0.0.1 -> 1.0.0.1
1.0.0.01 -> 1.0.0.1
1.0 -> 1.0.0
1.0.0.0 -> 1.0.0
1.0.0 -> 1.0.0

Hmm, yeah, but AFAICT, the 3 or 4 digits folder name will depend whether the NuGet package was generated with NuGet <3.4 or NuGet 3.4+, no?

About the normalization part, isn't possible to make nuget pack not normalize the version if explicitly not wanting? Or is the whole 3.4+ Normalized Versions Saga about normalizing the behavior (pun intended) of all NuGet behavior so it uses normalized versions everywhere? (pack + install + restore)

How I see this is, that NuGet is kinda forcing people to use normalized versions even if they don't want it, right :) ?

Normalizing solves many issues within NuGet. I think your scenario is valid, but less common than the problems normalizing fixes. You can work around this problem by finding the normalized version from the package after packing and using that for your mappings instead of the -Version input. You could also modify the nuspec in the package after pack to un-normalize it.

Does this mean that a PR that enables the NuGet Pack to generate the NuGet package "as is" from the NuSpec (without normalizing versions) would not be accepted into the client?

IIRC, there was once a warning when doing a pack for 4 digits (that the version doesn't satisfy SemVer 2?), but that warning does not show up now, and instead it directly normalizes the version (not sure why normalize it only when ending in '0', since SemVer2 is 3 digits only nevertheless the last 4th digit)

@timotei - yes, 3.4.* does this behavior during pack. Earlier versions didn't.
We'd prefer to not add more command line options to not normalize.
Is it possible for you to adapt your mapping file to understand ".0" as the 4th version number will be dropped? We'd prefer to keep everybody normalizing.

Well, in the end we managed to get a post-NuGet pack step that denormalizes the version, to keep the previous behavior. So far it seems to work.

But this is not a very satisfactory solution :( I'd rather have NuGet not change things I specifically set in the nuspec.

This is now causing problems downstream as tools now start upgrading their nuget versions. Octopack now uses 3.4.x which is dropping the 4th part of the version number if it's zero, and breaking templated builds in our TeamCity. Please consider command line options

@slaneyrw can you explain how TeamCity uses this? Which part of the build breaks due to this change?

Octopack generates an nupkg file which we are expecting to be in a specific format {package name}.{version number}.nupkg that we are publishing to our internal ProGet feed.

The version number is TC's system build number which is a 4 part number. The file name we expect is not present when it has been normalised. The TC configuration template is shared by many individual build projects.

All build projects run off a dedicated nuspec file in each project, this file is patched with TC's system build number before an Octopack build.

Today, I received a report from a user about NuGet mangling the version within the nuspec file that gets embedded into the nupkg file. Apparently, this "normalization" completely broke the package restore feature, with an error complaining about the package "not being found" until he manually re-added the final trailing zero.

Linked to ticket [https://system.data.sqlite.org/index.html/info/e9573e2d12387877].

@mistachkin restore could only break if the user is changing the package and re-packing it using an existing id/version. That scenario is not supported since packages are cached based on the id/version, having different copies of the same id/version will cause other problems.

Sorry, but no. The user stated the package would not restore until he manually "un-normalized" the version to add the trailing zero. To be perfectly honest, this is going to be a huge headache. The packages I manage have a total of around 3.3M downloads at this point. If even a small fraction of the users end up with issues like this, that will be a major problem. Looks like the solution is to stick with NuGet version 2.x until this is fixed. Meanwhile, I'll have to look into manually fixing the current production packages. Of course, that won't work either because I cannot ever delete anything to re-upload them with the same version. I'm very frustrated now.

@mistachkin would you open a new issue for what you are seeing with restore along with some repro steps?

This issue is around package creation, it sounds like you are seeing issues on the consuming side.

Respectfully, I disagree. The real issue is that what ended up in the embedded nuspec file was not what I originally authored. Subsequently, this "normalization" ended up breaking package restore (and other features?).

@mistachkin NuGet supports all both normalized and non-normalized versions during restore. The question is what part of the process is treating the nuspec version as a string instead of a version.

That part of the process, whatever it is, by definition, does not "support" the version normalization. Meanwhile, some of the most popular non-Microsoft packages on NuGet.org are effectively broken.

That part of the process, whatever it is, by definition, does not "support" the version normalization. Meanwhile, some of the most popular non-Microsoft packages on NuGet.org are effectively broken.

@mistachkin please open a new issue for the restore issues you are seeing. Any extra details on how this affects existing packages would be extremely helpful and I would like to understand it better to help you out.

Normalizing the version at pack time only, as this issue covers, only affects new packages from what I can see. Users installing those new packages will have the version form used in the nuspec file from the start, so there will be no changes on the consuming side.

I did not discover the issue myself and I do not know the reproduction steps. I will contact the original user and ask them to file a new issue. Done, email sent to original user.

Do we have any direction on what NuGet will be doing in regards to normalization. Are we doing to be able to turn OFF this behaviour during pack ?

I agree with @slaneyrw, there needs to be a -verbatim option (or similar) to the NuGet pack command that retains the originally authored nuspec file _exactly as authored_.

We are having issues as a result of this too - We use a build counter version number throughout our build, deploy, and test pipelines and having a mismatch causes failures when using the package version in a file system path.

Example scenario:

  • TeamCity build is version 1.0.100.0
  • Nuget pack creates version 1.0.100
  • Deploy application
  • Deploy the post-deploy tests to a test server, the package version is part of the target directory path Eg "c:\tests\post-deploy1.0.100"
  • The post-deploy tests fail to run as they use the build version number in the path Eg "c:\tests\post-deploy1.0.100.0"

If a version is specified in the nuspec file then the output package should contain that exact version. We have had to roll back to a specific older version of NuGet because of this.

The behaviour of using nuget pack should remain the same as previous versions, and a -Normalize switch should be present if you want Nuget to automatically normalize the version number.

I like the idea of -verbatim or possibly -verbatimversion for pack to keep nuget from trying to help out here.

Making non-normalized opt-in instead of by default makes sense for most users I think. It helps avoid duplicates having in the same folder on disk and the confusing builds that can result from that.

Nuget version 4.0.0.2283 is also removing leading zeros:
Converting: 27.0001.02220-alpha
to this: 27.1.2220-alpha

Do I have to fork my own repo to fix this? I hope not.
[Edit]
This is happening on versions 3.5, 4.0 and 4.1
Version 3.4 doesn't do the name mangling, so that's what I'm going back to...
Sorry Microsoft, looks like you dropped the ball on this: Forcing normalization when no one wanted it.

@chris1248 I would expect the verbatim option to leave leading zeros in also.

In general I strongly suggest avoiding leading zeros, older clients such as 2.x and even 3.4.4 have difficulty finding these packages from local folder sources.

After talking with some colleagues here at work we decided against against using a version with leading zeros.
[Edit]
This is only an issue in the first place because of version normalization. If it had been left alone in the first place... ??

Sent from my iPhone

On Apr 12, 2017, at 12:03 PM, Justin Emgarten <[email protected]notifications@github.com> wrote:

@chris1248https://github.com/chris1248 I would expect the verbatim option to leave leading zeros in also.

In general I strongly suggest avoiding leading zeros, older clients such as 2.x and even 3.4.4 have difficulty finding these packages from local folder sources.


You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHubhttps://github.com/NuGet/Home/issues/3050#issuecomment-293660003, or mute the threadhttps://github.com/notifications/unsubscribe-auth/ACyJCouHwCKvdT2ik4zK6pxLHaIRdJDVks5rvRHQgaJpZM4I-_5n.

Is there a workaround or fix to this issue? Or the workaround is to remove the leading zero from the version number? Like instead of starting the version number at 2.0.0.0 i need to start at 2.0.0.1?

Why not allow leading zeros? Version numbers have started with 0.0.1 before, and its useful in some cases when building development packages to use low numbers like that for those of us who are small shops with one nuget server that gets dev stuff on it from time to time.

I'm using trailing zero's and I need the 4 part version number to be left alone. 6.3.2.0 should be the package version.

If you want to add another cryptic error if a chosen number is going to be a problem, that's understandable. Other than that, there is really no reason for nuget to touch the version number the author associated with a package, ever.

This problem has also broken our builds and our version number is something that goes through much of the app. The testing effort to change the format is not terribly small and the build scripts also have to be updated. I guess there is not much choice at this point but I wish backwards compatibility was considered here.

While reading this discussion I got the impression that most build chains were broken while copying/deploying the generated package as they expected another filename (as was our build chain). What if the build script could “ask” nuget.exe to get the expected filename of a package? e.g.

nuget.exe resolvefilename -Version 1.0.0.0 foo.nuspec
foo-1.0.0.nupkg

or

nuget.exe resolvefilename -Version 1.0.0.0 foo
foo-1.0.0.nupkg

or

nuget.exe normalizeversion 1.0.0.0
1.0.0

This would allow build scripts to always get the right filename.

@JeanMarcHengen - Its not just build scripts. Some of us produce software that is used in regulated (pharmaceutical) environments, where changes to the software (or the means with which is produced) can require "re-validation".

Validation is tedious and costly - every action is pre-scripted, then executed, with evidence captured and signature or initials are needed for each action's result, for just about every point in the process. Most software activity isnt needing to adhere to that rigid of a process, but version numbers are visible things to be collected as evidence. Changing the number of digits can be an expensive update for that documentation and testing nightmare.

Also, its not up to a single tool to determine what is OK or not in my version numbering.

This is what the NuGet documentation says about version normalization (https://docs.microsoft.com/en-us/nuget/reference/package-versioning):

This normalization does not affect the version numbers in the packages themselves; it affects only how NuGet matches versions when resolving dependencies.

I think the version normalization should not be forced upon all existing users who rely on the version to be formatted in a certain way. At least there should be an option/parameter to skip version normalization when packing, as previously suggested. Else, many users will be stuck with using pre 3.4 version of NuGet.

Also, if someone normalizes a database and there is data that was present before normalization, but afterwards is not available anymore in any way, I'm betting probably everyone on this thread would agree that would constitute a problem.

Just a reminder that this issue is up for grabs, I'm willing to helping someone with a PR for adding the -VerbatimVersion flag to pack.

I believe normalization happens here:
https://github.com/NuGet/NuGet.Client/blob/a5abb1bdc1aecdbc1d46f36c3eced4062843c249/src/NuGet.Clients/NuGet.CommandLine/Commands/PackCommand.cs#L158

Using NuGetVersion.ToString() instead of NuGetVersion.ToFullString() would give the non-normalized form such as 1.0.

Other places where the version flows through:

https://github.com/NuGet/NuGet.Client/blob/a5abb1bdc1aecdbc1d46f36c3eced4062843c249/src/NuGet.Core/NuGet.Commands/CommandArgs/PackArgs.cs#L38

https://github.com/NuGet/NuGet.Client/blob/a5abb1bdc1aecdbc1d46f36c3eced4062843c249/src/NuGet.Core/NuGet.Packaging/PackageCreation/Authoring/ManifestMetadata.cs#L82

Pack command options:
https://github.com/NuGet/NuGet.Client/blob/a5abb1bdc1aecdbc1d46f36c3eced4062843c249/src/NuGet.Clients/NuGet.CommandLine/Commands/PackCommand.cs#L32

Scenarios to check:

  • nuget.exe pack -Version 1.0 -VerbatimVersion
  • nuget.exe pack project.nuspec -VerbatimVersion to verify that the nuspec version is left as-is.
  • All other ways that versions are populated in the nuspec.

I think it would be useful to have the -VerbatimVersion for legacy scenarios. From a correctness standpoint normalizing versions 1.0, 1.0.0, 1.0.0.0, 1.00, 1.0000000.00000 all to 1.0.0 which is the SemVer standard notation is correct, and it helps users avoid creating multiple packages that are actually an equivalent version which makes finding the latest version from a folder of nupkgs ambiguous.

I think that truncating a trailing zero (revision number) from a package`s version (i.e. 1.7.1.0 -> 1.7.1) is a mistake that causes harm.
The last digit is actual information, and code reading the version number must now assume the last zero, where it should not know anything about it.
we downgraded the client version to avoid this.

This version normalization is also causing issues with PowerShellGet Modules. Modules are internally versioned. So not only are the published versions getting changed when republishing, the installs are also not valid. The package version is getting used at install time and it does not match the module version at load time. This prevents it from working.

Just a reminder that this issue is up for grabs, I'm willing to helping someone with a PR for adding the -VerbatimVersion flag to pack.

@emgarten - This reads as "We broke it, but aren't willing to fix it. One of you can." Is that really what is being said?

Whomever had the burning desire to coerce a 3 part version number - when the target is microsoft assemblies, that have been 4 part for 30+ years and still are - should just put this back the way it was ASAP without imposing upon everyone to do something extra. I say everyone because we all are actually using 4 part versions whether we prefer to or not. Not reverting the original mistake is just making a second mistake.

I think I found the bug with 4 part version numbers that have a trailing 0, but I would like someone that knows the project take a look and run the tests.

https://github.com/NuGet/NuGet.Client/blob/6e6f469828435d0a3c88aa153808ba380c6d0d71/src/NuGet.Core/NuGet.Versioning/NuGetVersion.cs#L180

    public virtual bool IsLegacyVersion
    {
        get { return Version.Revision > 0; }
    }

In that sample, Version is a [Version] type. A revision value of 0 is a valid value. If the revision is not in use on a version, it has a value of -1.

[version]'1.2.3'
Major  Minor  Build  Revision
-----  -----  -----  --------
1      2      3      -1

I think we can make this fix to restore the trailing 0, but it does not address the other issues in this thread.

        get { return Version.Revision >= 0; }

Vote: leading zeros are needed here.

+1 for at least removing "normalization" on package restore. If I specify 0.1.1.0 in my packages.config, use that - it shouldn't go looking for package 0.1.1. Then the next time I build these packages, I can enforce semantic versioning, but as it is everything breaks after Nuget 3.3.

We are hitting the .0 version for the forth part causing an error at least once a month across our business. Request that this issues priority be increased.

@emgarten

Would you comment on @StingyJack's assessment of your position:

"This reads as 'We broke it, but aren't willing to fix it. One of you can.' Is that really what is being said?"

In out team, we use VS2015 and VS2017 in parallel for various reasons. All of them are updated to the latest version of nuget available using the visual studio installer (Nuget 3.4 on 2015 and 4.6 on 2017).

We run into issues with broken builds because of x.y.z.0 nuget packages that get lost due to different paths in the packages folder. We didn't find a schema for predicting or fixing the issue.

For example I saw today, that VS 2015 drops the .0 for a package with version 9.5.429.0, but keeps it for 9.4.326.0 of the same package. The only thing that changed in the .nuspec file is the version number.

Do you have any idea or help here?

@peter-B- one of the suggestions in this thread was to have a script or utility correct the version number on the built package, before publishing it.

This is probably going to be the only way as the nuget team is clearly not interested in fixing the defect that was introduced.

@emgarten

Would you comment on @StingyJack's assessment of your position:

"This reads as 'We broke it, but aren't willing to fix it. One of you can.' Is that really what is being said?"

Normalization is by design. Versions must be treated as Semantic Versions, not as strings.

External tools that read nuspec versions as strings should be fixed, or scripts should be added to work around this.

Most users in this thread are having problems due to powershell get unnecessarily extracting and re-packing packages just to copy them from one feed to another. This is an issue with powershell get. Re-packing a package will always lead to some changes.

@emgarten I guess the problem that I am having a hard time understanding is that we have legacy support for a string like 1.2.3.4 but not for 1.2.3.0. Why is it decided that one is to be changed, but we will preserve the other?

If the version contains a 4th non-zero digit, then it is also added since NuGet allowed 4 part versions at the start.

Why the 4th non-zero requirement? NuGet also allowed that 4th digit to be zero at the start. There is a strong request here to restore support for all 4 part version numbers. Is it worth breaking this off into its own issue to separate it from the rest of the normalization discussion?

What you could add to this conversation (that I am not seeing) is the rationale behind why the zero needs to be dropped for normalization. Someone made a conscious decision to normalize that value away and it would be healthy for this thread to know why that is. It would also be good to know what work effort would be required make that adjustment (outside of the -VerbatimVersion request)?

PowerShellGet does need to handle the republish correctly. It's silly that we solve the PowerShellGet issue by installing some 2.x version of nuget. Because as a module author, I specify my own version in my module and I expect to see that version when published to the gallery. Now that I am aware of this issue, I have appropriate workarounds but I had to dig through the source of PowerShellGet to track the issue back here.

@emgarten

_"Normalization is by design. Versions..."_

Is this your comment on @StingyJack's assessment?

@emgarten I am not talking about some custom script going crazy. I am talking about plain Visual Studio Nuget install and restore. Let me elaborate the situation I faced yesterday:

  • I used the VS2017 Nuget UI to update a package from 9.4.326.0 to 9.5.429.0. Within the packages .nuspec nothing changed except the version string.
  • The new package got downloaded into packages\name.9.5.429.0\. Everything built fine both in my machine and on our build server.

  • A college checked out my code and opened it with VS2015. On package restore, the package got downloaded into packages\name.9.5.429\ and the reference was broken.

  • He issued a -Reinstall from his package management console and the package was reinstalled into the same directory but the reference in the .csprojwas fixed. That broke the build on VS2017 and thereby on the build server.

And here comes the strange part:

  • My college used the VS2015 Nuget UI to revert to the original 9.4.326.0 and that package got installed into packages\name.9.4.326.0\.

We double checked the changes in the .nuspec-file, but there are none except the version string.

We didn't find a method yet, to install 9.5.429.0 in a way, so that we can use it in both VS 2015 and 2017.

Two other colleges face the same issue at the moment with System.Windows.Interactivity 4.5.0(.0).

So I am not talking about normalizing or not, I am talking about having the a consistent behavior with the last two (fully updated) versions of Visual Studio.

And I think it is fair to assume that it is a bug that the .0 gets skipped on one package version, but not on another.

Most users in this thread are having problems due to powershell get unnecessarily extracting and re-packing packages just to copy them from one feed to another. This is an issue with powershell get. Re-packing a package will always lead to some changes.

@emgarten - @KevinMarquette is an undeniable powershell powerhouse, but is the only one here who mentioned powershell. I know that reading can be hard or tedious sometimes, but there are 12+ other people in this thread. _Most_ of us are reacting to having someone else's versioning scheme forced upon us without notice, and without giving any consideration to its effects or any workaround or recourse.

SemVer is a good idea (for nuget.org), but that doesn't make it appropriate for everyone. Its not something to be wielded like Maslow's Hammer, or followed like a cargo cult.

We removed using Semver as well here at work. Too much complication for too little gain.

Sent from my iPhone

On Mar 24, 2018, at 7:17 AM, Andrew Stanton <[email protected]notifications@github.com> wrote:

Most users in this thread are having problems due to powershell get unnecessarily extracting and re-packing packages just to copy them from one feed to another. This is an issue with powershell get. Re-packing a package will always lead to some changes.

@emgartenhttps://eur03.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgithub.com%2Femgarten&data=02%7C01%7C%7Cb8a911ae29894874ff0e08d591899309%7C84df9e7fe9f640afb435aaaaaaaaaaaa%7C1%7C0%7C636574942414851351&sdata=Ng8a0OJelHd5%2FZVMov43jhHRzqVtpi5Qw%2B4OUxwlOXo%3D&reserved=0 - @KevinMarquettehttps://eur03.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgithub.com%2FKevinMarquette&data=02%7C01%7C%7Cb8a911ae29894874ff0e08d591899309%7C84df9e7fe9f640afb435aaaaaaaaaaaa%7C1%7C0%7C636574942414851351&sdata=qqOccXN%2Fr95gJXr3pbL4U8kblAmYedhtHJP2W9RWRT0%3D&reserved=0 is an undeniable powershell powerhouse, but is the only one here who mentioned powershell. I know that reading can be hard or tedious sometimeshttps://eur03.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgithub.com%2FNuGet%2FHome%2Fissues%2F6534%23issuecomment-363422986&data=02%7C01%7C%7Cb8a911ae29894874ff0e08d591899309%7C84df9e7fe9f640afb435aaaaaaaaaaaa%7C1%7C0%7C636574942414851351&sdata=o5FPeLdmn9bN8et1UHe6MWB%2F3bcgMwgWW85Fycy7Nck%3D&reserved=0, but there are 12+ other people in this thread. Most of us are reacting to having someone else's versioning scheme forced upon us without notice, and without giving any consideration to its effects or any workaround or recourse.

SemVer is a good idea (for nuget.orghttp://nuget.org), but that doesn't make it appropriate for everyone. Its not something to be wielded like Maslow's Hammer, or followed like a cargo cult.


You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHubhttps://eur03.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgithub.com%2FNuGet%2FHome%2Fissues%2F3050%23issuecomment-375888685&data=02%7C01%7C%7Cb8a911ae29894874ff0e08d591899309%7C84df9e7fe9f640afb435aaaaaaaaaaaa%7C1%7C0%7C636574942414851351&sdata=vHFj4h1gUSo9t7rcvF6LKDskBbNHOA6KODVulPhIFlI%3D&reserved=0, or mute the threadhttps://eur03.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgithub.com%2Fnotifications%2Funsubscribe-auth%2FACyJCujXhrZhTJk9ZvbDrp4ldOYknNdOks5thkdegaJpZM4I-_5n&data=02%7C01%7C%7Cb8a911ae29894874ff0e08d591899309%7C84df9e7fe9f640afb435aaaaaaaaaaaa%7C1%7C0%7C636574942414851351&sdata=Ft3%2BdrIYNRhJW9ZNkS5CneBpN0lfjKm21hfoko8Lmk4%3D&reserved=0.

Speaking for myself and for the System.Data.SQLite project, which has approximately 8 million downloads on NuGet.org, we will never use any newer version (of NuGet) that forces all versions to be "normalized", as forcing SemVer upon our users would be too much of a breaking change.

Versions must be treated as Semantic Versions, not as strings.

So NuGet only supports semver?
Four digit version numbers like Explicit Versioning are not supported?

@emgarten

Would you comment on @StingyJack's assessment of your position:

"This reads as 'We broke it, but aren't willing to fix it. One of you can.' Is that really what is being said?"

Four digit version numbers like Explicit Versioning are not supported?

@fabich NuGet supports four digits such as 1.2.3.4, that hasn't changed. This issue covers what happens when pack is used on an assembly version such as 1.0 or 1.0.0.0 and how it is normalized since they are the same version according to semver rules. Note also that having 1.0.0.0 in a nupkg is still fine, this issue is purely around how pack transforms the package if you create it using the latest tools.

Would you comment on @StingyJack's assessment of your position:

@InteXX I answered your question earlier here: https://github.com/NuGet/Home/issues/3050#issuecomment-374833832

And again, a pull request for this would be great! 🍰
Details on what is needed for a switch here: https://github.com/NuGet/Home/issues/3050#issuecomment-343800795

@emgarten

We're on the heels of two years with this very serious issue.

Your silence (and inaction) on the problem are deafening.

@emgarten

_"@InteXX I answered your question earlier here: #3050 (comment)"_

And your response was unclear that it was intended for me. I asked for clarification and received no reply.

_"Versions must be treated as Semantic Versions, not as strings"_

Two questions:

  1. Why?
  2. Are you somehow blinded to all the trouble this is causing?

@InteXX would you share your exact scenario where you are having problems?

@emgarten

_"would you share your exact scenario where you having problems"_

Certainly. I'd love to.

Would you answer my two questions first.

@emgarten

_"I asked for clarification and received no reply."_

In addition, in that answer you didn't comment on @StingyJack's assessment of your position. Your response may have been an answer, yes, but not to the question I asked.

@emgarten - there are a few specific problems here.

By your posture and position, we have come to know that the Nuget team has chosen to dismiss the (slightly odd but venerable) 30+ year old expected four part version numbering system. This _could_ be and in some cases _is_ a breaking change, and in other cases its unexpected and unwanted due to the work it has the potential to create.

I don't think I should need to state the obvious here, but Its _breaking_ because tools, process, and artifacts expect 4 parts. What happens when you "1.2.3".Split('.')[3] ? Or when going through the Big Pharma vendor audit or validation wringers and having to write up a deviation because one of the components that go into the software is actually version 2.3.4 instead of the expected 2.3.4.0?

If you (and the rest of MSFT) want to use semver for your stuff, and there are no regulatory compliance, legal, or other procedural issues (both process changes and document template changes) with doing so, and it helps you make better stuff, by all means go for it. However, "good for you" does not mean "good for me". I'm the guy who has an unexpected broken build because tooling cant find the expected outputs, or crashes outright with an IndexOutOfRange, and then has to deal with the hotseat and extra paperwork during system acceptance testing and validation.

@emgarten

_"And again, a pull request for this would be great!"_

You broke it, you can fix it. Have you considered how much you've cost us with this breaking—and arguably unnecessary—change of yours?

If I sound like I'm getting a bit frustrated here, it's because I am.

It's frustrating to attempt polite, reasonable discourse, only to encounter silence and obfuscation.

@emgarten
"Versions must be treated as Semantic Versions, not as strings"

I'll also ask Why?
I manage a couple hundred packages- anything from .net console apps to internal websites to SSRS report bundles and even a dozen Access front ends. SemVer is pretty much pointless- there's little cross package dependency, so I'd end up with a bunch of 1.0.XXX packages.

I use a Git -> TeamCity -> ProGet -> Octopus Deploy pattern for everything (Including Access!)
What I find much more useful is a yyyy.MM.dd.BuildCount format, i.e. 2018.06.07.44
While this is covered under the "Legacy" support, it's still stripping the leading zeros on the month/day.

As @mistachkin said- I authored a version value of "2018.06.07.44", and that's what I expect to come out, not "2018.6.7.44", and I am certainly not interested in the "SemVer" way of 1.0.0+2018.06.07.44

@emgarten

Would you comment on @StingyJack's assessment of your position:

"This reads as 'We broke it, but aren't willing to fix it. One of you can.' Is that really what is being said?"

@emgarten

"would you share your exact scenario where you having problems"

Certainly. I'd love to.

Would you answer my two questions first.

@StormRider01 is this for style purposes, or are your tools having trouble consuming 2018.6.7.44 over 2018.06.07.44?

I can see how you could consider the 0 padding to be data, but the same thing applies to XML for the nuspec. If you format the nuspec file one way, and after pack whitespace has been removed due to formatting, would you consider that a bug?

The nuspec is XML and should be used with tools that understand the XML format. It isn't safe to assume to treat the nuspec contents as a string. In the same way, the contents of the version element are of SemVer format, and it has more meaning than just a string.

@emgarten

The pervasive question that seems to be giving you significant trouble is Why?

_Why_ must you shove SemVer down our throats, in the face of us begging you not to? What problem does it solve that's worse than the problem it's creating?

Is this someone's mere personal preference that you're forcing upon us? What issues did the design team face when considering this decision? Did they consider the trouble they'd be causing us?

Your silence is very frustrating, Justin.

@emgarten it's certainly a style purpose, but it also creates a disconnect- TeamCity's build has 2018.06.07.44, but Octopus sees it as 2018.6.7.44. I don't do any automation against Octopus, so I don't know if that would cause a tooling problem.

As far as the nuspec being XML, well, here's the .xsd
<xs:element name="version" maxOccurs="1" minOccurs="1" type="xs:string" />
So yes, it's a string. Explicitly.

If it was an absolute requirement for version to be SemVer in XML, I would expect this:
<version major="1" minor="2" patch="3" pre-release="Alpha" meta="commit3a445b3c2f" />

With the .xsd:
<xs:element name="version"> <xs:complexType> <xs:simpleContent> <xs:extension base="xs:string"> <xs:attribute type="xs:int" name="major"/> <xs:attribute type="xs:int" name="minor"/> <xs:attribute type="xs:int" name="patch"/> <xs:attribute type="xs:string" name="pre-release"/> <xs:attribute type="xs:string" name="meta"/> </xs:extension> </xs:simpleContent> </xs:complexType> </xs:element>

@StormRider01 thanks for the example, I can see wanting to keep these versions in sync if TeamCity is producing the version string here.

This thread has been going on for 2 years this month and I would like to see this draw to a close. All questions have already been answered here ad nauseam in my opinion.

Summary of this thread: Version normalization does not work in some scenarios where external tooling is expecting a different format, or where different stylistic choices are desired.

Current state: Normalization does work for the majority of .NET project scenarios, and it has drastically reduced the number of problems seen from conflicting versions such as 1.0 vs 1.0.0.0. It has helped make things deterministic, and improved performance since the nupkg path on disk can be calculated.

Going forward: To solve both of these problems a switch should be added to pack that keeps the version as-is. -VerbatimVersion. This would be a minor change to the pack command.

I'm happy to see the passion for NuGet package creation in this thread, and I would like to see it go towards a pull request for fixing this. I would be happy to review this pull request, but I am no longer going to watch or participate on this issue.

If no one is willing to submit a pull request for -VerbatimVersion then I think this issue should be closed.

@emgarten

Please review the issue history. Much of the delay has been due to your own silence and obfuscation. We've posted problem report after problem report, with little to no response.

When there does come a response, it's in the form of telling us how we're doing it wrong. There's been no consideration offered toward the problems that this breaking change is causing; there's only been refusal to address the issue.

And you still haven't told us why you broke it in the first place!

So you've delayed and obfuscated for two years, and now you want to close the issue and ignore the problem you caused. Put our shoe on your foot for a little bit—would you enjoy being treated like this?

Why did you do this to us? What problem did the breaking change solve that's worse than the problems it's creating?

To break this for no apparent reason and then ask us to fix it is disingenuous at best, downright rude at worst.

Do I sound frustrated? Yes. You've frustrated me.

@emgarten

All questions have already been answered here ad nauseam in my opinion

They certainly have not. Anyone reading this thread can recognize this.

Here is a pull request. Please review.

https://github.com/NuGet/NuGet.Client/pull/2374

There is now a custom build of NuGet that addresses the issue under discussion, signed with my EV Code Signing certificate, available here. It is a "Debug" build because I was unable to figure out the necessary steps to make the "Release" build work. The PDB file is included.

I was referred to this issue by PowerShell/PowerShellGallery#55 because it seems that even Microsoft's own PowerShellGallery contributions are affected by unwanted normalisation in the .nuspec file as opposed to the .psd1 files.

Prominent examples that I've come across include:

  • SqlServerDscSqlServerDsc.nuspec says 12.3.0, SqlServerDsc.psd1 says 12.3.0.0
  • NetworkingDscNetworkingDsc.nuspec says 7.0.0, NetworkingDsc.psd1 says 7.0.0.0
  • xActiveDirectoryxActiveDirectory.nuspec says 2.24.0, xActiveDirectory.psd1 says 2.24.0.0

... but there are countless PowerShell/DSC packages on PowerShellGallery with the exact same issue. This is getting out of hand.

I've hit this problem with two separate tools now – Artifactory and ProGet. Apparently they use the .nuspec file to get the package version – to me this doesn't seem unreasonable, but I am happy to be corrected.

As a result, PowerShell will pull packages into C:\Program Files\WindowsPowerShell\Modules naming the folder after the .nuspec version, and then decides you can't import the module because the .psd1 has a different version number!

If you want semantic versioning to be enforced for packages, then fine, NuGet should hard-fail when a package version number does not comply with semantic versioning.

What it should absolutely not do is take the version from somewhere else, mangle it and hide the issue.

Incidentally, -VerbatimVersion in NuGet/NuGet.Client#2374 does not really fix the problem either. It is yet another attempt to hide the issue and not really solve it, especially because I am wondering just how many developers are out there not even realising that NuGet is doing this to their packages before they publish them.

Clearly not even Microsoft's own people realise this either, or else there would not be so many packages on PowerShellGallery that are broken in this way.

We'd prefer to keep everybody normalizing.

@rrelyea - We'd prefer to have the version numbers be used as they were specified as the added behavior is...

  • non-intuitive and this is outside of a reasonable expectation of behavior
  • does not inform the user and permit them to override it at the time of execution
  • causing subtle and difficult to deal with breakages throughout the ecosystem

Removing this coercion to your team's definition of semver (this was a breaking change that was introduced and did come with a major version incrementation of nuget - irony?) would stop the breakage that is happening with packages and would abate the loss of time wasted troubleshooting these breaks.

The nuget team at MSFT wanted this normalization to make dealing with packages on nuget.org easier, but as far as I have read here and elsewhere did not fix a breakage somewhere.

This should be reverted for the simple reason that QOL improvements cannot come at the cost of breakage to users' software or pipeline.

@StingyJack

I see the good work you've contributed in your PR remains unaccepted. Obtuse describes the response pretty well, especially from @emgarten (who seems to have left the conversation). The warden from Shawshank Redemption comes to mind.

I'd almost consider a PR fixing the original break and making normalization opt-in, but I doubt it'd gain much traction.

@InteXX - Thanks, but I actually wont submit a PR for this because I think there is a community negative behavior that needs to be addressed, and the pain of having to undo this change should be enough to correct that behavior.

Per his profile, @emgarten works on Azure IOT stuff now. For this issue, I dont know if he was griefing (again), spouting a party line, or both, but I let him off the hook when I saw that he moved on and have tagged @rrelyea (NuGet PM) instead.

From what I understand, the normalization was done to make dealing with packages @ nuget.org easier to manage. To me this means that any specific versioning rules need to be enforced for packages that go to nuget.org, but only for that. Any and all private repos should not be beholden to that rule, and if anything there should be a -NugetOrgPublishRules switch that performs the version coercion and any other nuget.org specific checks at pack time.

To me this means that any specific versioning rules need to be enforced for packages that go to nuget.org, but only for that

Right – and this train of thought is what also led me to raise PowerShell/PowerShellGallery#55 so that version numbers can be validated on the point of upload to PSGallery, rather than in the actual packaging process itself. I have no idea why NuGet mangling version numbers by itself is acceptable, especially when the process is invisible to the user and has resulted in invalid metadata being published to countless packages on PSGallery.

Any and all private repos should not be beholden to that rule, and if anything there should be a -NugetOrgPublishRules switch that performs the version coercion and any other nuget.org specific checks at pack time.

Exactly. Fix the default behaviour and make this semver-specific behaviour optional, rather than the other way around.

/cc: @rrelyea

The Octopus team also had to work around this issue: https://github.com/OctopusDeploy/Issues/issues/2809

Facing this issue when I replaced the 4th part of the version string of https://www.nuget.org/packages/WizardWrx.AnyCSV/ with a zero, to eliminate multiple versions of a given build in the repository, I devised a workaround in the form of a three-line custom task, of which only the first is strictly required.

Since the correction can be accomplished by a single C# statement, the task is implemented inline as a fragment.

<!-- 2019/08/11 20:17:28 - DAG Define custom task NuGetPackageNameFixup. --> <UsingTask TaskName="NuGetPackageNameFixup" TaskFactory="CodeTaskFactory" AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.Core.dll"> <ParameterGroup> <RawNugetPackageVersion ParameterType="System.String" Required="true" /> <ActualNugetPackageVersion ParameterType="System.String" Output="true" /> </ParameterGroup> <Task> <Code Type="Fragment" Language="cs"> <![CDATA[ ActualNugetPackageVersion = RawNugetPackageVersion.EndsWith ( ".0" ) ? RawNugetPackageVersion.Substring(0,RawNugetPackageVersion.Length-2) : RawNugetPackageVersion; Log.LogMessage ( "Custom Task NuGetPackageNameFixup: RawNugetPackageVersion = "+ RawNugetPackageVersion ); Log.LogMessage ( "Custom Task NuGetPackageNameFixup: ActualNugetPackageVersion = "+ ActualNugetPackageVersion ); ]]> </Code> </Task> </UsingTask>
The implementation is straightforward.

<!-- 2019/08/11 20:17:28 - DAG Add custom task NuGetPackageNameFixup. --> <Target Name="Publish" AfterTargets="Package" Condition=" '$(Configuration)' == 'Release' "> <NuGetPackageNameFixup RawNugetPackageVersion="%(OutputAssemblyInfo.Version)"> <Output PropertyName="NuGetPackageVersion" TaskParameter="ActualNugetPackageVersion" /> </NuGetPackageNameFixup> <Exec WorkingDirectory="$(PackageDir)" Command="NuGet.exe push $(AssemblyName).$(NuGetPackageVersion).nupkg" /> </Target>

The task has one input parameter and one output parameter, and the two Log.LogMessage statements are optional.

Since I had never done such a thing before, I spent several hours puzzling over why the task appeard to run, yet the push command had an empty string where I expected to see the output. The trick is that the Output tag inside the NuGetPackageNameFixup task block is required to convert the output into a MSBuild environment variable.

My next step is to move the custom task and the target that consumes it into my custom C# targets file, so that my other package builders can consume it.

@txwizard - that seems like a lot of work and complexity just to get the specified version number respected.

@rrelyea - is this two year old issue with 85 comments and 137 thumbs ups siding with the version normalization being unwanted and less than 20 thumbs ups siding with the POV defending the version normalization really going to continue to linger as a sore spot, or will the corrective work* be scheduled soon?

* _The correction being to revert the normalization from nuget core and enforce it for nuget.org and not require us to add an additional flag or parameter to continue what should be a compatible behavior. It does not matter how obscene or offensive anyone on the nuget team thinks non semver version numbers might be, Microsoft has had 4 part version numbers for like 40 years now. We are all using 4 part version numbers for everything. Using a 3 part number for this one part of our development ecosystem sometimes creates more work for us, and having a usually 4 part number show up as a 3 part number can become a ridiculous problem in some regulated and validated industries._

@StingyJack,, thanks for the backup.

@txwizard - that seems like a lot of work and complexity just to get the specified version number respected.

It seems that the issue has suddenly been elevated to Priority 1, as I believe it should be.

Not only was devising that task nontrivial, but making it part of the build script is even more work, which remains to be done. I would love to be able to set that thankless task aside, and find some better-tasting fish to fry.

@txwizard

It seems that the issue has suddenly been elevated to Priority 1

Please clarify: do you mean within the NuGet team? If so, where are you seeing the indication?

People in the Windows PowerShell DSC space are also suffering from that issue quite a lot. With the current way how NuGet forcefully normalized the versions we are unable to upload DSC resources to internal NuGet repositories. NuGet normalized the version in the package but not in the PSD1 file where PowerShell keeps track of versions. This mismatch causes the module to be unavailable when downloading it from in internal NuGet feed.

Actually I like the idea of SemVer but the force with how it is imposed makes live really hard. I can follow the arguments of people that version number should not be changed when packaging a piece of software. At least I would like to have a fallback to keep things as they have been.

I am involved in a number of IaC / DSC projects and this issue has cost me and the customers way too much time. From a customer perspective this change has made the whole way of providing software with NuGet unpredictable and overly complicated.

@anangaur - @rrelyea probably muted this issue long back and may need an IRL tag

@anangaur as I pointed out twitter 3 months ago, fixing this was effectively pocket vetoed.

@emgarten spent far more time arguing against fixing this on this issue as well as on a PR: https://github.com/NuGet/NuGet.Client/pull/2374 wearing it down to the point of @mistachkin giving up and closing the PR.

@rrelyea didn't publicly comment on the PR when @jainaashish asked for comment last year, so clearly something's going on, and it's not out in the open.

Microsoft's response to this problem they've created and maintained has been a clear lesson on how NOT to behave (toward one's customers).

Just asked on the powershell issue:
"Is there somebody from powershell gallery that could engage with the nuget team to discuss the variety of options to fix this?"

@rrelyea - "put it back the way it was" should cover the necessary work for all of those affected instead of just for one group of your choosing. Then you can add your nuget.org specific restrictions

@rrelyea

@StingyJack is correct.

@InteXX , I may have misinterpreted the labels shown in the upper right corner of the issue page, where I see a Priority 1 label. In any case, has anyone in this thread reviewed https://github.com/NuGet/Home/issues/8159?

@txwizard

Yes, the meaning of that label is unclear.

#8159: The hits just keep on coming.

@rrelyea Is the forced SemVer behavior going to be rolled back or not?

Also tagging @aortiz-msft since this item has had a Triage discussion

I see this issue has dragged on for nearly 4 years, without an end in sight. There must be some powerful forces wanting to ram SemVer down everyone's throats.

Was this page helpful?
0 / 5 - 0 ratings