From 51059c4c3a1841b0ae4cd70019e98cd8dba22b85 Mon Sep 17 00:00:00 2001 From: Bryan Cook <3217452+bryanbcook@users.noreply.github.com> Date: Fri, 25 Jul 2025 15:26:26 +0000 Subject: [PATCH 1/4] Add publish to powershellgallery workflow #9 --- .../manual-publish-powershell-gallery.yml | 195 ++++++++++++++++ .../workflows/publish-powershell-gallery.yml | 220 ++++++++++++++++++ 2 files changed, 415 insertions(+) create mode 100644 .github/workflows/manual-publish-powershell-gallery.yml create mode 100644 .github/workflows/publish-powershell-gallery.yml diff --git a/.github/workflows/manual-publish-powershell-gallery.yml b/.github/workflows/manual-publish-powershell-gallery.yml new file mode 100644 index 0000000..ae988b8 --- /dev/null +++ b/.github/workflows/manual-publish-powershell-gallery.yml @@ -0,0 +1,195 @@ +name: Manual Publish to PowerShell Gallery + +on: + workflow_dispatch: + inputs: + confirm_publish: + description: 'Type "PUBLISH" to confirm you want to publish to PowerShell Gallery' + required: true + type: string + +jobs: + publish: + runs-on: windows-latest + if: github.event.inputs.confirm_publish == 'PUBLISH' + + 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: | + # 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) { + 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 + } + } + + # Actually publish the module (no -WhatIf here) + try { + 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: | + # 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 + 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: | + 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 }}" diff --git a/.github/workflows/publish-powershell-gallery.yml b/.github/workflows/publish-powershell-gallery.yml new file mode 100644 index 0000000..a8a640f --- /dev/null +++ b/.github/workflows/publish-powershell-gallery.yml @@ -0,0 +1,220 @@ +name: Publish to PowerShell Gallery + +on: + push: + branches: [ main ] + paths: + - 'src/PSBlogger.psd1' + +jobs: + check-version: + runs-on: ubuntu-latest + 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 + } + + publish: + needs: check-version + if: needs.check-version.outputs.version-changed == 'true' + runs-on: windows-latest + + 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: 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: Get Commit Messages for Release Notes + id: release-notes + shell: pwsh + run: | + # Get the previous tag + $previousTag = git describe --tags --abbrev=0 HEAD~1 2>$null + if ($LASTEXITCODE -ne 0) { + # If no previous tag, get all commits + $commits = git log --oneline --pretty=format:"- %s (%h)" + } else { + # Get commits since the previous tag + $commits = git log --oneline --pretty=format:"- %s (%h)" "$previousTag..HEAD" + } + + $releaseNotes = @" + ## Changes in version ${{ needs.check-version.outputs.new-version }} + + $($commits -join "`n") + "@ + + # Escape for GitHub Actions + $releaseNotes = $releaseNotes -replace "`r`n", "`n" -replace "`n", "%0A" + echo "release-notes=$releaseNotes" >> $env:GITHUB_OUTPUT + + - name: Create Git Tag + shell: pwsh + run: | + git config user.name "github-actions" + git config user.email "github-actions@github.com" + git tag -a "v${{ needs.check-version.outputs.new-version }}" -m "Release version ${{ needs.check-version.outputs.new-version }}" + git push origin "v${{ needs.check-version.outputs.new-version }}" + + - name: Create GitHub Release + uses: actions/create-release@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + tag_name: v${{ needs.check-version.outputs.new-version }} + release_name: Release v${{ needs.check-version.outputs.new-version }} + body: ${{ steps.release-notes.outputs.release-notes }} + draft: false + prerelease: false + + - name: Publish to PowerShell Gallery + shell: pwsh + env: + NUGET_API_KEY: ${{ secrets.POWERSHELLGALLERY_API }} + run: | + # 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 ${{ needs.check-version.outputs.new-version }} to PowerShell Gallery..." + + # Check if this version already exists + try { + $existingModule = Find-Module -Name PSBlogger -RequiredVersion ${{ needs.check-version.outputs.new-version }} -ErrorAction SilentlyContinue + if ($existingModule) { + throw "Version ${{ needs.check-version.outputs.new-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 { + 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: Notify Success + if: success() + shell: pwsh + run: | + Write-Host "๐ŸŽ‰ Successfully published PSBlogger v${{ needs.check-version.outputs.new-version }} to PowerShell Gallery!" + Write-Host "๐Ÿ“ฆ Module is now available at: https://www.powershellgallery.com/packages/PSBlogger/${{ needs.check-version.outputs.new-version }}" + Write-Host "๐Ÿท๏ธ Created release: https://github.com/${{ github.repository }}/releases/tag/v${{ needs.check-version.outputs.new-version }}" From 98f3a2add6c6c79a153d5a8a8c38df8b8a60c98b Mon Sep 17 00:00:00 2001 From: Bryan Cook <3217452+bryanbcook@users.noreply.github.com> Date: Fri, 25 Jul 2025 15:34:46 +0000 Subject: [PATCH 2/4] Added dry-run capability to manual publish --- .../manual-publish-powershell-gallery.yml | 69 +++++++++++++++---- 1 file changed, 56 insertions(+), 13 deletions(-) diff --git a/.github/workflows/manual-publish-powershell-gallery.yml b/.github/workflows/manual-publish-powershell-gallery.yml index ae988b8..82df521 100644 --- a/.github/workflows/manual-publish-powershell-gallery.yml +++ b/.github/workflows/manual-publish-powershell-gallery.yml @@ -3,15 +3,23 @@ name: Manual Publish to PowerShell Gallery on: workflow_dispatch: inputs: - confirm_publish: - description: 'Type "PUBLISH" to confirm you want to publish to PowerShell Gallery' + 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.confirm_publish == 'PUBLISH' + if: github.event.inputs.mode == 'DRY_RUN' || (github.event.inputs.mode == 'PUBLISH' && github.event.inputs.confirm_publish == 'CONFIRM') steps: - name: Checkout code @@ -98,9 +106,15 @@ jobs: env: NUGET_API_KEY: ${{ secrets.POWERSHELLGALLERY_API }} run: | - # Validate that we have the API key - if (-not $env:NUGET_API_KEY) { - throw "POWERSHELLGALLERY_API secret is not set" + $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..." @@ -109,7 +123,11 @@ jobs: try { $existingModule = Find-Module -Name PSBlogger -RequiredVersion ${{ steps.version.outputs.version }} -ErrorAction SilentlyContinue if ($existingModule) { - throw "Version ${{ steps.version.outputs.version }} already exists on PowerShell Gallery" + 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*") { @@ -119,10 +137,15 @@ jobs: } } - # Actually publish the module (no -WhatIf here) + # Publish the module try { - Publish-Module -Path "./src" -NuGetApiKey $env:NUGET_API_KEY -Verbose -Force - Write-Host "โœ… Successfully published to PowerShell Gallery" + 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 @@ -131,6 +154,13 @@ jobs: - 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" @@ -176,6 +206,7 @@ jobs: 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 }} @@ -190,6 +221,18 @@ jobs: if: success() shell: pwsh run: | - 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 }}" + $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 }}" + } From 46566b45c8e9378a55720fe352ef55a0c49b1f3e Mon Sep 17 00:00:00 2001 From: Bryan Cook <3217452+bryanbcook@users.noreply.github.com> Date: Fri, 25 Jul 2025 15:40:10 +0000 Subject: [PATCH 3/4] Add simple test workflow --- .github/workflows/test-simple.yml | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 .github/workflows/test-simple.yml diff --git a/.github/workflows/test-simple.yml b/.github/workflows/test-simple.yml new file mode 100644 index 0000000..95046dd --- /dev/null +++ b/.github/workflows/test-simple.yml @@ -0,0 +1,11 @@ +name: Simple Test Workflow + +on: + workflow_dispatch: + +jobs: + test: + runs-on: ubuntu-latest + steps: + - name: Simple echo + run: echo "Hello from GitHub Actions" From b088ea2d59b02e41dfdb99520b7d12250430729e Mon Sep 17 00:00:00 2001 From: Bryan Cook <3217452+bryanbcook@users.noreply.github.com> Date: Fri, 25 Jul 2025 15:41:10 +0000 Subject: [PATCH 4/4] Revert "Add simple test workflow" This reverts commit 46566b45c8e9378a55720fe352ef55a0c49b1f3e. --- .github/workflows/test-simple.yml | 11 ----------- 1 file changed, 11 deletions(-) delete mode 100644 .github/workflows/test-simple.yml diff --git a/.github/workflows/test-simple.yml b/.github/workflows/test-simple.yml deleted file mode 100644 index 95046dd..0000000 --- a/.github/workflows/test-simple.yml +++ /dev/null @@ -1,11 +0,0 @@ -name: Simple Test Workflow - -on: - workflow_dispatch: - -jobs: - test: - runs-on: ubuntu-latest - steps: - - name: Simple echo - run: echo "Hello from GitHub Actions"