-
Notifications
You must be signed in to change notification settings - Fork 269
design spec for version property in project reference #12348
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
base: dev
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,201 @@ | ||
| # Allow users to define version ranges for ProjectReferences | ||
|
|
||
| - [Martin Ruiz](https://github.com/martinrrm) | ||
| - Start Date (2023-01-01) | ||
| - [5556](https://github.com/NuGet/Home/issues/5556) | ||
|
|
||
| # Summary | ||
|
|
||
| Add a `Version` to `ProjectReference` tag in CSPROJ, to allow customers to specify the referenced project version in the `.nupkg` and `nuspec` files when doing a pack command. | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. How about adding another As you can see in the below example, <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="ClassLibrary2" Version="[1.0.0, 2.0.0)" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\ClassLibrary2\ClassLibrary2.csproj" />
</ItemGroup>
</Project>I didn't think about the pros/cons or possibilities of this approach. |
||
|
|
||
| # Motivation | ||
|
|
||
| When using `ProjectReference` there is no option to define a Version to the reference like in `PackageReference` and the version will always be defined as `>= ProjectVersion`, this results in customers manually modifying the nuspec file if they want to declare a different version than the project version. | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could you be able to add little bit more details on exactly what is the project version here?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For project version I mean the value of About For example if ProjectA has a |
||
|
|
||
| # Explanation | ||
|
|
||
| Currently when adding a `ProjectReference` to a project, there is no property to specify which version(s) of it to be used when doing a pack. | ||
| When doing a pack to a package with a `ProjectReference` it will always be added as a range, where the minimum version will be the ProjectReference version and with an open maximum version. | ||
|
|
||
| ``` | ||
| <ItemGroup> | ||
| <ProjectReference Include="../MyReferencedPackage/MyReferencedPackage.csproj" /> | ||
| </ItemGroup> | ||
| ``` | ||
|
|
||
| Add a `Version` property to `ProjectReference` and store that value in the assets file when doing a restore so we can retrieve that information when doing a `pack` command. | ||
|
|
||
|
|
||
| ## Considerations | ||
|
|
||
| If there is no `Version` information then the behavior should be the current one. | ||
|
|
||
| If the `Version` is not a range, it will be treated as one, like in `PackageReference`. `Version="2.0.0"` means `Version="[2.0.0, )"` | ||
|
|
||
| Minimum version should not be open to users, and NuGet should always automatically fill in the min version from the project's version, this is for the protection of package consumers. | ||
|
|
||
| --- | ||
| ## Option 1 - Version with VersionRange | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. After doing more investigation (Nikolche also commented about this in #12348 (comment)), I think this option is not possible. I don't think we are aware of the project version during restore, meaning that we will have different information in the assets file and the .nupkg Example: MyReferencedPackage -> v.1.0.9 Will write this the assets file: And this can cause confusion when pack resolves to another min version. |
||
|
|
||
| ### .CSPROJ file | ||
| ``` | ||
| <ItemGroup> | ||
| <PackageReference Include="Newtonsoft.Json" Version="[9.0.0, 13.0.2)" /> | ||
| <ProjectReference Include="../MyReferencedPackage/MyReferencedPackage.csproj" Version="[1.0.0, 2.0.0)" /> | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think the minimum version should not be allowed to be specified on the ProjectReference, and NuGet should always automatically fill in the min version from the project's version. This might not be popular with customers who want this feature, but this is for the protection of package consumers, especially since NuGet only selected minimum version in its dependency resolution graph.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. With this I think we can take the customer suggestion and do something like this: With this in mind, you think saving this as a version range in the assets file (like the initial proposal) or change it to be different properties? Option 1 (I like this one more) : Option 2: I currently have an mvp for this in branch
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Apparently I forgot to reply to this 😕
That's not valid MSBuild syntax. While project files are XML, MSBuild has a strict syntax, and diverging from it will require changes to MSBuild if we feel stongly enough that it's needed to support a customer scenario (in which case you'd also need to consider what potential bugs it could introduce to non-NuGet scenarios if the syntax was extended). Anyway, MSBuild items are basically NuGet's However, I think another scenario that some customers may want, is to limit the package dependency to the exact version of the project when it's being packed. VersionRange defines this as
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @zivkan I like the idea of doing
What if we do something like
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As per our docs on version ranges,
Yes, that works with MSBuild's syntax. Something to keep in mind, although it's very unlikely, is that customers might have build custom build scripts, so if any customer already uses Customers are more likely to already be familiar with All this to say, I don't have an obvious answer/solution. Get more feedback from others. Perhaps my
How? What would the syntax be for "use the referenced project's version as the max" be?
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. magic word maybe?
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Today, the I don't love it though. It feels like the most completely way without misuse risk, but it's kind of ugly. |
||
| </ItemGroup> | ||
| ``` | ||
|
|
||
| ### Explanation | ||
| `Version` will be a version range, but the lower version will be replaced with the actual `Version` as an inclusive min version. | ||
|
|
||
| We will log a warning saying that the min version should be equal to the `ProjectVersion` and it was replaced. | ||
|
|
||
| ## Option 2 - Version without defined min version | ||
| ### .CSPROJ file | ||
| ``` | ||
| <ItemGroup> | ||
| <PackageReference Include="Newtonsoft.Json" Version="[X, 13.0.2)"/> | ||
| <ProjectReference Include="../MyReferencedPackage/MyReferencedPackage.csproj" Version="[1.0.0, 2.0.0)" /> | ||
| </ItemGroup> | ||
| ``` | ||
|
|
||
| ### Explanation | ||
| `Version` will be a version range, but the lower version will be defined by a 'X' and replaced with the actual `ProjectVersion` as an inclusive min version. | ||
|
|
||
| ### assets file | ||
| ``` | ||
| "frameworks": { | ||
| "net6.0": { | ||
| "targetAlias": "net6.0", | ||
| "projectReferences": { | ||
| "C:\\Users\\mruizmares\\source\\repos\\ConsoleApp1\\MyReferencedPackage\\MyReferencedPackage.csproj": { | ||
| "projectPath": "C:\\Users\\mruizmares\\source\\repos\\ConsoleApp1\\MyReferencedPackage\\MyReferencedPackage.csproj", | ||
| "version": "[1.0.0, 2.0.0)" | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Will this change be compatible with old version tools?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Tested doing a
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Did you use
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. My guess is that because it's additive it should work. |
||
| } | ||
| } | ||
| } | ||
| }, | ||
| ``` | ||
|
|
||
| ### nuspec file | ||
| ``` | ||
| <?xml version="1.0" encoding="utf-8"?> | ||
| <package xmlns="http://schemas.microsoft.com/packaging/2012/06/nuspec.xsd"> | ||
| <metadata> | ||
| <id>ConsoleApp1</id> | ||
| <version>1.2.4</version> | ||
| <authors>ConsoleApp1</authors> | ||
| <description>Package Description</description> | ||
| <dependencies> | ||
| <group targetFramework="net6.0"> | ||
| <dependency id="MyReferencedPackage" version="[1.0.0, 2.0.0)" exclude="Build,Analyzers" /> | ||
| <dependency id="Newtonsoft.Json" version="[9.0.0, 13.0.2)" exclude="Build,Analyzers" /> | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. May I know if there is any behavior change for package reference? Or will this change only impact project reference? Thanks!
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Right now, we consider ProjectReferences as packages when doing pack, so this code is shared. Since PackageReference's can handle ranges, I think the behavior is going to be the same. Currently we use
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why do we need to switch from legacy short string to short string? |
||
| </group> | ||
| </dependencies> | ||
| </metadata> | ||
| <files> | ||
| <file src="C:\Users\mruizmares\source\repos\ConsoleApp1\ConsoleApp1\bin\Debug\net6.0\ConsoleApp1.runtimeconfig.json" target="lib\net6.0\ConsoleApp1.runtimeconfig.json" /> | ||
| <file src="C:\Users\mruizmares\source\repos\ConsoleApp1\ConsoleApp1\bin\Debug\net6.0\ConsoleApp1.dll" target="lib\net6.0\ConsoleApp1.dll" /> | ||
| </files> | ||
| </package> | ||
| ``` | ||
|
|
||
| ### nupkg | ||
| ``` | ||
| Metadata: | ||
| id: ConsoleApp1 | ||
| version: 1.2.4 | ||
| authors: ConsoleApp1 | ||
| description: Package Description | ||
| Dependencies: | ||
| net6.0: | ||
| MyReferencedPackage: '>= 1.0.0 && < 2.0.0' | ||
| Newtonsoft.Json: '>= 9.0.0 && < 13.0.2' | ||
|
|
||
| Contents: | ||
| - File: _rels/.rels | ||
| - File: [Content_Types].xml | ||
| - File: ConsoleApp1.nuspec | ||
| - File: lib/net6.0/ConsoleApp1.dll | ||
| - File: lib/net6.0/ConsoleApp1.runtimeconfig.json | ||
| - File: package/services/metadata/core-properties/a638a18cb3b1449185ce67e16a13ebaf.psmdcp | ||
| ``` | ||
|
|
||
| # Drawbacks | ||
|
|
||
| I don't think there are drawbacks to this implementation when doing a `pack` command. For restore I'm not sure if adding a new propert to the assets file can affect the performance. | ||
|
|
||
| # Rationale and alternatives | ||
|
|
||
| ## Option 3 - Separate variables for max project version. | ||
| ### .CSPROJ file | ||
| ``` | ||
| <ItemGroup> | ||
| <PackageReference Include="Newtonsoft.Json" MaxProjectVersion="3.0.2" IsMaxProjectVersionInclusive="true" /> | ||
| <ProjectReference Include="../MyReferencedPackage/MyReferencedPackage.csproj" Version="[1.0.0, 2.0.0)" /> | ||
| </ItemGroup> | ||
| ``` | ||
|
|
||
| ### assets file | ||
| ``` | ||
| "frameworks": { | ||
| "net6.0": { | ||
| "targetAlias": "net6.0", | ||
| "projectReferences": { | ||
| "C:\\Users\\mruizmares\\source\\repos\\ConsoleApp1\\MyReferencedPackage\\MyReferencedPackage.csproj": { | ||
| "projectPath": "C:\\Users\\mruizmares\\source\\repos\\ConsoleApp1\\MyReferencedPackage\\MyReferencedPackage.csproj", | ||
| "MaxProjectVersion": "3.0.2" | ||
| "IsMaxProjectVersionInclusive": "true" | ||
| } | ||
| } | ||
| } | ||
| }, | ||
| ``` | ||
|
|
||
| ### nuspec file | ||
| ``` | ||
| <?xml version="1.0" encoding="utf-8"?> | ||
| <package xmlns="http://schemas.microsoft.com/packaging/2012/06/nuspec.xsd"> | ||
| <metadata> | ||
| <id>ConsoleApp1</id> | ||
| <version>1.2.4</version> | ||
| <authors>ConsoleApp1</authors> | ||
| <description>Package Description</description> | ||
| <dependencies> | ||
| <group targetFramework="net6.0"> | ||
| <dependency id="MyReferencedPackage" MaxProjectVersion="3.0.2" IsMaxProjectVersionInclusive="true" exclude="Build,Analyzers" /> | ||
| <dependency id="Newtonsoft.Json" version="[9.0.0, 13.0.2)" exclude="Build,Analyzers" /> | ||
| </group> | ||
| </dependencies> | ||
| </metadata> | ||
| <files> | ||
| <file src="C:\Users\mruizmares\source\repos\ConsoleApp1\ConsoleApp1\bin\Debug\net6.0\ConsoleApp1.runtimeconfig.json" target="lib\net6.0\ConsoleApp1.runtimeconfig.json" /> | ||
| <file src="C:\Users\mruizmares\source\repos\ConsoleApp1\ConsoleApp1\bin\Debug\net6.0\ConsoleApp1.dll" target="lib\net6.0\ConsoleApp1.dll" /> | ||
| </files> | ||
| </package> | ||
| ``` | ||
|
|
||
| ### nupkg | ||
| ``` | ||
| Metadata: | ||
| id: ConsoleApp1 | ||
| version: 1.2.4 | ||
| authors: ConsoleApp1 | ||
| description: Package Description | ||
| Dependencies: | ||
| net6.0: | ||
| MyReferencedPackage: '>= 1.0.0 && <= 3.0.2' | ||
| Newtonsoft.Json: '>= 9.0.0 && < 13.0.2' | ||
|
|
||
| Contents: | ||
| - File: _rels/.rels | ||
| - File: [Content_Types].xml | ||
| - File: ConsoleApp1.nuspec | ||
| - File: lib/net6.0/ConsoleApp1.dll | ||
| - File: lib/net6.0/ConsoleApp1.runtimeconfig.json | ||
| - File: package/services/metadata/core-properties/a638a18cb3b1449185ce67e16a13ebaf.psmdcp | ||
| ``` | ||
|
|
||
| # Unresolved Questions | ||
|
|
||
| # Future Possibilities | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For some reason, I think
Versionattribute doesn't belong toProjectReferencebecause it refers to the package version range. Looking at the schema forProjectReferenceelement https://github.com/dotnet/msbuild/blob/main/src/MSBuild/MSBuild/Microsoft.Build.CommonTypes.xsd#L643-L722, I thinkPackageVersionmight be more appropriate. The schema hasPackageas sub element forProjectReferencebut there are no comments to understand more about its usage. I noticed that there is alsoSpecificVersionattribute forProjectReferenceelement to specify whether the exact version of the assembly should be used.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
FYI - There is an MSBuild property
PackageVersionallowing customers to specify package version in the csproj file if the project is packed as nupkg.https://learn.microsoft.com/nuget/create-packages/package-authoring-best-practices#package-metadata