From 9c1db04e272c63ddbe0a293a02f899fa2fd835f8 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 14 Aug 2025 13:38:52 +0000 Subject: [PATCH] Improve semver parsing robustness for versions without 'v' prefix Replace chartify.FindSemVerInfo with enhanced findSemVerInfo function that handles versions with or without 'v' prefix. This addresses the "unable to find semver info in 5.7.1" error by ensuring consistent version parsing regardless of input format. - Add findSemVerInfo function with flexible regex pattern - Update parseHelmVersion to use enhanced version parsing - Add comprehensive test cases for various version formats including issue #2124 scenarios - Remove unused chartify import from helmexec package Co-authored-by: yxxhero <11087727+yxxhero@users.noreply.github.com> --- pkg/helmexec/exec.go | 43 +++++++++++++++++++------- pkg/helmexec/exec_test.go | 12 ++++++++ pkg/helmexec/semver_test.go | 60 +++++++++++++++++++++++++++++++++++++ 3 files changed, 105 insertions(+), 10 deletions(-) create mode 100644 pkg/helmexec/semver_test.go diff --git a/pkg/helmexec/exec.go b/pkg/helmexec/exec.go index e2df4423..ce18a0df 100644 --- a/pkg/helmexec/exec.go +++ b/pkg/helmexec/exec.go @@ -7,12 +7,12 @@ import ( "net/url" "os" "path/filepath" + "regexp" "strconv" "strings" "sync" "github.com/Masterminds/semver/v3" - "github.com/helmfile/chartify" "go.uber.org/zap" "go.uber.org/zap/zapcore" "helm.sh/helm/v3/pkg/chart" @@ -64,21 +64,44 @@ func NewLogger(writer io.Writer, logLevel string) *zap.SugaredLogger { return zap.New(core).Sugar() } +// findSemVerInfo extracts semantic version information from a version string. +// Unlike chartify.FindSemVerInfo, this function handles versions with or without "v" prefix +// and ensures the returned version always has the "v" prefix for consistency. +func findSemVerInfo(version string) (string, error) { + // Trim whitespace and clean the version string + version = strings.TrimSpace(version) + + // Regex pattern that matches semantic versions with optional "v" prefix + // This is based on chartify's semVerRegex but made more flexible + semVerRegex := `v?([0-9]+)(\.[0-9]+)?(\.[0-9]+)?` + + `(-([0-9A-Za-z\-]+(\.[0-9A-Za-z\-]+)*))?` + + `(\+([0-9A-Za-z\-]+(\.[0-9A-Za-z\-]+)*))?` + + // Try to find a version match + re := regexp.MustCompile(semVerRegex) + matches := re.FindStringSubmatch(version) + + if len(matches) == 0 { + return "", fmt.Errorf("unable to find semver info in %s", version) + } + + // Reconstruct the version with "v" prefix for consistency + versionPart := matches[0] + if !strings.HasPrefix(versionPart, "v") { + versionPart = "v" + versionPart + } + + return versionPart, nil +} + func parseHelmVersion(versionStr string) (*semver.Version, error) { if len(versionStr) == 0 { return nil, fmt.Errorf("empty helm version") } - // Check if version string starts with "v", if not add it - processedVersion := strings.TrimSpace(versionStr) - if !strings.HasPrefix(processedVersion, "v") { - processedVersion = "v" + processedVersion - } - - v, err := chartify.FindSemVerInfo(processedVersion) - + v, err := findSemVerInfo(versionStr) if err != nil { - return nil, fmt.Errorf("error find helm srmver version '%s': %w", versionStr, err) + return nil, fmt.Errorf("error find helm semver version '%s': %w", versionStr, err) } ver, err := semver.NewVersion(v) diff --git a/pkg/helmexec/exec_test.go b/pkg/helmexec/exec_test.go index bbf88808..803c303b 100644 --- a/pkg/helmexec/exec_test.go +++ b/pkg/helmexec/exec_test.go @@ -1158,6 +1158,18 @@ func TestParseHelmVersion(t *testing.T) { want: semver.MustParse("v3.2.4"), wantErr: false, }, + { + name: "kustomize version format - issue #2124", + version: "5.7.1", + want: semver.MustParse("v5.7.1"), + wantErr: false, + }, + { + name: "kustomize structured output format", + version: "{v5.7.1 2025-07-23T12:45:29Z }", + want: semver.MustParse("v5.7.1"), + wantErr: false, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { diff --git a/pkg/helmexec/semver_test.go b/pkg/helmexec/semver_test.go new file mode 100644 index 00000000..93e5c5f7 --- /dev/null +++ b/pkg/helmexec/semver_test.go @@ -0,0 +1,60 @@ +package helmexec + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +// Test the specific scenario mentioned in issue #2124 +func TestFindSemVerInfo_Issue2124(t *testing.T) { + testCases := []struct { + name string + input string + expected string + wantErr bool + }{ + { + name: "issue #2124 - kustomize version 5.7.1 without v prefix", + input: "5.7.1", + expected: "v5.7.1", + wantErr: false, + }, + { + name: "kustomize version with v prefix", + input: "v5.7.1", + expected: "v5.7.1", + wantErr: false, + }, + { + name: "kustomize structured output", + input: "{v5.7.1 2025-07-23T12:45:29Z }", + expected: "v5.7.1", + wantErr: false, + }, + { + name: "helm version format", + input: "v3.18.4+gd80839c", + expected: "v3.18.4+gd80839c", + wantErr: false, + }, + { + name: "invalid version", + input: "not-a-version", + wantErr: true, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + result, err := findSemVerInfo(tc.input) + + if tc.wantErr { + assert.Error(t, err) + } else { + assert.NoError(t, err) + assert.Equal(t, tc.expected, result) + } + }) + } +} \ No newline at end of file