Follow up to https://github.com/NuGet/Home/issues/3953
Repro
ProjectA has project reference to ProjectB.
ProjectB contains <VersionPrefix>3.0.0</VersionPrefix>
dotnet pack ProjectA.csproj --version-suffix build001
Expected
ProjectA.nupkg has dependency on ProjectB 3.0.0-build001
Actual
ProjectA.nupkg has dependency on ProjectB 3.0.0
Details
Using 4.0.0-rc3
Worked in project.json, doesn't work here.
Workaround: msbuild "/t:Restore;Pack" /p:VersionSuffix=build001"
. Set VersionSuffix property on all projects during restore, not pack.
cc @rohit21agrawal
moving to 4.0 RTM for visibility
likely by design, but will take more time to talk it through post-rtm. easy workaround in initial post.
If it is by design, I'd very much like to hear the reasoning. But I think it's just a bug.
If I have a project dependency, when packing that project the dependent project needs to packed first, and the actual version thus packaged must be depended upon.
More users hitting this: https://github.com/dotnet/cli/issues/5971
Its very weird that the VersionSuffix is only respected during pack if it's on disk.
I'm imagining it'd be by design to have build and pack basically concluding the same -- even if you also specify dotnet pack --no-build
... as would likely be preferred on say a build server whenever the build has already ran.
Seeing e.g. aspnet/Logging using a Version.props and Common.props works as long as Version.props is rewritten. The VersionSuffix Condition= they use is basically useless - not for build (or restore, apparently), but just for pack...
We're hitting this here:
https://dotnet.myget.org/feed/rx/package/nuget/System.Reactive.Core
We set the Version
at build time using GitVersionTask. This is causing bad refs in the packages.
We're using msbuild /t:pack
since GitVersionTask calcs the version. But something is missing the dependencies versions:
I just hit this with MiniProfiler, since I only have an alpha, people are unable to restore their packages. As an example: what should work is a simple reference in MiniProfiler.AspNetCore
, which has a <ProjectReference>
to MiniProfiler.Shared
.
Though the build passed --version-suffix="alpha23"
to both of these packages, you can see the MiniProfiler.AspNetCore
package depends on MiniProfiler.Shared
4.0.0 (which doesn't exist), rather than the 4.0.0-alpha23 it's supposed to.
This is a fairly big bug, as it breaks all pre-releases with any dependencies. And this is a time period with a lot of pre-releases for core.
You can repro this easily by cloning the MiniProfiler repo at this commit and running .\build.ps1 -VersionSuffix "ahlpa23"
in the root. Packages are output in .\nupkgs
.
@onovotny @NickCraver why can't you pass /p:VersionSuffix
when you do a restore?
arguments to build and restore should be similar as far as possible.
CC: @emgarten
I don't use VersionSuffix
I set Version
during the build step. Is it documented anywhere that Version
needs to be calculated during a Restore? Is there a Target we can hook before into to make this happen automatically?
/cc @AArnott for NB.GV too.
@rohit21agrawal I wouldn't expect that I need to - since there's no --version-suffix
on dotnet restore
, that's a very strong indicator that it's not needed in any way.
This sounds super similar (although the repro steps are wildly different) to the underlying problem behind https://github.com/NuGet/Home/issues/4790. I suggest we keep both in mind when developing a fix.
Same here, all my packages have been released on rc2 and cannot be resolved.
I've found a solution on the .NET Core Slack Channel:
You want to use this:
dotnet msbuild "/t:Restore" /p:VersionSuffix=<Suffix> /p:Configuration=Release
when restoring.
The new CLI version writes a project.assets.json file in /obj which then gets used by dotnet pack
to reference other packages in the resulting .nuspec file in the nuget package. So you have to provide the suffix when restoring for that to work in the desired way. Essentially the 'pack' and 'restore' commands are wrapper commands arround the dotnet msbuild
command with targets "/t" set as I understand it.
More detailed explanation here: http://christianhuening.de/?p=47
There is in fact another problem being that whatever I tried, unless VersionSuffix
is actually on disk, AssemblyInformationalVersion
will not match the version used during build.
That is after realizing that unless you actually do a dotnet clean
with the same configuration as the one you'll use to restore+build+pack+push, this value is not updated at all. It gets written to obj\$(Configuration)\$(TargetFramework)\$(ProjectName)\$(AssemblyName).AssemblyInfo.cs
and this file is never updated unless it is deleted first (by running clean or build /t:Clean) as far as I can tell.
<Project>
<PropertyGroup>
<VersionPrefix>1.0.0</VersionPrefix>
<VersionSuffix>alpha</VersionSuffix>
</PropertyGroup>
</Project>
```C#
var aiv = typeof(SomeClassInMyProjectReferenceLibrary).GetTypeInfo().Assembly
.GetCustomAttribute
.InformationalVersion;
Console.WriteLine(aiv);
rem Simulate working in Visual Studio
dotnet clean
dotnet restore
dotnet build
rem Now prepare to pack and push
dotnet restore /p:VersionSuffix=alpha-001
dotnet build /p:VersionSuffix=alpha-001
dotnet run --no-build
Output: 1.0.0-alpha
rem Now also clean -- this fixes VersionSuffix for the case where the assembly is the entry assembly
dotnet clean
dotnet restore /p:VersionSuffix=alpha-001
dotnet build /p:VersionSuffix=alpha-001
dotnet run --no-build
Output: 1.0.0-alpha
This is probably why say EFCore uses a file called Version.props in the build which comes with the warning that it might be overwritten: [link](https://github.com/aspnet/EntityFramework/blob/dev/version.props)
$v = [xml]::new()
$v.Load(".buildVersion.props")
$v.Project.PropertyGroup.VersionSuffix += "-001"
$v.Save(".buildVersion.props")
dotnet clean
dotnet restore
dotnet build
dotnet run --no-build
```
Output: 1.0.0-alpha-001
You'd have to wrap this in a try ... finally where you restore the original VersionSuffix since if the build fails a few times and then succeeds, you might end up with 1.0.0-alpha-001-001-001-001-001. 🥇
It gets written to obj$(Configuration)$(TargetFramework)$(ProjectName)$(AssemblyName).AssemblyInfo.cs and this file is never updated unless it is deleted first (by running clean or build /t:Clean) as far as I can tell.
Yes, the incremental build of this file is buggy. I mentioned this as well in https://github.com/dotnet/sdk/issues/650 but as it was a side-mention the issue was closed without fixing the incremental build issue.
AssemblyInformationalVersion will not match the version used during build
Just hit this is as well 😢. As this worked with the old CLI, i'd consider it a pretty big bug/breaking change that should be posted on some "Known issues" page until it is fixed (or considered by design).
Does such a page exist somewhere (it's not on the migration guide) or is there something like aspnet/Announcements for all of the tooling? It's just impossible to follow all the related repos like dotnet/cli, dotnet/sdk, nuget/home, dotnet/project-system, ... etc.
Regarding bug or not, I'd say it must be a bug because you currently can't achieve a correct result with the documented "dotnet restore" switches.
Just got bitten by this as well, but the solution in https://github.com/NuGet/Home/issues/4337#issuecomment-292089025 worked for me as I have my version generated as part of CI scripts and can pass it around to dotnet restore
.
Seems like a bug to me.
it's kind of a bug in the design rather than the implementation
the broader issue is that everything is now msbuild-based and msbuild no longer has standalone top-level targets. /t:build will not correctly produce your outputs unless you do a /t:restore - at which point you actually need /t:rebuild because restores aren't incremental-safe. similarly, /t:pack needs that restore first, which means you need either a rebuild or NoBuild=True..
visual studio understands most of these dependencies and performs restores at the appropriate points. but the command line tools don't - you or your build scripts have to know when inputs to restore have changed and run it manually, as well as understanding what the implications/outputs of a restore are. it kind of sucks!
here's another example of needing to deeply understand the process or experience weird bugs: the workaround people have been using is incomplete when it's part of a larger workflow. "msbuild /p VersionSuffix=beta /t:restore;pack" will get you nuget packages with -beta, yes- but it won't perform a nonincremental build (so your obj/AssemblyInfo.cs isn't updated) and it won't leave your workspace in a working state, either! any subsequent build will burn incorrect transitive dependencies into .deps files until you do another restore..
basically restore is weird. it statefully modifies the intermediates in a way which other targets depend upon, but do not understand how to invoke. if they did invoke it, there would be a major perf cost since you can't detect whether a restore is necessary and skip it. further, there are some nasty edge cases like this issue where your ideal outcome is that a restore is done before the build, but not before the pack, because you're temporarily overwriting version numbers in a way which you want to flow through to subsequent artefact production..
We're encountering this issue as well.
The dotnet restore
with version suffix does not work for us; we use authenticated NuGet feeds from build machines, so we must use nuget restore
(as it provides credential management). NuGet's restore
command does not accept MSBuild parameters or the -Suffix
argument.
So, when project B references project A, B picks up the version from A's csproj
(1.0.0-beta) in our case; since A 1.0.0-beta doesn't exist on a feed, it just picks the lowest version it can find, which is missing methods that have been added to A since that version.
Currently I am working on implementing the above-suggested method of updating a Version.props
file at build time. However, this is a very hacky workaround for something that appears to be a bug.
Is this issue still slated to be fixed in an upcoming version of dotnet
/NuGet/MSBuild?
@ekumlin yes, we will be fixing this issue, however i can't provide a timeline just yet.
But i can suggest another hack that will unblock you. There is a way to inject msbuild variables using nuget.exe. You need to set an environment variable called NUGET_RESTORE_MSBUILD_ARGS
and set its value to something like /p:VersionSuffix=abcd-1234
But this will only work if you are using NuGet 4.0 and up.
See: https://github.com/NuGet/NuGet.Client/blob/dev/src/NuGet.Clients/NuGet.CommandLine/MsBuildUtility.cs#L121
@rohit21agrawal That's good to know. We are using NuGet 4.0, so that's a good possibility. Thanks for the tip!
looks like this just bit us in our Final Preview 2 build. When do we plan to have this addressed?
I'm stuck on this issue. I am not using VersionSuffix, I am using msbuild My.sln /t:Pack /p:Version="1.0.0-alpha"
and GitVersion.Task to calculate the version. I have already created an issue but think it's probably related: https://github.com/dotnet/sdk/issues/1320
Doing a dotnet msbuild /t:Restore /p:Version<Version> /p:Configuration=Release
as per the comment above seems to have worked.. Hopefully this won't be necessary in the future?
Bump? What is the status of getting this resolved. We have to double-restore currently to workaround this.
It would be great if this could be resolved in a way that also fixes https://github.com/NuGet/Home/issues/4790 (allow build logic acquired via nuget to set the version - like GitVersion - which is impossible during restore), which is in the 4.4 milestone.
with SDK 2.0, a restore is automatically implied on build (and pack builds by default, unless you specify the nobuild option), so you shouldn't have to do a double restore.
This doesn't help since I need versions to calculate for interpackage dependencies. Also, I need to use msbuild /t:restore
and msbuild /t:build
for things that dotnet
cannot build. This is also related to #4790
Calling a target per p2p to get $(PackageId)
and $(PackageVersion)
would be great although it might slow down projects using the generate-package-on-bulid functionality a little.
The integrated restore is great and solves a lot of these edge case problems yet this does not solve the imported targets/props issue (e.g. distributing this target in a NuGet package) and isn't very obvious when directly using other build systems (mono's msbuild, cake to invoke (dotnet/mono) msbuild, …)
btw There also are instances when users want to change their package IDs (.Signed
versions) - https://github.com/Microsoft/msbuild/issues/2463
@natemcmaster @onovotny @NickCraver others - if anyone wants to try out private bits to validate this fix, please let me know.
I am interested, but what does the fix do, how does it work? Looking at the PR, adding VersionSuffix alone doesn't seem like it'd fix it. I don't set/directly use VersionSuffix at all, I use Version/PackageVersion and that's calculated on build. It needs to be calculated/used on pack. It's not a matter of using a different variable.
these test cases should explain the behavior: https://github.com/NuGet/NuGet.Client/pull/1688/files#diff-0a8ea4346824f4b1f738f32446ce80caR412
but if not, let me know and i'll explain the behavior.
As mentioned in the PR thread, this does not solve the issue. Pack cannot read from the assets file since the assets file is written on restore. This behavior is forcing an extra restore if the version is calculated during a build step.
The pack targets need to do the same calculation on p2p refs.
FYI this fix is going to be release in Update 6 of Visual Studio aka 15.6
@rohit21agrawal, I assume the fix is actually in .NET Core SDK and will be integrated in VS 15.6. Is that correct? We're using .NET Core SDK to build in CI.
@dazhao-msft that is correct. the nightly builds of .NET Core SDK have this fix.
hi, what version is this fix in?
Most helpful comment
If it is by design, I'd very much like to hear the reasoning. But I think it's just a bug.
If I have a project dependency, when packing that project the dependent project needs to packed first, and the actual version thus packaged must be depended upon.