Multiple versions of a package in Azure Artifact - azure-devops

I've set up an artifact feed in Azure Devops and pushed some of our private packages to it using "nuget.exe push".
The problem I have is some packages have multiple versions (e.g. 1.1, 1.2, 1.3 etc) and we have a number of projects where some will use 1.1, some will use 1.2 etc.
After uploading versions 1.1, 1.2 and 1.3 to the artifact feed, only 1.3 is available to my projects as it is the latest version. If I click into the uploaded package in the Devops interface I can see the previous versions, but none of the devops projects that use 1.1 or 1.2 will build as they can't find the older versions.
I've read in a few places that a way around it would be to have one artifact feed per project, with the required versions pushed to that feed. The issue I have with that is that I've simplified the scale of my problem as in reality we have around 20 packages, each one could have up to 30 different versions, and I have around 50 projects. To create a feed for each one would be massively time consuming and would involve duplicating a lot of packages when I push them.
If I add any package to a project from nuget, I get to choose which version I want to add but it seems like I can't replicate this when using an artifact feed. Am I doing this incorrectly or is there a better way to achieve what I need?
EDIT:
I'm not using a project-scoped feed, it is listed in Devops as a organisation-scoped feed.
The packages.config file specifically targets a certain version e.g.
<package id="CommonResourceAssembly" version="2.17.60.0" targetFramework="net451" />
and the error log shows that is can't find this version:
##[error].nuget\NuGet.targets(103,9): Error : Unable to find version '2.17.60.0' of package 'CommonResourceAssembly'.
The feed itself shows that version 2.17.61 is the current one, but 2.17.60 is what is needed for this particular project and does appear in the version history:

Am I doing this incorrectly or is there a better way to achieve what I need?
I am afraid you may have made some incorrect settings. That because the Azure Artifact supports multiple versions of a packages. That also is reason why you can see the previous versions in the Devops interface.
When we use the nuget restore in the Azure devops pipeline, nuget restore task will restore the package according to the version of the package specified in the packages.config/PackageReference, like:
Packages.config:
<packages>
<package id="Newtonsoft.Json" version="8.0.3" targetFramework="net46" />
</packages>
PackageReference:
<ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="8.0.3" />
</ItemGroup>
So, please check the following possibilities that may cause this issue:
Check if your Azure Artifact is project scoped feeds(If your Azure Artifact feeds are created before 11/4/2019, please go to second point):
Check if you use wildcards in the packages.config/PackageReference:
<PackageReference Include="Packagename" Version="1.*" />
Check if there is a nuget.config in your solution with following settings:
<configuration>
<config>
<add key="dependencyversion" value="Highest" />
</config>
</configuration>
If above not help you, please share us more info about this issue, the info/image about the packages.config/PackageReference for the build failed project, info/image about the Azure Artifact including the package version 1.1, 1.2, the latest but not important, the error log.
Hope this helps.

Thanks to the help from #Leo Liu-MSFT I worked out what needed to be modified:
1 Delete the nuget.exe and nuget.targets files from the .nuget folder
2 Delete the references in all .csproj files that pointed to the nuget.targets file:
<Import Project="$(SolutionDir)\.nuget\NuGet.targets" Condition="Exists('$(SolutionDir)\.nuget\NuGet.targets')" /> <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('$(SolutionDir)\.nuget\NuGet.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\.nuget\NuGet.targets'))" /> </Target>
3 Add a step in the pipeline YAML before the build that looks at the nuget.config file to restore the packages:
task: NuGetCommand#2
displayName: 'NuGet restore'
inputs:
restoreSolution: '**\*.sln'
feedsToUse: config
nugetConfigPath: '.nuget/NuGet.config'
This now builds the solution correctly and can reference any previous version of a package

Related

Referenced DLL not working in Azure build pipeline

We have upgraded our TFS server to Azure Git, but few old projects are still sitting in TFS. one of my new project needs to reference the dll from the old project from TFS. Everything working ok locally, but Azure build pipeline is failing due to "can't find the reference to dll". How can I reference a dll from TFS project in Azre build pipeline?
This is the path in the project file
<ItemGroup>
<Reference Include="Apps.Reserve">
<HintPath>..\..\..\..\Apps\Reserve\bin\Debug\Apps.Reserve.dll</HintPath>
</Reference>
You use MSBuild hardcoded paths which work as a fallback for MSBuild and you shouldn't assume that they will be filled with DLLs on new standalone agents.
You should create lib folder from which you will take libraries or create a NuGet feed server (or folder) and setup it up through nuget.config.
From csproj
<ItemGroup>
<Reference Include="lib\$(TargetFramework)\*.dll" HintPath="%(FilePath)" />
</ItemGroup>
Or from nuget.config
<config>
<add key="globalPackagesFolder" value="<your path>" />
</config>
It's up to you which approach you will take but from my perspective the best approach is to create your own NuGet Server. Migrate all artifacts there and then migrate projects to Azure Pipelines.
Old TFS "thinking" isn't the best approach to handling feeds.

azure devops & public nuget upstreams behavior when building

I tried to follow the best practices by using a single feed from the client. So I've setup a Nuget.config file with a single entry to my feed, with a <clear/> tag as stated in the doc.
On the devops server side, I've set up the feed with an Upstream source to the public Nuget Gallery (in order to cache, as this sounded nice in case of public package managers outages.
When I directly use the nuget.exe client on any machine, I can install any nuget.org package in any case. But at build time, when a public package isn't already in my serve's upstream cache, it won't be found by the build agent... (it seems that in this case, the upstreams isn't been used to feed the cache).
Is this normal? Is it limited to already cached packages at build time?
In our develoment team, we are used to add nuget packages through the VS UI (right click project "manage nuget packages"). In this mode, we can not see those upstreams packages, so we toggle the source to nuget directly at dev time.
The solutions that I found could be either:
to add a second entry to the Nuget.config to declare nuget.org for build (but we loose the caching capability)
to systematically use the command line nuget.exe to install the packages at development time?
What did I miss? Do you have any other ideas/solutions?
EDIT: it seems that it failed due to the following error:
BTW: I'm quite new to Azure Devops (using an on premise version "Dev18.M170.6").
Is this normal? Is it limited to already cached packages at build time?
This is not normal. It is not limited to the cached packages at build time.
For example, I create a new test feed with enable Upstream source to the public Nuget Gallery:
Now only a few packages I tested before are cached, then I add another test package log4net and restore it with my following nuget.config:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<packageSources>
<clear />
<add key="NewFeed" value="https://pkgs.dev.azure.com/<MyOrgName>/_packaging/NewFeed/nuget/v3/index.json" />
</packageSources>
<config>
</config>
<packageSourceCredentials>
<NewFeed>
<add key="Username" value="XXX" />
<add key="ClearTextPassword" value="XXX" />
</NewFeed>
</packageSourceCredentials>
</configuration>
The nuget restore result:
The feed result:
So, It is not limited to the cached packages at build time. The reason why this method is invalid for you requires specific analysis of your nuget restore task log.
As a reminder, please check if project Build Services have permission to access your feed:
Feed settings->Permissions->...->Allow Project-scoped build:
In our develoment team, we are used to add nuget packages through the
VS UI (right click project "manage nuget packages"). In this mode, we
can not see those upstreams packages, so we toggle the source to nuget
directly at dev time.
You could add the upstream source nuget.org as nuget scource in Visual Studio, which you could dd nuget packages through the VS UI. When you build the pipeline in Azure devops, nuget will restore the package from the custom feed and cache the package from upstream source:

Managing nuget versions from beta to release in VS2017 for .net core2.1 when building pipeline in Azure Devops

I need to create nuget package for a .net core 2.1 as part of build and release process in Azure Devops
What I would like to do
1) In the build section build the project and then add the compiled code to artifact
2) In Release definition will have 2 deployments one for Beta release where the version will be like 1.2.3-Beat.2 and push to azure artifact nuget and another deployment to release where the version will be like 1.2.3.2 and push to azure artifact nuget.
Currently I have only one build definition which will build (nuget package gets created during build process) and push to azure artifact nuget.
Pipeline I would like to create
Use the dotnet pack task with the --no-build option, and in your pre-release stage set the VersionSuffix value.
Note: My current team uses a set of Powershell scripts to append build number data to the Major.Minor data found in the .csproj (or AssemblyInfo.cs for netFramework), but that doesn't change the answer to your question. Once you figure out what the Major.Minor.Patch[.Build] data is going to be, you can use the VersionSuffix property in a dotnet pack task with --no-build to communicate quality of the package as it moves through your pipeline.
Given a .csproj file that looks like this:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
</PropertyGroup>
<PropertyGroup>
<PackageVersion>1.0.0.1</PackageVersion>
<AssemblyVersion>1.0.1812.201</AssemblyVersion>
<FileVersion>1.0.1812.201</FileVersion>
</PropertyGroup>
<ItemGroup>
<Content Include="Assemblies\*">
<Pack>true</Pack>
<PackagePath>lib\$(TargetFramework)</PackagePath>
</Content>
</ItemGroup>
</Project>
Again, if we ignore the versioning step that we use, the dotnet pack task in the pipeline image above will produce a package with the version 1.0.0.1-Beta.
Then in your stable release stage, don't set the suffix value and let the package get its version from the .csproj file like normal (eg. 1.0.0.1).
The elements and values in the sample .csproj file above can be written as direct edits to the .csproj or they can be set using the Properties >> Package tab.
If the values are not changed in the properties menu or added explicitly, the elements and values do not appear in the .csproj and are assumed by dotnet build|test|pack commands.
Finding the right combination of these properties and values can be daunting if you aren't familiar with how they're fitted together. I found this article useful when trying to decipher the version properties.
Also, you should understand 1.0.1-b2 < 1.0.1, so your pre-release version might be 1.2.3.2-beta1 and your stable version would be 1.2.3.2.
As the package version is included the moment you perform 'nuget pack', which you would generally perform during build, it might become a bit complicated to change that version afterwards.
What may be interesting in your case is using the concept of views in Azure Artifacts, this would allow you to promote a package to the release view at a later state without having to rebuild the package.
There is a nice extension on the marketplace that would allow you to do this from within a release: https://marketplace.visualstudio.com/items?itemName=rvo.vsts-promotepackage-task
using this flow you can have the packages in the pre-release view/feed as long as you like and make them available in the release view whenever you see fit.
downside of this is that the packages are not identified as pre-release packages by Nuget as you would not be packaging them with the proper semver for that

Consuming Nuget packages with specific pre-release tag

In our dev environment, we have a Git repo which houses a common component. This repo has multiple feature branches which are publishing Nuget packages through a CI build to a common feed. In the feed, packages coming from these feature branches are identified with a prerelease tag of the branch name. As a consumer, I am looking into this feed through sources mentioned in Nuget.config file. And, I am trying to consume packages coming from a particular feature branch of that common component. But the Nuget update command which I am calling from consumer project can potentially pull a pre-release version from other branch if that package has a higher version. Pls share your inputs on how to resolve this. I am not seeing any additional arguments in update command to mention the specific pre-release tag
Thanks
Sandeep
There are a few options:
Use different feeds - clearly most complicated from the infrastructure point of view unless you can easily create feeds through a service. But this makes "update everything" commands easy.
Give those packages a different identity (name), so can publish My.Product.With.FeatureA and My.Product.With.FeatureB.
Use allowedVersions in packages.config to restrict updates to a version range. For this you might also need to use different minor/patch versions and not only prerelease tags for packages.
When using the new PackageReference format in VS 2017 15.1+ (already released), you have some more options
Use floating references for parts of the perelease tag. e.g. 1.2.3-coolfeatureA-*.
Since PackageReference is used from MSBuild, you can also define a central feature and build version (e.g. in a Directory.Build.props file) and use these in package references. E.g. you could use definitions like this in your csproj file:
<ItemGroup>
<PackageReference Include="My.Shared.LibA" Version="1.2.3-$(LibsFeatureBranch)-$(LibsBuildNumber)" />
<PackageReference Include="My.Shared.LibB" Version="1.2.3-$(LibsFeatureBranch)-$(LibsBuildNumber)" />
</ItemGroup>
Together with a Directory.Build.props file (at project or solution level) containing:
<Project>
<PropertyGroup>
<LibsFeatureBranch>CoolFeatureA</LibsFeatureBranch>
<LibsBuildNumber>20170510-</LibsBuildNumber>
</PropertyGroup>
</Project>

How do I update a single nuget package in a project from the command line?

I am trying to update a single package in a csproj with multiple dependencies. That is, the packages.config file looks like this:
<packages>
<package id="PackageA" version="1.2.1" targetFramework="net40" />
<package id="PackageB" version="2.3.4" targetFramework="net40" />
<package id="PackageC" version="1.0.0" targetFramework="net40" />
</packages>
I'd like to update PackageA without updating the others. I see that Update-Package in the Visual Studio package manager has this capability, but this needs to run on a TFS build machine.
Is there a way to do this from the command line? The anticipated workflow is the build machine running
Nuget.exe restore
Nuget.exe update (on each csproj file)
But the update command does not allow us to specify which package to update on. I know there is an allowedVersions tag for the packages, but that is would require us to change the packages.config file when creating different branches that require different components to update or not, whereas a package-specific, csproj-specific command-line would allow us to associate the dependencies to update with each TFS branch via its build definitions.
nuget.exe update has an -Id argument that specifies the project. So, for instance,
nuget.exe update X.csproj -Id PackageA