Skip to content

Manual Publish to PowerShell Gallery #6

Manual Publish to PowerShell Gallery

Manual Publish to PowerShell Gallery #6

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
Import-Module $manifestPath -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 }}"
}