2 Commits

Author SHA1 Message Date
gsadmin 09af8939c7 Merge pull request 'Fix certificate chain install hang, elevation-aware stores, and idempotent gallery publish' (#20) from dev into main
Reviewed-on: #20
2026-07-30 23:20:57 +00:00
gsadmin dadba2f4c8 Make the PowerShell Gallery publish step idempotent
Publish to PowerShell Gallery / build (pull_request) Successful in 25s
Publish to PowerShell Gallery / release (pull_request) Successful in 10s
Publish to PowerShell Gallery / publish (pull_request) Successful in 8s
The publish job failed on PR #19 with a 409 for version 2026.7.30.2309, but
that version is live on the gallery (created 23:10:04) - the push landed and
the client still surfaced an error, so the retry collided with the upload that
had just succeeded. The run went red over a publish that actually worked.

The step now checks the gallery before pushing and skips when the version is
already there, and on a publish error it re-checks before failing. This mirrors
the release job, which already looks for an existing tag and skips.

Version comparison normalizes each segment the way NuGet does, since the
manifest carries zero-padded segments (2026.07.30.2309) while the gallery lists
the stripped form (2026.7.30.2309); comparing the raw strings would never match
and the guard would never fire.

Verified: both workflows still parse as YAML with the same three jobs, the
normalizer reproduces the gallery form for four published versions, and a live
lookup confirms the guard would have exited 0 on the run that failed.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-30 19:15:13 -04:00
2 changed files with 124 additions and 12 deletions
+62 -6
View File
@@ -319,9 +319,65 @@ jobs:
run: |
$ErrorActionPreference = 'Stop'
$moduleDir = Join-Path $PWD 'Module/PSInfisicalAPI'
Write-Host "Publishing module from: $moduleDir"
Publish-PSResource `
-Path $moduleDir `
-Repository PSGallery `
-ApiKey $env:PSGALLERY_API_KEY `
-Verbose
$manifest = Test-ModuleManifest -Path (Join-Path $moduleDir 'PSInfisicalAPI.psd1')
$version = $manifest.Version.ToString()
# NuGet strips leading zeros from each segment, so the manifest's 2026.07.30.2309 is listed on the
# gallery as 2026.7.30.2309. Compare on the normalized form or every lookup misses.
function Get-NormalizedVersion {
param([string]$Value)
$parts = $Value -split '\.'
$normalized = foreach ($part in $parts) {
$number = 0
if ([int]::TryParse($part, [ref]$number)) { $number.ToString([System.Globalization.CultureInfo]::InvariantCulture) } else { $part }
}
return ($normalized -join '.')
}
function Test-PublishedVersion {
param([string]$Normalized)
$uri = "https://www.powershellgallery.com/api/v2/FindPackagesById()?id='PSInfisicalAPI'&`$select=Version"
try {
$feed = Invoke-RestMethod -Uri $uri -TimeoutSec 120
} catch {
Write-Host "==> Could not query the gallery for existing versions: $($_.Exception.Message)"
return $false
}
foreach ($entry in @($feed)) {
$candidate = $entry.properties.Version
if ([string]::IsNullOrWhiteSpace($candidate)) { continue }
if ((Get-NormalizedVersion -Value $candidate) -eq $Normalized) { return $true }
}
return $false
}
$normalizedVersion = Get-NormalizedVersion -Value $version
Write-Host "==> Module version : $version (gallery form: $normalizedVersion)"
Write-Host "==> Publishing from: $moduleDir"
if (Test-PublishedVersion -Normalized $normalizedVersion) {
Write-Host "==> Version $normalizedVersion is already on the PowerShell Gallery; nothing to publish."
exit 0
}
try {
Publish-PSResource `
-Path $moduleDir `
-Repository PSGallery `
-ApiKey $env:PSGALLERY_API_KEY `
-Verbose
Write-Host "==> Published $normalizedVersion to the PowerShell Gallery."
} catch {
# A push can be accepted by the gallery and still surface as an error here; when that happens the
# retry comes back as 409. Re-check before failing the run over an upload that actually landed.
Write-Host "==> Publish-PSResource reported: $($_.Exception.Message)"
Start-Sleep -Seconds 15
if (Test-PublishedVersion -Normalized $normalizedVersion) {
Write-Host "==> Version $normalizedVersion is present on the gallery; treating the publish as successful."
exit 0
}
throw
}
+62 -6
View File
@@ -320,9 +320,65 @@ jobs:
run: |
$ErrorActionPreference = 'Stop'
$moduleDir = Join-Path $PWD 'Module/PSInfisicalAPI'
Write-Host "Publishing module from: $moduleDir"
Publish-PSResource `
-Path $moduleDir `
-Repository PSGallery `
-ApiKey $env:PSGALLERY_API_KEY `
-Verbose
$manifest = Test-ModuleManifest -Path (Join-Path $moduleDir 'PSInfisicalAPI.psd1')
$version = $manifest.Version.ToString()
# NuGet strips leading zeros from each segment, so the manifest's 2026.07.30.2309 is listed on the
# gallery as 2026.7.30.2309. Compare on the normalized form or every lookup misses.
function Get-NormalizedVersion {
param([string]$Value)
$parts = $Value -split '\.'
$normalized = foreach ($part in $parts) {
$number = 0
if ([int]::TryParse($part, [ref]$number)) { $number.ToString([System.Globalization.CultureInfo]::InvariantCulture) } else { $part }
}
return ($normalized -join '.')
}
function Test-PublishedVersion {
param([string]$Normalized)
$uri = "https://www.powershellgallery.com/api/v2/FindPackagesById()?id='PSInfisicalAPI'&`$select=Version"
try {
$feed = Invoke-RestMethod -Uri $uri -TimeoutSec 120
} catch {
Write-Host "==> Could not query the gallery for existing versions: $($_.Exception.Message)"
return $false
}
foreach ($entry in @($feed)) {
$candidate = $entry.properties.Version
if ([string]::IsNullOrWhiteSpace($candidate)) { continue }
if ((Get-NormalizedVersion -Value $candidate) -eq $Normalized) { return $true }
}
return $false
}
$normalizedVersion = Get-NormalizedVersion -Value $version
Write-Host "==> Module version : $version (gallery form: $normalizedVersion)"
Write-Host "==> Publishing from: $moduleDir"
if (Test-PublishedVersion -Normalized $normalizedVersion) {
Write-Host "==> Version $normalizedVersion is already on the PowerShell Gallery; nothing to publish."
exit 0
}
try {
Publish-PSResource `
-Path $moduleDir `
-Repository PSGallery `
-ApiKey $env:PSGALLERY_API_KEY `
-Verbose
Write-Host "==> Published $normalizedVersion to the PowerShell Gallery."
} catch {
# A push can be accepted by the gallery and still surface as an error here; when that happens the
# retry comes back as 409. Re-check before failing the run over an upload that actually landed.
Write-Host "==> Publish-PSResource reported: $($_.Exception.Message)"
Start-Sleep -Seconds 15
if (Test-PublishedVersion -Normalized $normalizedVersion) {
Write-Host "==> Version $normalizedVersion is present on the gallery; treating the publish as successful."
exit 0
}
throw
}