Publish-PackageToGithub.ps1
|
<#
Build and publish a PowerShell module to a GitHub organization NuGet feed (no repo linkage, no auto-registration), with explicit module name. Usage:./ $env:GITHUB_PAT = '<PAT with write:packages>' # add repo scope if pushing from a private repo .\Publish-PackageToGithub.ps1 -Org '<github-org>' -ModuleName '<github-module>' -Path '.' -Username '<github-username>' Parameters: -Org GitHub organization that owns the NuGet feed. -ModuleName Module name/manifest basename (expects <ModuleName>.psd1 in -Path). -Username GitHub username used for authentication; PAT goes in $env:GITHUB_PAT or -Token. -Path Path to the module root (default: current directory). -Token GitHub PAT; defaults to $env:GITHUB_PAT (needs write:packages; add repo if private). Notes: - Requires a pre-registered PSRepository whose SourceLocation matches https://nuget.pkg.github.com/<Org>/index.json. - The module manifest file must exist as <ModuleName>.psd1 in -Path, with a valid ModuleVersion. - Each publish requires a unique ModuleVersion (GitHub Packages rejects duplicate versions). #> param( [Parameter(Mandatory = $true)] [string]$Org, [Parameter(Mandatory = $true)] [string]$ModuleName, [Parameter(Mandatory = $true)] [string]$Username, [string]$Path = ".", [string]$Token = $env:GITHUB_PAT ) function Fail([string]$Message) { Write-Host $Message -ForegroundColor Red exit 1 } Set-StrictMode -Version Latest $ErrorActionPreference = "Stop" if ([string]::IsNullOrWhiteSpace($Token)) { Fail "GitHub PAT is required. Set -Token or \$env:GITHUB_PAT (needs write:packages; add repo if private)." } $resolvedPath = Resolve-Path -Path $Path $manifestPath = Join-Path $resolvedPath "$ModuleName.psd1" if (-not (Test-Path $manifestPath)) { Fail "Module manifest not found at $manifestPath. Ensure -ModuleName matches the psd1 filename." } $manifest = Import-PowerShellDataFile -Path $manifestPath $moduleVersion = $manifest.ModuleVersion if (-not $moduleVersion) { Fail "ModuleVersion is missing in $manifestPath." } $source = "https://nuget.pkg.github.com/$Org/index.json" $secure = ConvertTo-SecureString $Token -AsPlainText -Force $credential = New-Object System.Management.Automation.PSCredential($Username, $secure) # Require an existing PSRepository pointing to this source; do not register automatically. $existingRepo = Get-PSRepository -ErrorAction SilentlyContinue | Where-Object { $_.SourceLocation -eq $source } if (-not $existingRepo) { Fail "No PSRepository found for $source. Please register it manually (Register-PSRepository -Name 'GitHubPackages-$Org' -SourceLocation $source -PublishLocation $source ...)." } $repoName = $existingRepo[0].Name Write-Verbose "Using existing PSRepository '$repoName' for $source." # Guard against pushing a version that already exists (preflight instead of failing late). try { $existingVersion = Find-Module -Name $ModuleName -Repository $repoName -RequiredVersion $moduleVersion -Credential $credential -ErrorAction Stop } catch { $existingVersion = $null } if ($existingVersion) { Fail "$ModuleName $moduleVersion already exists in '$repoName'. Bump ModuleVersion in the manifest before publishing." } Write-Host "Publishing $ModuleName version $moduleVersion to GitHub Packages org feed '$Org' via repository '$repoName'..." -ForegroundColor Cyan try { Publish-Module ` -Path $resolvedPath ` -Repository $repoName ` -NuGetApiKey $Token ` -ErrorAction Stop } catch { $msg = $_.Exception.Message if ($msg -match 'already exists' -or $msg -match 'duplicate' -or $msg -match 'conflict') { Fail "$ModuleName $moduleVersion already exists. Bump ModuleVersion in the manifest and retry." } elseif ($msg -match '401' -or $msg -match 'unauthorized') { Fail "Unauthorized. Verify PAT has write:packages (and repo if private) and username/owner are correct." } else { $fqid = $_.FullyQualifiedErrorId if ($fqid) { Fail $fqid } else { Fail $msg } } } Write-Host "Publish complete: $ModuleName $moduleVersion pushed to https://nuget.pkg.github.com/$Org" -ForegroundColor Green |