From 757624b134f2e5f5a3d117423a2e4df46f6b0285 Mon Sep 17 00:00:00 2001 From: Rail Aliiev Date: Thu, 8 May 2025 15:49:31 -0400 Subject: [PATCH 1/2] Add IncPatch and IncPreRelease methods In the release process we bump the version at the end of the process. At this moment this applies to the patch and pre-release versions. This commit implements the `IncPatch()` and `IncPreRelease()` methods to bump the version. --- version.go | 32 ++++++++++++++++++++++++++++ version_test.go | 55 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 87 insertions(+) diff --git a/version.go b/version.go index 054caa4..90950d8 100644 --- a/version.go +++ b/version.go @@ -364,3 +364,35 @@ func (v Version) CompareSeries(w Version) int { func (v Version) AtLeast(w Version) bool { return v.Compare(w) >= 0 } + +// IncPatch returns a new version with the patch number incremented by 1. +// The metadata part of the version (pre release, cloudonly, etc) is dropped. +// In other words, the version becomes a stable version. +func (v Version) IncPatch() Version { + nextVersion := Version{ + phase: stable, + year: v.year, + ordinal: v.ordinal, + patch: v.patch + 1, + } + nextVersion.raw = nextVersion.Format("v%X.%Y.%Z") + return nextVersion +} + +// IncPreRelease returns a new version with the pre-release part incremented by 1. +// This method returns an error if the version is not a pre-release. +func (v Version) IncPreRelease() (Version, error) { + if !(v.IsPrerelease()) { + return Version{}, errors.New("version is not a prerelease") + } + nextVersion := Version{ + raw: v.raw, + phase: v.phase, + year: v.year, + ordinal: v.ordinal, + patch: v.patch, + phaseOrdinal: v.phaseOrdinal + 1, + } + nextVersion.raw = nextVersion.Format("v%X.%Y.%Z-%P.%o") + return nextVersion, nil +} diff --git a/version_test.go b/version_test.go index 14ef93b..76c72ec 100644 --- a/version_test.go +++ b/version_test.go @@ -662,3 +662,58 @@ func TestScan(t *testing.T) { err = v.Scan(123) // or any other type require.ErrorContains(t, err, "cannot convert int to Version") } + +func TestIncPatch(t *testing.T) { + testCases := []struct { + currentVersion string + nextVersion string + }{ + {"v21.2.0-alpha.1", "v21.2.1"}, + {"v21.1.0-beta.3", "v21.1.1"}, + {"v21.1.0-rc.3", "v21.1.1"}, + {"v20.2.7", "v20.2.8"}, + {"v21.1.2", "v21.1.3"}, + {"v21.1.3", "v21.1.4"}, + {"v20.2.11", "v20.2.12"}, + {"v21.1.0", "v21.1.1"}, + {"v21.1.0-customLabel", "v21.1.1"}, + } + for i, tc := range testCases { + t.Run(fmt.Sprintf("Version.IncPatch #%d: %s -> %s", i, tc.currentVersion, tc.nextVersion), func(t *testing.T) { + a := MustParse(tc.currentVersion) + b := a.IncPatch() + require.Equal(t, MustParse(tc.nextVersion), b) + }) + } +} + +func TestIncPreRelease(t *testing.T) { + testCases := []struct { + currentVersion string + nextVersion string + expectError bool + }{ + {"v21.2.0-alpha.1", "v21.2.0-alpha.2", false}, + {"v21.1.0-beta.3", "v21.1.0-beta.4", false}, + {"v21.1.0-rc.3", "v21.1.0-rc.4", false}, + {"v21.1.0-cloudonly.1", "", true}, + {"v21.1.0", "", true}, + {"v21.1.8", "", true}, + {"v26.4.8", "", true}, + {"v21.1.0-customLabel", "", true}, + {"v21.1.0-1-g9cbe7c5281", "", true}, + {"v21.1.0-1-g9cbe7c5281-customLabel", "", true}, + } + for i, tc := range testCases { + t.Run(fmt.Sprintf("Version.IncPhaseOrdinal #%d: %s -> %s", i, tc.currentVersion, tc.nextVersion), func(t *testing.T) { + a := MustParse(tc.currentVersion) + b, err := a.IncPreRelease() + if tc.expectError { + require.Error(t, err) + return + } + require.NoError(t, err) + require.Equal(t, MustParse(tc.nextVersion), b) + }) + } +} From 7dfa3b73fbec5ca855c237acb7b4bc806eab1c38 Mon Sep 17 00:00:00 2001 From: Rail Aliiev Date: Fri, 9 May 2025 09:07:52 -0400 Subject: [PATCH 2/2] Address PR comments --- version.go | 12 +++++++----- version_test.go | 28 ++++++++++++++++++---------- 2 files changed, 25 insertions(+), 15 deletions(-) diff --git a/version.go b/version.go index 90950d8..50d56b6 100644 --- a/version.go +++ b/version.go @@ -366,17 +366,19 @@ func (v Version) AtLeast(w Version) bool { } // IncPatch returns a new version with the patch number incremented by 1. -// The metadata part of the version (pre release, cloudonly, etc) is dropped. -// In other words, the version becomes a stable version. -func (v Version) IncPatch() Version { +// This method returns an error if the version is not a stable version. +func (v Version) IncPatch() (Version, error) { + if v.phase != stable { + return Version{}, fmt.Errorf("version %s is not a stable version", v.String()) + } nextVersion := Version{ - phase: stable, + phase: v.phase, year: v.year, ordinal: v.ordinal, patch: v.patch + 1, } nextVersion.raw = nextVersion.Format("v%X.%Y.%Z") - return nextVersion + return nextVersion, nil } // IncPreRelease returns a new version with the pre-release part incremented by 1. diff --git a/version_test.go b/version_test.go index 76c72ec..7baa926 100644 --- a/version_test.go +++ b/version_test.go @@ -667,21 +667,29 @@ func TestIncPatch(t *testing.T) { testCases := []struct { currentVersion string nextVersion string + expectError bool }{ - {"v21.2.0-alpha.1", "v21.2.1"}, - {"v21.1.0-beta.3", "v21.1.1"}, - {"v21.1.0-rc.3", "v21.1.1"}, - {"v20.2.7", "v20.2.8"}, - {"v21.1.2", "v21.1.3"}, - {"v21.1.3", "v21.1.4"}, - {"v20.2.11", "v20.2.12"}, - {"v21.1.0", "v21.1.1"}, - {"v21.1.0-customLabel", "v21.1.1"}, + {"v21.2.0-alpha.1", "", true}, + {"v21.1.0-beta.3", "", true}, + {"v21.1.0-rc.3", "", true}, + {"v21.1.0-rc.3-cloudonly.1", "", true}, + {"v21.1.0-customLabel", "", true}, + {"v21.1.0-cloudonly.3", "", true}, + {"v20.2.7", "v20.2.8", false}, + {"v21.1.2", "v21.1.3", false}, + {"v21.1.3", "v21.1.4", false}, + {"v20.2.11", "v20.2.12", false}, + {"v21.1.0", "v21.1.1", false}, } for i, tc := range testCases { t.Run(fmt.Sprintf("Version.IncPatch #%d: %s -> %s", i, tc.currentVersion, tc.nextVersion), func(t *testing.T) { a := MustParse(tc.currentVersion) - b := a.IncPatch() + b, err := a.IncPatch() + if tc.expectError { + require.Error(t, err) + return + } + require.NoError(t, err) require.Equal(t, MustParse(tc.nextVersion), b) }) }