Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
238 changes: 238 additions & 0 deletions .github/workflows/manual-publish-powershell-gallery.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,238 @@
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 }}"
}
Loading