PublishAndTest-ActionLogging.ps1
# ============================================================= # PublishAndTest-ActionLogging # ============================================================= # Script Version : 1.0 # Date Created: 01-17-2025 # Last Revised: 01-17-2025 # Revision details: Initial creation - PowerShell Gallery publication automation # Created by : Gonzalo More # Required files: .env (with PSGALLERY_API_KEY), Action.Logging module files # Required folders: PSGallery\Action.Logging # Licensed under MIT License. # ============================================================= <# .SYNOPSIS Automated PowerShell Gallery publication and testing script for Action.Logging module. .DESCRIPTION This script automates the complete publication pipeline for the Action.Logging module: 1. Loads API key from environment file 2. Validates module quality and compliance 3. Publishes to PowerShell Gallery 4. Tests the published module functionality 5. Provides comprehensive reporting .PARAMETER WhatIf Shows what would be published without actually publishing. .PARAMETER SkipTests Skips post-publication testing (not recommended). .PARAMETER Verbose Provides detailed output during execution. .EXAMPLE .\PublishAndTest-ActionLogging.ps1 Publishes the Action.Logging module to PowerShell Gallery and tests it. .EXAMPLE .\PublishAndTest-ActionLogging.ps1 -WhatIf Shows what would be published without actually doing it. .EXAMPLE .\PublishAndTest-ActionLogging.ps1 -Verbose Provides detailed output during the publication process. #> [CmdletBinding(SupportsShouldProcess)] param( [Parameter(Mandatory = $false)] [switch]$SkipTests ) # Simple console logging function - no file logging to avoid conflicts function Write-Log { param([string]$Message, [string]$Level = 'INFO') $timestamp = Get-Date -Format 'MM-dd-yyyy HH:mm:ss' $logEntry = "$timestamp [$Level] $Message" $color = switch($Level) { 'ERROR' {'Red'} 'WARN' {'Yellow'} 'INFO' {'Green'} 'DEBUG' {'Cyan'} 'TRACE' {'Gray'} default {'White'} } Write-Host $logEntry -ForegroundColor $color } Set-StrictMode -Version Latest $ErrorActionPreference = 'Stop' #region Helper Functions <# .SYNOPSIS Loads environment variables from .env file. #> function Load-EnvironmentVariables { [CmdletBinding()] param() Write-Log -Message "Loading environment variables from .env file" -Level INFO $envPath = Join-Path $PSScriptRoot "..\.env" if (-not (Test-Path $envPath)) { throw "Environment file not found at: $envPath" } try { Get-Content $envPath | ForEach-Object { if ($_ -match '^([^#=]+)=(.*)$') { $key = $matches[1].Trim() $value = $matches[2].Trim() [Environment]::SetEnvironmentVariable($key, $value, "Process") Write-Log -Message "Loaded environment variable: $key" -Level DEBUG } } # Verify required variables if (-not $env:PSGALLERY_API_KEY) { throw "PSGALLERY_API_KEY not found in environment variables" } Write-Log -Message "Environment variables loaded successfully" -Level INFO return $env:PSGALLERY_API_KEY } catch { Write-Log -Message "Failed to load environment variables: $($_.Exception.Message)" -Level ERROR throw } } <# .SYNOPSIS Validates the Action.Logging module for publication readiness. #> function Test-ModuleReadiness { [CmdletBinding()] param( [Parameter(Mandatory = $true)] [string]$ModulePath ) Write-Log -Message "Starting module readiness validation" -Level INFO # Test 1: Verify module directory exists if (-not (Test-Path $ModulePath)) { throw "Module directory not found: $ModulePath" } $manifestPath = Join-Path $ModulePath "Action.Logging.psd1" $modulePath = Join-Path $ModulePath "Action.Logging.psm1" # Test 2: Verify required files exist @($manifestPath, $modulePath) | ForEach-Object { if (-not (Test-Path $_)) { throw "Required file not found: $_" } } Write-Log -Message "Module files found successfully" -Level INFO # Test 3: Validate module manifest try { $manifest = Test-ModuleManifest -Path $manifestPath -ErrorAction Stop Write-Log -Message "Module manifest is valid - Version: $($manifest.Version)" -Level INFO } catch { Write-Log -Message "Module manifest validation failed: $($_.Exception.Message)" -Level ERROR throw } # Test 4: Run PSScriptAnalyzer Write-Log -Message "Running PSScriptAnalyzer validation" -Level INFO try { $analyzerResults = Invoke-ScriptAnalyzer -Path $ModulePath -Recurse -ExcludeRule PSAvoidUsingWriteHost -Severity Error,Warning if ($analyzerResults) { # Handle single result or array $issueCount = if ($analyzerResults -is [array]) { $analyzerResults.Count } else { 1 } Write-Log -Message "PSScriptAnalyzer found $issueCount issues:" -Level WARN $analyzerResults | ForEach-Object { Write-Log -Message " $($_.Severity): $($_.Message) in $($_.ScriptName):$($_.Line)" -Level WARN } $errors = @($analyzerResults | Where-Object {$_.Severity -eq 'Error'}) $errorCount = $errors.Count if ($errorCount -gt 0) { throw "PSScriptAnalyzer found $errorCount error(s). Publication blocked." } } else { Write-Log -Message "PSScriptAnalyzer validation passed - no issues found" -Level INFO } } catch { Write-Log -Message "PSScriptAnalyzer execution failed: $($_.Exception.Message)" -Level ERROR throw } # Test 5: Test module import Write-Log -Message "Testing module import" -Level INFO try { # Remove any existing Action.Logging module first to avoid conflicts Remove-Module Action.Logging -Force -ErrorAction SilentlyContinue Import-Module $manifestPath -Force -ErrorAction Stop $expectedFunctions = @('Write-EnhancedLog', 'Clear-OldLog', 'Start-AsyncLogger', 'Stop-AsyncLogger', 'Write-EnhancedLogAsync', 'Set-LoggingConsoleOutput', 'Set-LogRetention') $availableFunctions = Get-Command -Module Action.Logging Write-Log -Message "Found functions: $($availableFunctions.Name -join ', ')" -Level DEBUG $functionCheckResults = @() foreach ($function in $expectedFunctions) { if ($availableFunctions.Name -contains $function) { Write-Log -Message "Function '$function' found in module exports" -Level DEBUG $functionCheckResults += $true } else { $functionCheckResults += $false Write-Log -Message "Function '$function' NOT found. Available: $($availableFunctions.Name -join ', ')" -Level ERROR } } # Check if all functions were found if ($functionCheckResults -contains $false) { throw "One or more expected functions not found in module exports" } Write-Log -Message "Module imports successfully - all $($expectedFunctions.Count) functions available" -Level INFO # Clean up Remove-Module Action.Logging -Force -ErrorAction SilentlyContinue } catch { Write-Log -Message "Module import test failed: $($_.Exception.Message)" -Level ERROR throw } Write-Log -Message "Module readiness validation completed successfully" -Level INFO return $manifest } <# .SYNOPSIS Publishes the module to PowerShell Gallery. #> function Publish-ModuleToGallery { [CmdletBinding(SupportsShouldProcess)] param( [Parameter(Mandatory = $true)] [string]$ModulePath, [Parameter(Mandatory = $true)] [string]$ApiKey, [Parameter(Mandatory = $true)] [object]$Manifest ) if ($PSCmdlet.ShouldProcess("Action.Logging v$($Manifest.Version)", "Publish to PowerShell Gallery")) { Write-Log -Message "Publishing Action.Logging v$($Manifest.Version) to PowerShell Gallery" -Level INFO try { Publish-Module -Path $ModulePath -NuGetApiKey $ApiKey -Verbose:$VerbosePreference -Force -ErrorAction Stop Write-Log -Message "Module published successfully to PowerShell Gallery" -Level INFO # Wait for propagation Write-Log -Message "Waiting 15 seconds for module propagation..." -Level INFO Start-Sleep -Seconds 15 return $true } catch { Write-Log -Message "Module publication failed: $($_.Exception.Message)" -Level ERROR throw } } else { Write-Log -Message "WhatIf: Would publish Action.Logging v$($Manifest.Version) to PowerShell Gallery" -Level INFO return $false } } <# .SYNOPSIS Tests the published module functionality. #> function Test-PublishedModule { [CmdletBinding()] param( [Parameter(Mandatory = $true)] [string]$ModuleName, [Parameter(Mandatory = $true)] [string]$ExpectedVersion ) Write-Log -Message "Starting published module testing" -Level INFO # Test 1: Verify module is available in gallery try { $publishedModule = Find-Module -Name $ModuleName -ErrorAction Stop Write-Log -Message "Module found in PowerShell Gallery - Version: $($publishedModule.Version)" -Level INFO if ($publishedModule.Version -ne $ExpectedVersion) { Write-Log -Message "Warning: Published version ($($publishedModule.Version)) differs from expected ($ExpectedVersion)" -Level WARN } } catch { Write-Log -Message "Failed to find module in PowerShell Gallery: $($_.Exception.Message)" -Level ERROR throw } # Test 2: Install from gallery Write-Log -Message "Installing module from PowerShell Gallery" -Level INFO try { # Uninstall any existing version first $existingModule = Get-Module -Name $ModuleName -ListAvailable -ErrorAction SilentlyContinue if ($existingModule) { Write-Log -Message "Removing existing module installation" -Level INFO Uninstall-Module -Name $ModuleName -AllVersions -Force -ErrorAction SilentlyContinue } Install-Module -Name $ModuleName -Scope CurrentUser -Force -ErrorAction Stop Write-Log -Message "Module installed successfully from PowerShell Gallery" -Level INFO } catch { Write-Log -Message "Module installation failed: $($_.Exception.Message)" -Level ERROR throw } # Test 3: Import and test functionality Write-Log -Message "Testing module functionality" -Level INFO try { Import-Module $ModuleName -Force -ErrorAction Stop # Test basic logging functionality Write-Log -Message "Testing basic logging functions" -Level INFO # Temporarily disable console output for testing Set-LoggingConsoleOutput -Enabled $false # Test each log level using the Action.Logging module functions Write-EnhancedLog -Message "Test INFO message" -Level INFO Write-EnhancedLog -Message "Test WARN message" -Level WARN Write-EnhancedLog -Message "Test ERROR message" -Level ERROR Write-EnhancedLog -Message "Test DEBUG message" -Level DEBUG Write-EnhancedLog -Message "Test TRACE message" -Level TRACE # Test async functions (just check they exist and can be called) $asyncStart = Get-Command Start-AsyncLogger -ErrorAction SilentlyContinue $asyncStop = Get-Command Stop-AsyncLogger -ErrorAction SilentlyContinue $clearLog = Get-Command Clear-OldLog -ErrorAction SilentlyContinue if (-not $asyncStart) { throw "Start-AsyncLogger function not found" } if (-not $asyncStop) { throw "Stop-AsyncLogger function not found" } if (-not $clearLog) { throw "Clear-OldLog function not found" } # Re-enable console output Set-LoggingConsoleOutput -Enabled $true Write-Log -Message "All module functionality tests passed" -Level INFO } catch { Write-Log -Message "Module functionality test failed: $($_.Exception.Message)" -Level ERROR throw } finally { # Clean up Remove-Module $ModuleName -Force -ErrorAction SilentlyContinue } Write-Log -Message "Published module testing completed successfully" -Level INFO } <# .SYNOPSIS Generates a publication summary report. #> function Write-PublicationSummary { [CmdletBinding()] param( [Parameter(Mandatory = $true)] [object]$Manifest, [Parameter(Mandatory = $true)] [bool]$PublishSuccess, [Parameter(Mandatory = $true)] [bool]$TestSuccess ) Write-Host "`n" -NoNewline Write-Host "===============================================" -ForegroundColor Cyan Write-Host " Action.Logging Publication Summary" -ForegroundColor Cyan Write-Host "===============================================" -ForegroundColor Cyan Write-Host "Module: Action.Logging" -ForegroundColor White Write-Host "Version: $($Manifest.Version)" -ForegroundColor White Write-Host "GUID: $($Manifest.GUID)" -ForegroundColor Gray Write-Host "Publication Time: $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')" -ForegroundColor Gray if ($PublishSuccess) { Write-Host "Publication Status: SUCCESS" -ForegroundColor Green Write-Host "Gallery URL: https://www.powershellgallery.com/packages/Action.Logging" -ForegroundColor Gray } else { Write-Host "Publication Status: SKIPPED (WhatIf mode)" -ForegroundColor Yellow } if ($PublishSuccess -and $TestSuccess) { Write-Host "Testing Status: SUCCESS" -ForegroundColor Green } elseif ($PublishSuccess) { Write-Host "Testing Status: FAILED" -ForegroundColor Red } else { Write-Host "Testing Status: SKIPPED" -ForegroundColor Yellow } Write-Host "`nNext Steps:" -ForegroundColor Cyan if ($PublishSuccess) { Write-Host " 1. Module is now available worldwide via: Install-Module Action.Logging" -ForegroundColor Gray Write-Host " 2. Update documentation with gallery badges and links" -ForegroundColor Gray Write-Host " 3. Consider setting up automated CI/CD for future releases" -ForegroundColor Gray Write-Host " 4. Monitor PowerShell Gallery statistics and feedback" -ForegroundColor Gray } else { Write-Host " 1. Run without -WhatIf to actually publish the module" -ForegroundColor Gray Write-Host " 2. Ensure all validation checks pass before publication" -ForegroundColor Gray } Write-Host "===============================================" -ForegroundColor Cyan } #endregion #region Main Script Logic try { Write-Log -Message "Starting Action.Logging PowerShell Gallery publication process" -Level INFO # Define paths - script is already in the Action.Logging directory $moduleDirectory = $PSScriptRoot # Step 1: Load environment variables Write-Log -Message "Step 1: Loading environment configuration" -Level INFO $apiKey = Load-EnvironmentVariables # Step 2: Validate module readiness Write-Log -Message "Step 2: Validating module readiness" -Level INFO $manifest = Test-ModuleReadiness -ModulePath $moduleDirectory # Step 3: Publish to PowerShell Gallery Write-Log -Message "Step 3: Publishing to PowerShell Gallery" -Level INFO $publishSuccess = Publish-ModuleToGallery -ModulePath $moduleDirectory -ApiKey $apiKey -Manifest $manifest # Step 4: Test published module (if actually published and not skipped) $testSuccess = $true if ($publishSuccess -and -not $SkipTests) { Write-Log -Message "Step 4: Testing published module" -Level INFO try { Test-PublishedModule -ModuleName "Action.Logging" -ExpectedVersion $manifest.Version } catch { $testSuccess = $false Write-Log -Message "Published module testing failed, but publication was successful" -Level WARN } } elseif ($SkipTests) { Write-Log -Message "Step 4: Skipping published module testing (SkipTests specified)" -Level INFO } # Step 5: Generate summary report Write-Log -Message "Step 5: Generating publication summary" -Level INFO Write-PublicationSummary -Manifest $manifest -PublishSuccess $publishSuccess -TestSuccess $testSuccess if ($publishSuccess -and $testSuccess) { Write-Log -Message "Action.Logging publication and testing completed successfully!" -Level INFO exit 0 } elseif ($publishSuccess) { Write-Log -Message "Action.Logging published successfully, but testing had issues" -Level WARN exit 1 } else { Write-Log -Message "Action.Logging publication process completed (WhatIf mode)" -Level INFO exit 0 } } catch { Write-Log -Message "Action.Logging publication failed: $($_.Exception.Message)" -Level ERROR Write-Host "`nPublication failed. Check logs for details." -ForegroundColor Red exit 1 } #endregion |