<# .SYNOPSIS List and delete package versions in the Gitea NuGet registry. .DESCRIPTION Listing without -Token uses the anonymous NuGet v3 search endpoint - the same view Q-SYS Designer gets, so it doubles as a feed health check. Listing with -Token uses Gitea's management API and adds publish dates. Deleting always requires -Token (package write scope). .EXAMPLE ./tools/packages.ps1 -List -Owner jodamaster ./tools/packages.ps1 -List -Owner jodamaster -Id ExamplePlugin -Token $env:GITEA_TOKEN ./tools/packages.ps1 -Delete -Owner jodamaster -Id ExamplePlugin -Version 1.0.0 -Token $env:GITEA_TOKEN #> [CmdletBinding(DefaultParameterSetName = "List")] param( [Parameter(ParameterSetName = "List")] [switch]$List, [Parameter(ParameterSetName = "Delete", Mandatory)] [switch]$Delete, [string]$GiteaUrl = "https://3f4dzl.gitea.cloud", [Parameter(Mandatory)] [string]$Owner, [Parameter(ParameterSetName = "List")] [Parameter(ParameterSetName = "Delete", Mandatory)] [string]$Id, [Parameter(ParameterSetName = "Delete", Mandatory)] [string]$Version, [string]$Token, # required for -Delete; optional for -List (adds publish dates) [switch]$Force # skip the delete confirmation prompt ) $ErrorActionPreference = "Stop" $base = $GiteaUrl.TrimEnd('/') $headers = @{} if ($Token) { $headers["Authorization"] = "token $Token" } # ---------------- Delete ---------------- if ($PSCmdlet.ParameterSetName -eq "Delete") { if (-not $Token) { throw "Deleting requires -Token (package write scope)." } if (-not $Force) { $answer = Read-Host "Delete $Id $Version from $Owner's registry? This is immediate and permanent. [y/N]" if ($answer -notmatch '^[Yy]') { Write-Host "Aborted."; exit 0 } } $uri = "$base/api/packages/$Owner/nuget/$Id/$Version" Invoke-RestMethod -Uri $uri -Headers $headers -Method Delete | Out-Null Write-Host "Deleted $Id $Version." -ForegroundColor Green Write-Host "Note: Q-SYS expects strictly ascending versions - prefer publishing a higher" Write-Host "version over deleting and re-using a version number (clients may have cached it)." exit 0 } # ---------------- List ---------------- if ($Token) { # Management API: full info including publish dates (requires sign-in on Gitea Cloud) $all = @(); $page = 1 while ($true) { $uri = "$base/api/v1/packages/$($Owner)?type=nuget&limit=50&page=$page" $batch = Invoke-RestMethod -Uri $uri -Headers $headers -Method Get if (-not $batch -or $batch.Count -eq 0) { break } $all += $batch if ($batch.Count -lt 50) { break } $page++ } if ($Id) { $all = $all | Where-Object { $_.name -ieq $Id } } if (-not $all -or $all.Count -eq 0) { Write-Host "No packages found."; exit 0 } $all | Sort-Object name, created_at | Group-Object name | ForEach-Object { Write-Host "`n$($_.Name)" -ForegroundColor Cyan $_.Group | ForEach-Object { $created = ([datetime]$_.created_at).ToLocalTime().ToString("yyyy-MM-dd HH:mm") Write-Host (" {0,-20} published {1}" -f $_.version, $created) } } } else { # Anonymous NuGet v3 search - exactly what Q-SYS Designer sees $q = if ($Id) { $Id } else { "" } $uri = "$base/api/packages/$Owner/nuget/query?q=$q&skip=0&take=100" $result = Invoke-RestMethod -Uri $uri -Method Get $items = $result.data if ($Id) { $items = $items | Where-Object { $_.id -ieq $Id } } if (-not $items -or $items.Count -eq 0) { Write-Host "No packages visible in the anonymous feed for '$Owner'."; exit 0 } foreach ($pkg in $items) { Write-Host "`n$($pkg.id) (latest: $($pkg.version))" -ForegroundColor Cyan foreach ($v in $pkg.versions) { Write-Host " $($v.version)" } Write-Host " Designer 'Add Personal Package' URL:" -ForegroundColor DarkGray Write-Host " $base/api/packages/$Owner/nuget/registration/$($pkg.id)/index.json" -ForegroundColor Yellow } Write-Host "`n(Anonymous view = what Q-SYS Designer sees. Add -Token for publish dates.)" } Write-Host ""