Update workflow for release notes (#43) #9
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: PowerShell Gallery Publishing | |
| on: | |
| # Automatic trigger: when module version changes on main branch | |
| push: | |
| branches: [ main ] | |
| paths: | |
| - 'src/PSBlogger.psd1' | |
| # Manual trigger: workflow dispatch with options | |
| 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: | |
| # Version check job (only runs for automatic triggers) | |
| check-version: | |
| runs-on: ubuntu-latest | |
| if: github.event_name == 'push' | |
| outputs: | |
| version-changed: ${{ steps.version-check.outputs.version-changed }} | |
| new-version: ${{ steps.version-check.outputs.new-version }} | |
| old-version: ${{ steps.version-check.outputs.old-version }} | |
| steps: | |
| - name: Checkout current commit | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 2 | |
| - name: Check if version changed | |
| id: version-check | |
| shell: pwsh | |
| run: | | |
| # Get the current version from the manifest | |
| $manifestPath = "src/PSBlogger.psd1" | |
| $manifest = Import-PowerShellDataFile -Path $manifestPath | |
| $currentVersion = $manifest.ModuleVersion | |
| Write-Host "Current version: $currentVersion" | |
| # Get the previous version from the previous commit | |
| git checkout HEAD~1 -- $manifestPath 2>$null | |
| if ($LASTEXITCODE -eq 0) { | |
| $previousManifest = Import-PowerShellDataFile -Path $manifestPath | |
| $previousVersion = $previousManifest.ModuleVersion | |
| Write-Host "Previous version: $previousVersion" | |
| } else { | |
| Write-Host "No previous version found (first commit?)" | |
| $previousVersion = "0.0.0" | |
| } | |
| # Restore current version | |
| git checkout HEAD -- $manifestPath | |
| # Check if version changed | |
| if ($currentVersion -ne $previousVersion) { | |
| Write-Host "Version changed from $previousVersion to $currentVersion" | |
| echo "version-changed=true" >> $env:GITHUB_OUTPUT | |
| echo "new-version=$currentVersion" >> $env:GITHUB_OUTPUT | |
| echo "old-version=$previousVersion" >> $env:GITHUB_OUTPUT | |
| } else { | |
| Write-Host "Version unchanged: $currentVersion" | |
| echo "version-changed=false" >> $env:GITHUB_OUTPUT | |
| echo "new-version=$currentVersion" >> $env:GITHUB_OUTPUT | |
| echo "old-version=$previousVersion" >> $env:GITHUB_OUTPUT | |
| } | |
| # Main publishing job | |
| publish: | |
| runs-on: windows-latest | |
| needs: [check-version] | |
| if: | | |
| always() && ( | |
| (github.event_name == 'push' && needs.check-version.outputs.version-changed == 'true') || | |
| (github.event_name == 'workflow_dispatch' && ( | |
| 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 | |
| with: | |
| fetch-depth: 0 | |
| - 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: Determine Run Mode | |
| id: run-mode | |
| shell: pwsh | |
| run: | | |
| if ("${{ github.event_name }}" -eq "push") { | |
| # Automatic publish on version change | |
| echo "is-dry-run=false" >> $env:GITHUB_OUTPUT | |
| echo "trigger-type=automatic" >> $env:GITHUB_OUTPUT | |
| } else { | |
| # Manual workflow dispatch | |
| $isDryRun = "${{ github.event.inputs.mode }}" -eq "DRY_RUN" | |
| echo "is-dry-run=$isDryRun" >> $env:GITHUB_OUTPUT | |
| echo "trigger-type=manual" >> $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 | |
| # Use absolute path to the manifest file | |
| $manifestAbsolutePath = Resolve-Path $manifestPath | |
| Import-Module $manifestAbsolutePath -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: Inject Values into Module | |
| shell: pwsh | |
| env: | |
| CLIENT_ID: ${{ secrets.GOOGLE_CLIENT_ID }} | |
| CLIENT_SECRET: ${{ secrets.GOOGLE_CLIENT_SECRET }} | |
| run: | | |
| $file = "./src/public/Initialize-Blogger.ps1" | |
| $content = Get-Content $file -Raw | |
| $content = $content -replace "<<CLIENT_ID>>", $env:CLIENT_ID | |
| $content = $content -replace "<<CLIENT_SECRET>>", $env:CLIENT_SECRET | |
| $content | Set-Content -Path $file -Force | |
| - name: Publish to PowerShell Gallery | |
| shell: pwsh | |
| env: | |
| NUGET_API_KEY: ${{ secrets.POWERSHELLGALLERY_APIKEY }} | |
| run: | | |
| $isDryRun = "${{ steps.run-mode.outputs.is-dry-run }}" -eq "true" | |
| $triggerType = "${{ steps.run-mode.outputs.trigger-type }}" | |
| Write-Host "🔧 Trigger: $triggerType" | |
| if ($isDryRun) { | |
| Write-Host "🧪 DRY RUN MODE - No actual publishing will occur" | |
| } else { | |
| Write-Host "🚀 PUBLISH MODE - Will publish to PowerShell Gallery" | |
| # Validate that we have the API key | |
| if (-not $env:NUGET_API_KEY) { | |
| throw "POWERSHELLGALLERY_APIKEY 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 { | |
| # Create a proper module structure for publishing | |
| $tempModuleDir = Join-Path $env:TEMP "PSBlogger" | |
| if (Test-Path $tempModuleDir) { | |
| Remove-Item $tempModuleDir -Recurse -Force | |
| } | |
| New-Item -ItemType Directory -Path $tempModuleDir -Force | Out-Null | |
| # Copy module files excluding tests | |
| Copy-Item "./src/PSBlogger.psd1" $tempModuleDir -Force | |
| Copy-Item "./src/PSBlogger.psm1" $tempModuleDir -Force | |
| Copy-Item "./src/private" $tempModuleDir -Recurse -Force | |
| Copy-Item "./src/public" $tempModuleDir -Recurse -Force | |
| if ($isDryRun) { | |
| Write-Host "🧪 DRY RUN: Would publish to PowerShell Gallery (no actual publishing)" | |
| Publish-Module -Path $tempModuleDir -NuGetApiKey $env:NUGET_API_KEY -WhatIf -Verbose | |
| } else { | |
| Publish-Module -Path $tempModuleDir -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 | |
| if: steps.run-mode.outputs.is-dry-run == 'false' | |
| shell: pwsh | |
| run: | | |
| Write-Host "🏷️ Creating Git tag and GitHub release..." | |
| # 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: Create GitHub Release | |
| if: steps.run-mode.outputs.is-dry-run == 'false' | |
| uses: softprops/action-gh-release@v2 | |
| with: | |
| tag_name: v${{ steps.version.outputs.version }} | |
| name: Release v${{ steps.version.outputs.version }} | |
| generate_release_notes: true | |
| append_body: true | |
| body: | | |
| ## Installation | |
| ```powershell | |
| Install-Module -Name PSBlogger -RequiredVersion ${{ steps.version.outputs.version }} | |
| ``` | |
| draft: false | |
| prerelease: false | |
| - name: Notify Success | |
| if: success() | |
| shell: pwsh | |
| run: | | |
| $isDryRun = "${{ steps.run-mode.outputs.is-dry-run }}" -eq "true" | |
| $triggerType = "${{ steps.run-mode.outputs.trigger-type }}" | |
| 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 }}" | |
| Write-Host "🔧 Triggered by: $triggerType" | |
| } |