I would like to cleanup our nuget repositories to only have the latest version of each package. Is there a simple way to do that?
Hi, Orion! That’s a good question; the answer is “kind of,” and it depends on your use case.
What’s the goal here? Are you trying to free up space, get developers to use certain packages, reduce risk, etc. etc.?
Reduce disk space - we only install the latest version of packages so we don’t need the old versions.
Okay, thank you! There’s not an easy way to eliminate everything but the latest version in a nuget repository. If disk space is your concern, adjust your cleanup policies to be more aggressive. I’m sure you know there’s a huge variance in the release cadence of nuget packages, so I can’t recommend a default value, but since the issue is disk space, go low!
Preview the results with the button at the bottom of the “Create Cleanup Policy” page to get a sense for how effective your policy will be, and be sure you have Cleanup Tasks and Compact Blob Store Tasks to actually reclaim the disk space.
I find the included cleanup options limited for what I’m interested in. I ended up with the following script run as a jenkins task to handle the cleanup:
[CmdletBinding()]
param (
[Parameter(Mandatory)]
[string]
$ProdRepoApiKey,
[Parameter(Mandatory)]
[PSCredential]$Credential
)
# List of Nexus server URLs
$servers = @(
"https://repo1.example.com:8443",
"https://repo2.example.com"
)
# Helper function to get NuGet repositories
function Get-NuGetRepositories {
param ($ServerUrl)
$uri = "$ServerUrl/service/rest/v1/repositories"
$response = Invoke-RestMethod -Uri $uri -Headers @{Accept = "application/json"} -Authentication Basic -Credential $Credential -Verbose:$false
return $response | Where-Object { $_.format -eq "nuget" -and $_.type -ne "group" } | Select-Object -ExpandProperty name
}
# Helper function to get components
function Get-Components {
param ($ServerUrl, $Repository, $Token)
$uri = "$ServerUrl/service/rest/v1/components?repository=$Repository"
if ($Token) {
$uri += "&continuationToken=$Token"
}
return Invoke-RestMethod -Uri $uri -Headers @{Accept = "application/json"} -Authentication Basic -Credential $Credential -Verbose:$false
}
# Helper function to delete a component
function Delete-Component {
param ($ServerUrl, $Component)
$uri = "$ServerUrl/service/rest/v1/components/$($Component.id)"
$response = Invoke-WebRequest -Uri $uri -Method Delete -Authentication Basic -Credential $Credential -ErrorAction SilentlyContinue -Verbose:$false -SkipHTTPErrorCheck
#$response = @{'StatusCode' = 204}
if ($response.StatusCode -eq 204) {
Write-Verbose "Deleted $($Component.name)/$($Component.version) $($Component.assets) $($Component.assets.Count) component $($Component.id) from $ServerUrl"
} else {
Write-Warning "Failed to delete $($Component.name)/$($Component.version) $($Component.id) from ${ServerUrl}: $($response.StatusCode)"
}
}
# Main logic
foreach ($serverUrl in $servers) {
try {
$repos = Get-NuGetRepositories -ServerUrl $serverUrl
foreach ($repo in $repos) {
Write-Verbose "Processing repository '$repo' on $serverUrl"
$token = $null
do {
$result = Get-Components -ServerUrl $serverUrl -Repository $repo -Token $token
foreach ($component in $result.items) {
$assets = $component.assets
if ($assets.Count -eq 0) { continue }
$allNotLatest = $true
foreach ($asset in $assets) {
# Do not delete if filesize is 0 - chocolatey repo has stub entries
if ($asset.nuget -and $asset.nuget.is_latest_version -eq $true -or $asset.fileSize -eq 0) {
$allNotLatest = $false
break
}
}
if ($allNotLatest) {
Delete-Component -ServerUrl $serverUrl -Component $component
}
}
$token = $result.continuationToken
} while ($token)
}
} catch {
Write-Error "Error processing ${serverUrl}: $_"
}
}