.github/templates/scripts/Publish-Package.ps1

<#
.SYNOPSIS
    Publishes PowerShell module to GitHub Packages via K.PSGallery.PackageRepoProvider.
 
.DESCRIPTION
    Installs K.PSGallery.PackageRepoProvider from GitHub Packages and uses it for
    intelligent package publishing. Falls back to built-in Publish-PSResource
    if provider module installation fails.
 
.PARAMETER ModuleName
    Name of the PowerShell module to publish.
 
.PARAMETER NewVersion
    Version to publish (used for verification).
 
.PARAMETER GitHubToken
    GitHub token for package publishing authentication.
 
.PARAMETER RepositoryOwner
    GitHub repository owner (e.g., 'GrexyLoco').
 
.OUTPUTS
    Writes publish summary to GITHUB_STEP_SUMMARY.
    Sets GITHUB_OUTPUT variable: package-published (true/false)
 
.EXAMPLE
    ./Publish-Package.ps1 -ModuleName "MyModule" -NewVersion "1.2.3" -GitHubToken $env:GITHUB_TOKEN -RepositoryOwner "GrexyLoco"
 
.NOTES
    Platform-independent script for GitHub Actions workflows.
    Installs K.PSGallery.PackageRepoProvider from GitHub Packages, then uses it to publish.
    Handles repository registration, package publishing, and cleanup.
#>


[CmdletBinding()]
param(
    [Parameter(Mandatory = $true)]
    [string]$ModuleName,
    
    [Parameter(Mandatory = $true)]
    [string]$NewVersion,
    
    [Parameter(Mandatory = $true)]
    [string]$GitHubToken,
    
    [Parameter(Mandatory = $true)]
    [string]$RepositoryOwner
)

# ═══════════════════════════════════════════════════════════════════════════
# 📋 Summary Header
# ═══════════════════════════════════════════════════════════════════════════
Write-Output "<details open><summary>📦 Package Publishing</summary>" >> $env:GITHUB_STEP_SUMMARY
Write-Output "" >> $env:GITHUB_STEP_SUMMARY
Write-Output "| Property | Value |" >> $env:GITHUB_STEP_SUMMARY
Write-Output "|----------|-------|" >> $env:GITHUB_STEP_SUMMARY
Write-Output "| **Module** | ``$ModuleName`` |" >> $env:GITHUB_STEP_SUMMARY
Write-Output "| **Version** | ``$NewVersion`` |" >> $env:GITHUB_STEP_SUMMARY
Write-Output "| **Target** | GitHub Packages |" >> $env:GITHUB_STEP_SUMMARY

# ═══════════════════════════════════════════════════════════════════════════
# 🔧 Configuration
# ═══════════════════════════════════════════════════════════════════════════
$registryUri = "https://nuget.pkg.github.com/$RepositoryOwner/index.json"
$repoName = 'GitHubPackages'

# ═══════════════════════════════════════════════════════════════════════════
# 📦 Install K.PSGallery.PackageRepoProvider from GitHub Packages
# ═══════════════════════════════════════════════════════════════════════════
function Install-PackageRepoProvider {
    param([string]$Token, [string]$Owner)
    
    Write-Output "📦 Installing K.PSGallery.PackageRepoProvider from GitHub Packages..."
    
    # Create credential for GitHub Packages
    $secureToken = ConvertTo-SecureString $Token -AsPlainText -Force
    $credential = New-Object PSCredential($Owner, $secureToken)
    
    # Register GitHub Packages as PSResource repository (for installation)
    $tempRepoName = 'GHPackages-Temp'
    $uri = "https://nuget.pkg.github.com/$Owner/index.json"
    
    Write-Output "🔍 Registry URI: $uri"
    Write-Output "🔍 Owner: $Owner"
    
    # Remove if exists
    Unregister-PSResourceRepository -Name $tempRepoName -ErrorAction SilentlyContinue
    
    # Register
    Write-Output "📝 Registering temporary repository: $tempRepoName"
    Register-PSResourceRepository -Name $tempRepoName -Uri $uri -Trusted -ErrorAction Stop
    
    # Install the provider module
    Write-Output "📥 Installing K.PSGallery.PackageRepoProvider..."
    $moduleName = 'K.PSGallery.PackageRepoProvider'
    Install-PSResource -Name $moduleName `
        -Repository $tempRepoName `
        -Credential $credential `
        -Scope CurrentUser `
        -TrustRepository `
        -Verbose `
        -ErrorAction Stop
    
    # ═══════════════════════════════════════════════════════════════════════
    # 🔧 PSResourceGet Issue #1402 Workaround: Lowercase Folder Bug on Linux
    # On Linux/macOS, Install-PSResource creates module folders in lowercase
    # which causes Import-Module to fail due to case-sensitive filesystem
    # See: https://github.com/PowerShell/PSResourceGet/issues/1402
    # ═══════════════════════════════════════════════════════════════════════
    if ($IsLinux -or $IsMacOS) {
        $modulesPath = Join-Path $HOME '.local/share/powershell/Modules'
        $lowercasePath = Join-Path $modulesPath $moduleName.ToLower()
        $correctPath = Join-Path $modulesPath $moduleName
        
        if ((Test-Path $lowercasePath) -and -not (Test-Path $correctPath)) {
            Write-Output "🔧 Fixing PSResourceGet #1402: Renaming lowercase module folder..."
            Write-Output " From: $lowercasePath"
            Write-Output " To: $correctPath"
            Rename-Item -Path $lowercasePath -NewName $moduleName -Force
        }
    }
    
    # Import the module
    Write-Output "📦 Importing $moduleName..."
    Import-Module $moduleName -Force -ErrorAction Stop
    
    Write-Output "✅ $moduleName installed and imported"
    
    # Cleanup temp repository
    Unregister-PSResourceRepository -Name $tempRepoName -ErrorAction SilentlyContinue
}

# ═══════════════════════════════════════════════════════════════════════════
# 🚀 Main Publishing Logic
# ═══════════════════════════════════════════════════════════════════════════
try {
    # Step 1: Install PackageRepoProvider from GitHub Packages
    Install-PackageRepoProvider -Token $GitHubToken -Owner $RepositoryOwner
    
    Write-Output "📝 Registering repository: $repoName"
    
    # Step 2: Register the target repository using PackageRepoProvider
    Register-PackageRepo `
        -RepositoryName $repoName `
        -RegistryUri $registryUri `
        -Token $GitHubToken `
        -Trusted
    
    Write-Output "🚀 Publishing module: $ModuleName"
    
    # Step 3: Publish the module
    Publish-Package `
        -RepositoryName $repoName `
        -Token $GitHubToken
    
    # Success summary
    Write-Output "" >> $env:GITHUB_STEP_SUMMARY
    Write-Output "### ✅ Published via K.PSGallery.PackageRepoProvider" >> $env:GITHUB_STEP_SUMMARY
    Write-Output "" >> $env:GITHUB_STEP_SUMMARY
    Write-Output "- **Registry:** ``$registryUri``" >> $env:GITHUB_STEP_SUMMARY
    Write-Output "- **Package:** ``$ModuleName@$NewVersion``" >> $env:GITHUB_STEP_SUMMARY
    Write-Output "- **View Package:** [GitHub Packages](https://github.com/$RepositoryOwner?tab=packages)" >> $env:GITHUB_STEP_SUMMARY
    Write-Output "" >> $env:GITHUB_STEP_SUMMARY
    Write-Output "</details>" >> $env:GITHUB_STEP_SUMMARY
    
    "package-published=true" >> $env:GITHUB_OUTPUT
    
    Write-Output "✅ Successfully published $ModuleName@$NewVersion to GitHub Packages"
}
catch {
    Write-Output "⚠️ PackageRepoProvider failed: $($_.Exception.Message)"
    Write-Output "🔄 Falling back to Publish-PSResource..."
    Write-Output "" >> $env:GITHUB_STEP_SUMMARY
    Write-Output "### ⚠️ Fallback: Publish-PSResource" >> $env:GITHUB_STEP_SUMMARY
    Write-Output "" >> $env:GITHUB_STEP_SUMMARY
    
    # ═══════════════════════════════════════════════════════════════════════
    # 🔄 Fallback: Built-in Publish-PSResource
    # ═══════════════════════════════════════════════════════════════════════
    try {
        # Create credential
        $secureToken = ConvertTo-SecureString $GitHubToken -AsPlainText -Force
        $credential = New-Object PSCredential($RepositoryOwner, $secureToken)
        
        # Register repository
        Unregister-PSResourceRepository -Name $repoName -ErrorAction SilentlyContinue
        Register-PSResourceRepository -Name $repoName -Uri $registryUri -Trusted -ErrorAction Stop
        
        # Find module manifest using robust discovery
        $scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
        $findManifestScript = Join-Path $scriptDir 'Find-ModuleManifest.ps1'
        
        if (-not (Test-Path $findManifestScript)) {
            Write-Warning "Find-ModuleManifest.ps1 not found, using legacy discovery"
            $moduleSubPath = Join-Path -Path '.' -ChildPath $ModuleName
            $modulePath = if (Test-Path $moduleSubPath) { $moduleSubPath } else { '.' }
        } else {
            $manifestResult = & $findManifestScript -ModuleName $ModuleName -SearchPath '.' -Verbose
            
            if (-not $manifestResult.IsValid) {
                $errorMsg = "Manifest validation failed:`n" + ($manifestResult.Errors -join "`n")
                throw $errorMsg
            }
            
            if ($manifestResult.Warnings.Count -gt 0) {
                foreach ($warning in $manifestResult.Warnings) {
                    Write-Warning $warning
                }
            }
            
            # Use directory containing the manifest
            $modulePath = Split-Path -Parent $manifestResult.ManifestPath
            Write-Output "✅ Using manifest: $($manifestResult.ManifestPath) (Method: $($manifestResult.ValidationMethod))"
        }
        
        # Publish module
        Publish-PSResource `
            -Path $modulePath `
            -Repository $repoName `
            -ApiKey $GitHubToken `
            -ErrorAction Stop
        
        Write-Output "- ✅ Published via Publish-PSResource" >> $env:GITHUB_STEP_SUMMARY
        Write-Output "- **Package:** ``$ModuleName@$NewVersion``" >> $env:GITHUB_STEP_SUMMARY
        Write-Output "- **View Package:** [GitHub Packages](https://github.com/$RepositoryOwner?tab=packages)" >> $env:GITHUB_STEP_SUMMARY
        Write-Output "" >> $env:GITHUB_STEP_SUMMARY
        Write-Output "</details>" >> $env:GITHUB_STEP_SUMMARY
        
        "package-published=true" >> $env:GITHUB_OUTPUT
        
        Write-Output "✅ Successfully published $ModuleName@$NewVersion via fallback"
    }
    catch {
        Write-Error "❌ Package publishing failed: $($_.Exception.Message)"
        Write-Output "" >> $env:GITHUB_STEP_SUMMARY
        Write-Output "### ❌ Publishing Failed" >> $env:GITHUB_STEP_SUMMARY
        Write-Output "" >> $env:GITHUB_STEP_SUMMARY
        Write-Output "``````" >> $env:GITHUB_STEP_SUMMARY
        Write-Output $_.Exception.Message >> $env:GITHUB_STEP_SUMMARY
        Write-Output "``````" >> $env:GITHUB_STEP_SUMMARY
        Write-Output "" >> $env:GITHUB_STEP_SUMMARY
        Write-Output "</details>" >> $env:GITHUB_STEP_SUMMARY
        
        "package-published=false" >> $env:GITHUB_OUTPUT
        exit 1
    }
    finally {
        # Cleanup
        Unregister-PSResourceRepository -Name $repoName -ErrorAction SilentlyContinue
    }
}
finally {
    # Final cleanup - only if PackageRepoProvider was loaded
    if (Get-Command Remove-PackageRepo -ErrorAction SilentlyContinue) {
        Remove-PackageRepo -RepositoryName $repoName -ErrorAction SilentlyContinue
    }
}