diff --git a/CHANGELOG.md b/CHANGELOG.md index 46b974a..ccaccd4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), ### Fixed +- `Update-NovaModuleVersion`, `% nova bump`, and `Invoke-NovaRelease` now preserve an exact stable `1.0.0` as the first stable release target instead of auto-advancing it from inferred fix, feature, or breaking-change history. + - Once you manually select `1.0.0` in `project.json`, Nova still reports the detected semantic label, but the next stable release stays `1.0.0`. + - Preview bumps from exact stable `1.0.0` still enter the next patch preview track as `1.0.1-preview`. + ### Security ## [3.4.1] - 2026-10-08 @@ -556,4 +560,3 @@ This release was yanked because it removed the implicit `Pester` dependency, bef [0.0.6]: https://github.com/stiwicourage/NovaModuleTools/compare/Version_0.0.5...Version_0.0.6 [0.0.5]: https://github.com/stiwicourage/NovaModuleTools/compare/Version_0.0.4...Version_0.0.5 [0.0.4]: https://github.com/stiwicourage/NovaModuleTools/compare/Version_0.0.3...Version_0.0.4 - diff --git a/README.md b/README.md index a821b94..f571138 100644 --- a/README.md +++ b/README.md @@ -245,10 +245,11 @@ These switches keep the behavior explicit and opt-in: - `Update-NovaModuleVersion -ContinuousIntegration` also falls back to a patch bump when the current `HEAD` already matches the latest tag, so release automation can seed the next prerelease line without requiring an extra commit first - `Update-NovaModuleVersion` and `% nova bump` now stop when Git-based bump inference is unavailable, unless you explicitly opt in to the Patch fallback with `-OverrideWarning` / `--override-warning` / `-o` for a non-git example/template flow - `Update-NovaModuleVersion` and `% nova bump` treat stable `0.y.z` versions as the SemVer initial-development phase, so breaking-change bumps stay on the `0.y.z` line by planning the next minor version instead of jumping to `1.0.0` +- `Update-NovaModuleVersion`, `% nova bump`, and `Invoke-NovaRelease` keep an exact stable `1.0.0` at `1.0.0` for the first stable release, even when the inferred history is Patch, Minor, or Major - `Publish-NovaModule -ContinuousIntegration` restores the built module after publish completes - `Invoke-NovaRelease -ContinuousIntegration` forwards that CI intent through the nested build/bump boundaries and then restores the built module again after publish -When the current stable version is still `0.y.z`, Nova also prints one warning that major version zero is still the initial-development line and that `1.0.0` must be set manually once the software is stable. Preview bumps keep their current behavior and are not remapped by this rule. +When the current stable version is still `0.y.z`, Nova also prints one warning that major version zero is still the initial-development line and that `1.0.0` must be set manually once the software is stable. After you intentionally set the stable project version to exact `1.0.0`, Nova treats that value as the first stable release target, so the next stable bump still resolves to `1.0.0` even when the detected history is Patch, Minor, or Major. Preview bumps keep their current behavior and are not remapped by this rule. Useful local helper: diff --git a/RELEASE_NOTE.md b/RELEASE_NOTE.md index 8091d26..d6f80cb 100644 --- a/RELEASE_NOTE.md +++ b/RELEASE_NOTE.md @@ -14,6 +14,9 @@ This file summarizes the release notes for NovaModuleTools. **UNRELEASED** chang ### Fixed +- `Update-NovaModuleVersion`, `% nova bump`, and `Invoke-NovaRelease` now keep an exact stable `1.0.0` on `1.0.0` for the first stable release, even when the detected history is fix, feature, or breaking-change based. + - Preview bumps from exact stable `1.0.0` still move to `1.0.1-preview`. + ### Security ## [3.4.1] - 2026-10-08 @@ -294,4 +297,3 @@ This release was yanked because it removed the implicit `Pester` dependency befo ## [0.0.4] - 2024-06-25 ### Added - First PowerShell Gallery release of NovaModuleTools with the initial module workflow support. - diff --git a/docs/NovaModuleTools/en-US/Update-NovaModuleVersion.md b/docs/NovaModuleTools/en-US/Update-NovaModuleVersion.md index 989e097..c79cc00 100644 --- a/docs/NovaModuleTools/en-US/Update-NovaModuleVersion.md +++ b/docs/NovaModuleTools/en-US/Update-NovaModuleVersion.md @@ -36,7 +36,9 @@ The release label is inferred from the commit set: - `Minor` for `feat:` commits - `Patch` for `fix:` commits and all other cases -When the current stable version is still on `0.y.z` and the inferred label is `Major`, Nova keeps the release on the initial-development line and plans the next minor version instead of jumping straight to `1.0.0`. The result still reports the detected `Major` label so you can see that the commit set contained a breaking change, and Nova prints guidance about manually setting `1.0.0` once the software is stable. With `-Preview`, stable versions still enter the next patch preview track instead of applying semantic history inference to the semantic core. +When the current stable version is still on `0.y.z` and the inferred label is `Major`, Nova keeps the release on the initial-development line and plans the next minor version instead of jumping straight to `1.0.0`. The result still reports the detected `Major` label so you can see that the commit set contained a breaking change, and Nova prints guidance about manually setting `1.0.0` once the software is stable. + +When the current stable version is exactly `1.0.0`, Nova treats that as the manually selected initial stable release target. Fix, feature, and breaking-change histories still report their detected labels, but the planned stable release stays `1.0.0` instead of auto-advancing to `1.0.1`, `1.1.0`, or `2.0.0`. With `-Preview`, stable versions still enter the next patch preview track instead of applying semantic history inference to the semantic core. When Git tags exist, only commits since the latest tag are considered. If Git-based inference is unavailable because the project path is not inside a Git repository, the command stops with a clear warning/error instead of silently presenting an inferred-looking patch result. Use `-OverrideWarning` only when you intentionally want that Patch fallback, for example in example/template flows outside Git. @@ -169,6 +171,21 @@ Shows how stable `0.y.z` bumps still warn that `1.0.0` must be set manually when ### EXAMPLE 10 +```text +PS> Update-NovaModuleVersion -WhatIf + +What if: Performing the operation "Update module version using Major release label" on target "project.json". + +PreviousVersion: 1.0.0 +NewVersion: 1.0.0 +Label: Major +CommitCount: 34 +``` + +Shows how an exact stable `1.0.0` remains the selected first stable release target even when the inferred commit history contains a breaking change. Fix and feature histories behave the same way until that first stable release has been published and the project version moves beyond `1.0.0`. + +### EXAMPLE 11 + ```text PS> Update-NovaModuleVersion -Path ./src/resources/example -OverrideWarning -WhatIf diff --git a/docs/versioning-and-updates.html b/docs/versioning-and-updates.html index 6108b06..7de6206 100644 --- a/docs/versioning-and-updates.html +++ b/docs/versioning-and-updates.html @@ -172,6 +172,15 @@

How Nova chooses the bump label

0.0.1 + Patch -> 0.0.2
 0.1.0 + Minor -> 0.2.0
 0.1.0 + Major -> 0.2.0
+

Once you intentionally set the stable project version to exact 1.0.0, Nova treats that + value as the first stable release target. Fix, feature, and breaking-change histories still report + their detected semantic labels, but the selected stable release remains 1.0.0 instead + of auto-advancing to 1.0.1, 1.1.0, or 2.0.0. Preview mode + still starts the next patch preview track from that same stable target.

+
1.0.0 + Patch -> 1.0.0
+1.0.0 + Minor -> 1.0.0
+1.0.0 + Major -> 1.0.0
+1.0.0 + Major + -Preview -> 1.0.1-preview

When Git tags exist, Nova uses commits since the latest tag. When Git-based inference is unavailable because the project path is not inside a Git repository, Nova stops instead of silently presenting a normal-looking patch result. Use -OverrideWarning or the CLI form % nova bump diff --git a/project.json b/project.json index cdae5b8..f471e46 100644 --- a/project.json +++ b/project.json @@ -1,7 +1,7 @@ { "ProjectName": "NovaModuleTools", "Description": "NovaModuleTools is an enterprise-focused build tool for PowerShell module development, with a strong emphasis on structure, maintainability, and build for automated CI/CD pipelines.", - "Version": "3.4.1", + "Version": "3.4.2-preview", "Preamble": [ "Set-StrictMode -Version Latest", "$ErrorActionPreference = 'Stop'" diff --git a/src/private/release/GetNovaVersionUpdatePlan.ps1 b/src/private/release/GetNovaVersionUpdatePlan.ps1 index 58c5972..7db8c3f 100644 --- a/src/private/release/GetNovaVersionUpdatePlan.ps1 +++ b/src/private/release/GetNovaVersionUpdatePlan.ps1 @@ -57,6 +57,10 @@ function Get-NovaVersionPartForUpdatePlan { [switch]$PreviewRelease ) + if (Test-NovaVersionShouldPreserveInitialStableReleaseTarget -CurrentVersion $CurrentVersion -PreviewRelease:$PreviewRelease) { + return Get-NovaVersionPartObject -CurrentVersion $CurrentVersion + } + if ($PreviewRelease) { if (-not [string]::IsNullOrWhiteSpace($CurrentVersion.PreReleaseLabel)) { return Get-NovaVersionPartObject -CurrentVersion $CurrentVersion @@ -67,3 +71,21 @@ function Get-NovaVersionPartForUpdatePlan { return Get-NovaVersionPartForLabel -CurrentVersion $CurrentVersion -Label $Label } + +function Test-NovaVersionShouldPreserveInitialStableReleaseTarget { + [CmdletBinding()] + param( + [Parameter(Mandatory)][semver]$CurrentVersion, + [switch]$PreviewRelease + ) + + if ($PreviewRelease) { + return $false + } + + if (-not [string]::IsNullOrWhiteSpace($CurrentVersion.PreReleaseLabel)) { + return $false + } + + return $CurrentVersion.Major -eq 1 -and $CurrentVersion.Minor -eq 0 -and $CurrentVersion.Patch -eq 0 +} diff --git a/tests/private/release/GetNovaVersionUpdatePlan.Tests.ps1 b/tests/private/release/GetNovaVersionUpdatePlan.Tests.ps1 index 92f8273..bf085c6 100644 --- a/tests/private/release/GetNovaVersionUpdatePlan.Tests.ps1 +++ b/tests/private/release/GetNovaVersionUpdatePlan.Tests.ps1 @@ -53,6 +53,20 @@ Describe 'Get-NovaVersionPartForUpdatePlan' { } } +Describe 'Test-NovaVersionShouldPreserveInitialStableReleaseTarget' { + It 'returns true for exact stable 1.0.0 without preview mode' { + Test-NovaVersionShouldPreserveInitialStableReleaseTarget -CurrentVersion ([semver]'1.0.0') | Should -BeTrue + } + + It 'returns false when preview mode is requested' { + Test-NovaVersionShouldPreserveInitialStableReleaseTarget -CurrentVersion ([semver]'1.0.0') -PreviewRelease | Should -BeFalse + } + + It 'returns false when the current version is already a prerelease' { + Test-NovaVersionShouldPreserveInitialStableReleaseTarget -CurrentVersion ([semver]'1.0.0-preview01') | Should -BeFalse + } +} + Describe 'Get-NovaVersionUpdatePlan' { It 'returns a plan with project file and new version' { $info = [pscustomobject]@{ProjectJSON='/project.json'; Version='1.2.3'} @@ -60,4 +74,24 @@ Describe 'Get-NovaVersionUpdatePlan' { $plan.ProjectFile | Should -Be '/project.json' $plan.NewVersion.ToString() | Should -Be '1.2.4' } + + It 'keeps exact stable 1.0.0 regardless of inferred release label' -ForEach @( + @{ Scenario = 'fix commits'; Label = 'Patch' } + @{ Scenario = 'feature commits'; Label = 'Minor' } + @{ Scenario = 'breaking commits'; Label = 'Major' } + ) { + $info = [pscustomobject]@{ProjectJSON='/project.json'; Version='1.0.0'} + + $plan = Get-NovaVersionUpdatePlan -ProjectInfo $info -Label $Label + + $plan.NewVersion.ToString() | Should -Be '1.0.0' -Because "$Scenario should respect a manually selected initial stable release target" + } + + It 'keeps preview mode on the next patch preview track for exact stable 1.0.0' { + $info = [pscustomobject]@{ProjectJSON='/project.json'; Version='1.0.0'} + + $plan = Get-NovaVersionUpdatePlan -ProjectInfo $info -Label Major -PreviewRelease + + $plan.NewVersion.ToString() | Should -Be '1.0.1-preview' + } }