Skip to content

Commit 302c910

Browse files
committed
feat(#163): enhance preview mode for stable version bumps
- Make `Update-NovaModuleVersion -Preview` enter the next patch preview track deterministically from stable versions - Ensure stable versions increment the patch version and append `-preview` - Maintain existing prerelease versions' semantic core and sequence
1 parent ffd6877 commit 302c910

7 files changed

Lines changed: 93 additions & 32 deletions

File tree

CHANGELOG.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,13 @@ Keep stable `Update-NovaModuleVersion` / `% nova bump` releases on the SemVer ma
2121
minor version instead of auto-jumping to `1.0.0`.
2222
- Stable `0.y.z` bump results now print one warning about manually setting `1.0.0` once the software is stable,
2323
while breaking-change bumps still report the detected `Major` label.
24-
- `-Preview` behavior is unchanged.
24+
- Make `Update-NovaModuleVersion -Preview` / `% nova bump --preview` enter the preview track deterministically from
25+
stable versions.
26+
- Stable versions now always become the next patch preview, for example `0.2.0 -> 0.2.1-preview`, instead of
27+
reusing semantic history inference for the semantic core.
28+
- Existing prerelease versions still keep their current semantic core and continue the prerelease sequence.
29+
- Running the bump without `-Preview` still finalizes or advances prerelease versions by Nova's normal semantic
30+
rules.
2531

2632
### Deprecated
2733

docs/NovaModuleTools/en-US/Update-NovaModuleVersion.md

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,9 @@ project repository, chooses a semantic version bump label, calculates the next s
3030
version back to `project.json`.
3131

3232
Use `-Preview` when you want an explicit prerelease-continuation bump instead of the default prerelease finalization
33-
behavior. In preview mode, stable versions first calculate the normal semantic bump target and then append
34-
`-preview`. Existing prerelease versions keep the same semantic core and preserve the current prerelease stem while
33+
behavior. In preview mode, stable versions always enter the next patch preview track by incrementing the patch version
34+
and appending `-preview`. Existing prerelease versions keep the same semantic core and preserve the current prerelease
35+
stem while
3536
appending or incrementing trailing digits. Any bare prerelease label now starts at `01` for predictable ordering,
3637
for example `preview -> preview01`, `preview09 -> preview10`, `rc -> rc01`, `rc1 -> rc2`, and
3738
`SNAPSHOT -> SNAPSHOT01`.
@@ -45,7 +46,8 @@ The release label is inferred from the commit set:
4546
When the current stable version is still on `0.y.z` and the inferred label is `Major`, Nova keeps the release on the
4647
initial-development line and plans the next minor version instead of jumping straight to `1.0.0`. The result still
4748
reports the detected `Major` label so you can see that the commit set contained a breaking change, and Nova prints
48-
guidance about manually setting `1.0.0` once the software is stable. `-Preview` behavior stays unchanged.
49+
guidance about manually setting `1.0.0` once the software is stable. With `-Preview`, stable versions still enter the
50+
next patch preview track instead of applying semantic history inference to the semantic core.
4951

5052
When Git tags exist, only commits since the latest tag are considered. If the folder is not a Git repository, the
5153
command falls back to a patch bump.
@@ -120,13 +122,13 @@ PS> Update-NovaModuleVersion -Preview -WhatIf
120122
What if: Performing the operation "Update module version using Minor release label" on target "project.json".
121123
122124
PreviousVersion: 1.5.3
123-
NewVersion: 1.6.0-preview
125+
NewVersion: 1.5.4-preview
124126
Label: Minor
125127
CommitCount: 12
126128
```
127129

128-
Shows how `-Preview` keeps the normal bump label selection but emits a preview target when the current version is
129-
stable.
130+
Shows how `-Preview` keeps the detected semantic label for reporting but deterministically enters the next patch preview
131+
track when the current version is stable.
130132

131133
### EXAMPLE 6
132134

@@ -211,7 +213,7 @@ HelpMessage: ''
211213
212214
Opt into preview bump mode.
213215
214-
When the current version is stable, Nova calculates the normal semantic target and appends `-preview`. When the current
216+
When the current version is stable, Nova increments the patch version and appends `-preview`. When the current
215217
version already has any prerelease label, Nova keeps the same semantic core version and increments the current
216218
prerelease suffix instead of finalizing or advancing to another release line. Any prerelease stem without a trailing
217219
number starts at `01`, while labels that already include a number simply increment that number.

src/private/release/GetNovaVersionUpdatePlan.ps1

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,12 @@ function Get-NovaVersionPartForUpdatePlan {
5757
[switch]$PreviewRelease
5858
)
5959

60-
if ($PreviewRelease -and -not [string]::IsNullOrWhiteSpace($CurrentVersion.PreReleaseLabel)) {
61-
return Get-NovaVersionPartObject -CurrentVersion $CurrentVersion
60+
if ($PreviewRelease) {
61+
if (-not [string]::IsNullOrWhiteSpace($CurrentVersion.PreReleaseLabel)) {
62+
return Get-NovaVersionPartObject -CurrentVersion $CurrentVersion
63+
}
64+
65+
return Get-NovaVersionPartForLabel -CurrentVersion $CurrentVersion -Label Patch
6266
}
6367

6468
return Get-NovaVersionPartForLabel -CurrentVersion $CurrentVersion -Label $Label

src/private/release/GetNovaVersionUpdateWorkflowContext.ps1

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,10 @@ function Get-NovaVersionUpdateLabelResolution {
2626
$effectiveLabel = $Label
2727
$advisoryMessage = $null
2828
$currentVersion = Get-NovaCurrentVersionForUpdatePlan -ProjectInfo $ProjectInfo
29+
if (Test-NovaVersionUpdateUsesPreviewPatchFallback -CurrentVersion $currentVersion -PreviewRelease:$PreviewRelease) {
30+
$effectiveLabel = 'Patch'
31+
}
32+
2933
if (Test-NovaVersionUpdateUsesInitialDevelopmentAdvisory -CurrentVersion $currentVersion -PreviewRelease:$PreviewRelease) {
3034
$advisoryMessage = Get-NovaInitialDevelopmentVersioningMessage
3135
}
@@ -40,6 +44,20 @@ function Get-NovaVersionUpdateLabelResolution {
4044
}
4145
}
4246

47+
function Test-NovaVersionUpdateUsesPreviewPatchFallback {
48+
[CmdletBinding()]
49+
param(
50+
[Parameter(Mandatory)][semver]$CurrentVersion,
51+
[switch]$PreviewRelease
52+
)
53+
54+
if (-not $PreviewRelease) {
55+
return $false
56+
}
57+
58+
return [string]::IsNullOrWhiteSpace($CurrentVersion.PreReleaseLabel)
59+
}
60+
4361
function Test-NovaVersionUpdateUsesInitialDevelopmentAdvisory {
4462
[CmdletBinding()]
4563
param(

tests/CoverageGaps.ReleaseInternals.Tests.ps1

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -129,9 +129,9 @@ Describe 'Coverage gaps for release and git internals' {
129129
}
130130
}
131131

132-
It 'Get-NovaVersionUpdatePlan appends a preview label to the normal bump target when preview mode starts from stable' -ForEach @(
133-
@{CurrentVersion = '1.5.3'; Label = 'Major'; ExpectedVersion = '2.0.0-preview'}
134-
@{CurrentVersion = '1.5.3'; Label = 'Minor'; ExpectedVersion = '1.6.0-preview'}
132+
It 'Get-NovaVersionUpdatePlan enters the next patch preview track from stable versions regardless of the inferred label' -ForEach @(
133+
@{CurrentVersion = '1.5.3'; Label = 'Major'; ExpectedVersion = '1.5.4-preview'}
134+
@{CurrentVersion = '1.5.3'; Label = 'Minor'; ExpectedVersion = '1.5.4-preview'}
135135
@{CurrentVersion = '1.5.3'; Label = 'Patch'; ExpectedVersion = '1.5.4-preview'}
136136
) {
137137
InModuleScope $script:moduleName -Parameters @{TestCase = $_} {
@@ -170,14 +170,14 @@ Describe 'Coverage gaps for release and git internals' {
170170
ExpectedPlanLabel = 'Minor'
171171
}
172172
@{
173-
Name = 'preview mode remains unchanged'
173+
Name = 'preview mode enters the next patch preview from stable major-zero versions'
174174
CurrentVersion = '0.1.0'
175175
Label = 'Major'
176176
PreviewRelease = $true
177-
PlannedVersion = '1.0.0-preview'
178-
ExpectedEffectiveLabel = 'Major'
177+
PlannedVersion = '0.1.1-preview'
178+
ExpectedEffectiveLabel = 'Patch'
179179
ExpectedAdvisoryPattern = $null
180-
ExpectedPlanLabel = 'Major'
180+
ExpectedPlanLabel = 'Patch'
181181
}
182182
) {
183183
InModuleScope $script:moduleName -Parameters @{TestCase = $_} {
@@ -284,9 +284,9 @@ Describe 'Coverage gaps for release and git internals' {
284284
$updatedProject = Get-Content -LiteralPath $projectJsonPath -Raw | ConvertFrom-Json
285285

286286
$result.PreviousVersion | Should -Be '1.2.3'
287-
$result.NewVersion | Should -Be '1.3.0-preview'
287+
$result.NewVersion | Should -Be '1.2.4-preview'
288288
$result.Applied | Should -BeTrue
289-
$updatedProject.Version | Should -Be '1.3.0-preview'
289+
$updatedProject.Version | Should -Be '1.2.4-preview'
290290
$updatedProject.Package.Auth.HeaderName | Should -Be 'Authorization'
291291
$updatedProject.Package.Repositories.Count | Should -Be 1
292292
($updatedProject.Package.Repositories[0] -is [string]) | Should -BeFalse
@@ -301,7 +301,7 @@ Describe 'Coverage gaps for release and git internals' {
301301
Mock Get-NovaVersionUpdatePlan {
302302
[pscustomobject]@{
303303
ProjectFile = '/tmp/project.json'
304-
NewVersion = [semver]'1.3.0-preview'
304+
NewVersion = [semver]'1.2.4-preview'
305305
}
306306
}
307307
Mock Read-ProjectJsonData {
@@ -322,12 +322,12 @@ Describe 'Coverage gaps for release and git internals' {
322322

323323
$result.ProjectFile | Should -Be '/tmp/project.json'
324324
$result.PreviousVersion | Should -Be '1.2.3'
325-
$result.NewVersion | Should -Be '1.3.0-preview'
325+
$result.NewVersion | Should -Be '1.2.4-preview'
326326
$result.Applied | Should -BeTrue
327327
Assert-MockCalled Read-ProjectJsonData -Times 1 -ParameterFilter {$ProjectJsonPath -eq '/tmp/project.json'}
328328
Assert-MockCalled Write-ProjectJsonData -Times 1 -ParameterFilter {
329329
$ProjectJsonPath -eq '/tmp/project.json' -and
330-
$Data.Version -eq '1.3.0-preview' -and
330+
$Data.Version -eq '1.2.4-preview' -and
331331
$Data.Package.Repositories[0].Name -eq 'staging'
332332
}
333333
}
@@ -338,7 +338,7 @@ Describe 'Coverage gaps for release and git internals' {
338338
Mock Get-NovaVersionUpdatePlan {
339339
[pscustomobject]@{
340340
ProjectFile = '/tmp/project.json'
341-
NewVersion = [semver]'1.3.0-preview'
341+
NewVersion = [semver]'1.2.4-preview'
342342
}
343343
}
344344
Mock Read-ProjectJsonData {
@@ -352,7 +352,7 @@ Describe 'Coverage gaps for release and git internals' {
352352

353353
$result.ProjectFile | Should -Be '/tmp/project.json'
354354
$result.PreviousVersion | Should -Be '1.2.3'
355-
$result.NewVersion | Should -Be '1.3.0-preview'
355+
$result.NewVersion | Should -Be '1.2.4-preview'
356356
$result.Applied | Should -BeFalse
357357
Assert-MockCalled Read-ProjectJsonData -Times 1 -ParameterFilter {$ProjectJsonPath -eq '/tmp/project.json'}
358358
Assert-MockCalled Write-ProjectJsonData -Times 0

tests/NovaCommandModel.BumpAndCli.Tests.ps1

Lines changed: 38 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,36 @@ Describe 'Nova command model - bump and CLI confirmation behavior' {
138138
}
139139
}
140140

141+
It 'Get-NovaVersionUpdateWorkflowContext keeps the detected label but enters the next patch preview track from a stable version' {
142+
InModuleScope $script:moduleName {
143+
Mock Get-NovaProjectInfo {
144+
[pscustomobject]@{
145+
ProjectName = 'NovaModuleTools'
146+
Version = '1.5.3'
147+
ProjectJSON = '/tmp/project.json'
148+
}
149+
}
150+
Mock Get-GitCommitMessageForVersionBump {@('feat: add change')}
151+
Mock Get-NovaVersionLabelForBump {'Minor'}
152+
Mock Get-NovaVersionUpdatePlan {
153+
[pscustomobject]@{
154+
NewVersion = [semver]'1.5.4-preview'
155+
}
156+
}
157+
158+
$result = Get-NovaVersionUpdateWorkflowContext -ProjectRoot '/tmp/project' -PreviewRelease
159+
160+
$result.Label | Should -Be 'Minor'
161+
$result.EffectiveLabel | Should -Be 'Patch'
162+
$result.NewVersion | Should -Be '1.5.4-preview'
163+
Assert-MockCalled Get-NovaVersionUpdatePlan -Times 1 -ParameterFilter {
164+
$ProjectInfo.ProjectName -eq 'NovaModuleTools' -and
165+
$Label -eq 'Patch' -and
166+
$PreviewRelease
167+
}
168+
}
169+
}
170+
141171
It 'Get-NovaVersionUpdateWorkflowContext carries ContinuousIntegrationRequested when requested' {
142172
InModuleScope $script:moduleName {
143173
Mock Get-NovaProjectInfo {
@@ -423,11 +453,11 @@ Describe 'Nova command model - bump and CLI confirmation behavior' {
423453
}
424454

425455
It 'Update-NovaModuleVersion -WhatIf returns the expected next version without persisting it when <Name>' -ForEach @(
426-
@{Name = 'the default bump flow is used'; CurrentVersion = '1.0.0'; CommitMessages = @('feat: add change'); Label = 'Minor'; NewVersion = '1.1.0'; Preview = $false}
427-
@{Name = 'preview mode starts from a stable version'; CurrentVersion = '1.5.3'; CommitMessages = @('feat: add change'); Label = 'Minor'; NewVersion = '1.6.0-preview'; Preview = $true}
428-
@{Name = 'preview mode zero-pads compact preview labels for gallery ordering'; CurrentVersion = '1.5.3-preview'; CommitMessages = @('fix: patch bug'); Label = 'Patch'; NewVersion = '1.5.3-preview01'; Preview = $true}
429-
@{Name = 'preview mode starts any bare prerelease stem at 01'; CurrentVersion = '1.5.3-SNAPSHOT'; CommitMessages = @('feat!: breaking api'); Label = 'Major'; NewVersion = '1.5.3-SNAPSHOT01'; Preview = $true}
430-
@{Name = 'preview mode continues an existing prerelease version'; CurrentVersion = '1.5.3-rc1'; CommitMessages = @('feat!: breaking api'); Label = 'Major'; NewVersion = '1.5.3-rc2'; Preview = $true}
456+
@{Name = 'the default bump flow is used'; CurrentVersion = '1.0.0'; CommitMessages = @('feat: add change'); Label = 'Minor'; EffectiveLabel = 'Minor'; NewVersion = '1.1.0'; Preview = $false}
457+
@{Name = 'preview mode enters the next patch preview track from a stable version'; CurrentVersion = '1.5.3'; CommitMessages = @('feat: add change'); Label = 'Minor'; EffectiveLabel = 'Patch'; NewVersion = '1.5.4-preview'; Preview = $true}
458+
@{Name = 'preview mode zero-pads compact preview labels for gallery ordering'; CurrentVersion = '1.5.3-preview'; CommitMessages = @('fix: patch bug'); Label = 'Patch'; EffectiveLabel = 'Patch'; NewVersion = '1.5.3-preview01'; Preview = $true}
459+
@{Name = 'preview mode starts any bare prerelease stem at 01'; CurrentVersion = '1.5.3-SNAPSHOT'; CommitMessages = @('feat!: breaking api'); Label = 'Major'; EffectiveLabel = 'Major'; NewVersion = '1.5.3-SNAPSHOT01'; Preview = $true}
460+
@{Name = 'preview mode continues an existing prerelease version'; CurrentVersion = '1.5.3-rc1'; CommitMessages = @('feat!: breaking api'); Label = 'Major'; EffectiveLabel = 'Major'; NewVersion = '1.5.3-rc2'; Preview = $true}
431461
) {
432462
InModuleScope $script:moduleName -Parameters @{TestCase = $_} {
433463
param($TestCase)
@@ -459,9 +489,10 @@ Describe 'Nova command model - bump and CLI confirmation behavior' {
459489
$result.PreviousVersion | Should -Be $TestCase.CurrentVersion
460490
$result.NewVersion | Should -Be $TestCase.NewVersion
461491
$result.Label | Should -Be $TestCase.Label
462-
Assert-MockCalled Get-NovaVersionUpdatePlan -Times 1 -ParameterFilter {$Label -eq $TestCase.Label}
492+
$result.EffectiveLabel | Should -Be $TestCase.EffectiveLabel
493+
Assert-MockCalled Get-NovaVersionUpdatePlan -Times 1 -ParameterFilter {$Label -eq $TestCase.EffectiveLabel}
463494
Assert-MockCalled Get-NovaVersionUpdatePlan -Times 1 -ParameterFilter {
464-
$Label -eq $TestCase.Label -and
495+
$Label -eq $TestCase.EffectiveLabel -and
465496
([bool]$PreviewRelease) -eq ([bool]$TestCase.Preview)
466497
}
467498

tests/NovaCommandModel.TestSupport/CliProjectSupport.ps1

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -216,7 +216,7 @@ function Assert-TestNovaCliWhatIfResultMap {
216216

217217
$ResultMap.Bump.Text | Should -Match 'Version plan: 0\.0\.1 -> 0\.1\.0 \| Label: Minor \| Commits: 1'
218218
$ResultMap.BumpCi.Text | Should -Match 'Version plan: 0\.0\.1 -> 0\.1\.0 \| Label: Minor \| Commits: 1'
219-
$ResultMap.PreviewBump.Text | Should -Match 'Version plan: 0\.0\.1 -> 0\.1\.0-preview \| Label: Minor \| Commits: 1'
219+
$ResultMap.PreviewBump.Text | Should -Match 'Version plan: 0\.0\.1 -> 0\.0\.2-preview \| Label: Minor \| Commits: 1'
220220
$ResultMap.Bump.Text | Should -Not -Match 'Version bumped to :'
221221
$ResultMap.PreviewBump.Text | Should -Not -Match 'Version bumped to :'
222222
((Get-Content -LiteralPath $ProjectJsonPath -Raw | ConvertFrom-Json).Version) | Should -Be '0.0.1'

0 commit comments

Comments
 (0)