NuGet / Home

Repo for NuGet Client issues
Other
1.49k stars 252 forks source link

Feature Request: Add options for patching csproj for nuget packages #7117

Closed nguerrera closed 6 years ago

nguerrera commented 6 years ago

From @dasjestyr on July 13, 2018 20:40

When running dotnet pack or dotnet build (when csproj is set to package on build) it would be helpful to have the ability to include a version number that will be auto-patched into the nuspec. The use case being CI/CD systems where I want packages to be pushed as part of the automated deployment step. So for example, my build script would call something like

dotnet pack --package-version 4.3.2.${bamboo.buildNumber}

or something to that effect.

At the moment, to my knowledge anyway, I would have to write an executable or script that would modify the csproj for me before attempting to pack or build the project.

Copied from original issue: dotnet/cli#9660

nguerrera commented 6 years ago

Does dotnet pack /p:PackageVersion=4.3.2${bamboo.buildNumber} not work?

dasjestyr commented 6 years ago

It does, however it's very specific in that I have to specify the entire version so I'm not sure how I could keep a major.minor.patch theme going. For example, I'd want to set the version in the csproj (e.g. 4.3.2) and then be able to have the build server set the revision/build number (e.g. 4.3.1.5121) or even pre-release suffixes as well (e.g. 4.3.1.5121-pre). I would have to update the build configuration with each new version which could get very complicated when dealing with multiple releases. I think I would have to write something that extracts the version from the csproj, figures out the version and then substitutes it into the CLI command. Does that make sense?

dasjestyr commented 6 years ago

I'm not sure what would be possible, but maybe something along the lines of dotnet pack myproject.csproj /p:PackageVersion=PackageVersion.${bamboo.buildNumber}. That would allow me to append to whatever version is already set in the file. I'm not sure how to work the internal variable though... but basically, this would allow the user to work with the values within the csproj

StingyJack commented 6 years ago

XDT may also be useful for patching the proj file, and its already in (was?) the package install process.

dasjestyr commented 6 years ago

Not 100% what you're referring to. I mean, I know what xdt is, just not clear on what you're thinking. But, I did a quick search and landed on a global tool here: https://github.com/nil4/dotnet-transform-xdt that seems like it might possibly be able to get the job done once I figure out how to work with it. Not quite sure though... it has to work with both linux and windows build agents; not sure if the variable syntax is compatible with bash or of it's just powershell like it appears...

Either way, I'd need to be able to either feed in some values or at least set them into the build environment (not globally) in order for the transform to get at it.

StingyJack commented 6 years ago

These are the XDT stuffs I mean. You can alter the config files in the same way VS does for web.config debug/release transforms. I use this to add a few elements or endpoints in a few private packages.

The csproj is XML so it seems like a "natural" fit to use XDT on it, however looks like this is not available if you are using package reference. An install.ps1 would also be useful as powershell runs on both windows and linux now, but it also may no longer be available in the version of nuget you are using.

nguerrera commented 6 years ago

msbuild is very dynamic. You can condition and populate things based on properties and you can pass arbitrary properties via /p:propertyname=value.

It should be possible to cause the evaluation of your project to match what you have in mind as a transform without actually editing the .csproj file on disk.

dasMulli commented 6 years ago

You could also edit the csproj file to set the version number like this:

<PropertyGroup>
  <BuildNumber Condition="'$(BuildNumber)' == ''">0</BuildNumber>
  <VersionPrefix>4.3.2.$(BuildNumber)</VersionPrefix>
</PropertyGroup>

This will allow you to build using

# produces 4.3.2.657
dotnet pack -p:BuildNumber=${bamboo.buildNumber}
# produces 4.3.2.657-pre
dotnet pack -p:BuildNumber=${bamboo.buildNumber} --version-suffix pre
# produces 4.3.2.0-pre
dotnet pack --version-suffix pre
dasjestyr commented 6 years ago

Oh! I was unaware of this. Excellent, thank you! I will give this a try today hopefully

You can condition and populate things based on properties and you can pass arbitrary properties via /p:propertyname=value.

@nguerrera I don't think I ever really learned this about msbuild; totally makes sense now that I look at it. Very cool. Is this documented somewhere I can dig into it??

dasMulli commented 6 years ago

fyi there are 2 related issues (I've been posting snippets similar to the one above everywhere): https://github.com/dotnet/cli/issues/2676 https://github.com/dotnet/cli/issues/4859

Tricks like these are notoriously hard to document since "the MSBuild language" that csproj uses is more like a programming language than a static DSL / config file. So whatever your requirements, you may be able to come up with some "MSBuild code" that helps you implement them. On the plus side: Before csproj, ppl have been writing horrible PowerShell scripts to go through all project.json files in a repo just to change the version numbers everywhere 😱 .

Since you'll likely need it: You can put the snippet above, enclose it in a <Project>…</Project> tag and save it as a Directory.Build.props file next to your .sln file (or at the project root) and all projects will use it automatically and you can manage the version in one place for all assemblies / packages.

dasjestyr commented 6 years ago

Oh yeah, I just took a minute to try it out. Gangbusters. This'll work. Thanks!

rohit21agrawal commented 6 years ago

closing issue. thanks everyone!