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
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ preference to decide whether prerelease self-updates are eligible. When prerelea
self-update stays on stable releases. When they are enabled, self-update may target a prerelease, but it asks for
explicit confirmation before proceeding.


Successful `Update-NovaModuleTool`, CLI:`% nova update`, and `Install-NovaCli` runs print the release notes link from
the
installed module manifest. When `Invoke-NovaBuild` detects a newer `NovaModuleTools` version after a build, the update
Expand Down
3 changes: 2 additions & 1 deletion scripts/build/ci/Install-CiPowerShellModules.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,9 @@ function Install-CiModule {
[Parameter(Mandatory)][string]$Name
)

$repositoryName = 'PSGallery'
Write-Host "Installing PowerShell module '$Name'..."
Install-Module -Name $Name -AllowPrerelease -Scope CurrentUser -Force -ErrorAction Stop | Out-Null
Install-Module -Name $Name -Repository $repositoryName -AllowPrerelease -Scope CurrentUser -Force -ErrorAction Stop | Out-Null

$installedModule = Get-InstalledModule -Name $Name -ErrorAction Stop |
Sort-Object Version -Descending |
Expand Down
76 changes: 74 additions & 2 deletions src/private/update/ConvertToNovaModuleSelfUpdatePlan.ps1
Original file line number Diff line number Diff line change
@@ -1,8 +1,77 @@
function Get-NovaModuleSelfUpdateLookupCandidate {
[CmdletBinding()]
param(
[pscustomobject]$LookupResult,
[Parameter(Mandatory)][bool]$PrereleaseNotificationsEnabled
)

if ($null -eq $LookupResult) {
return $null
}

if ($PrereleaseNotificationsEnabled -and $null -ne $LookupResult.Prerelease) {
return $LookupResult.Prerelease
}

if ($null -ne $LookupResult.Stable) {
return $LookupResult.Stable
}

return $LookupResult.Prerelease
}

function Get-NovaModuleSelfUpdateLookupRepository {
[CmdletBinding()]
param(
[pscustomobject]$LookupResult,
[object]$LookupCandidate
)

if ($null -ne $LookupCandidate -and $LookupCandidate.PSObject.Properties.Name -contains 'Repository') {
return $LookupCandidate.Repository
}

if ($null -ne $LookupResult -and $LookupResult.PSObject.Properties.Name -contains 'SourceRepository') {
return $LookupResult.SourceRepository
}

return $null
}

function Get-NovaModuleSelfUpdatePlanContext {
[CmdletBinding()]
param(
[pscustomobject]$LookupResult,
[Parameter(Mandatory)][bool]$PrereleaseNotificationsEnabled
)

$lookupCandidate = Get-NovaModuleSelfUpdateLookupCandidate -LookupResult $LookupResult -PrereleaseNotificationsEnabled:$PrereleaseNotificationsEnabled
$lookupCandidateVersion = if ($null -ne $lookupCandidate -and $lookupCandidate.PSObject.Properties.Name -contains 'Version') {
$lookupCandidate.Version
}
else {
$null
}
$lookupCandidateChannel = if ($null -ne $lookupCandidate -and $lookupCandidate.PSObject.Properties.Name -contains 'Channel') {
$lookupCandidate.Channel
}
else {
$null
}

return [pscustomobject]@{
LookupCandidateVersion = $lookupCandidateVersion
LookupCandidateChannel = $lookupCandidateChannel
LookupRepository = Get-NovaModuleSelfUpdateLookupRepository -LookupResult $LookupResult -LookupCandidate $lookupCandidate
PrereleaseNotificationsEnabled = $PrereleaseNotificationsEnabled
}
}

function ConvertTo-NovaModuleSelfUpdatePlan {
[CmdletBinding()]
param(
[Parameter(Mandatory)][pscustomobject]$InstalledModule,
[Parameter(Mandatory)][bool]$PrereleaseNotificationsEnabled,
[Parameter(Mandatory)][pscustomobject]$PlanContext,
[string]$TargetVersion,
[switch]$PrereleaseTarget
)
Expand All @@ -11,7 +80,10 @@ function ConvertTo-NovaModuleSelfUpdatePlan {
ModuleName = $InstalledModule.ModuleName
CurrentVersion = $InstalledModule.Version
TargetVersion = $TargetVersion
PrereleaseNotificationsEnabled = $PrereleaseNotificationsEnabled
LookupCandidateVersion = $PlanContext.LookupCandidateVersion
LookupCandidateChannel = $PlanContext.LookupCandidateChannel
LookupRepository = $PlanContext.LookupRepository
PrereleaseNotificationsEnabled = $PlanContext.PrereleaseNotificationsEnabled
UpdateAvailable = -not [string]::IsNullOrWhiteSpace($TargetVersion)
Updated = $false
Cancelled = $false
Expand Down
7 changes: 4 additions & 3 deletions src/private/update/GetNovaModuleSelfUpdatePlan.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,15 @@ function Get-NovaModuleSelfUpdatePlan {
[Parameter(Mandatory)][bool]$PrereleaseNotificationsEnabled
)

$planContext = Get-NovaModuleSelfUpdatePlanContext -LookupResult $LookupResult -PrereleaseNotificationsEnabled:$PrereleaseNotificationsEnabled
$stableVersion = Get-NovaAvailableSemanticVersion -VersionInfo $LookupResult.Stable
if (Test-NovaPrereleaseUpdateAvailable -LookupResult $LookupResult -InstalledVersion $InstalledModule.SemanticVersion -StableVersion $stableVersion -PrereleaseNotificationsEnabled $PrereleaseNotificationsEnabled) {
return ConvertTo-NovaModuleSelfUpdatePlan -InstalledModule $InstalledModule -PrereleaseNotificationsEnabled:$PrereleaseNotificationsEnabled -TargetVersion $LookupResult.Prerelease.Version -PrereleaseTarget
return ConvertTo-NovaModuleSelfUpdatePlan -InstalledModule $InstalledModule -PlanContext $planContext -TargetVersion $LookupResult.Prerelease.Version -PrereleaseTarget
}

if (Test-NovaStableUpdateAvailable -StableVersion $stableVersion -InstalledVersion $InstalledModule.SemanticVersion) {
return ConvertTo-NovaModuleSelfUpdatePlan -InstalledModule $InstalledModule -PrereleaseNotificationsEnabled:$PrereleaseNotificationsEnabled -TargetVersion $LookupResult.Stable.Version
return ConvertTo-NovaModuleSelfUpdatePlan -InstalledModule $InstalledModule -PlanContext $planContext -TargetVersion $LookupResult.Stable.Version
}

return ConvertTo-NovaModuleSelfUpdatePlan -InstalledModule $InstalledModule -PrereleaseNotificationsEnabled:$PrereleaseNotificationsEnabled
return ConvertTo-NovaModuleSelfUpdatePlan -InstalledModule $InstalledModule -PlanContext $planContext
}
7 changes: 5 additions & 2 deletions src/resources/update/ModuleUpdateLookup.ps1.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ $WarningPreference = 'SilentlyContinue'
$InformationPreference = 'SilentlyContinue'
$VerbosePreference = 'SilentlyContinue'
$ErrorActionPreference = 'Stop'
$repositoryName = 'PSGallery'

function Get-PrereleaseLabel {
param([object]$Item)
Expand Down Expand Up @@ -47,19 +48,21 @@ function ConvertTo-VersionInfo {
return [pscustomobject]@{
ModuleName = $ResolvedModuleName
Channel = $Channel
Repository = $repositoryName
Version = $versionText
}
}

$stableItem = Find-Module $ResolvedModuleName -ErrorAction Stop -WarningAction SilentlyContinue
$stableItem = Find-Module $ResolvedModuleName -Repository $repositoryName -ErrorAction Stop -WarningAction SilentlyContinue
$prereleaseItem = if ($IncludePrerelease) {
Find-Module $ResolvedModuleName -AllowPrerelease -ErrorAction Stop -WarningAction SilentlyContinue
Find-Module $ResolvedModuleName -Repository $repositoryName -AllowPrerelease -ErrorAction Stop -WarningAction SilentlyContinue
}
else {
$null
}

[pscustomobject]@{
SourceRepository = $repositoryName
Stable = ConvertTo-VersionInfo -Item $stableItem -Channel 'Stable'
Prerelease = ConvertTo-VersionInfo -Item $prereleaseItem -Channel 'Prerelease'
}
79 changes: 79 additions & 0 deletions tests/UpdateNotification.Tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,71 @@ Describe 'Update notification behavior' {
}
}

It 'Get-NovaModuleSelfUpdatePlan preserves the lookup candidate and repository for no-update results' {
InModuleScope $script:moduleName {
$installedModule = [pscustomobject]@{
ModuleName = 'NovaModuleTools'
Version = '2.0.0-preview9920'
SemanticVersion = [semver]'2.0.0-preview9920'
IsPrerelease = $true
}
$lookupResult = [pscustomobject]@{
SourceRepository = 'PSGallery'
Stable = [pscustomobject]@{
Version = '1.9.1'
Channel = 'Stable'
Repository = 'PSGallery'
}
Prerelease = [pscustomobject]@{
Version = '2.0.0-beta'
Channel = 'Prerelease'
Repository = 'PSGallery'
}
}

$result = Get-NovaModuleSelfUpdatePlan -InstalledModule $installedModule -LookupResult $lookupResult -PrereleaseNotificationsEnabled:$true

$result.UpdateAvailable | Should -BeFalse
$result.TargetVersion | Should -BeNullOrEmpty
$result.LookupCandidateVersion | Should -Be '2.0.0-beta'
$result.LookupCandidateChannel | Should -Be 'Prerelease'
$result.LookupRepository | Should -Be 'PSGallery'
}
}

It 'Get-NovaModuleSelfUpdatePlanContext returns empty lookup fields when no lookup result is available' {
InModuleScope $script:moduleName {
$result = Get-NovaModuleSelfUpdatePlanContext -LookupResult $null -PrereleaseNotificationsEnabled:$true

$result.LookupCandidateVersion | Should -BeNullOrEmpty
$result.LookupCandidateChannel | Should -BeNullOrEmpty
$result.LookupRepository | Should -BeNullOrEmpty
$result.PrereleaseNotificationsEnabled | Should -BeTrue
}
}

It 'Get-NovaModuleSelfUpdatePlanContext falls back to SourceRepository when the selected lookup candidate omits Repository' {
InModuleScope $script:moduleName {
$lookupResult = [pscustomobject]@{
SourceRepository = 'PSGallery'
Stable = [pscustomobject]@{
Version = '1.9.1'
Channel = 'Stable'
}
Prerelease = [pscustomobject]@{
Version = '2.0.0-beta'
Channel = 'Prerelease'
}
}

$result = Get-NovaModuleSelfUpdatePlanContext -LookupResult $lookupResult -PrereleaseNotificationsEnabled:$true

$result.LookupCandidateVersion | Should -Be '2.0.0-beta'
$result.LookupCandidateChannel | Should -Be 'Prerelease'
$result.LookupRepository | Should -Be 'PSGallery'
}
}

It 'Get-NovaModuleSelfUpdateWorkflowContext throws when update lookup cannot resolve a candidate' {
InModuleScope $script:moduleName {
Mock Read-NovaUpdateNotificationPreference {[pscustomobject]@{PrereleaseNotificationsEnabled = $true}}
Expand Down Expand Up @@ -549,6 +614,9 @@ Describe 'Update notification behavior' {
ModuleName = 'NovaModuleTools'
CurrentVersion = '2.0.0-prerelease3'
TargetVersion = $null
LookupCandidateVersion = '2.0.0-beta'
LookupCandidateChannel = 'Prerelease'
LookupRepository = 'PSGallery'
PrereleaseNotificationsEnabled = $true
UpdateAvailable = $false
Updated = $false
Expand All @@ -567,6 +635,17 @@ Describe 'Update notification behavior' {
}
}

It 'Get-NovaModuleUpdateLookupScript pins lookups to PSGallery and returns repository metadata' {
InModuleScope $script:moduleName {
$scriptText = Get-NovaModuleUpdateLookupScript

$scriptText | Should -Match 'Find-Module \$ResolvedModuleName -Repository \$repositoryName'
$scriptText | Should -Match 'Find-Module \$ResolvedModuleName -Repository \$repositoryName -AllowPrerelease'
$scriptText | Should -Match 'SourceRepository = \$repositoryName'
$scriptText | Should -Match 'Repository = \$repositoryName'
}
}

It 'ConvertFrom-NovaUpdateCliArgument allows no arguments and rejects unsupported usage' {
InModuleScope $script:moduleName {
(ConvertFrom-NovaUpdateCliArgument).Count | Should -Be 0
Expand Down
Loading