'Issue restoring local NuGet package through Azure Pipelines

I have come across an issue in Azure Pipelines where I have a local NuGet package in my repo that I wish to include in the pipelines build alongside all other NuGet packages (which are all picked up from nuget.org normally). My project is built on ASP.NET Core, more specifically it is a Blazor server-side web application.

The local NuGet package "Breeze.Sharp.0.9.6.nupkg" is stored in my repo under: MySolution/packages

What is happening is that the nuget.org packages restore OK in pipelines but it fails when it tries to find my local NuGet package location and throws the below error:

     1>/usr/share/dotnet/sdk/3.1.402/NuGet.targets(128,5): error : The local source '/home/vsts/work/1/Nuget/MySolution/packages' doesn't exist. [/home/vsts/work/1/s/MySolution/MySolution.sln]
         NuGet.Protocol.Core.Types.FatalProtocolException: The local source '/home/vsts/work/1/Nuget/MySolution/packages' doesn't exist.
            at NuGet.Protocol.LocalV3FindPackageByIdResource.GetVersionsCore(String id, ILogger logger)
            at NuGet.Protocol.LocalV3FindPackageByIdResource.<>c__DisplayClass22_0.<GetVersions>b__0(String keyId)
            at System.Collections.Concurrent.ConcurrentDictionary`2.GetOrAdd(TKey key, Func`2 valueFactory)
            at NuGet.Protocol.LocalV3FindPackageByIdResource.GetVersions(String id, SourceCacheContext cacheContext, ILogger logger)
            at NuGet.Protocol.LocalV3FindPackageByIdResource.GetAllVersionsAsync(String id, SourceCacheContext cacheContext, ILogger logger, CancellationToken cancellationToken)
            at NuGet.Commands.SourceRepositoryDependencyProvider.GetAllVersionsAsync(String id, SourceCacheContext cacheContext, ILogger logger, CancellationToken cancellationToken)
            at NuGet.Commands.SourceRepositoryDependencyProvider.FindLibraryCoreAsync(LibraryRange libraryRange, SourceCacheContext cacheContext, ILogger logger, CancellationToken cancellationToken)
            at NuGet.Commands.SourceRepositoryDependencyProvider.<>c__DisplayClass19_0.<<FindLibraryAsync>b__0>d.MoveNext()
         --- End of stack trace from previous location where exception was thrown ---
            at NuGet.Commands.SourceRepositoryDependencyProvider.FindLibraryAsync(LibraryRange libraryRange, NuGetFramework targetFramework, SourceCacheContext cacheContext, ILogger logger, CancellationToken cancellationToken)
            at NuGet.DependencyResolver.ResolverUtility.<>c__DisplayClass9_1.<<FindLibraryFromSourcesAsync>b__0>d.MoveNext()
         --- End of stack trace from previous location where exception was thrown ---
            at NuGet.DependencyResolver.ResolverUtility.FindLibraryFromSourcesAsync(LibraryRange libraryRange, IEnumerable`1 providers, Func`2 action)
            at NuGet.DependencyResolver.ResolverUtility.FindLibraryByVersionAsync(LibraryRange libraryRange, NuGetFramework framework, IEnumerable`1 providers, SourceCacheContext cacheContext, ILogger logger, CancellationToken token)
            at NuGet.DependencyResolver.ResolverUtility.FindPackageLibraryMatchAsync(LibraryRange libraryRange, NuGetFramework framework, IEnumerable`1 remoteProviders, IEnumerable`1 localProviders, SourceCacheContext cacheContext, ILogger logger, CancellationToken cancellationToken)
            at NuGet.DependencyResolver.ResolverUtility.FindLibraryMatchAsync(LibraryRange libraryRange, NuGetFramework framework, String runtimeIdentifier, IEnumerable`1 remoteProviders, IEnumerable`1 localProviders, IEnumerable`1 projectProviders, IDictionary`2 lockFileLibraries, SourceCacheContext cacheContext, ILogger logger, CancellationToken cancellationToken)
            at NuGet.DependencyResolver.ResolverUtility.FindLibraryEntryAsync(LibraryRange libraryRange, NuGetFramework framework, String runtimeIdentifier, RemoteWalkContext context, CancellationToken cancellationToken)
            at NuGet.DependencyResolver.RemoteDependencyWalker.CreateGraphNode(LibraryRange libraryRange, NuGetFramework framework, String runtimeName, RuntimeGraph runtimeGraph, Func`2 predicate, GraphEdge`1 outerEdge, TransitiveCentralPackageVersions transitiveCentralPackageVersions)
            at NuGet.DependencyResolver.RemoteDependencyWalker.CreateGraphNode(LibraryRange libraryRange, NuGetFramework framework, String runtimeName, RuntimeGraph runtimeGraph, Func`2 predicate, GraphEdge`1 outerEdge, TransitiveCentralPackageVersions transitiveCentralPackageVersions)
            at NuGet.DependencyResolver.RemoteDependencyWalker.WalkAsync(LibraryRange library, NuGetFramework framework, String runtimeIdentifier, RuntimeGraph runtimeGraph, Boolean recursive)
            at NuGet.Commands.ProjectRestoreCommand.WalkDependenciesAsync(LibraryRange projectRange, NuGetFramework framework, String runtimeIdentifier, RuntimeGraph runtimeGraph, RemoteDependencyWalker walker, RemoteWalkContext context, CancellationToken token)
            at NuGet.Commands.ProjectRestoreCommand.TryRestoreAsync(LibraryRange projectRange, IEnumerable`1 frameworkRuntimePairs, NuGetv3LocalRepository userPackageFolder, IReadOnlyList`1 fallbackPackageFolders, RemoteDependencyWalker remoteWalker, RemoteWalkContext context, Boolean forceRuntimeGraphCreation, CancellationToken token, TelemetryActivity telemetryActivity)
            at NuGet.Commands.RestoreCommand.ExecuteRestoreAsync(NuGetv3LocalRepository userPackageFolder, IReadOnlyList`1 fallbackPackageFolders, RemoteWalkContext context, CancellationToken token, TelemetryActivity telemetryActivity)
            at NuGet.Commands.RestoreCommand.ExecuteAsync(CancellationToken token)
            at NuGet.Commands.RestoreRunner.ExecuteAsync(RestoreSummaryRequest summaryRequest, CancellationToken token)
            at NuGet.Commands.RestoreRunner.ExecuteAndCommitAsync(RestoreSummaryRequest summaryRequest, CancellationToken token)
            at NuGet.Commands.RestoreRunner.CompleteTaskAsync(List`1 restoreTasks)
            at NuGet.Commands.RestoreRunner.RunAsync(IEnumerable`1 restoreRequests, RestoreArgs restoreContext, CancellationToken token)
            at NuGet.Commands.RestoreRunner.RunAsync(RestoreArgs restoreContext, CancellationToken token)
            at NuGet.Build.Tasks.BuildTasksUtility.RestoreAsync(DependencyGraphSpec dependencyGraphSpec, Boolean interactive, Boolean recursive, Boolean noCache, Boolean ignoreFailedSources, Boolean disableParallel, Boolean force, Boolean forceEvaluate, Boolean hideWarningsAndErrors, Boolean restorePC, Boolean cleanupAssetsForUnsupportedProjects, ILogger log, CancellationToken cancellationToken)
            at NuGet.Build.Tasks.RestoreTask.ExecuteAsync(ILogger log)
       Done executing task "RestoreTask" -- FAILED.
     1>Done building target "Restore" in project "MySolution.sln" -- FAILED.
     1>Done Building Project "/home/vsts/work/1/s/MySolution/MySolution.sln" (Restore target(s)) -- FAILED.

Build FAILED.

       "/home/vsts/work/1/s/MySolution/MySolution.sln" (Restore target) (1) ->
       (Restore target) -> 


My first thoughts were the same as anyone elses... AH the path must be incorrect! However... I cannot seem to get it to work after trying various different paths to get to the packages folder to pick up my local NuGet package.

To assist, my config files are below.

azure-pipelines.yml:

trigger:
- master

pool:
  vmImage: 'ubuntu-latest'

variables:
  buildConfiguration: 'Release'

steps:   
- task: NuGetToolInstaller@1
  displayName: 'Use NuGet 4.9.1'
  inputs:
    versionSpec: 4.9.1

- task: DotNetCoreCLI@2
  displayName: 'Restore NuGet Packages'
  inputs:
    command: 'restore'
    projects: '**/*.sln'
    feedsToUse: 'config'
    nugetConfigPath: 'MySolution/NuGet.Config'

- task: DotNetCoreCLI@2
  displayName: 'Build web project'
  inputs:
    command: 'build'
    projects: $(SolutionPath)
    

NuGet.Config:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
    <packageSources>
        <clear />
        <add key="nuget.org" value="https://api.nuget.org/v3/index.json" protocolVersion="3" />
        <add key="LocalPackages" value="MySolution/packages" />
    </packageSources>
</configuration>

The part in question I have been messing about with is the "LocalPackages" element which is where I thought the issue could be, so have been trying all sorts of combinations of paths to try and narrow it down - but no luck - which has made me think this could be a red herring, but you never know I could be doing something stupid!

I understand there are best practices which can be followed here such as creating my own Artifacts feed of NuGet packages for maintainability, but this is going to be a refinement phase later for me, my focus at the moment is just to simply get the pipeline in a build state ready for deployment and testing.

Any help or guidance on this or things I can try to fix this would be greatly appreciated!

Let me know if more specific info is needed and I can provide!

Thank you.



Solution 1:[1]

It is the local packages path that causes the problem. You should set the value as <add key="LocalPackages" value="../s/MySolution/packages" />

If you check the dotnet restore task log, you will find a temp config was created, And the restore task was using this temp config file. See below.

enter image description here

So the LocalPackages path you specified in nuget.config file is relative to the temp config folder /home/vsts/work/1/Nuget.

Since your project is cloned in folder /home/vsts/work/1/s (ie. $(system.defaultworkingdirectory)). You should specify the LocalPackages path like below:

<add key="LocalPackages" value="../s/MySolution/packages" />

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Levi Lu-MSFT