would also be helpfull with a nuget example
⚠Do not edit this section. It is required for docs.microsoft.com ➟ GitHub issue linking.
Not really practical without wildcard support in keys (need to list all packages.config / csproj files), I guess they are waiting for if before adding the Nuget example.
Presumably this will require https://github.com/NuGet/Home/wiki/Centrally-managing-NuGet-packages to be available, since there isn't currently in-box support for a single 'package.lock' analog, similar to yarn and npm.
However, one could probably come pretty close if relying on the Microsoft.Build.CentralPackageVersions nuget package. Once you set up a solution with a Packages.props file, that file could act as the key, with the version numbers centrally managed. It's not a perfect translation, since transitive dependency versions aren't required to be mentioned, but I _think_ it would get the job done in a CI scenario.
I sketched out what the tasks would presumably look like, but I haven't been able to test because this update isn't yet deployed on my tenant of choice.
variables:
NUGET_PACKAGES: $(Pipeline.Workspace)/.nuget
steps:
- task: CacheBeta@0
inputs:
key: |
nuget
$(Build.SourcesDirectory)/Package.props
path: $(NUGET_PACKAGES)
displayName: Cache nuget packages
- task: NuGetCommand@2
displayName: 'NuGet restore **/*.sln'
inputs:
restoreSolution: '**/*.sln'
Note that this requires usage of <PackageReference> in all projects, since this restores packages to the global cache at $(NUGET_PACKAGES)
Why couldn't you cache the entire C:\Users\[username]\.nuget\packages directory?
The existing document's guidance recommends caching directories within the $(Pipeline.Workspace), so I incorporated that into my example. If pipeline caching can work in any directory, I suppose caching a user directory would work, but some downsides that come to mind:
Given that, setting the directory using the already-available environment variable certainly seems more robust.
@RehanSaeed. Because once created, cache contents are immutable (See above). You need a method to determine whether to rebuild the cache.
One option (short of using centralized versions), is to generate a string containing all the distinct PackageReference and/or packages.config entries in sorted order and use a hash as the cache key,
I see that a Nuget example has been added now, but I feel it's misleading. packages.lock.json is only available at the _project level_ right now. This might work for single-project solutions, but I doubt this is the norm for .Net applications.
To generate the key I wrote a powershell script to grab all of the NuGet package references from a solution (below) and run this powershell script in the pipeline before the cache task. It's working using the sample above with NUGET_PACKAGES variable set to $(Pipeline.Workspace)/.nuget/packages
==================== Yaml pipeline
- task: CacheBeta@0
displayName: 'Restore cache'
inputs:
key: 'scripts/packages.txt'
path: '$(NUGET_PACKAGES)'
==================== Create-Solution-Nuget-Packages-Hash.ps1
param
(
[string] $solutionPath=$(throw "The solution path is required"),
[string] $outputFilePath="$PSScriptRoot/packages.txt"
)
if(!(Test-Path $solutionPath)) {
Throw [System.IO.FileNotFoundException] "No solution file was found at $solutionPath"
}
Set-Location -Path (get-item $solutionPath).Directory
$projectList = Get-Content $solutionPath | where { $_ -Match ".csproj" } | where { $_ -match "Project.+, ""(.+)""," } | foreach { $matches[1] } | % { Get-Content $_ }
$nugetPackageList = [System.Collections.Generic.List[string]]::new()
foreach($i in $($projectList -split "rn")){
if($i -match "
}
}
$nugetPackageList = $nugetPackageList | Sort-Object -Unique
Write-Host "NuGet packages:"
Write-Host "=============="
Write-Host $nugetPackageList
Write-Host "=============="
Set-Content -Path "$outputFilePath" -Value $nugetPackageList -Force
Write-Host "Wrote list of NuGet packages to $outputFilePath"
In case it's not obvious the sample for powershell yaml is below but in reality I use the Agent.TempDirectory
- task: PowerShell@2
inputs:
filePath: 'scripts/Create-Solution-Nuget-Packages-Hash.ps1'
arguments: '-solutionPath "Test.sln" -outputFilePath "scripts/packages.txt"'
failOnStderr: true
pwsh: true
@dammejed @alanwales Comparing to the Maven example, would this not work?
- task: CacheBeta@0
inputs:
key: nuget | **/packages.lock.json
path: $(NUGET_PACKAGES)
displayName: Cache NuGet packages
Thanks for the tip, was not aware of this, looks like an easy option to add to projects
https://devblogs.microsoft.com/nuget/enable-repeatable-package-restores-using-a-lock-file/
Would be great to have a version of the task that is package ecosystem aware eg a select box with ‘npm,nuget,yarn,custom’ with some logic in each option like ‘use lock file’ or ‘use package references in solution file’ etc?
This issue hasn't been updated in more than 180 days, so we've closed it. If you feel the issue is still relevant and needs fixed, please reopen it and we'll take another look. We appreciate your feedback and apologize for any inconvenience.
Most helpful comment
Thanks for the tip, was not aware of this, looks like an easy option to add to projects
https://devblogs.microsoft.com/nuget/enable-repeatable-package-restores-using-a-lock-file/
Would be great to have a version of the task that is package ecosystem aware eg a select box with ‘npm,nuget,yarn,custom’ with some logic in each option like ‘use lock file’ or ‘use package references in solution file’ etc?