Description
Background
We use C# for our build scripts, with reusable build steps shared via a private NuGet package. Migrating to dotnet run Build.cs
seems like a perfect use case for this new .NET 10 feature.
We always want our build tooling to use the latest package version, so we use a floating 1.*
version in the <PackageReference>
. However, we also use central package management, so we use a VersionOverride
attribute in the csproj (because central package management doesn't support floating versions).
I can't figure out an ideal way to support this with dotnet run Build.cs
.
Current Situation
Directory.Package.props
<Project>
<PropertyGroup>
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
</PropertyGroup>
<ItemGroup>
<!-- all non-Build packages here -->
</ItemGroup>
</Project>
tools\Build\Build.csproj
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net9.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Example.BuildTools" VersionOverride="1.*" />
</ItemGroup>
</Project>
tools\Build\Build.cs
return BuildRunner.Execute(args, ...);
Attempted Approaches
In all approaches, I have deleted Build.csproj
.
Floating #:package Version
Directory.Packages.props
as above, Build.cs
:
#:package Example.BuildTools@1.*
return BuildRunner.Execute(args, ...);
Error:
tools\Build\Build.csproj : error NU1008: Projects that use central package version management should not define the version on the PackageReference items but on the PackageVersion items: Example.BuildTools.
Done building project "Build.csproj" -- FAILED.
#:property ManagePackageVersionsCentrally false
Edit: This suggestion is thanks to @WeihanLi and is a decent workaround. Use #:property
to disable CPM for this file.
#:property ManagePackageVersionsCentrally false
#:package Example.BuildTools@1.*
return BuildRunner.Execute(args, ...);
dotnet run Build.cs
executes without errors.
Floating PackageVersion version
In Directory.Packages.props
, add <PackageVersion Include="Example.BuildTools" Version="1.*" />
. Build.cs
as in previous example, but drop @1.*
.
Error:
tools\Build\Build.csproj : error NU1011: Centrally defined floating package versions are not allowed.
Done building project "Build.csproj" -- FAILED.
As per https://learn.microsoft.com/en-us/nuget/reference/errors-and-warnings/nu1011 we can avoid that with <CentralPackageFloatingVersionsEnabled>true</CentralPackageFloatingVersionsEnabled>
, but (a) I don't want to enable that for everything in Directory.Package.props, and (b) the documentation strongly discourages the use of this setting. (Well, technically, it discourages the use of floating versions... which is the thing I do want.)
Hard-coded version
In Directory.Packages.props
, add <PackageVersion Include="Example.BuildTools" Version="1.23.4" />
. Build.cs
as in previous example, but drop @1.*
.
Works, but is a lot of churn in Directory.Packages.props when updates are shipped to our shared NuGet package. We want to use a floating version here.
Desired Solution
If dotnet run Build.cs
is being executed in a folder that uses CPM, it would be nice if it auto-detected this scenario and output VersionOverride
on the auto-generated <PackageReference>
, instead of Version
, avoiding NU1008.
To some extent, it feels odd that the implicit csproj does even inherit the Directory.Packages.props settings from a parent directory of the *.cs
file being run. (I can see the arguments for and against, but it does raise some questions of how "self-contained" these single-file C# scripts should be. If I were to copy Build.cs
from the "Floating #:package Version" example above to a different folder, say C:\Temp
, it would "just work".)
Edit: I see that the behaviour of the implicit project file is by design.