diff --git a/private/Get-Commands.ps1 b/private/Get-Commands.ps1 index 590509a..38b7e21 100644 --- a/private/Get-Commands.ps1 +++ b/private/Get-Commands.ps1 @@ -28,7 +28,7 @@ function Get-Commands { [Command]::new("list", { Write-Host "TODO: Output todo list" }) ) ) - [Command]::new("version", { Write-Host (Get-MyModuleVersion) }) + [Command]::new("version", { Write-Host (Get-MyModuleVersion) } ) [Command]::new("update", "Update-QuickPath") ) } diff --git a/private/Get-MyModuleVersion.ps1 b/private/Get-MyModuleVersion.ps1 index 156c6d7..f7ecf8a 100644 --- a/private/Get-MyModuleVersion.ps1 +++ b/private/Get-MyModuleVersion.ps1 @@ -1,19 +1,52 @@ function Get-MyModuleVersion { - # Get all installed versions of the module - $moduleName = $MyInvocation.MyCommand.Module.Name - $modules = Get-Module -Name $moduleName -ListAvailable + try { + $moduleName = "quickpath" + $commandName = "qp" - if ($modules) { - # Filter to only include modules from the current module path, to avoid listing multiple versions in different paths - $currentPath = (Get-Module -Name $moduleName).ModuleBase + $module = Get-Module -Name $moduleName -ErrorAction SilentlyContinue + if ($module) { + return $module.Version + } - $modules = $modules | Where-Object { $_.ModuleBase -eq $currentPath } - - # Sort by version and select the latest one - $latestModule = $modules | Sort-Object Version -Descending | Select-Object -First 1 - return $latestModule.Version - } else { - throw "Module 'YourModuleName' is not installed." + $module = Get-ModuleFromCommand($commandName) + if ($module) { + return $module.Version + } + + $module = Get-ModuleFromManifest($moduleName) + if ($module) { + return $module.Version + } + Write-Error "Module version could not be found." + } + catch { + Write-Error "Could not determine module version: $($_.Exception.Message)" + } +} + +function Get-ModuleFromCommand { + param ( + [string]$commandName + ) + + $qpCommand = Get-Command -Name $commandName -ErrorAction SilentlyContinue + if ($qpCommand -and $qpCommand.Module) { + return $qpCommand.Module } + + return $null } +function Get-ModuleFromManifest { + param( + [string]$moduleName = "quickpath" + ) + $manifest = "$PSScriptRoot\..\output\$moduleName\$moduleName.psd1" + + if (Test-Path $manifest) { + $data = Test-ModuleManifest -Path $manifest -ErrorAction Stop + return $data + } + + return $null +} \ No newline at end of file diff --git a/private/Update-QuickPath.ps1 b/private/Update-QuickPath.ps1 index ed5f583..8ff28bb 100644 --- a/private/Update-QuickPath.ps1 +++ b/private/Update-QuickPath.ps1 @@ -1,99 +1,52 @@ function Update-QuickPath { + param( + [switch]$FromGallery + ) + + Write-Host "Updating quickpath..." -ForegroundColor Cyan + + if ($FromGallery) { + Update-QuickPathFromGallery + return + } + + Update-QuickPathFromBuild +} + +function Update-QuickPathFromGallery { try { - Update-Module -Name quickpath -Force -ErrorAction Stop - Import-Module quickpath -Force -ErrorAction Stop - Write-Host "quickpath updated from gallery and reloaded." -ForegroundColor Green + $moduleName = "quickpath" + if (Get-Module $moduleName) { + Remove-Module $moduleName -Force -ErrorAction SilentlyContinue + } + Update-Module -Name $moduleName -Force -ErrorAction Stop + Import-Module $moduleName -Force -ErrorAction Stop + Write-Host "$moduleName updated from gallery and reloaded." -ForegroundColor Green } catch { - Write-Error "Failed to update quickpath from gallery: $($_.Exception.Message)" + Write-Error "Failed to update '$moduleName' from gallery: $($_.Exception.Message)" throw } - # [CmdletBinding()] - # param( - # [ValidateSet('Patch', 'Minor', 'Major')] - # [string]$Increment = 'Patch', - - # [switch]$SkipTests, - - # # Force update from the PowerShell Gallery instead of local source - # [switch]$FromGallery - # ) - - # try { - # Write-Host "Updating quickpath..." -ForegroundColor Cyan - - # if ($FromGallery) { - - # Update-QuickPathFromGallery - # return - # } - - # $buildFile = Get-BuildFile - - # if (-not $buildFile) { - # Write-Verbose "Build script not found near '$startPath'; falling back to gallery update." - # Update-QuickPathFromGallery - # return - # } - - # ValidateOrInstallTools - - # # Build argument list for Invoke-Build - # $tasks = @() - # if (-not $SkipTests) { $tasks += 'Test' } - # $tasks += 'Refresh' - - # # Execute build in the current session so Import-Module in Refresh affects this session - # Invoke-Build -File $buildFile -Increment $Increment -Task $tasks - - # # As an extra safety, try re-importing the freshly built manifest - # $outManifest = Join-Path (Split-Path $buildFile -Parent) 'output\quickpath\quickpath.psd1' - # if (Test-Path $outManifest) { - # Import-Module $outManifest -Force -ErrorAction SilentlyContinue - # } - - # Write-Host "quickpath has been built, tested, and reloaded." -ForegroundColor Green - # } - # catch { - # Write-Error "Failed to update quickpath: $($_.Exception.Message)" - # throw - # } } -# function Update-QuickPathFromGallery { -# try { -# Update-Module -Name quickpath -Force -ErrorAction Stop -# Import-Module quickpath -Force -ErrorAction Stop -# Write-Host "quickpath updated from gallery and reloaded." -ForegroundColor Green -# } -# catch { -# Write-Error "Failed to update quickpath from gallery: $($_.Exception.Message)" -# throw -# } -# } - -# function Get-BuildFile { -# $startPath = (Get-Location).Path -# $dir = $startPath -# $buildFile = $null -# for ($i = 0; $i -lt 6; $i++) { -# $candidate = Join-Path $dir 'quickpath.build.ps1' -# if (Test-Path $candidate) { $buildFile = $candidate; break } -# $parent = Split-Path $dir -Parent -# if ([string]::IsNullOrEmpty($parent) -or $parent -eq $dir) { break } -# $dir = $parent -# } -# return $buildFile -# } - -# function ValidateOrInstallTools { -# # Ensure required tools are available -# if (-not (Get-Module -ListAvailable -Name InvokeBuild)) { -# Write-Verbose "Installing InvokeBuild..." -# Install-Module -Name InvokeBuild -Scope CurrentUser -Force -ErrorAction Stop -# } -# if (-not (Get-Module -ListAvailable -Name Pester)) { -# Write-Verbose "Installing Pester..." -# Install-Module -Name Pester -Scope CurrentUser -Force -ErrorAction Stop -# } -# } \ No newline at end of file +function Update-QuickPathFromBuild { + try { + $moduleName = "quickpath" + $quickPathManifest = Join-Path -Path $PSScriptRoot -ChildPath "..\output\quickpath\quickpath.psd1" + if ( -not (Test-Path $quickPathManifest)) { + Write-Warning "Built quickpath module not found at '$quickPathManifest'. Please run 'Invoke-Build Build' first." + return + } + + if (Get-Module $moduleName) { + Remove-Module $moduleName -Force -ErrorAction SilentlyContinue + } + + Import-Module $quickPathManifest -Force -ErrorAction Stop + Write-Host "$moduleName has been built, tested, and reloaded." -ForegroundColor Green + } + catch { + Write-Error "An error occurred while updating from build: $($_.Exception.Message)" + throw + } +} diff --git a/quickpath.build.ps1 b/quickpath.build.ps1 index 333adca..bf99dd1 100644 --- a/quickpath.build.ps1 +++ b/quickpath.build.ps1 @@ -1,8 +1,11 @@ param( - [string]$Increment = "Patch", # Can be "Patch", "Minor", or "Major" + [ValidateSet('Patch', 'Minor', 'Major')] + [string]$Increment = "Patch", [string]$Output = "Normal" ) +. $PSScriptRoot/private/Update-QuickPath.ps1 + function Update-Version { $psd1Path = 'quickpath.psd1' @@ -88,7 +91,14 @@ task Publish -Jobs Package, { task Refresh -Jobs Build, { Write-Host 'Refreshing module...' + Remove-Module quickpath -Force -ErrorAction SilentlyContinue Import-Module './output/quickpath/quickpath.psd1' -Force } +task Update -Jobs Build, Test, { + Write-Host 'Updating module...' + + Update-QuickPath +} + task . Clean, Build, Test, Package \ No newline at end of file diff --git a/quickpath.psd1 b/quickpath.psd1 index e14ba28..e2df229 100644 --- a/quickpath.psd1 +++ b/quickpath.psd1 @@ -12,7 +12,7 @@ RootModule = 'quickpath.psm1' # Version number of this module. - ModuleVersion = '0.14.3' + ModuleVersion = '0.16.28' # ID used to uniquely identify this module GUID = '376719b2-2cdd-47e8-b82b-b01870c08ac8' diff --git a/tests/Get-ModuleVersion.Tests.ps1 b/tests/Get-ModuleVersion.Tests.ps1 new file mode 100644 index 0000000..fa29669 --- /dev/null +++ b/tests/Get-ModuleVersion.Tests.ps1 @@ -0,0 +1,78 @@ +Describe "Get-ModuleVersion" { + BeforeAll { + . $PSScriptRoot\..\private\Get-MyModuleVersion.ps1 + } + It "Get Loaded Module version" { + $expectedVersion = "1.2.3" + Mock Get-Module { + [PSCustomObject]@{ + Version = [version]$expectedVersion + } + } + + $actualVersion = Get-MyModuleVersion + + $actualVersion | Should -Be $expectedVersion + } + It "Get Module version from command" { + $expectedVersion = "2.3.4" + Mock Get-Module { + return $null + } + Mock Get-Command { + [PSCustomObject]@{ + Module = [PSCustomObject]@{ + Version = [version]$expectedVersion + } + } + } + + $actualVersion = Get-MyModuleVersion + + $actualVersion | Should -Be $expectedVersion + } + It "Get Module version from manifest" { + $expectedVersion = "3.4.5" + Mock Get-Module { + return $null + } + Mock Get-Command { + return $null + } + Mock Test-ModuleManifest { + [PSCustomObject]@{ + Version = [version]$expectedVersion + } + } + + $actualVersion = Get-MyModuleVersion + + $actualVersion | Should -Be $expectedVersion + } + It 'Failed to find module version, writes error' { + Mock Get-Module { + return $null + } + Mock Get-Command { + return $null + } + Mock Test-Path { + return $false + } + Mock Write-Error {} + + Get-MyModuleVersion + + Assert-MockCalled Write-Error -Exactly 1 + } + It 'Catches exception and writes error' { + Mock Get-Module { + throw "Some error" + } + Mock Write-Error {} + + Get-MyModuleVersion + + Assert-MockCalled Write-Error -Exactly 1 + } +} \ No newline at end of file diff --git a/tests/Update-QuickPath.Tests.ps1 b/tests/Update-QuickPath.Tests.ps1 index e488bc0..4057d81 100644 --- a/tests/Update-QuickPath.Tests.ps1 +++ b/tests/Update-QuickPath.Tests.ps1 @@ -3,29 +3,56 @@ Context 'Update-QuickPath' { BeforeAll { . $PSScriptRoot\..\private\Update-QuickPath.ps1 } - It 'Should call Update-Module and Import-Module' { + BeforeEach { + Mock Remove-Module Mock Update-Module Mock Import-Module - Mock Write-Host - Update-QuickPath - - Assert-MockCalled -CommandName Update-Module -Times 1 -Exactly -Scope It -ParameterFilter { - $Name -eq 'quickpath' -and $Force -eq $true -and $ErrorAction -eq 'Stop' - } - - Assert-MockCalled -CommandName Import-Module -Times 1 -Exactly -Scope It -ParameterFilter { - $Name -eq 'quickpath' -and $Force -eq $true -and $ErrorAction -eq 'Stop' - } + } + It 'Should be updated from gallery when FromGallery is set' { + Mock Update-QuickPathFromGallery + Update-QuickPath -FromGallery - Assert-MockCalled -CommandName Write-Host -Times 1 -Exactly -Scope It -ParameterFilter { - $Object -eq "quickpath updated from gallery and reloaded." -and $ForegroundColor -eq 'Green' - } + Assert-MockCalled -CommandName Update-QuickPathFromGallery -Times 1 -Exactly -Scope It } It 'Should handle errors from Update-Module' { Mock Update-Module { throw [System.Exception]::new("Update failed") } Mock Write-Error - { Update-QuickPath } | Should -Throw + { Update-QuickPath -FromGallery } | Should -Throw Assert-MockCalled -CommandName Write-Error -Times 1 -Exactly -Scope It } + It 'Should be updated from build when FromGallery is not set' { + Mock Update-QuickPathFromBuild + Update-QuickPath + + Assert-MockCalled -CommandName Update-QuickPathFromBuild -Times 1 -Exactly -Scope It + } + It 'Should handle missing built module in Update-QuickPathFromBuild' { + Mock Test-Path { $false } + Mock Write-Warning + Update-QuickPathFromBuild + + Assert-MockCalled -CommandName Write-Warning -Times 1 -Exactly -Scope It + } + It 'Should handle errors during build update' { + Mock Test-Path { $true } + Mock Import-Module { throw [System.Exception]::new("Import failed") } + Mock Write-Error + { Update-QuickPathFromBuild } | Should -Throw + + Assert-MockCalled -CommandName Write-Error -Times 1 -Exactly -Scope It + } + It 'Should remove existing module before updating from gallery' { + Mock Get-Module { @{ Name = "quickpath" } } + Update-QuickPath -FromGallery + + Assert-MockCalled -CommandName Remove-Module -ParameterFilter { $Name -eq "quickpath" } -Times 1 -Exactly -Scope It + } + It 'Should remove existing module before updating from build' { + Mock Get-Module { @{ Name = "quickpath" } } + Mock Test-Path { $true } + Update-QuickPathFromBuild + + Assert-MockCalled -CommandName Remove-Module -ParameterFilter { $Name -eq "quickpath" } -Times 1 -Exactly -Scope It + } }