mirror of
https://github.com/lukaszraczylo/semver-generator.git
synced 2026-06-05 22:49:25 +00:00
dfeb03b8bb
Rolling tags like 'v1' (and any other tag that doesn't parse as x.y.z after prefix stripping) used to enter the latest-tag candidate set in CalculateSemver. When such a tag shared a commit with a real semver tag (e.g. v1 and v1.16.3 both pointing at the same release commit), go-git's alphabetical tag iteration made 'v1' win, ParseExistingSemver bailed out because '1' has only one component, and the calculator silently reset the baseline to 0.0.0 — producing nonsense like 0.0.5 on this branch. ListExistingTags now filters tags through a new IsParseableSemverTag helper before recording them, so non-semver tags never participate in latest-tag selection. The behavior change is invisible for repos that only use proper vX.Y.Z tags, and it's covered by a new test table.
281 lines
6.2 KiB
Go
281 lines
6.2 KiB
Go
package utils
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
)
|
|
|
|
func TestFormatSemver(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
semver SemVer
|
|
want string
|
|
}{
|
|
{
|
|
name: "Basic version",
|
|
semver: SemVer{
|
|
Major: 1,
|
|
Minor: 2,
|
|
Patch: 3,
|
|
},
|
|
want: "1.2.3",
|
|
},
|
|
{
|
|
name: "With release candidate",
|
|
semver: SemVer{
|
|
Major: 2,
|
|
Minor: 0,
|
|
Patch: 1,
|
|
Release: 5,
|
|
EnableReleaseCandidate: true,
|
|
},
|
|
want: "2.0.1-rc.5",
|
|
},
|
|
{
|
|
name: "With release candidate disabled",
|
|
semver: SemVer{
|
|
Major: 3,
|
|
Minor: 1,
|
|
Patch: 0,
|
|
Release: 2,
|
|
EnableReleaseCandidate: false,
|
|
},
|
|
want: "3.1.0",
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
got := FormatSemver(tt.semver)
|
|
assert.Equal(t, tt.want, got)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestParseExistingSemver(t *testing.T) {
|
|
// Initialize logger for tests
|
|
InitLogger(false)
|
|
|
|
tests := []struct {
|
|
name string
|
|
tagName string
|
|
currentSemver SemVer
|
|
prefixes []string
|
|
want SemVer
|
|
}{
|
|
{
|
|
name: "Standard semver",
|
|
tagName: "1.2.3",
|
|
currentSemver: SemVer{},
|
|
prefixes: []string{},
|
|
want: SemVer{
|
|
Major: 1,
|
|
Minor: 2,
|
|
Patch: 3,
|
|
},
|
|
},
|
|
{
|
|
name: "With v prefix configured",
|
|
tagName: "v2.3.4",
|
|
currentSemver: SemVer{},
|
|
prefixes: []string{"v"},
|
|
want: SemVer{
|
|
Major: 2,
|
|
Minor: 3,
|
|
Patch: 4,
|
|
},
|
|
},
|
|
{
|
|
name: "With app- prefix configured",
|
|
tagName: "app-1.2.3",
|
|
currentSemver: SemVer{},
|
|
prefixes: []string{"app-", "infra-"},
|
|
want: SemVer{
|
|
Major: 1,
|
|
Minor: 2,
|
|
Patch: 3,
|
|
},
|
|
},
|
|
{
|
|
name: "With prefix but not in config - should still parse numbers",
|
|
tagName: "v2.3.4",
|
|
currentSemver: SemVer{},
|
|
prefixes: []string{}, // v not in prefixes
|
|
want: SemVer{
|
|
Major: 2,
|
|
Minor: 3,
|
|
Patch: 4,
|
|
},
|
|
},
|
|
{
|
|
name: "With release candidate",
|
|
tagName: "3.4.5-rc.2",
|
|
currentSemver: SemVer{},
|
|
prefixes: []string{},
|
|
want: SemVer{
|
|
Major: 3,
|
|
Minor: 4,
|
|
Patch: 5,
|
|
Release: 2,
|
|
EnableReleaseCandidate: true,
|
|
},
|
|
},
|
|
{
|
|
name: "With prefix and release candidate",
|
|
tagName: "app-1.0.0-rc.3",
|
|
currentSemver: SemVer{},
|
|
prefixes: []string{"app-"},
|
|
want: SemVer{
|
|
Major: 1,
|
|
Minor: 0,
|
|
Patch: 0,
|
|
Release: 3,
|
|
EnableReleaseCandidate: true,
|
|
},
|
|
},
|
|
{
|
|
name: "Prefixed tag without RC should NOT be RC",
|
|
tagName: "app-0.0.16",
|
|
currentSemver: SemVer{},
|
|
prefixes: []string{"app-"},
|
|
want: SemVer{
|
|
Major: 0,
|
|
Minor: 0,
|
|
Patch: 16,
|
|
EnableReleaseCandidate: false,
|
|
},
|
|
},
|
|
{
|
|
name: "Invalid format",
|
|
tagName: "not-a-semver",
|
|
currentSemver: SemVer{
|
|
Major: 1,
|
|
Minor: 1,
|
|
Patch: 1,
|
|
},
|
|
prefixes: []string{},
|
|
want: SemVer{
|
|
Major: 1,
|
|
Minor: 1,
|
|
Patch: 1,
|
|
},
|
|
},
|
|
{
|
|
name: "Incomplete format",
|
|
tagName: "1.2",
|
|
currentSemver: SemVer{
|
|
Major: 5,
|
|
Minor: 5,
|
|
Patch: 5,
|
|
},
|
|
prefixes: []string{},
|
|
want: SemVer{
|
|
Major: 5,
|
|
Minor: 5,
|
|
Patch: 5,
|
|
},
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
got := ParseExistingSemver(tt.tagName, tt.currentSemver, tt.prefixes)
|
|
assert.Equal(t, tt.want.Major, got.Major, "Major version mismatch")
|
|
assert.Equal(t, tt.want.Minor, got.Minor, "Minor version mismatch")
|
|
assert.Equal(t, tt.want.Patch, got.Patch, "Patch version mismatch")
|
|
assert.Equal(t, tt.want.Release, got.Release, "Release version mismatch")
|
|
assert.Equal(t, tt.want.EnableReleaseCandidate, got.EnableReleaseCandidate, "EnableReleaseCandidate mismatch")
|
|
})
|
|
}
|
|
}
|
|
func TestIsParseableSemverTag(t *testing.T) {
|
|
InitLogger(false)
|
|
|
|
tests := []struct {
|
|
name string
|
|
tag string
|
|
prefixes []string
|
|
want bool
|
|
}{
|
|
{name: "plain x.y.z", tag: "1.2.3", want: true},
|
|
{name: "v prefix", tag: "v1.16.5", want: true},
|
|
{name: "v prefix with rc", tag: "v2.0.0-rc.3", want: true},
|
|
{name: "configured app- prefix", tag: "app-1.2.3", prefixes: []string{"app-"}, want: true},
|
|
|
|
{name: "rolling v1 tag", tag: "v1", want: false},
|
|
{name: "rolling latest tag", tag: "latest", want: false},
|
|
{name: "two-component", tag: "1.2", want: false},
|
|
{name: "empty", tag: "", want: false},
|
|
{name: "non-numeric major", tag: "vX.Y.Z", want: false},
|
|
{name: "just text", tag: "release-day", want: false},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
assert.Equal(t, tt.want, IsParseableSemverTag(tt.tag, tt.prefixes))
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestCheckMatches(t *testing.T) {
|
|
// Initialize logger for tests
|
|
InitLogger(false)
|
|
|
|
// Mock the fuzzy find function for testing
|
|
originalFuzzyFind := FuzzyFind
|
|
defer func() { FuzzyFind = originalFuzzyFind }()
|
|
|
|
FuzzyFind = func(needle string, haystack []string) []string {
|
|
// Simple mock implementation for testing
|
|
for _, h := range haystack {
|
|
if h == needle {
|
|
return []string{h}
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
tests := []struct {
|
|
name string
|
|
content []string
|
|
targets []string
|
|
blacklist []string
|
|
want bool
|
|
}{
|
|
{
|
|
name: "Simple match",
|
|
content: []string{"update", "dependencies"},
|
|
targets: []string{"update", "fix"},
|
|
want: true,
|
|
},
|
|
{
|
|
name: "No match",
|
|
content: []string{"chore", "dependencies"},
|
|
targets: []string{"update", "fix"},
|
|
want: false,
|
|
},
|
|
{
|
|
name: "Match but blacklisted",
|
|
content: []string{"update", "dependencies", "skip-ci"},
|
|
targets: []string{"update", "fix"},
|
|
blacklist: []string{"skip-ci"},
|
|
want: false,
|
|
},
|
|
{
|
|
name: "Match with empty blacklist",
|
|
content: []string{"update", "dependencies"},
|
|
targets: []string{"update", "fix"},
|
|
blacklist: []string{},
|
|
want: true,
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
got := CheckMatches(tt.content, tt.targets, tt.blacklist)
|
|
assert.Equal(t, tt.want, got)
|
|
})
|
|
}
|
|
}
|