Manual Publish to PowerShell Gallery #3
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Manual Publish to PowerShell Gallery | |
| on: | |
| workflow_dispatch: | |
| inputs: | |
| mode: | |
| description: 'Select mode' | |
| required: true | |
| type: choice | |
| options: | |
| - 'DRY_RUN' | |
| - 'PUBLISH' | |
| default: 'DRY_RUN' | |
| confirm_publish: | |
| description: 'If PUBLISH mode: Type "CONFIRM" to proceed' | |
| required: false | |
| type: string | |
| jobs: | |
| publish: | |
| runs-on: windows-latest | |
| if: github.event.inputs.mode == 'DRY_RUN' || (github.event.inputs.mode == 'PUBLISH' && github.event.inputs.confirm_publish == 'CONFIRM') | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Install PowerShell Module Dependencies | |
| shell: pwsh | |
| run: | | |
| Set-PSRepository PSGallery -InstallationPolicy Trusted | |
| Install-Module -Name PowerShell-Yaml -Force -SkipPublisherCheck | |
| - name: Get Module Version | |
| id: version | |
| shell: pwsh | |
| run: | | |
| $manifestPath = "src/PSBlogger.psd1" | |
| $manifest = Import-PowerShellDataFile -Path $manifestPath | |
| $version = $manifest.ModuleVersion | |
| Write-Host "Module version: $version" | |
| echo "version=$version" >> $env:GITHUB_OUTPUT | |
| - name: Validate Module Manifest | |
| shell: pwsh | |
| run: | | |
| # Test module manifest | |
| $manifestPath = "./src/PSBlogger.psd1" | |
| Write-Host "Testing module manifest at: $manifestPath" | |
| # Test manifest syntax | |
| $manifest = Test-ModuleManifest -Path $manifestPath -Verbose | |
| Write-Host "Module manifest is valid" | |
| Write-Host "Module Name: $($manifest.Name)" | |
| Write-Host "Module Version: $($manifest.Version)" | |
| Write-Host "Module Author: $($manifest.Author)" | |
| Write-Host "Module Description: $($manifest.Description)" | |
| # Check required fields for PowerShell Gallery | |
| if (-not $manifest.Description) { | |
| throw "Module description is required for PowerShell Gallery" | |
| } | |
| if (-not $manifest.Author) { | |
| throw "Module author is required for PowerShell Gallery" | |
| } | |
| # Test that the module can be imported successfully | |
| $moduleDir = Resolve-Path (Split-Path $manifestPath) | |
| Import-Module $moduleDir -Force | |
| $loadedModule = Get-Module PSBlogger | |
| Write-Host "Successfully imported module. Exported commands:" | |
| $loadedModule.ExportedCommands.Keys | Sort-Object | ForEach-Object { Write-Host " - $_" } | |
| - name: Run Tests | |
| shell: pwsh | |
| run: | | |
| # Install Pester for testing | |
| Install-Module -Name Pester -Force -SkipPublisherCheck | |
| # Install pandoc for tests | |
| choco install pandoc -y | |
| # Change to src directory and run tests | |
| Set-Location "./src" | |
| # Configure Pester | |
| $PesterConfig = @{ | |
| Run = @{ | |
| Path = './tests' | |
| } | |
| Output = @{ | |
| Verbosity = 'Normal' | |
| } | |
| Should = @{ | |
| ErrorAction = 'Stop' | |
| } | |
| } | |
| # Run tests and fail if any tests fail | |
| $testResults = Invoke-Pester -Configuration $PesterConfig | |
| if ($testResults.FailedCount -gt 0) { | |
| throw "Tests failed. Cannot publish to PowerShell Gallery." | |
| } | |
| - name: Publish to PowerShell Gallery | |
| shell: pwsh | |
| env: | |
| NUGET_API_KEY: ${{ secrets.POWERSHELLGALLERY_API }} | |
| run: | | |
| $isDryRun = "${{ github.event.inputs.mode }}" -eq "DRY_RUN" | |
| if ($isDryRun) { | |
| Write-Host "🧪 DRY RUN MODE - No actual publishing will occur" | |
| } else { | |
| # Validate that we have the API key | |
| if (-not $env:NUGET_API_KEY) { | |
| throw "POWERSHELLGALLERY_API secret is not set" | |
| } | |
| } | |
| Write-Host "Publishing PSBlogger version ${{ steps.version.outputs.version }} to PowerShell Gallery..." | |
| # Check if this version already exists | |
| try { | |
| $existingModule = Find-Module -Name PSBlogger -RequiredVersion ${{ steps.version.outputs.version }} -ErrorAction SilentlyContinue | |
| if ($existingModule) { | |
| if ($isDryRun) { | |
| Write-Host "⚠️ DRY RUN: Version ${{ steps.version.outputs.version }} already exists on PowerShell Gallery" | |
| } else { | |
| throw "Version ${{ steps.version.outputs.version }} already exists on PowerShell Gallery" | |
| } | |
| } | |
| } catch { | |
| if ($_.Exception.Message -notlike "*Version*already exists*") { | |
| Write-Host "Could not check existing versions (this is normal for new modules): $($_.Exception.Message)" | |
| } else { | |
| throw | |
| } | |
| } | |
| # Publish the module | |
| try { | |
| if ($isDryRun) { | |
| Publish-Module -Path "./src" -WhatIf -Verbose | |
| Write-Host "🧪 DRY RUN: Would publish to PowerShell Gallery (no actual publishing)" | |
| } else { | |
| Publish-Module -Path "./src" -NuGetApiKey $env:NUGET_API_KEY -Verbose -Force | |
| Write-Host "✅ Successfully published to PowerShell Gallery" | |
| } | |
| } catch { | |
| Write-Error "❌ Failed to publish to PowerShell Gallery: $_" | |
| throw | |
| } | |
| - name: Create Git Tag and Release | |
| shell: pwsh | |
| run: | | |
| $isDryRun = "${{ github.event.inputs.mode }}" -eq "DRY_RUN" | |
| if ($isDryRun) { | |
| Write-Host "🧪 DRY RUN: Would create tag v${{ steps.version.outputs.version }} and GitHub release" | |
| return | |
| } | |
| # Configure git | |
| git config user.name "github-actions" | |
| git config user.email "github-actions@github.com" | |
| # Check if tag already exists | |
| $tagExists = git tag -l "v${{ steps.version.outputs.version }}" | |
| if ($tagExists) { | |
| Write-Host "Tag v${{ steps.version.outputs.version }} already exists" | |
| } else { | |
| # Create and push tag | |
| git tag -a "v${{ steps.version.outputs.version }}" -m "Release version ${{ steps.version.outputs.version }}" | |
| git push origin "v${{ steps.version.outputs.version }}" | |
| Write-Host "Created and pushed tag v${{ steps.version.outputs.version }}" | |
| } | |
| - name: Get Commit Messages for Release Notes | |
| id: release-notes | |
| shell: pwsh | |
| run: | | |
| # Get the previous tag | |
| $previousTag = git describe --tags --abbrev=0 "v${{ steps.version.outputs.version }}~1" 2>$null | |
| if ($LASTEXITCODE -ne 0) { | |
| # If no previous tag, get last 10 commits | |
| $commits = git log --oneline --pretty=format:"- %s (%h)" -n 10 | |
| } else { | |
| # Get commits since the previous tag | |
| $commits = git log --oneline --pretty=format:"- %s (%h)" "$previousTag..v${{ steps.version.outputs.version }}" | |
| } | |
| $releaseNotes = @" | |
| ## Changes in version ${{ steps.version.outputs.version }} | |
| $($commits -join "`n") | |
| ## Installation | |
| ``````powershell | |
| Install-Module -Name PSBlogger -RequiredVersion ${{ steps.version.outputs.version }} | |
| `````` | |
| "@ | |
| # Escape for GitHub Actions | |
| $releaseNotes = $releaseNotes -replace "`r`n", "`n" -replace "`n", "%0A" | |
| echo "release-notes=$releaseNotes" >> $env:GITHUB_OUTPUT | |
| - name: Create GitHub Release | |
| if: github.event.inputs.mode == 'PUBLISH' | |
| uses: actions/create-release@v1 | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| with: | |
| tag_name: v${{ steps.version.outputs.version }} | |
| release_name: Release v${{ steps.version.outputs.version }} | |
| body: ${{ steps.release-notes.outputs.release-notes }} | |
| draft: false | |
| prerelease: false | |
| - name: Notify Success | |
| if: success() | |
| shell: pwsh | |
| run: | | |
| $isDryRun = "${{ github.event.inputs.mode }}" -eq "DRY_RUN" | |
| if ($isDryRun) { | |
| Write-Host "🧪 DRY RUN COMPLETED SUCCESSFULLY!" | |
| Write-Host "✅ Module manifest validation passed" | |
| Write-Host "✅ All tests passed" | |
| Write-Host "✅ Module can be imported successfully" | |
| Write-Host "" | |
| Write-Host "Ready to publish PSBlogger v${{ steps.version.outputs.version }} to PowerShell Gallery" | |
| Write-Host "To actually publish, run this workflow again with PUBLISH mode and type CONFIRM" | |
| } else { | |
| Write-Host "🎉 Successfully published PSBlogger v${{ steps.version.outputs.version }} to PowerShell Gallery!" | |
| Write-Host "📦 Module is now available at: https://www.powershellgallery.com/packages/PSBlogger/${{ steps.version.outputs.version }}" | |
| Write-Host "🏷️ Created release: https://github.com/${{ github.repository }}/releases/tag/v${{ steps.version.outputs.version }}" | |
| } |