Retrieve created NuGet package filename from 'nuget pack' command? - nuget

I'm writing a script that will automatically pack and publish Nuget files to my private repository (a fileshare) and a private symbol server (on localhost).
When I run nuget pack in Powershell I get a string output that contains the file location of both the nuget and symbol package, but as far as I can tell there's no way to programmatically get those paths without parsing the string. The package version is determined by the .csproj itself, so I don't necessarily know which version will be placed in the filename.
Here's the output from the pack command:
Attempting to build package from 'MyProject.csproj'.
Building project 'C:\Users\me\prg\MyProject.csproj' for target framework '.NETFramework,Version=v4.0'.
Packing files from 'C:\Users\me\prg\bin\Release'.
Using 'Myproject.nuspec' for metadata.
Successfully created package 'C:\nuget\MyProject.1.0.0.0.nupkg'.
Attempting to build symbols package for 'MyProject.csproj'.
Building project 'C:\Users\me\prg\MyProject.csproj' for target framework '.NETFramework,Version=v4.0'.
Packing files from 'C:\Users\me\prg\bin\Release'.
Using 'MyProject.nuspec' for metadata.
Successfully created package 'C:\nuget\Myproject.1.0.0.0.symbols.nupkg'.
Should I just bite the bullet and write some regex to parse out the "successfully created package" lines?

By default nuget pack will output the created packages to the current directory. You can override this by specifying the OutputDirectory option. It is not clear to me from where you run the nuget command (be it from within C:\Users\me\prg\, C:\nuget\, or somewhere else), so you might already know this, but it can offer you an alternative option:
You can create yourself a temporary directory (e.g. C:\nuget\temp\), which you can specify as your OutputDirectory option. If you then in your script make sure that this directory is empty before you run nuget pack, your can simply copy *.nupkg to your fileshare (and then afterwards move it to C:\nuget\, if that is required).

Parsing the output in powershell is not too hard.
$a = nuget pack .\Exceptional.csproj -Prop Configuration=Release | Select-String nupkg
$a -Replace "^[^']'", "" -Replace "'[^']$", ""
gives
C:\Users\phelan\workspace\Exceptional\Exceptional\Weingartner.Exceptional.1.2.6011.19372.nupkg

I made a slight change to the answer provided by #bradgonesurfing as his partly worked for me.
$pack = . $nugetPath pack rest of command........ | Select-String nupkg
$pack -match "'(?<nupkg>.*)'"
$packageFile = $Matches["nupkg"]
To get it in a post build event, I would use the powershell.exe to shell out to a powershell script. I have an example here that I used to automate running editbin that can be modified for nuget: https://gist.github.com/tcartwright/cc1bd4dc98349579630c43283c5f1fe9

Related

Is it possible to get Octopus Release path in Octopus step?

I'm using Jenkins with Octopus plugin to create Release in Octopus. This works nicely. However, when in Octopus, more specifically in my first 'Script' step, I can't get hold of the Release package. Only variable I seem to be able to get is:
$OctopusParameters["Octopus.Release.Number"]
What I need is original path for that same Release. My script step in powershell script unpacks nuget package, adds an extra level/folder, zips it, before deploying to an API. If I, in Octopus step, specify "Referenced package" (sourcepackage) then Jenkins will not build it's Post-Build step and complain that "sourcepackage" is missing. I would like to get original path for my package like this:
$OctopusParameters["Octopus.Action.Package[sourcepackage].OriginalPath"]
But I can't find a way without "Referenced package", and if I use it Jenkins will not build. :(
I ended up doing a work around. I added Octopus variable "FeedPath" pointing to "D:\Octopus\Packages\Spaces-1\feeds-builtin[packagename]". In powershell I simply combined "FeedPath" with Release number to get full nuget file path:
$packagepath = $OctopusParameters["FeedPath"] + "[packagename]." + $OctopusParameters["Octopus.Release.Number"] + ".nupkg"
I've used the following to get the installation path for the package: Octopus.Action[Name of Process step].Output.Package.InstallationDirectoryPath. To get the compressed package prior to installation, I assume something similar can be used. Here is a link to the output variables: https://octopus.com/docs/projects/variables/output-variables

MSBuild with WebPublishMethod to package produces wrong file names in zip file

We have standard CI/CD on Azure DevOps. Recently we found, that files with diacritics (accent) in names are published wrong. Seems that instead of original chars all is in utf-8 (or something like that).
In build phase the is normal Visual Studio Build task with common msbuild command and arguments
/t:XXX /p:BuildProjectReferences=true /p:DeployOnBuild=true /p:WebPublishMethod=Package /p:PackageAsSingleFile=true /p:SkipInvalidConfigurations=true /p:DesktopBuildPackageLocation="$(build.artifactstagingdirectory)\XXX" /p:outputDir="$(build.artifactstagingdirectory)\XXX" /P:PackageTempRootDir=
After build, zip file contains encoded filenames. So encoding is part of build process.
Tried to simply call msbuild and publish to package from local machine on sample project and the same problem. Output zip package contains encoded filenames. And now it is impossible to extract zip file to get original naming.
My question is - how to force build and package task to not encode names, or use extract zip task to get filanames as they are in project? I found no info how to extract encoded files from artifacts.
Recently we found, that files with diacritics (accent) in names are published wrong.
Based on my test, I could reproduce this issue. When the Folder Name or File name contain the diacritics, their names will be encoded into other formats after Msbuild.
For example:
As you said, this problem also exists in the local msbuild, so this problem exists in msbuild itself. Since the SDK used by msbuild may be of a lower version, it cannot recognize these special characters
I am afraid that there is no such arguments in msbuild to force the original encoding of the file to be maintained.
Workaround1:
In Azure Devops, you could use Extract files task to unzip the zip file.
Then you could use Powershell task to run the script to change the file or folder name:
Folder:
Rename-Item 'C:\xxx\diakritik├│s' -newName 'C:\xxxm\diakritikós'
File:
Rename-Item -Path "c:\logfiles\daily_file.txt" -NewName "monday_file.txt"
Finally, you could use Archive files task to zip the files again.
Sample:
Workaround2:
Based on my test, you could use template for dotnet build.
In this case, dotnet build can keep the file name.
For the issue itself, I suggest you can report it here: Msbuild Issue.

nuget is not a recognized as an internal or external command

While running a batch file, I get the below error:
nuget is not a recognized as an internal or external command
It's not working from command prompt. Have a look at the below screenshot.
This happens when either you are not in the directory where the nuget.exe is located or your environment variables are not set for it.
Make sure you have downloaded NuGet.exe.
Navigate to it and right click, then click on properties.
Copy the location of it.
Navigate to Control Panel > System > Advanced System Settings > Environment Variables.
Windows 10
Double click the variable Path click add new, paste in the location of the nuget.exe.
Restart Command Prompt and the issue should be fixed.
Other operating Systems
Double click the variable Path, If there is no other locations simply paste it in. If there is add a semi colon to the end of it and the paste it in.
Restart Command Prompt and the issue should be fixed.
nuget is not a recognized as an internal or external command
That because NuGet is a external command, can not be recognized by Windows in an arbitrary directory, you should type the "NuGet" or "NuGet.exe" in the path where NuGet.exe exists and if you want type it in an arbitrary directory, you should download the NuGet.exe (Not VSIX) from NuGet.org and set the local path of NuGet.exe into your path environment variable.
Instead of using nuget.exe in your path, use .net version
dotnet nuget
Download the Nuget Exe, keep it in a folder you want to. For ex : D:\Software\Nuget
Open Cmd prompt with the same path.
To create this .nuspec file, execute the following command in a command prompt.
D:\Software\Nuget>Nuget.exe spec
For .NET Core / .NET 5:
Use the command dotnet pack
Instead of using a .nuspec file you set those properties in your .csproj file, for example:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
<PackageId>MyCompany.Project</PackageId>
<Version>1.0.0.1</Version>
</PropertyGroup>
...
</Project>
With above config, running dotnet pack will create a file named
MyCompany.Project.1.0.0.1.nupkg
For more details and config options, see: https://learn.microsoft.com/en-us/nuget/reference/msbuild-targets#pack-target
I follow this link and it work fine with me
How to Fix “not recognized as an internal or external command” in Windows
just add the path of the nuget in the path variable
1 - Installing Package:
I followed this Microsoft documentation. Use the nuget.exe CLI in the package console
Note:- This configuration is specific to a project and this adds dependency to the projects package.config
2 - Installing exe:
You can also follow the below documentation, again from Microsoft to download and set the path to nuget.exe folder, as others in this thread has explained.
NuGet CLI reference

How do I correct the output directory of a CI/CD NuGet package build using Visual Studio Team Services?

I've just started trying to configure a CI/CD process using Visual Studio Team Services, with a view to having a gated check-in process which then automatically packs and pushes the output to a private NuGet Feed. I'm successfully getting through the "Get Sources" task which exists natively in the build definition, however my package task is failing at this stage:
d:\a\_tool\NuGet\4.0.0\x64\nuget.exe pack
d:\a\1\s\Core\Core\Core.csproj -NonInteractive -
OutputDirectory d:\a\1\a -Properties Configuration=$Release;OutDir=$(OutDir)
-Symbols -version 1.0.0-CI-20170811-095629 -Verbosity Detailed
NuGet Version: 4.0.0.2283
Attempting to build package from 'Core.csproj'.
MSBuild auto-detection: using msbuild version '14.0' from 'C:\Program Files (x86)\MSBuild\14.0\bin\amd64'. Use option -MSBuildVersion to force nuget to use a specific version of MSBuild.
NuGet.CommandLine.CommandLineException: Unable to find 'd:\a\1\s\Core\Core\$(OutDir)\Core.dll'. Make sure the project has been built.
Essentially, the 2nd line of the log demonstrates that my project file is in d:\a\1\s, however the output is directed to d\a\1\a - not the same place. The instruction to NuGet to package my file then looks in the correct location (d:\a\1\s), but the file isn't here.
I understand that I can specify a Package Folder within the build definition, however I've not changed this from the default ($(Build.ArtifactStagingDirectory)) - I expect this to work natively, but for reasons I can't explain, it's not.
Is there a token or wildcard I can provide in an additional build property that will rectify this? I've taken the guidance of the first posted answer in here and changed $(Build.ArtifactStagingDirectory) to $(Build.Repository.LocalPath), which gets me much closer to the goal as the error now reads -OutputDirectory d:\a\1\s\... - I've tried manually putting a variety of sensible paths no the end of this, but the error persists.
Refer to this article. It has the build variables for the TFS/VSTS environment.
$(Build.ArtifactStagingDirectory) itself refers to the \1\a folder. You might want to try the $(Build.Repository.LocalPath) variable.
Not a 100% if it would work, but might as well try.
The issue is related to OutDir=$(OutDir) instead of OutputDirectory.
The OutputDirectory specifies the folder in which the created package is stored and the OutDir specifies the build output, but the project need to be built before NuGet pack task, so you need to add Visual Studio Build task or related to build project.
You can leave Additional build properties box blank to use default output per to configuration, because you just need to know the package stored path to push package to remote feed.
If you want to change build output, you can specify /p:OutDir msbuild argument to change build output location. For example:
Visual Studio Build task (MSBuild Arguments: /p:OutDir=$(Build.ArtifactStagingDirectory))
NuGet pack task (Additional build properties: OutDir=$(Build.ArtifactStagingDirectory))
BTW, to change package stored location, you need to specify OutputDirectory.

How do I get enumerate the PropertyGroup elements in a csproj file from powershell

I'm writing a nuget install script in powershell and I want to access to all the PropertyGroup elements of the project file (*.csproj)?
I have access to a variable called $project which represents an object, I believe it to implement the Project interface from EnvDTE - an abstraction of the project file (*.csproj).
How does I get the PropertyGroup instances from the $project object?
I want the ability from the nuget install powershell script to change the
OutputPath for all PropertyGroup elements that contain this child element.
PropertyGroup is an internal implementation (MSBuild technology) of the .csproj file, and EnvDTE.Project is an interface, so with EnvDTE.Project you can't get or modify directly the MSBuild elements, because in fact before VS 2005 the .csproj was not MSBuild-based and the EnvDTE.Project interface already existed and worked with the previous technology.
But being an interface, you can certainly do your task:
The OutputPath is a property of each project configuration. You can get all the configurations of an EnvDTE.Project as explained in:
HOWTO: Get the projects configurations / platforms from a Visual Studio add-in
(add-ins use EnvDTE)
and once you have an EnvDTE.Configuration, you can access its EnvDTE.Configuration.Properties collection and specifically the "OutputPath". See:
HOWTO: Get the output build folder from a Visual Studio add-in or macro
Once all the project configurations are changed, you can call EnvDTE.Project.Save or EnvDTE.Project.SaveAs passing the EnvDTE.Project.FullName value as parameter.
I found this answer which led me to the solution: Transforming .csproj using nuget package
Here is the script I used in the NuGet package:
$msbuild = [Microsoft.Build.Evaluation.ProjectCollection]::GlobalProjectCollection.GetLoadedProjects($project.FullName) | Select-Object -First 1
($msbuild.Xml.PropertyGroups | Select-Object -First 1).AddProperty("TypeScriptCompileBlocked", "true")
$project.Save()