From 36341d5ef3050ecb4f2f2d05bbcc7b5ed161c9e0 Mon Sep 17 00:00:00 2001 From: Jakob Jensen Date: Thu, 5 Mar 2026 20:59:42 +0100 Subject: [PATCH 1/8] feat: narrow the special handling of github to just latest version --- internal/generator/factory.go | 61 +++++++------------- internal/generator/generator.go | 47 +++++++++++++++- internal/generator/git.go | 92 ++++++++++++++++++++++--------- internal/generator/helm.go | 7 +-- internal/generator/http.go | 7 +-- internal/generator/oci.go | 19 +++---- internal/generator/preparedGit.go | 37 +++++++++---- 7 files changed, 168 insertions(+), 102 deletions(-) diff --git a/internal/generator/factory.go b/internal/generator/factory.go index 3420ef045..1ad345bc8 100644 --- a/internal/generator/factory.go +++ b/internal/generator/factory.go @@ -8,14 +8,12 @@ import ( "regexp" "runtime" "slices" - "sort" "strconv" "strings" "github.com/CustomResourceDefinition/catalog/internal/configuration" "github.com/CustomResourceDefinition/catalog/internal/crd" "github.com/CustomResourceDefinition/catalog/internal/registry" - "github.com/CustomResourceDefinition/catalog/internal/semver" ) type Builder struct { @@ -29,7 +27,13 @@ type Builder struct { registry *registry.SourceRegistry } -func NewBuilder(config configuration.Configuration, reader crd.CrdReader, generatedRepository, schemaRepository, definitionRepository string, logger io.Writer, reg *registry.SourceRegistry) (*Builder, error) { +func NewBuilder( + config configuration.Configuration, + reader crd.CrdReader, + generatedRepository, schemaRepository, definitionRepository string, + logger io.Writer, + reg *registry.SourceRegistry, +) (*Builder, error) { generator, err := resolveGenerator(config, reader, logger) if err != nil { return nil, err @@ -78,13 +82,16 @@ func (builder Builder) Build() error { fmt.Fprintf(logger, "Producing for %s@%s:\n", builder.config.Name, builder.config.Kind) defer fmt.Fprintf(logger, "End.\n") - latestVersion, isUpdated := builder.registryStatus() + latestVersion, isUpdated, err := builder.registryStatus() + if err != nil { + return err + } if isUpdated { fmt.Fprintf(logger, " - skipping %s@%s (version %s unchanged)\n", builder.config.Name, builder.config.Kind, latestVersion) return nil } - versions, err := builder.versions() + versions, err := builder.generator.Versions(builder.versionFilter) if err != nil { return err } @@ -157,51 +164,23 @@ func (builder Builder) Build() error { return nil } -func (builder Builder) versions() ([]string, error) { - versions, err := builder.generator.Versions() +// registryStatus reports on the state in registry based on the latest version +// available and only uses the decided interface method for latest version information +func (builder Builder) registryStatus() (string, bool, error) { + version, err := builder.generator.LatestVersion(builder.versionFilter) if err != nil { - return nil, err + return "", false, fmt.Errorf("unable to check registry: %w", err) } - filtered := make([]string, 0) - for _, v := range versions { - if builder.versionFilter.MatchString(v) { - filtered = append(filtered, v) - } - } - - sort.Slice(filtered, func(i, j int) bool { - keyA, errA := builder.generator.VersionSortKey(filtered[i]) - keyB, errB := builder.generator.VersionSortKey(filtered[j]) - - if errA == nil && errB == nil && keyA != 0 && keyB != 0 && keyA != keyB { - return keyA > keyB - } - - a := normalizeVersion(builder.versionFilter.FindAllStringSubmatch(filtered[i], -1)) - b := normalizeVersion(builder.versionFilter.FindAllStringSubmatch(filtered[j], -1)) - return semver.Compare(a, b) > 0 - }) - return filtered, nil -} - -func (builder Builder) registryStatus() (string, bool) { - versions, err := builder.versions() - if err != nil || len(versions) == 0 { - return "", false - } - - version := versions[0] - if builder.registry == nil { - return version, false + return version, false, nil } if entry, ok := builder.registry.Get(builder.config.Name); ok { - return version, entry.Kind == string(builder.config.Kind) && entry.Version == version + return version, entry.Kind == string(builder.config.Kind) && entry.Version == version, nil } - return version, false + return version, false, nil } func (builder Builder) updateRegistry(version string) { diff --git a/internal/generator/generator.go b/internal/generator/generator.go index 87148cb29..a3694046f 100644 --- a/internal/generator/generator.go +++ b/internal/generator/generator.go @@ -1,15 +1,58 @@ package generator import ( + "fmt" "io" + "regexp" + "sort" "github.com/CustomResourceDefinition/catalog/internal/crd" + "github.com/CustomResourceDefinition/catalog/internal/semver" ) type Generator interface { - Versions() ([]string, error) + AllVersions() ([]string, error) + Versions(filter *regexp.Regexp) ([]string, error) + LatestVersion(filter *regexp.Regexp) (string, error) MetaData(version string) ([]crd.CrdMetaSchema, error) Crds(version string) ([]crd.Crd, error) - VersionSortKey(version string) (int64, error) io.Closer } + +type baseGenerator struct{} + +func (b *baseGenerator) LatestVersion(filter *regexp.Regexp) (string, error) { + versions, err := b.Versions(filter) + if err != nil { + return "", err + } + if len(versions) == 0 { + return "", fmt.Errorf("no versions are available") + } + return versions[0], nil +} + +func (b baseGenerator) Versions(filter *regexp.Regexp) ([]string, error) { + versions, err := b.AllVersions() + if err != nil { + return nil, err + } + + filtered := make([]string, 0) + for _, v := range versions { + if filter.MatchString(v) { + filtered = append(filtered, v) + } + } + + sort.Slice(filtered, func(i, j int) bool { + a := normalizeVersion(filter.FindAllStringSubmatch(filtered[i], -1)) + b := normalizeVersion(filter.FindAllStringSubmatch(filtered[j], -1)) + return semver.Compare(a, b) > 0 + }) + return filtered, nil +} + +func (b baseGenerator) AllVersions() ([]string, error) { + panic("base implementation should not be called") +} diff --git a/internal/generator/git.go b/internal/generator/git.go index 7d1efea8d..b4879e6e9 100644 --- a/internal/generator/git.go +++ b/internal/generator/git.go @@ -8,6 +8,8 @@ import ( "os/exec" "path" "path/filepath" + "regexp" + "sort" "strconv" "strings" @@ -15,9 +17,11 @@ import ( "github.com/CustomResourceDefinition/catalog/internal/crd" "github.com/CustomResourceDefinition/catalog/internal/genall" "github.com/CustomResourceDefinition/catalog/internal/kustomize" + "github.com/CustomResourceDefinition/catalog/internal/semver" ) type GitGenerator struct { + *baseGenerator config configuration.Configuration reader crd.CrdReader tmpDir, gitDir string @@ -36,27 +40,6 @@ func (generator *GitGenerator) Close() error { return os.RemoveAll(generator.tmpDir) } -func (generator *GitGenerator) VersionSortKey(version string) (int64, error) { - if err := generator.ensureLoaded(); err != nil { - return 0, err - } - - out, err := exec.Command("git", "--git-dir", generator.gitDir, "log", "-1", "--format=%ct", version).Output() // tag - if err != nil { - out, err = exec.Command("git", "--git-dir", generator.gitDir, "log", "-1", "--format=%ct", fmt.Sprintf("origin/%s", version)).Output() // branch - if err != nil { - return 0, fmt.Errorf("unable to get commit date for '%s': %w", version, err) - } - } - - ts, err := strconv.ParseInt(strings.TrimSpace(string(out)), 10, 64) - if err != nil { - return 0, fmt.Errorf("unable to parse commit date for '%s': %w", version, err) - } - - return ts, nil -} - func (generator *GitGenerator) MetaData(version string) ([]crd.CrdMetaSchema, error) { if err := generator.ensureLoaded(); err != nil { return nil, err @@ -89,11 +72,13 @@ func (generator *GitGenerator) Crds(version string) ([]crd.Crd, error) { } if len(version) == 0 { - versions, err := generator.Versions() - if err != nil { - return nil, err - } - version = versions[0] + return nil, fmt.Errorf("no version was provided") + // FIXME: verify + // versions, err := generator.Versions() + // if err != nil { + // return nil, err + // } + // version = versions[0] } err := exec.Command("git", "--git-dir", generator.gitDir, "--work-tree", generator.tmpDir, "checkout", "--force", version).Run() @@ -157,7 +142,39 @@ func (generator *GitGenerator) Crds(version string) ([]crd.Crd, error) { return crds, nil } -func (generator *GitGenerator) Versions() ([]string, error) { +func (generator *GitGenerator) Versions(filter *regexp.Regexp) ([]string, error) { + versions, err := generator.AllVersions() + if err != nil { + return nil, err + } + + filtered := make([]string, 0) + for _, v := range versions { + if filter.MatchString(v) { + filtered = append(filtered, v) + } + } + + sort.Slice(filtered, func(i, j int) bool { + a, err := generator.sortKey(filtered[i]) + if err != nil { + return false + } + b, err := generator.sortKey(filtered[j]) + if err != nil { + return true + } + if a != b { + return a < b + } + aa := normalizeVersion(filter.FindAllStringSubmatch(filtered[i], -1)) + bb := normalizeVersion(filter.FindAllStringSubmatch(filtered[j], -1)) + return semver.Compare(aa, bb) > 0 + }) + return filtered, nil +} + +func (generator *GitGenerator) AllVersions() ([]string, error) { if err := generator.ensureLoaded(); err != nil { return nil, err } @@ -168,6 +185,27 @@ func (generator *GitGenerator) Versions() ([]string, error) { return versions, nil } +func (generator *GitGenerator) sortKey(version string) (int64, error) { + if err := generator.ensureLoaded(); err != nil { + return 0, err + } + + out, err := exec.Command("git", "--git-dir", generator.gitDir, "log", "-1", "--format=%ct", version).Output() // tag + if err != nil { + out, err = exec.Command("git", "--git-dir", generator.gitDir, "log", "-1", "--format=%ct", fmt.Sprintf("origin/%s", version)).Output() // branch + if err != nil { + return 0, fmt.Errorf("unable to get commit date for '%s': %w", version, err) + } + } + + ts, err := strconv.ParseInt(strings.TrimSpace(string(out)), 10, 64) + if err != nil { + return 0, fmt.Errorf("unable to parse commit date for '%s': %w", version, err) + } + + return ts, nil +} + func (generator *GitGenerator) ensureLoaded() error { if len(generator.tmpDir) != 0 { return nil diff --git a/internal/generator/helm.go b/internal/generator/helm.go index c29b03212..db4a3d55e 100644 --- a/internal/generator/helm.go +++ b/internal/generator/helm.go @@ -20,6 +20,7 @@ import ( ) type HelmGenerator struct { + *baseGenerator target string config configuration.Configuration reader crd.CrdReader @@ -95,7 +96,7 @@ func (generator *HelmGenerator) Crds(version string) ([]crd.Crd, error) { return crds, nil } -func (generator *HelmGenerator) Versions() ([]string, error) { +func (generator *HelmGenerator) AllVersions() ([]string, error) { if err := generator.ensureLoaded(); err != nil { return nil, err } @@ -115,10 +116,6 @@ func (generator *HelmGenerator) Close() error { return os.RemoveAll(generator.tmpDir) } -func (generator *HelmGenerator) VersionSortKey(version string) (int64, error) { - return 0, nil -} - func (generator *HelmGenerator) ensureLoaded() error { if len(generator.tmpDir) != 0 { return nil diff --git a/internal/generator/http.go b/internal/generator/http.go index 580d201d2..7639bc497 100644 --- a/internal/generator/http.go +++ b/internal/generator/http.go @@ -12,6 +12,7 @@ import ( ) type HttpGenerator struct { + *baseGenerator client http.Client config configuration.Configuration reader crd.CrdReader @@ -80,7 +81,7 @@ func (generator *HttpGenerator) Crds(version string) ([]crd.Crd, error) { return crds, nil } -func (generator *HttpGenerator) Versions() ([]string, error) { +func (generator *HttpGenerator) AllVersions() ([]string, error) { versions := make([]string, len(generator.config.Downloads)) for i, download := range generator.config.Downloads { @@ -94,10 +95,6 @@ func (generator *HttpGenerator) Close() error { return nil } -func (generator *HttpGenerator) VersionSortKey(version string) (int64, error) { - return 0, nil -} - func (generator *HttpGenerator) read(resp *http.Response) ([]byte, error) { defer resp.Body.Close() diff --git a/internal/generator/oci.go b/internal/generator/oci.go index c4daaac4d..7a0b4657e 100644 --- a/internal/generator/oci.go +++ b/internal/generator/oci.go @@ -14,6 +14,7 @@ import ( ) type OciGenerator struct { + *baseGenerator realmClient realmClient config configuration.Configuration reader crd.CrdReader @@ -44,10 +45,6 @@ func (generator *OciGenerator) Close() error { return os.RemoveAll(generator.tmpDir) } -func (generator *OciGenerator) VersionSortKey(version string) (int64, error) { - return 0, nil -} - func (generator *OciGenerator) MetaData(version string) ([]crd.CrdMetaSchema, error) { if err := generator.ensureLoaded(); err != nil { return nil, err @@ -80,11 +77,13 @@ func (generator *OciGenerator) Crds(version string) ([]crd.Crd, error) { } if len(version) == 0 { - versions, err := generator.Versions() - if err != nil { - return nil, err - } - version = versions[0] + return nil, fmt.Errorf("no version was provided") + // FIXME: verify + // versions, err := generator.Versions() + // if err != nil { + // return nil, err + // } + // version = versions[0] } savedPath, _, err := generator.downloader.DownloadTo(generator.config.Repository, version, generator.tmpDir) @@ -110,7 +109,7 @@ func (generator *OciGenerator) Crds(version string) ([]crd.Crd, error) { return crds, nil } -func (generator *OciGenerator) Versions() ([]string, error) { +func (generator *OciGenerator) AllVersions() ([]string, error) { if err := generator.ensureLoaded(); err != nil { return nil, err } diff --git a/internal/generator/preparedGit.go b/internal/generator/preparedGit.go index 21a75eee4..cb75ea1d4 100644 --- a/internal/generator/preparedGit.go +++ b/internal/generator/preparedGit.go @@ -2,11 +2,14 @@ package generator import ( "fmt" + "regexp" + "sort" "github.com/CustomResourceDefinition/catalog/internal/crd" ) type PreparedGitGenerator struct { + *baseGenerator gitGenerator *GitGenerator versions []versionInfo } @@ -23,21 +26,31 @@ func NewPreparedGitGenerator(gitGenerator *GitGenerator, versions []versionInfo) } } -func (g *PreparedGitGenerator) Versions() ([]string, error) { - versions := make([]string, len(g.versions)) - for i, v := range g.versions { - versions[i] = v.name - } - return versions, nil -} - -func (g *PreparedGitGenerator) VersionSortKey(version string) (int64, error) { +func (g *PreparedGitGenerator) LatestVersion(filter *regexp.Regexp) (string, error) { + filtered := make([]versionInfo, 0) for _, v := range g.versions { - if v.name == version { - return v.timestamp, nil + if filter.MatchString(v.name) { + filtered = append(filtered, v) } } - return 0, fmt.Errorf("version %q not found", version) + + sort.Slice(filtered, func(i, j int) bool { + return filtered[i].timestamp < filtered[j].timestamp + }) + + if len(filtered) == 0 { + return "", fmt.Errorf("no versions are available") + } + + return filtered[0].name, nil +} + +func (g *PreparedGitGenerator) Versions(filter *regexp.Regexp) ([]string, error) { + return g.gitGenerator.Versions(filter) +} + +func (g *PreparedGitGenerator) AllVersions() ([]string, error) { + return g.gitGenerator.AllVersions() } func (g *PreparedGitGenerator) MetaData(version string) ([]crd.CrdMetaSchema, error) { From c9a2077f2a379a411bda0b721fd173cf3307ca79 Mon Sep 17 00:00:00 2001 From: Jakob Jensen Date: Thu, 5 Mar 2026 23:00:33 +0100 Subject: [PATCH 2/8] has fixmes and rough edges --- internal/generator/factory_test.go | 120 ++------------- internal/generator/generator.go | 42 ------ internal/generator/generatorVersions.go | 38 +++++ internal/generator/generatorVersions_test.go | 139 ++++++++++++++++++ internal/generator/git.go | 28 ++-- .../generator/gitGeneratorFactory_test.go | 74 +--------- internal/generator/git_test.go | 69 ++++----- internal/generator/helm.go | 15 +- internal/generator/helm_test.go | 23 +-- internal/generator/http.go | 15 +- internal/generator/http_test.go | 84 +++++++++-- internal/generator/oci.go | 17 ++- internal/generator/oci_test.go | 25 +--- internal/generator/preparedGit.go | 9 +- internal/generator/preparedGit_test.go | 27 +--- 15 files changed, 360 insertions(+), 365 deletions(-) create mode 100644 internal/generator/generatorVersions.go create mode 100644 internal/generator/generatorVersions_test.go diff --git a/internal/generator/factory_test.go b/internal/generator/factory_test.go index 16c17a5ac..6872e541b 100644 --- a/internal/generator/factory_test.go +++ b/internal/generator/factory_test.go @@ -1,7 +1,6 @@ package generator import ( - "fmt" "net/http" "net/http/httptest" "os" @@ -14,109 +13,6 @@ import ( "github.com/stretchr/testify/assert" ) -func TestBuilderVersionSorting(t *testing.T) { - seedVersions := []string{ - "2.10.0", "1.0.0", "2.2.0", "2.1.0", "1.01.01", - } - bundles := make([]gitBundle, 0) - for _, v := range seedVersions { - bundles = append(bundles, gitBundle{tag: v, paths: []gitPath{}}) - } - expectedVersions := []string{seedVersions[0], seedVersions[2], seedVersions[3], seedVersions[4], seedVersions[1]} - - p, err := setupGit(t, bundles) - assert.Nil(t, err) - assert.NotNil(t, p) - - config := configuration.Configuration{ - Kind: configuration.Git, - Repository: fmt.Sprintf("file://%s", *p), - VersionPattern: `^([0-9]+\.[0-9]+\.[0-9]+)$`, - } - - b, err := NewBuilder(config, nil, "-", "-", "-", nil, nil) - assert.Nil(t, err) - - versions, err := b.versions() - assert.Nil(t, err) - assert.NotNil(t, versions) - assert.Equal(t, expectedVersions, versions) -} - -type testScenario struct { - versions []string - expectedVersions []string - pattern string -} - -func TestBuilderVersionFiltering(t *testing.T) { - tests := []testScenario{ - { - versions: []string{"2.0.0", "1.3.0", "1.0.0"}, - expectedVersions: []string{"2.0.0", "1.3.0", "1.0.0"}, - }, - { - versions: []string{"v2.0.0", "v1.3.0", "v1.0.0"}, - expectedVersions: []string{}, - }, - { - versions: []string{"v2.0.0", "v1.3.0", "v1.0.0"}, - expectedVersions: []string{"v2.0.0", "v1.3.0", "v1.0.0"}, - pattern: `^v([0-9]+\.[0-9]+\.[0-9]+)$`, - }, - { - versions: []string{"2.0.0", "v1.3.0", "v1.0.0"}, - expectedVersions: []string{"2.0.0", "v1.3.0", "v1.0.0"}, - pattern: `^v?([0-9]+\.[0-9]+\.[0-9]+)$`, - }, - { - versions: []string{"2.0.0", "v1.3.0v", "v1.0.0"}, - expectedVersions: []string{"2.0.0", "v1.0.0"}, - pattern: `^v?([0-9]+\.[0-9]+\.[0-9]+)$`, - }, - { - versions: []string{"2.0.0-2", "1.3.0-1892", "1.0.0-01"}, - expectedVersions: []string{"2.0.0-2", "1.3.0-1892", "1.0.0-01"}, - pattern: `^([0-9]+\.[0-9]+\.[0-9]+-\d+)$`, - }, - { - versions: []string{"v1.33.2+k0s.0"}, - expectedVersions: []string{"v1.33.2+k0s.0"}, - pattern: `^v([0-9]+\.[0-9]+\.[0-9]+\+k0s\.0)$`, - }, - { - versions: []string{"main", "v1.0", "master"}, - expectedVersions: []string{"main", "master"}, - pattern: `^(main|master)$`, - }, - { - versions: []string{"main", "v1.0.0", "2.0.0", "master"}, - expectedVersions: []string{"2.0.0", "main", "master"}, - pattern: `^([0-9]+\.[0-9]+\.[0-9]+)|(main|master)$`, - }, - } - - for i, test := range tests { - downloads := make([]configuration.ConfigurationDownload, 0) - for _, v := range test.versions { - downloads = append(downloads, configuration.ConfigurationDownload{Version: v}) - } - config := configuration.Configuration{ - Kind: configuration.Http, - Downloads: downloads, - VersionPattern: test.pattern, - } - - b, err := NewBuilder(config, nil, "-", "-", "-", nil, nil) - assert.Nil(t, err) - - versions, err := b.versions() - assert.Nil(t, err, "index %d failed", i) - assert.NotNil(t, versions, "index %d failed", i) - assert.Equal(t, test.expectedVersions, versions, "index %d failed", i) - } -} - func TestResolveGenerator(t *testing.T) { invalidConfigs := []configuration.Configuration{ { @@ -241,11 +137,12 @@ func TestRegistryStatusNoRegistry(t *testing.T) { Downloads: []configuration.ConfigurationDownload{{Version: "1.0.0"}}, } - b, err := NewBuilder(config, nil, "-", "-", "-", nil, nil) + builder, err := NewBuilder(config, nil, "-", "-", "-", nil, nil) assert.Nil(t, err) - assert.NotNil(t, b) + assert.NotNil(t, builder) - version, result := b.registryStatus() + version, result, err := builder.registryStatus() + assert.Nil(t, err) assert.False(t, result) assert.Equal(t, "1.0.0", version) } @@ -283,7 +180,8 @@ func TestRegistryStatusSameVersion(t *testing.T) { builder, err := NewBuilder(config, reader, tmpDir, tmpDir, tmpDir, setupLogger(), reg) assert.Nil(t, err) - version, result := builder.registryStatus() + version, result, err := builder.registryStatus() + assert.Nil(t, err) assert.True(t, result) assert.Equal(t, "1.0.0", version) } @@ -321,7 +219,8 @@ func TestRegistryStatusDifferentVersion(t *testing.T) { builder, err := NewBuilder(config, reader, tmpDir, tmpDir, tmpDir, setupLogger(), reg) assert.Nil(t, err) - version, result := builder.registryStatus() + version, result, err := builder.registryStatus() + assert.Nil(t, err) assert.False(t, result) assert.Equal(t, "2.0.0", version) } @@ -359,7 +258,8 @@ func TestRegistryStatusDifferentKind(t *testing.T) { builder, err := NewBuilder(config, reader, tmpDir, tmpDir, tmpDir, setupLogger(), reg) assert.Nil(t, err) - version, result := builder.registryStatus() + version, result, err := builder.registryStatus() + assert.Nil(t, err) assert.False(t, result) assert.Equal(t, "1.0.0", version) } diff --git a/internal/generator/generator.go b/internal/generator/generator.go index a3694046f..27aaaca94 100644 --- a/internal/generator/generator.go +++ b/internal/generator/generator.go @@ -1,58 +1,16 @@ package generator import ( - "fmt" "io" "regexp" - "sort" "github.com/CustomResourceDefinition/catalog/internal/crd" - "github.com/CustomResourceDefinition/catalog/internal/semver" ) type Generator interface { - AllVersions() ([]string, error) Versions(filter *regexp.Regexp) ([]string, error) LatestVersion(filter *regexp.Regexp) (string, error) MetaData(version string) ([]crd.CrdMetaSchema, error) Crds(version string) ([]crd.Crd, error) io.Closer } - -type baseGenerator struct{} - -func (b *baseGenerator) LatestVersion(filter *regexp.Regexp) (string, error) { - versions, err := b.Versions(filter) - if err != nil { - return "", err - } - if len(versions) == 0 { - return "", fmt.Errorf("no versions are available") - } - return versions[0], nil -} - -func (b baseGenerator) Versions(filter *regexp.Regexp) ([]string, error) { - versions, err := b.AllVersions() - if err != nil { - return nil, err - } - - filtered := make([]string, 0) - for _, v := range versions { - if filter.MatchString(v) { - filtered = append(filtered, v) - } - } - - sort.Slice(filtered, func(i, j int) bool { - a := normalizeVersion(filter.FindAllStringSubmatch(filtered[i], -1)) - b := normalizeVersion(filter.FindAllStringSubmatch(filtered[j], -1)) - return semver.Compare(a, b) > 0 - }) - return filtered, nil -} - -func (b baseGenerator) AllVersions() ([]string, error) { - panic("base implementation should not be called") -} diff --git a/internal/generator/generatorVersions.go b/internal/generator/generatorVersions.go new file mode 100644 index 000000000..6b6baab46 --- /dev/null +++ b/internal/generator/generatorVersions.go @@ -0,0 +1,38 @@ +package generator + +import ( + "fmt" + "regexp" + "sort" + + "github.com/CustomResourceDefinition/catalog/internal/semver" +) + +type GeneratorVersions struct{} + +func (v *GeneratorVersions) latest(versions []string) (string, error) { + if len(versions) == 0 { + return "", fmt.Errorf("no versions are available") + } + return versions[0], nil +} + +func (v *GeneratorVersions) semverSort(versions []string, filter *regexp.Regexp) ([]string, error) { + if filter == nil { + return nil, fmt.Errorf("filter is required") + } + + filtered := make([]string, 0) + for _, v := range versions { + if filter.MatchString(v) { + filtered = append(filtered, v) + } + } + + sort.Slice(filtered, func(i, j int) bool { + a := normalizeVersion(filter.FindAllStringSubmatch(filtered[i], -1)) + b := normalizeVersion(filter.FindAllStringSubmatch(filtered[j], -1)) + return semver.Compare(a, b) > 0 + }) + return filtered, nil +} diff --git a/internal/generator/generatorVersions_test.go b/internal/generator/generatorVersions_test.go new file mode 100644 index 000000000..a5ad1c4ff --- /dev/null +++ b/internal/generator/generatorVersions_test.go @@ -0,0 +1,139 @@ +package generator + +import ( + "regexp" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestGeneratorVersionsSemverSortNoFilter(t *testing.T) { + gv := GeneratorVersions{} + + _, err := gv.semverSort([]string{"1.0.0", "2.0.0", "1.5.0"}, nil) + assert.NotNil(t, err) +} + +func TestGeneratorVersionsSemverSortWithFilter(t *testing.T) { + gv := GeneratorVersions{} + + filter := regexp.MustCompile(`^v([0-9]+\.[0-9]+\.[0-9]+)$`) + versions, err := gv.semverSort([]string{"v1.0.0", "v2.0.0", "main"}, filter) + assert.Nil(t, err) + assert.Equal(t, []string{"v2.0.0", "v1.0.0"}, versions) +} + +func TestGeneratorVersionsSemverSortFiltersCorrectly(t *testing.T) { + gv := GeneratorVersions{} + + filter := regexp.MustCompile(`^[0-9]+\.[0-9]+\.[0-9]+$`) + versions, err := gv.semverSort([]string{"1.0.0", "main", "2.0.0", "master"}, filter) + assert.Nil(t, err) + assert.Equal(t, []string{"2.0.0", "1.0.0"}, versions) +} + +func TestGeneratorVersionsSemverSortSortsDescending(t *testing.T) { + gv := GeneratorVersions{} + + filter := regexp.MustCompile(`^[0-9]+\.[0-9]+\.[0-9]+$`) + versions, err := gv.semverSort([]string{"1.0.0", "2.10.0", "2.2.0", "1.5.0", "1.01.01"}, filter) + assert.Nil(t, err) + assert.Equal(t, []string{"2.10.0", "2.2.0", "1.5.0", "1.01.01", "1.0.0"}, versions) +} + +func TestGeneratorVersionsFiltering(t *testing.T) { + gv := GeneratorVersions{} + + tests := []struct { + name string + versions []string + expectedVersions []string + pattern string + }{ + { + name: "no filter matches all", + versions: []string{"2.0.0", "1.3.0", "1.0.0"}, + expectedVersions: []string{"2.0.0", "1.3.0", "1.0.0"}, + pattern: ".*", + }, + { + name: "v prefix versions no pattern", + versions: []string{"v2.0.0", "v1.3.0", "v1.0.0"}, + expectedVersions: []string{}, + pattern: "", + }, + { + name: "v prefix with pattern", + versions: []string{"v2.0.0", "v1.3.0", "v1.0.0"}, + expectedVersions: []string{"v2.0.0", "v1.3.0", "v1.0.0"}, + pattern: `^v([0-9]+\.[0-9]+\.[0-9]+)$`, + }, + { + name: "optional v prefix", + versions: []string{"2.0.0", "v1.3.0", "v1.0.0"}, + expectedVersions: []string{"2.0.0", "v1.3.0", "v1.0.0"}, + pattern: `^v?([0-9]+\.[0-9]+\.[0-9]+)$`, + }, + { + name: "optional v prefix filters non-matching", + versions: []string{"2.0.0", "v1.3v", "v1.0.0"}, + expectedVersions: []string{"2.0.0", "v1.0.0"}, + pattern: `^v?([0-9]+\.[0-9]+\.[0-9]+)$`, + }, + { + name: "prerelease versions", + versions: []string{"2.0.0-2", "1.3.0-1892", "1.0.0-01"}, + expectedVersions: []string{"2.0.0-2", "1.3.0-1892", "1.0.0-01"}, + pattern: `^([0-9]+\.[0-9]+\.[0-9]+-\d+)$`, + }, + { + name: "version with build metadata", + versions: []string{"v1.33.2+k0s.0"}, + expectedVersions: []string{"v1.33.2+k0s.0"}, + pattern: `^v([0-9]+\.[0-9]+\.[0-9]+\+k0s\.0)$`, + }, + { + name: "branch names only", + versions: []string{"main", "v1.0", "master"}, + expectedVersions: []string{"main", "master"}, + pattern: `^(main|master)$`, + }, + { + name: "mixed versions and branches", + versions: []string{"main", "v1.0.0", "2.0.0", "master"}, + expectedVersions: []string{"2.0.0", "main", "master"}, + pattern: `^([0-9]+\.[0-9]+\.[0-9]+)|(main|master)$`, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + var filter *regexp.Regexp + if test.pattern != "" { + filter = regexp.MustCompile(test.pattern) + } else { + filter = regexp.MustCompile(".*") + } + + versions, err := gv.semverSort(test.versions, filter) + assert.Nil(t, err) + assert.Equal(t, test.expectedVersions, versions) + }) + } +} + +func TestGeneratorVersionsLatestEmpty(t *testing.T) { + gv := GeneratorVersions{} + + version, err := gv.latest([]string{}) + assert.NotNil(t, err) + assert.Equal(t, "", version) +} + +func TestGeneratorVersionsLatestReturnsFirst(t *testing.T) { + gv := GeneratorVersions{} + + version, err := gv.latest([]string{"1.0.0", "2.0.0", "1.5.0"}) + assert.Nil(t, err) + assert.Equal(t, "1.0.0", version) +} diff --git a/internal/generator/git.go b/internal/generator/git.go index b4879e6e9..8aba503fa 100644 --- a/internal/generator/git.go +++ b/internal/generator/git.go @@ -21,7 +21,7 @@ import ( ) type GitGenerator struct { - *baseGenerator + *GeneratorVersions config configuration.Configuration reader crd.CrdReader tmpDir, gitDir string @@ -142,12 +142,23 @@ func (generator *GitGenerator) Crds(version string) ([]crd.Crd, error) { return crds, nil } -func (generator *GitGenerator) Versions(filter *regexp.Regexp) ([]string, error) { - versions, err := generator.AllVersions() +func (generator *GitGenerator) LatestVersion(filter *regexp.Regexp) (string, error) { + versions, err := generator.Versions(filter) if err != nil { + return "", err + } + return generator.latest(versions) +} + +func (generator *GitGenerator) Versions(filter *regexp.Regexp) ([]string, error) { + if err := generator.ensureLoaded(); err != nil { return nil, err } + versions := make([]string, 0, len(generator.tags)+len(generator.branches)) + versions = append(versions, generator.tags...) + versions = append(versions, generator.branches...) + filtered := make([]string, 0) for _, v := range versions { if filter.MatchString(v) { @@ -174,17 +185,6 @@ func (generator *GitGenerator) Versions(filter *regexp.Regexp) ([]string, error) return filtered, nil } -func (generator *GitGenerator) AllVersions() ([]string, error) { - if err := generator.ensureLoaded(); err != nil { - return nil, err - } - - versions := make([]string, 0, len(generator.tags)+len(generator.branches)) - versions = append(versions, generator.tags...) - versions = append(versions, generator.branches...) - return versions, nil -} - func (generator *GitGenerator) sortKey(version string) (int64, error) { if err := generator.ensureLoaded(); err != nil { return 0, err diff --git a/internal/generator/gitGeneratorFactory_test.go b/internal/generator/gitGeneratorFactory_test.go index afc3321a9..02831caf8 100644 --- a/internal/generator/gitGeneratorFactory_test.go +++ b/internal/generator/gitGeneratorFactory_test.go @@ -5,6 +5,7 @@ import ( "net/http" "net/http/httptest" "os" + "regexp" "testing" "github.com/CustomResourceDefinition/catalog/internal/configuration" @@ -111,7 +112,7 @@ func TestGitGeneratorFactoryBuildGitHubSuccessWithVersions(t *testing.T) { defer generator.Close() assert.IsType(t, &PreparedGitGenerator{}, generator) - versions, err := generator.Versions() + versions, err := generator.Versions(regexp.MustCompile(".*")) assert.Nil(t, err) assert.Contains(t, versions, "v1.0.0") assert.Contains(t, versions, "v0.9.0") @@ -119,49 +120,6 @@ func TestGitGeneratorFactoryBuildGitHubSuccessWithVersions(t *testing.T) { assert.Contains(t, versions, "develop") } -func TestGitGeneratorFactoryBuildGitHubSuccessWithSortKey(t *testing.T) { - t.Setenv("GITHUB_TOKEN", "test-token") - - cleanup := setupGitHubServer(t, []gitHubResponse{ - { - prefix: "refs/tags/", - tags: []githubRef{ - {name: "v1.0.0", committedDate: "2000-01-15T10:00:00Z"}, - }, - }, - { - prefix: "refs/heads/", - branches: []githubRef{ - {name: "main", committedDate: "2000-01-20T10:00:00Z"}, - }, - }, - }) - defer cleanup() - - config := configuration.Configuration{ - Kind: configuration.Git, - Repository: "https://github.com/owner/repo", - } - - generator, err := NewGitGeneratorFactory(config, nil, nil).Build() - assert.Nil(t, err) - defer generator.Close() - assert.IsType(t, &PreparedGitGenerator{}, generator) - - key1, err := generator.VersionSortKey("v1.0.0") - assert.Nil(t, err) - assert.Greater(t, key1, int64(0)) - - key2, err := generator.VersionSortKey("main") - assert.Nil(t, err) - assert.Greater(t, key2, int64(0)) - - assert.Greater(t, key2, key1, "main (2000-01-20) should have later timestamp than v1.0.0 (2000-01-15)") - - _, err = generator.VersionSortKey("nonexistent") - assert.NotNil(t, err) -} - func TestPreparedGitGeneratorVersionsSortedByDate(t *testing.T) { t.Setenv("GITHUB_TOKEN", "test-token") @@ -193,7 +151,7 @@ func TestPreparedGitGeneratorVersionsSortedByDate(t *testing.T) { defer generator.Close() assert.IsType(t, &PreparedGitGenerator{}, generator) - versions, err := generator.Versions() + versions, err := generator.Versions(regexp.MustCompile(".*")) assert.Nil(t, err) assert.Equal(t, []string{"v0.9.0", "v1.0.0", "develop", "main"}, versions) } @@ -314,21 +272,12 @@ func TestGitGeneratorFactoryAnnotatedTags(t *testing.T) { defer generator.Close() assert.IsType(t, &PreparedGitGenerator{}, generator) - versions, err := generator.Versions() + versions, err := generator.Versions(regexp.MustCompile(".*")) assert.Nil(t, err) assert.Contains(t, versions, "v1.0.0") assert.Contains(t, versions, "v0.9.0") assert.Contains(t, versions, "v0.8.0") assert.Contains(t, versions, "main") - - key1, _ := generator.VersionSortKey("v1.0.0") - key2, _ := generator.VersionSortKey("v0.9.0") - key3, _ := generator.VersionSortKey("v0.8.0") - keyMain, _ := generator.VersionSortKey("main") - - assert.Greater(t, keyMain, key1, "main > v1.0.0") - assert.Greater(t, key1, key2, "v1.0.0 > v0.9.0 (via target.tagger.date)") - assert.Greater(t, key2, key3, "v0.9.0 > v0.8.0 (via target.target.committedDate)") } func TestGitGeneratorFactoryNestedTags(t *testing.T) { @@ -366,21 +315,12 @@ func TestGitGeneratorFactoryNestedTags(t *testing.T) { defer generator.Close() assert.IsType(t, &PreparedGitGenerator{}, generator) - versions, err := generator.Versions() + versions, err := generator.Versions(regexp.MustCompile(".*")) assert.Nil(t, err) assert.Contains(t, versions, "v1.0.0") assert.Contains(t, versions, "v0.9.0") assert.Contains(t, versions, "nested-tag") assert.Contains(t, versions, "main") - - key1, _ := generator.VersionSortKey("v1.0.0") - key2, _ := generator.VersionSortKey("v0.9.0") - keyNested, _ := generator.VersionSortKey("nested-tag") - keyMain, _ := generator.VersionSortKey("main") - - assert.Greater(t, keyMain, key1, "main > v1.0.0") - assert.Greater(t, key1, key2, "v1.0.0 > v0.9.0") - assert.Greater(t, key2, keyNested, "v0.9.0 > nested-tag (via nested target.target.committedDate)") } func TestGitGeneratorFactoryPagination(t *testing.T) { @@ -416,7 +356,7 @@ func TestGitGeneratorFactoryPagination(t *testing.T) { defer generator.Close() assert.IsType(t, &PreparedGitGenerator{}, generator) - versions, err := generator.Versions() + versions, err := generator.Versions(regexp.MustCompile(".*")) assert.Nil(t, err) assert.Equal(t, 5, len(versions), "should have all 4 tags + 1 branch") assert.Contains(t, versions, "v1.0.0") @@ -473,7 +413,7 @@ func TestGitGeneratorFactoryEmptyResponses(t *testing.T) { defer generator.Close() assert.IsType(t, &PreparedGitGenerator{}, generator) - versions, err := generator.Versions() + versions, err := generator.Versions(regexp.MustCompile(".*")) assert.Nil(t, err) assert.Equal(t, tt.expectedVersions, len(versions)) }) diff --git a/internal/generator/git_test.go b/internal/generator/git_test.go index d2663a0c1..33ec2f392 100644 --- a/internal/generator/git_test.go +++ b/internal/generator/git_test.go @@ -3,6 +3,7 @@ package generator import ( "fmt" "os" + "regexp" "testing" "github.com/CustomResourceDefinition/catalog/internal/configuration" @@ -43,7 +44,7 @@ func TestGitGeneratorVersionsCombinesTagsAndBranches(t *testing.T) { generator := NewGitGenerator(config, nil) defer generator.Close() - versions, err := generator.Versions() + versions, err := generator.Versions(regexp.MustCompile(".*")) assert.Nil(t, err) assert.Contains(t, versions, expectedVersion) assert.Contains(t, versions, expectedDevelop) @@ -203,41 +204,6 @@ func TestGitGeneratorMetadataForSourceFiles(t *testing.T) { assert.Equal(t, "v1", metadata[0].Version) } -func TestGitGeneratorVersionSortKeyForBranch(t *testing.T) { - bundles := []gitBundle{ - { - tag: "1.0.0", - branch: "develop", - paths: []gitPath{ - { - path: "regular/crd.yaml", - file: "testdata/test-crd.yaml", - }, - }, - }, - } - - p, err := setupGit(t, bundles) - assert.Nil(t, err) - assert.NotNil(t, p) - - config := configuration.Configuration{ - Kind: configuration.Git, - Repository: fmt.Sprintf("file://%s", *p), - } - - generator := NewGitGenerator(config, nil) - defer generator.Close() - - key, err := generator.VersionSortKey("main") - assert.Nil(t, err) - assert.Greater(t, key, int64(0)) - - key, err = generator.VersionSortKey("develop") - assert.Nil(t, err) - assert.Greater(t, key, int64(0)) -} - func TestGitGeneratorCloneFailure(t *testing.T) { config := configuration.Configuration{ Kind: configuration.Git, @@ -247,7 +213,7 @@ func TestGitGeneratorCloneFailure(t *testing.T) { generator := NewGitGenerator(config, nil) defer generator.Close() - _, err := generator.Versions() + _, err := generator.Versions(regexp.MustCompile(".*")) assert.NotNil(t, err) assert.Contains(t, err.Error(), "unable to clone") } @@ -307,7 +273,7 @@ func TestGitGeneratorClose(t *testing.T) { generator := NewGitGenerator(config, nil) defer generator.Close() - versions, err := generator.Versions() + versions, err := generator.Versions(regexp.MustCompile(".*")) assert.Nil(t, err) assert.NotEmpty(t, versions) @@ -319,3 +285,30 @@ func TestGitGeneratorClose(t *testing.T) { _, err = os.Stat(tmpDir) assert.True(t, os.IsNotExist(err), "temp dir should be removed after Close()") } + +func TestGitGeneratorVersionsCustomSort(t *testing.T) { + seedVersions := []string{ + "2.10.0", "1.0.0", "2.2.0", "2.1.0", "1.01.01", + } + bundles := make([]gitBundle, 0) + for _, v := range seedVersions { + bundles = append(bundles, gitBundle{tag: v, paths: []gitPath{}}) + } + + p, err := setupGit(t, bundles) + assert.Nil(t, err) + assert.NotNil(t, p) + + config := configuration.Configuration{ + Kind: configuration.Git, + Repository: fmt.Sprintf("file://%s", *p), + } + + generator := NewGitGenerator(config, nil) + defer generator.Close() + + filter := regexp.MustCompile(`^([0-9]+\.[0-9]+\.[0-9]+)$`) + versions, err := generator.Versions(filter) + assert.Nil(t, err) + assert.Equal(t, []string{"2.10.0", "2.2.0", "2.1.0", "1.01.01", "1.0.0"}, versions) +} diff --git a/internal/generator/helm.go b/internal/generator/helm.go index db4a3d55e..e8e634bda 100644 --- a/internal/generator/helm.go +++ b/internal/generator/helm.go @@ -5,6 +5,7 @@ import ( "fmt" "os" "path" + "regexp" "strings" "github.com/CustomResourceDefinition/catalog/internal/configuration" @@ -20,7 +21,7 @@ import ( ) type HelmGenerator struct { - *baseGenerator + *GeneratorVersions target string config configuration.Configuration reader crd.CrdReader @@ -96,7 +97,15 @@ func (generator *HelmGenerator) Crds(version string) ([]crd.Crd, error) { return crds, nil } -func (generator *HelmGenerator) AllVersions() ([]string, error) { +func (generator *HelmGenerator) LatestVersion(filter *regexp.Regexp) (string, error) { + versions, err := generator.Versions(filter) + if err != nil { + return "", err + } + return generator.latest(versions) +} + +func (generator *HelmGenerator) Versions(filter *regexp.Regexp) ([]string, error) { if err := generator.ensureLoaded(); err != nil { return nil, err } @@ -109,7 +118,7 @@ func (generator *HelmGenerator) AllVersions() ([]string, error) { } } - return versions, nil + return generator.semverSort(versions, filter) } func (generator *HelmGenerator) Close() error { diff --git a/internal/generator/helm_test.go b/internal/generator/helm_test.go index 66b193e99..8d537d8d6 100644 --- a/internal/generator/helm_test.go +++ b/internal/generator/helm_test.go @@ -2,6 +2,7 @@ package generator import ( "os" + "regexp" "strings" "testing" @@ -24,7 +25,7 @@ func TestHelmGeneratorVersions(t *testing.T) { generator := NewHelmGenerator("connect", config, nil) defer generator.Close() - versions, err := generator.Versions() + versions, err := generator.Versions(regexp.MustCompile(".*")) assert.Nil(t, err) assert.Equal(t, expectedVersions, versions) } @@ -41,7 +42,7 @@ func TestHelmGeneratorUnknownTarget(t *testing.T) { generator := NewHelmGenerator("unknown", config, nil) defer generator.Close() - versions, err := generator.Versions() + versions, err := generator.Versions(regexp.MustCompile(".*")) assert.Nil(t, versions) assert.NotNil(t, err) } @@ -92,21 +93,3 @@ func TestHelmGeneratorMetadata(t *testing.T) { assert.Equal(t, "onepassworditem", metadata[0].Kind) assert.Equal(t, "v1", metadata[0].Version) } - -func TestHelmGeneratorHasInertSortingKeys(t *testing.T) { - config := configuration.Configuration{ - Kind: configuration.Helm, - Repository: "http:localhost", - } - - generator := NewHelmGenerator("connect", config, nil) - defer generator.Close() - - versions := []string{"0.0.0", "1.0.0", "3.2.1", "999.999.999"} - - for _, version := range versions { - key, err := generator.VersionSortKey(version) - assert.Nil(t, err) - assert.Equal(t, key, int64(0)) - } -} diff --git a/internal/generator/http.go b/internal/generator/http.go index 7639bc497..bd0882582 100644 --- a/internal/generator/http.go +++ b/internal/generator/http.go @@ -5,6 +5,7 @@ import ( "fmt" "io" "net/http" + "regexp" "time" "github.com/CustomResourceDefinition/catalog/internal/configuration" @@ -12,7 +13,7 @@ import ( ) type HttpGenerator struct { - *baseGenerator + *GeneratorVersions client http.Client config configuration.Configuration reader crd.CrdReader @@ -81,14 +82,22 @@ func (generator *HttpGenerator) Crds(version string) ([]crd.Crd, error) { return crds, nil } -func (generator *HttpGenerator) AllVersions() ([]string, error) { +func (generator *HttpGenerator) LatestVersion(filter *regexp.Regexp) (string, error) { + versions, err := generator.Versions(filter) + if err != nil { + return "", err + } + return generator.latest(versions) +} + +func (generator *HttpGenerator) Versions(filter *regexp.Regexp) ([]string, error) { versions := make([]string, len(generator.config.Downloads)) for i, download := range generator.config.Downloads { versions[i] = download.Version } - return versions, nil + return generator.semverSort(versions, filter) } func (generator *HttpGenerator) Close() error { diff --git a/internal/generator/http_test.go b/internal/generator/http_test.go index aad9944e1..39f0ffdc6 100644 --- a/internal/generator/http_test.go +++ b/internal/generator/http_test.go @@ -1,6 +1,7 @@ package generator import ( + "regexp" "testing" "github.com/CustomResourceDefinition/catalog/internal/configuration" @@ -23,7 +24,7 @@ func TestHttpGeneratorVersions(t *testing.T) { generator := NewHttpGenerator(config, nil) defer generator.Close() - versions, err := generator.Versions() + versions, err := generator.Versions(regexp.MustCompile(".*")) assert.Nil(t, err) assert.Equal(t, expectedVersions, versions) } @@ -211,22 +212,79 @@ func TestHttpGeneratorNoSchemas(t *testing.T) { assert.Equal(t, 0, len(schemas)) } -func TestHttpGeneratorHasInertSortingKeys(t *testing.T) { - config := configuration.Configuration{ - Kind: configuration.Http, - Downloads: []configuration.ConfigurationDownload{ - {Version: "1.0.0"}, +func TestHttpGeneratorVersionsFiltering(t *testing.T) { + tests := []struct { + versions []string + expectedVersions []string + pattern string + }{ + { + versions: []string{"2.0.0", "1.3.0", "1.0.0"}, + expectedVersions: []string{"2.0.0", "1.3.0", "1.0.0"}, + }, + { + versions: []string{"v2.0.0", "v1.3.0", "v1.0.0"}, + expectedVersions: []string{}, + }, + { + versions: []string{"v2.0.0", "v1.3.0", "v1.0.0"}, + expectedVersions: []string{"v2.0.0", "v1.3.0", "v1.0.0"}, + pattern: `^v([0-9]+\.[0-9]+\.[0-9]+)$`, + }, + { + versions: []string{"2.0.0", "v1.3.0", "v1.0.0"}, + expectedVersions: []string{"2.0.0", "v1.3.0", "v1.0.0"}, + pattern: `^v?([0-9]+\.[0-9]+\.[0-9]+)$`, + }, + { + versions: []string{"2.0.0", "v1.3v", "v1.0.0"}, + expectedVersions: []string{"2.0.0", "v1.0.0"}, + pattern: `^v?([0-9]+\.[0-9]+\.[0-9]+)$`, + }, + { + versions: []string{"2.0.0-2", "1.3.0-1892", "1.0.0-01"}, + expectedVersions: []string{"2.0.0-2", "1.3.0-1892", "1.0.0-01"}, + pattern: `^([0-9]+\.[0-9]+\.[0-9]+-\d+)$`, + }, + { + versions: []string{"v1.33.2+k0s.0"}, + expectedVersions: []string{"v1.33.2+k0s.0"}, + pattern: `^v([0-9]+\.[0-9]+\.[0-9]+\+k0s\.0)$`, + }, + { + versions: []string{"main", "v1.0", "master"}, + expectedVersions: []string{"main", "master"}, + pattern: `^(main|master)$`, + }, + { + versions: []string{"main", "v1.0.0", "2.0.0", "master"}, + expectedVersions: []string{"2.0.0", "main", "master"}, + pattern: `^([0-9]+\.[0-9]+\.[0-9]+)|(main|master)$`, }, } - generator := NewHttpGenerator(config, nil) - defer generator.Close() + for i, test := range tests { + downloads := make([]configuration.ConfigurationDownload, 0) + for _, v := range test.versions { + downloads = append(downloads, configuration.ConfigurationDownload{Version: v}) + } + config := configuration.Configuration{ + Kind: configuration.Http, + Downloads: downloads, + } - versions := []string{"0.0.0", "1.0.0", "3.2.1", "999.999.999"} + generator := NewHttpGenerator(config, nil) + defer generator.Close() + + var filter *regexp.Regexp + if test.pattern != "" { + filter = regexp.MustCompile(test.pattern) + } else { + filter = regexp.MustCompile(".*") + } - for _, version := range versions { - key, err := generator.VersionSortKey(version) - assert.Nil(t, err) - assert.Equal(t, key, int64(0)) + versions, err := generator.Versions(filter) + assert.Nil(t, err, "index %d failed", i) + assert.Equal(t, test.expectedVersions, versions, "index %d failed", i) } } diff --git a/internal/generator/oci.go b/internal/generator/oci.go index 7a0b4657e..9a29a08c8 100644 --- a/internal/generator/oci.go +++ b/internal/generator/oci.go @@ -4,6 +4,7 @@ import ( "bytes" "fmt" "os" + "regexp" "strconv" "github.com/CustomResourceDefinition/catalog/internal/configuration" @@ -14,7 +15,7 @@ import ( ) type OciGenerator struct { - *baseGenerator + *GeneratorVersions realmClient realmClient config configuration.Configuration reader crd.CrdReader @@ -109,17 +110,25 @@ func (generator *OciGenerator) Crds(version string) ([]crd.Crd, error) { return crds, nil } -func (generator *OciGenerator) AllVersions() ([]string, error) { +func (generator *OciGenerator) LatestVersion(filter *regexp.Regexp) (string, error) { + versions, err := generator.Versions(filter) + if err != nil { + return "", err + } + return generator.latest(versions) +} + +func (generator *OciGenerator) Versions(filter *regexp.Regexp) ([]string, error) { if err := generator.ensureLoaded(); err != nil { return nil, err } - tags, err := generator.realmClient.ListOciTags(generator.config.Repository) + versions, err := generator.realmClient.ListOciTags(generator.config.Repository) if err != nil { return nil, err } - return tags, nil + return generator.semverSort(versions, filter) } func (generator *OciGenerator) ensureLoaded() error { diff --git a/internal/generator/oci_test.go b/internal/generator/oci_test.go index 8b4a55a6f..d4142011d 100644 --- a/internal/generator/oci_test.go +++ b/internal/generator/oci_test.go @@ -2,6 +2,7 @@ package generator import ( "fmt" + "regexp" "testing" "github.com/CustomResourceDefinition/catalog/internal/configuration" @@ -28,7 +29,7 @@ func TestOciGeneratorVersions(t *testing.T) { generator := NewOciGenerator(config, nil) defer generator.Close() - versions, err := generator.Versions() + versions, err := generator.Versions(regexp.MustCompile(".*")) assert.Nil(t, err) assert.Equal(t, []string{"2.0.0"}, versions) } @@ -88,25 +89,3 @@ func TestOciGeneratorMetadata(t *testing.T) { assert.Equal(t, "onepassworditem", metadata[0].Kind) assert.Equal(t, "v1", metadata[0].Version) } - -func TestOciGeneratorHasInertSortingKeys(t *testing.T) { - config := configuration.Configuration{ - Name: "oci", - Kind: configuration.HelmOci, - Repository: fmt.Sprintf("%s%s", "http://localhost", "/helm/connect"), - } - - reader, err := crd.NewCrdReader(setupLogger()) - assert.Nil(t, err) - - generator := NewOciGenerator(config, reader) - defer generator.Close() - - versions := []string{"0.0.0", "1.0.0", "3.2.1", "999.999.999"} - - for _, version := range versions { - key, err := generator.VersionSortKey(version) - assert.Nil(t, err) - assert.Equal(t, key, int64(0)) - } -} diff --git a/internal/generator/preparedGit.go b/internal/generator/preparedGit.go index cb75ea1d4..2b759883c 100644 --- a/internal/generator/preparedGit.go +++ b/internal/generator/preparedGit.go @@ -9,7 +9,6 @@ import ( ) type PreparedGitGenerator struct { - *baseGenerator gitGenerator *GitGenerator versions []versionInfo } @@ -19,7 +18,7 @@ type versionInfo struct { timestamp int64 } -func NewPreparedGitGenerator(gitGenerator *GitGenerator, versions []versionInfo) *PreparedGitGenerator { +func NewPreparedGitGenerator(gitGenerator *GitGenerator, versions []versionInfo) Generator { return &PreparedGitGenerator{ gitGenerator: gitGenerator, versions: versions, @@ -35,7 +34,7 @@ func (g *PreparedGitGenerator) LatestVersion(filter *regexp.Regexp) (string, err } sort.Slice(filtered, func(i, j int) bool { - return filtered[i].timestamp < filtered[j].timestamp + return filtered[i].timestamp > filtered[j].timestamp }) if len(filtered) == 0 { @@ -49,10 +48,6 @@ func (g *PreparedGitGenerator) Versions(filter *regexp.Regexp) ([]string, error) return g.gitGenerator.Versions(filter) } -func (g *PreparedGitGenerator) AllVersions() ([]string, error) { - return g.gitGenerator.AllVersions() -} - func (g *PreparedGitGenerator) MetaData(version string) ([]crd.CrdMetaSchema, error) { return g.gitGenerator.MetaData(version) } diff --git a/internal/generator/preparedGit_test.go b/internal/generator/preparedGit_test.go index 15797b07d..ebb84294b 100644 --- a/internal/generator/preparedGit_test.go +++ b/internal/generator/preparedGit_test.go @@ -1,6 +1,7 @@ package generator import ( + "regexp" "testing" "github.com/stretchr/testify/assert" @@ -15,37 +16,21 @@ func TestPreparedGitGeneratorVersions(t *testing.T) { generator := NewPreparedGitGenerator(nil, versions) - result, err := generator.Versions() + result, err := generator.Versions(regexp.MustCompile(".*")) assert.Nil(t, err) assert.Equal(t, []string{"v1.0.0", "main", "develop"}, result) } -func TestPreparedGitGeneratorVersionSortKey(t *testing.T) { +func TestPreparedGitGeneratorLatestVersionByTimestamp(t *testing.T) { versions := []versionInfo{ {name: "v1.0.0", timestamp: 1705317600}, + {name: "v2.0.0", timestamp: 1706000000}, {name: "main", timestamp: 1705749600}, } generator := NewPreparedGitGenerator(nil, versions) - key, err := generator.VersionSortKey("v1.0.0") + result, err := generator.LatestVersion(regexp.MustCompile(".*")) assert.Nil(t, err) - assert.Equal(t, int64(1705317600), key) - - key, err = generator.VersionSortKey("main") - assert.Nil(t, err) - assert.Equal(t, int64(1705749600), key) - - _, err = generator.VersionSortKey("nonexistent") - assert.NotNil(t, err) -} - -func TestPreparedGitGeneratorVersionSortKeyEmpty(t *testing.T) { - versions := []versionInfo{} - - generator := NewPreparedGitGenerator(nil, versions) - - _, err := generator.VersionSortKey("v1.0.0") - assert.NotNil(t, err) - assert.ErrorContains(t, err, "not found") + assert.Equal(t, "v2.0.0", result) } From be4431bbf1d07e948a0f7ca6e79122dc70ed2aea Mon Sep 17 00:00:00 2001 From: Jakob Jensen Date: Fri, 6 Mar 2026 20:39:37 +0100 Subject: [PATCH 3/8] tmp --- internal/generator/factory.go | 54 ++++-------- internal/generator/generator.go | 5 +- internal/generator/generatorVersions.go | 31 +++++++ internal/generator/generatorVersions_test.go | 23 ++--- internal/generator/git.go | 28 +++--- internal/generator/gitGeneratorFactory.go | 8 +- .../generator/gitGeneratorFactory_test.go | 88 +++++++------------ internal/generator/git_test.go | 28 +++--- internal/generator/helm.go | 12 +-- internal/generator/helm_test.go | 12 +-- internal/generator/http.go | 12 +-- internal/generator/http_test.go | 26 +++--- internal/generator/oci.go | 24 ++--- internal/generator/oci_test.go | 8 +- internal/generator/preparedGit.go | 12 +-- internal/generator/preparedGit_test.go | 18 +--- 16 files changed, 173 insertions(+), 216 deletions(-) diff --git a/internal/generator/factory.go b/internal/generator/factory.go index 1ad345bc8..7e28b31b4 100644 --- a/internal/generator/factory.go +++ b/internal/generator/factory.go @@ -8,8 +8,6 @@ import ( "regexp" "runtime" "slices" - "strconv" - "strings" "github.com/CustomResourceDefinition/catalog/internal/configuration" "github.com/CustomResourceDefinition/catalog/internal/crd" @@ -23,7 +21,6 @@ type Builder struct { logger io.Writer config configuration.Configuration generator Generator - versionFilter *regexp.Regexp registry *registry.SourceRegistry } @@ -39,24 +36,9 @@ func NewBuilder( return nil, err } - if len(config.Namespace) == 0 { - config.Namespace = "namespace" - } - - pattern := defaultVersionPattern(config.Kind) - if len(config.VersionPattern) > 0 { - pattern = config.VersionPattern - } - - re, err := regexp.Compile(pattern) - if err != nil { - return nil, err - } - return &Builder{ config: config, generator: generator, - versionFilter: re, logger: logger, schemaRepository: schemaRepository, generatedRepository: generatedRepository, @@ -91,7 +73,7 @@ func (builder Builder) Build() error { return nil } - versions, err := builder.generator.Versions(builder.versionFilter) + versions, err := builder.generator.Versions() if err != nil { return err } @@ -167,7 +149,7 @@ func (builder Builder) Build() error { // registryStatus reports on the state in registry based on the latest version // available and only uses the decided interface method for latest version information func (builder Builder) registryStatus() (string, bool, error) { - version, err := builder.generator.LatestVersion(builder.versionFilter) + version, err := builder.generator.LatestVersion() if err != nil { return "", false, fmt.Errorf("unable to check registry: %w", err) } @@ -191,37 +173,31 @@ func (builder Builder) updateRegistry(version string) { builder.registry.Set(builder.config.Name, string(builder.config.Kind), version) } -func normalizeVersion(matches [][]string) string { - if len(matches) == 0 || len(matches[0]) < 2 { - return "v0.0.0" +func resolveGenerator(config configuration.Configuration, reader crd.CrdReader, logger io.Writer) (Generator, error) { + if len(config.Namespace) == 0 { + config.Namespace = "namespace" } - version := matches[0][1] - parts := strings.Split(version, ".") - if len(parts) < 3 { - return "v0.0.0" + pattern := defaultVersionPattern(config.Kind) + if len(config.VersionPattern) > 0 { + pattern = config.VersionPattern } - ints := make([]int, 3) - for i := range 3 { - n, _ := strconv.Atoi(parts[i]) - ints[i] = n + re, err := regexp.Compile(pattern) + if err != nil { + return nil, err } - return fmt.Sprintf("v%d.%d.%d", ints[0], ints[1], ints[2]) -} - -func resolveGenerator(config configuration.Configuration, reader crd.CrdReader, logger io.Writer) (Generator, error) { switch config.Kind { case configuration.Git: - return NewGitGeneratorFactory(config, reader, logger).Build() + return NewGitGeneratorFactory(config, reader, re, logger).Build() case configuration.Http: - return NewHttpGenerator(config, reader), nil + return NewHttpGenerator(config, reader, re), nil case configuration.Helm: target := config.Entries[len(config.Entries)-1] - return NewHelmGenerator(target, config, reader), nil + return NewHelmGenerator(target, config, reader, re), nil case configuration.HelmOci: - return NewOciGenerator(config, reader), nil + return NewOciGenerator(config, reader, re), nil default: return nil, fmt.Errorf("no generators matched for kind '%s'", config.Kind) } diff --git a/internal/generator/generator.go b/internal/generator/generator.go index 27aaaca94..6cf73e374 100644 --- a/internal/generator/generator.go +++ b/internal/generator/generator.go @@ -2,14 +2,13 @@ package generator import ( "io" - "regexp" "github.com/CustomResourceDefinition/catalog/internal/crd" ) type Generator interface { - Versions(filter *regexp.Regexp) ([]string, error) - LatestVersion(filter *regexp.Regexp) (string, error) + Versions() ([]string, error) + LatestVersion() (string, error) MetaData(version string) ([]crd.CrdMetaSchema, error) Crds(version string) ([]crd.Crd, error) io.Closer diff --git a/internal/generator/generatorVersions.go b/internal/generator/generatorVersions.go index 6b6baab46..fd5f1d219 100644 --- a/internal/generator/generatorVersions.go +++ b/internal/generator/generatorVersions.go @@ -4,6 +4,7 @@ import ( "fmt" "regexp" "sort" + "strconv" "github.com/CustomResourceDefinition/catalog/internal/semver" ) @@ -36,3 +37,33 @@ func (v *GeneratorVersions) semverSort(versions []string, filter *regexp.Regexp) }) return filtered, nil } + +var versionFormat = regexp.MustCompile(`^([0-9]+)\.([0-9]+)\.([0-9]+)$`) + +func normalizeVersion(matches [][]string) string { + for _, match := range matches { + if len(match) == 0 { + continue + } + + var version string + if len(match) == 1 { + version = match[0] // no capture groups - use entire match + } else { + version = match[1] // use matched capture group + } + + var parts = versionFormat.FindAllStringSubmatch(version, -1) + if len(parts) == 0 { + continue + } + ints := make([]int, 3) + for i := range 3 { + n, _ := strconv.Atoi(parts[0][i+1]) + ints[i] = n + } + return fmt.Sprintf("v%d.%d.%d", ints[0], ints[1], ints[2]) + } + + return "v0.0.0" +} diff --git a/internal/generator/generatorVersions_test.go b/internal/generator/generatorVersions_test.go index a5ad1c4ff..93265568d 100644 --- a/internal/generator/generatorVersions_test.go +++ b/internal/generator/generatorVersions_test.go @@ -26,7 +26,7 @@ func TestGeneratorVersionsSemverSortWithFilter(t *testing.T) { func TestGeneratorVersionsSemverSortFiltersCorrectly(t *testing.T) { gv := GeneratorVersions{} - filter := regexp.MustCompile(`^[0-9]+\.[0-9]+\.[0-9]+$`) + filter := regexp.MustCompile(`^([0-9]+\.[0-9]+\.[0-9]+)$`) versions, err := gv.semverSort([]string{"1.0.0", "main", "2.0.0", "master"}, filter) assert.Nil(t, err) assert.Equal(t, []string{"2.0.0", "1.0.0"}, versions) @@ -35,7 +35,7 @@ func TestGeneratorVersionsSemverSortFiltersCorrectly(t *testing.T) { func TestGeneratorVersionsSemverSortSortsDescending(t *testing.T) { gv := GeneratorVersions{} - filter := regexp.MustCompile(`^[0-9]+\.[0-9]+\.[0-9]+$`) + filter := regexp.MustCompile(`^([0-9]+\.[0-9]+\.[0-9]+)$`) versions, err := gv.semverSort([]string{"1.0.0", "2.10.0", "2.2.0", "1.5.0", "1.01.01"}, filter) assert.Nil(t, err) assert.Equal(t, []string{"2.10.0", "2.2.0", "1.5.0", "1.01.01", "1.0.0"}, versions) @@ -51,17 +51,11 @@ func TestGeneratorVersionsFiltering(t *testing.T) { pattern string }{ { - name: "no filter matches all", + name: "filter matches all", versions: []string{"2.0.0", "1.3.0", "1.0.0"}, expectedVersions: []string{"2.0.0", "1.3.0", "1.0.0"}, pattern: ".*", }, - { - name: "v prefix versions no pattern", - versions: []string{"v2.0.0", "v1.3.0", "v1.0.0"}, - expectedVersions: []string{}, - pattern: "", - }, { name: "v prefix with pattern", versions: []string{"v2.0.0", "v1.3.0", "v1.0.0"}, @@ -90,7 +84,7 @@ func TestGeneratorVersionsFiltering(t *testing.T) { name: "version with build metadata", versions: []string{"v1.33.2+k0s.0"}, expectedVersions: []string{"v1.33.2+k0s.0"}, - pattern: `^v([0-9]+\.[0-9]+\.[0-9]+\+k0s\.0)$`, + pattern: `^v([0-9]+\.[0-9]+\.[0-9]+)\+k0s\.0$`, }, { name: "branch names only", @@ -108,14 +102,7 @@ func TestGeneratorVersionsFiltering(t *testing.T) { for _, test := range tests { t.Run(test.name, func(t *testing.T) { - var filter *regexp.Regexp - if test.pattern != "" { - filter = regexp.MustCompile(test.pattern) - } else { - filter = regexp.MustCompile(".*") - } - - versions, err := gv.semverSort(test.versions, filter) + versions, err := gv.semverSort(test.versions, regexp.MustCompile(test.pattern)) assert.Nil(t, err) assert.Equal(t, test.expectedVersions, versions) }) diff --git a/internal/generator/git.go b/internal/generator/git.go index 8aba503fa..421bc0bf6 100644 --- a/internal/generator/git.go +++ b/internal/generator/git.go @@ -24,15 +24,17 @@ type GitGenerator struct { *GeneratorVersions config configuration.Configuration reader crd.CrdReader + filter *regexp.Regexp tmpDir, gitDir string tags []string branches []string } -func NewGitGenerator(config configuration.Configuration, reader crd.CrdReader) Generator { +func NewGitGenerator(config configuration.Configuration, reader crd.CrdReader, filter *regexp.Regexp) Generator { return &GitGenerator{ config: config, reader: reader, + filter: filter, } } @@ -72,13 +74,11 @@ func (generator *GitGenerator) Crds(version string) ([]crd.Crd, error) { } if len(version) == 0 { - return nil, fmt.Errorf("no version was provided") - // FIXME: verify - // versions, err := generator.Versions() - // if err != nil { - // return nil, err - // } - // version = versions[0] + versions, err := generator.Versions() + if err != nil { + return nil, err + } + version = versions[0] } err := exec.Command("git", "--git-dir", generator.gitDir, "--work-tree", generator.tmpDir, "checkout", "--force", version).Run() @@ -142,15 +142,15 @@ func (generator *GitGenerator) Crds(version string) ([]crd.Crd, error) { return crds, nil } -func (generator *GitGenerator) LatestVersion(filter *regexp.Regexp) (string, error) { - versions, err := generator.Versions(filter) +func (generator *GitGenerator) LatestVersion() (string, error) { + versions, err := generator.Versions() if err != nil { return "", err } return generator.latest(versions) } -func (generator *GitGenerator) Versions(filter *regexp.Regexp) ([]string, error) { +func (generator *GitGenerator) Versions() ([]string, error) { if err := generator.ensureLoaded(); err != nil { return nil, err } @@ -161,7 +161,7 @@ func (generator *GitGenerator) Versions(filter *regexp.Regexp) ([]string, error) filtered := make([]string, 0) for _, v := range versions { - if filter.MatchString(v) { + if generator.filter.MatchString(v) { filtered = append(filtered, v) } } @@ -178,8 +178,8 @@ func (generator *GitGenerator) Versions(filter *regexp.Regexp) ([]string, error) if a != b { return a < b } - aa := normalizeVersion(filter.FindAllStringSubmatch(filtered[i], -1)) - bb := normalizeVersion(filter.FindAllStringSubmatch(filtered[j], -1)) + aa := normalizeVersion(generator.filter.FindAllStringSubmatch(filtered[i], -1)) + bb := normalizeVersion(generator.filter.FindAllStringSubmatch(filtered[j], -1)) return semver.Compare(aa, bb) > 0 }) return filtered, nil diff --git a/internal/generator/gitGeneratorFactory.go b/internal/generator/gitGeneratorFactory.go index d95e55108..ae97dfc11 100644 --- a/internal/generator/gitGeneratorFactory.go +++ b/internal/generator/gitGeneratorFactory.go @@ -19,26 +19,28 @@ import ( type gitGeneratorFactory struct { config configuration.Configuration reader crd.CrdReader + filter *regexp.Regexp logger io.Writer } -func NewGitGeneratorFactory(config configuration.Configuration, reader crd.CrdReader, logger io.Writer) *gitGeneratorFactory { +func NewGitGeneratorFactory(config configuration.Configuration, reader crd.CrdReader, filter *regexp.Regexp, logger io.Writer) *gitGeneratorFactory { return &gitGeneratorFactory{ config: config, reader: reader, + filter: filter, logger: logger, } } func (f *gitGeneratorFactory) Build() (Generator, error) { - generator := NewGitGenerator(f.config, f.reader).(*GitGenerator) + generator := NewGitGenerator(f.config, f.reader, f.filter).(*GitGenerator) if isGitHub, owner, repo := isGitHubRepo(f.config.Repository); isGitHub { token := os.Getenv("GITHUB_TOKEN") if token != "" { versions, err := f.fetchGitHubVersions(owner, repo, token) if err == nil { - return NewPreparedGitGenerator(generator, versions), nil + return NewPreparedGitGenerator(generator, versions, f.filter), nil } fmt.Fprintf(f.logger, "Use git fallback instead of GitHub APIs for %s: %s\n", f.config.Name, err.Error()) } diff --git a/internal/generator/gitGeneratorFactory_test.go b/internal/generator/gitGeneratorFactory_test.go index 02831caf8..9e6e43641 100644 --- a/internal/generator/gitGeneratorFactory_test.go +++ b/internal/generator/gitGeneratorFactory_test.go @@ -107,53 +107,14 @@ func TestGitGeneratorFactoryBuildGitHubSuccessWithVersions(t *testing.T) { Repository: "https://github.com/owner/repo", } - generator, err := NewGitGeneratorFactory(config, nil, nil).Build() + generator, err := NewGitGeneratorFactory(config, nil, regexp.MustCompile(".*"), nil).Build() assert.Nil(t, err) defer generator.Close() assert.IsType(t, &PreparedGitGenerator{}, generator) - versions, err := generator.Versions(regexp.MustCompile(".*")) + version, err := generator.LatestVersion() assert.Nil(t, err) - assert.Contains(t, versions, "v1.0.0") - assert.Contains(t, versions, "v0.9.0") - assert.Contains(t, versions, "main") - assert.Contains(t, versions, "develop") -} - -func TestPreparedGitGeneratorVersionsSortedByDate(t *testing.T) { - t.Setenv("GITHUB_TOKEN", "test-token") - - cleanup := setupGitHubServer(t, []gitHubResponse{ - { - prefix: "refs/tags/", - tags: []githubRef{ - {name: "v0.9.0", committedDate: "2000-01-10T10:00:00Z"}, - {name: "v1.0.0", committedDate: "2000-01-15T10:00:00Z"}, - }, - }, - { - prefix: "refs/heads/", - branches: []githubRef{ - {name: "develop", committedDate: "2000-01-18T10:00:00Z"}, - {name: "main", committedDate: "2000-01-20T10:00:00Z"}, - }, - }, - }) - defer cleanup() - - config := configuration.Configuration{ - Kind: configuration.Git, - Repository: "https://github.com/owner/repo", - } - - generator, err := NewGitGeneratorFactory(config, nil, nil).Build() - assert.Nil(t, err) - defer generator.Close() - assert.IsType(t, &PreparedGitGenerator{}, generator) - - versions, err := generator.Versions(regexp.MustCompile(".*")) - assert.Nil(t, err) - assert.Equal(t, []string{"v0.9.0", "v1.0.0", "develop", "main"}, versions) + assert.Equal(t, version, "main") } var logger = bytes.NewBuffer([]byte{}) @@ -177,7 +138,7 @@ func TestGitGeneratorFactoryBuildGitHubFailure(t *testing.T) { Repository: "https://github.com/owner/repo", } - generator, err := NewGitGeneratorFactory(config, nil, logger).Build() + generator, err := NewGitGeneratorFactory(config, nil, regexp.MustCompile(".*"), logger).Build() assert.Nil(t, err) defer generator.Close() assert.IsType(t, &GitGenerator{}, generator) @@ -207,7 +168,7 @@ func TestGitGeneratorFactoryBuildGitHubSuccess(t *testing.T) { Repository: "https://github.com/owner/repo", } - generator, err := NewGitGeneratorFactory(config, nil, nil).Build() + generator, err := NewGitGeneratorFactory(config, nil, regexp.MustCompile(".*"), nil).Build() assert.Nil(t, err) defer generator.Close() assert.IsType(t, &PreparedGitGenerator{}, generator) @@ -267,13 +228,18 @@ func TestGitGeneratorFactoryAnnotatedTags(t *testing.T) { Repository: "https://github.com/owner/repo", } - generator, err := NewGitGeneratorFactory(config, nil, nil).Build() + generator, err := NewGitGeneratorFactory(config, nil, regexp.MustCompile(".*"), nil).Build() assert.Nil(t, err) defer generator.Close() assert.IsType(t, &PreparedGitGenerator{}, generator) - versions, err := generator.Versions(regexp.MustCompile(".*")) - assert.Nil(t, err) + info := generator.(*PreparedGitGenerator).versions + versions := make([]string, 0) + for _, i := range info { + versions = append(versions, i.name) + } + + assert.Equal(t, len(versions), 4) assert.Contains(t, versions, "v1.0.0") assert.Contains(t, versions, "v0.9.0") assert.Contains(t, versions, "v0.8.0") @@ -310,13 +276,18 @@ func TestGitGeneratorFactoryNestedTags(t *testing.T) { Repository: "https://github.com/owner/repo", } - generator, err := NewGitGeneratorFactory(config, nil, nil).Build() + generator, err := NewGitGeneratorFactory(config, nil, regexp.MustCompile(".*"), nil).Build() assert.Nil(t, err) defer generator.Close() assert.IsType(t, &PreparedGitGenerator{}, generator) - versions, err := generator.Versions(regexp.MustCompile(".*")) - assert.Nil(t, err) + info := generator.(*PreparedGitGenerator).versions + versions := make([]string, 0) + for _, i := range info { + versions = append(versions, i.name) + } + + assert.Equal(t, len(versions), 4) assert.Contains(t, versions, "v1.0.0") assert.Contains(t, versions, "v0.9.0") assert.Contains(t, versions, "nested-tag") @@ -351,14 +322,18 @@ func TestGitGeneratorFactoryPagination(t *testing.T) { Repository: "https://github.com/owner/repo", } - generator, err := NewGitGeneratorFactory(config, nil, nil).Build() + generator, err := NewGitGeneratorFactory(config, nil, regexp.MustCompile(".*"), nil).Build() assert.Nil(t, err) defer generator.Close() assert.IsType(t, &PreparedGitGenerator{}, generator) - versions, err := generator.Versions(regexp.MustCompile(".*")) - assert.Nil(t, err) - assert.Equal(t, 5, len(versions), "should have all 4 tags + 1 branch") + info := generator.(*PreparedGitGenerator).versions + versions := make([]string, 0) + for _, i := range info { + versions = append(versions, i.name) + } + + assert.Equal(t, len(versions), 5) assert.Contains(t, versions, "v1.0.0") assert.Contains(t, versions, "v0.9.0") assert.Contains(t, versions, "v0.8.0") @@ -408,13 +383,12 @@ func TestGitGeneratorFactoryEmptyResponses(t *testing.T) { Repository: "https://github.com/owner/repo", } - generator, err := NewGitGeneratorFactory(config, nil, nil).Build() + generator, err := NewGitGeneratorFactory(config, nil, regexp.MustCompile(".*"), nil).Build() assert.Nil(t, err) defer generator.Close() assert.IsType(t, &PreparedGitGenerator{}, generator) - versions, err := generator.Versions(regexp.MustCompile(".*")) - assert.Nil(t, err) + versions := generator.(*PreparedGitGenerator).versions assert.Equal(t, tt.expectedVersions, len(versions)) }) } diff --git a/internal/generator/git_test.go b/internal/generator/git_test.go index 33ec2f392..afa962e5c 100644 --- a/internal/generator/git_test.go +++ b/internal/generator/git_test.go @@ -41,10 +41,10 @@ func TestGitGeneratorVersionsCombinesTagsAndBranches(t *testing.T) { Repository: fmt.Sprintf("file://%s", *p), } - generator := NewGitGenerator(config, nil) + generator := NewGitGenerator(config, nil, regexp.MustCompile(".*")) defer generator.Close() - versions, err := generator.Versions(regexp.MustCompile(".*")) + versions, err := generator.Versions() assert.Nil(t, err) assert.Contains(t, versions, expectedVersion) assert.Contains(t, versions, expectedDevelop) @@ -69,7 +69,7 @@ func TestGitGeneratorUnknownVersion(t *testing.T) { Repository: fmt.Sprintf("file://%s", *p), } - generator := NewGitGenerator(config, nil) + generator := NewGitGenerator(config, nil, regexp.MustCompile(".*")) defer generator.Close() metadata, err := generator.MetaData("4.5.6") @@ -103,7 +103,7 @@ func TestGitGeneratorMetadataForRegularFile(t *testing.T) { reader, err := crd.NewCrdReader(setupLogger()) assert.Nil(t, err) - generator := NewGitGenerator(config, reader) + generator := NewGitGenerator(config, reader, regexp.MustCompile(".*")) defer generator.Close() metadata, err := generator.MetaData("") @@ -148,7 +148,7 @@ func TestGitGeneratorMetadataForKustomizeFile(t *testing.T) { reader, err := crd.NewCrdReader(setupLogger()) assert.Nil(t, err) - generator := NewGitGenerator(config, reader) + generator := NewGitGenerator(config, reader, regexp.MustCompile(".*")) defer generator.Close() metadata, err := generator.MetaData("") @@ -193,7 +193,7 @@ func TestGitGeneratorMetadataForSourceFiles(t *testing.T) { reader, err := crd.NewCrdReader(setupLogger()) assert.Nil(t, err) - generator := NewGitGenerator(config, reader) + generator := NewGitGenerator(config, reader, regexp.MustCompile(".*")) defer generator.Close() metadata, err := generator.MetaData("") @@ -210,10 +210,10 @@ func TestGitGeneratorCloneFailure(t *testing.T) { Repository: "file:///nonexistent/path/repo.git", } - generator := NewGitGenerator(config, nil) + generator := NewGitGenerator(config, nil, regexp.MustCompile(".*")) defer generator.Close() - _, err := generator.Versions(regexp.MustCompile(".*")) + _, err := generator.Versions() assert.NotNil(t, err) assert.Contains(t, err.Error(), "unable to clone") } @@ -240,7 +240,7 @@ func TestGitGeneratorCheckoutFailure(t *testing.T) { Repository: fmt.Sprintf("file://%s", *p), } - generator := NewGitGenerator(config, nil) + generator := NewGitGenerator(config, nil, regexp.MustCompile(".*")) defer generator.Close() _, err = generator.Crds("nonexistent-branch-tag") @@ -270,10 +270,10 @@ func TestGitGeneratorClose(t *testing.T) { Repository: fmt.Sprintf("file://%s", *p), } - generator := NewGitGenerator(config, nil) + generator := NewGitGenerator(config, nil, regexp.MustCompile(".*")) defer generator.Close() - versions, err := generator.Versions(regexp.MustCompile(".*")) + versions, err := generator.Versions() assert.Nil(t, err) assert.NotEmpty(t, versions) @@ -304,11 +304,11 @@ func TestGitGeneratorVersionsCustomSort(t *testing.T) { Repository: fmt.Sprintf("file://%s", *p), } - generator := NewGitGenerator(config, nil) + filter := regexp.MustCompile(`^([0-9]+\.[0-9]+\.[0-9]+)$`) + generator := NewGitGenerator(config, nil, filter) defer generator.Close() - filter := regexp.MustCompile(`^([0-9]+\.[0-9]+\.[0-9]+)$`) - versions, err := generator.Versions(filter) + versions, err := generator.Versions() assert.Nil(t, err) assert.Equal(t, []string{"2.10.0", "2.2.0", "2.1.0", "1.01.01", "1.0.0"}, versions) } diff --git a/internal/generator/helm.go b/internal/generator/helm.go index e8e634bda..6c7adaba1 100644 --- a/internal/generator/helm.go +++ b/internal/generator/helm.go @@ -25,16 +25,18 @@ type HelmGenerator struct { target string config configuration.Configuration reader crd.CrdReader + filter *regexp.Regexp tmpDir string versions repo.ChartVersions downloader downloader.ChartDownloader } -func NewHelmGenerator(target string, config configuration.Configuration, reader crd.CrdReader) Generator { +func NewHelmGenerator(target string, config configuration.Configuration, reader crd.CrdReader, filter *regexp.Regexp) Generator { return &HelmGenerator{ target: target, config: config, reader: reader, + filter: filter, } } @@ -97,15 +99,15 @@ func (generator *HelmGenerator) Crds(version string) ([]crd.Crd, error) { return crds, nil } -func (generator *HelmGenerator) LatestVersion(filter *regexp.Regexp) (string, error) { - versions, err := generator.Versions(filter) +func (generator *HelmGenerator) LatestVersion() (string, error) { + versions, err := generator.Versions() if err != nil { return "", err } return generator.latest(versions) } -func (generator *HelmGenerator) Versions(filter *regexp.Regexp) ([]string, error) { +func (generator *HelmGenerator) Versions() ([]string, error) { if err := generator.ensureLoaded(); err != nil { return nil, err } @@ -118,7 +120,7 @@ func (generator *HelmGenerator) Versions(filter *regexp.Regexp) ([]string, error } } - return generator.semverSort(versions, filter) + return generator.semverSort(versions, generator.filter) } func (generator *HelmGenerator) Close() error { diff --git a/internal/generator/helm_test.go b/internal/generator/helm_test.go index 8d537d8d6..e66478fd6 100644 --- a/internal/generator/helm_test.go +++ b/internal/generator/helm_test.go @@ -22,10 +22,10 @@ func TestHelmGeneratorVersions(t *testing.T) { Repository: server.URL, } - generator := NewHelmGenerator("connect", config, nil) + generator := NewHelmGenerator("connect", config, nil, regexp.MustCompile(".*")) defer generator.Close() - versions, err := generator.Versions(regexp.MustCompile(".*")) + versions, err := generator.Versions() assert.Nil(t, err) assert.Equal(t, expectedVersions, versions) } @@ -39,10 +39,10 @@ func TestHelmGeneratorUnknownTarget(t *testing.T) { Repository: server.URL, } - generator := NewHelmGenerator("unknown", config, nil) + generator := NewHelmGenerator("unknown", config, nil, regexp.MustCompile(".*")) defer generator.Close() - versions, err := generator.Versions(regexp.MustCompile(".*")) + versions, err := generator.Versions() assert.Nil(t, versions) assert.NotNil(t, err) } @@ -57,7 +57,7 @@ func TestHelmGeneratorUnknownVersion(t *testing.T) { Repository: server.URL, } - generator := NewHelmGenerator("connect", config, nil) + generator := NewHelmGenerator("connect", config, nil, regexp.MustCompile(".*")) defer generator.Close() metadata, err := generator.MetaData("4.5.6") @@ -83,7 +83,7 @@ func TestHelmGeneratorMetadata(t *testing.T) { reader, err := crd.NewCrdReader(setupLogger()) assert.Nil(t, err) - generator := NewHelmGenerator("connect", config, reader) + generator := NewHelmGenerator("connect", config, reader, regexp.MustCompile(".*")) defer generator.Close() metadata, err := generator.MetaData("") diff --git a/internal/generator/http.go b/internal/generator/http.go index bd0882582..a4af51054 100644 --- a/internal/generator/http.go +++ b/internal/generator/http.go @@ -17,15 +17,17 @@ type HttpGenerator struct { client http.Client config configuration.Configuration reader crd.CrdReader + filter *regexp.Regexp } -func NewHttpGenerator(config configuration.Configuration, reader crd.CrdReader) Generator { +func NewHttpGenerator(config configuration.Configuration, reader crd.CrdReader, filter *regexp.Regexp) Generator { return &HttpGenerator{ client: http.Client{ Timeout: 15 * time.Second, }, config: config, reader: reader, + filter: filter, } } @@ -82,22 +84,22 @@ func (generator *HttpGenerator) Crds(version string) ([]crd.Crd, error) { return crds, nil } -func (generator *HttpGenerator) LatestVersion(filter *regexp.Regexp) (string, error) { - versions, err := generator.Versions(filter) +func (generator *HttpGenerator) LatestVersion() (string, error) { + versions, err := generator.Versions() if err != nil { return "", err } return generator.latest(versions) } -func (generator *HttpGenerator) Versions(filter *regexp.Regexp) ([]string, error) { +func (generator *HttpGenerator) Versions() ([]string, error) { versions := make([]string, len(generator.config.Downloads)) for i, download := range generator.config.Downloads { versions[i] = download.Version } - return generator.semverSort(versions, filter) + return generator.semverSort(versions, generator.filter) } func (generator *HttpGenerator) Close() error { diff --git a/internal/generator/http_test.go b/internal/generator/http_test.go index 39f0ffdc6..9142e9626 100644 --- a/internal/generator/http_test.go +++ b/internal/generator/http_test.go @@ -21,10 +21,10 @@ func TestHttpGeneratorVersions(t *testing.T) { }, } - generator := NewHttpGenerator(config, nil) + generator := NewHttpGenerator(config, nil, regexp.MustCompile(".*")) defer generator.Close() - versions, err := generator.Versions(regexp.MustCompile(".*")) + versions, err := generator.Versions() assert.Nil(t, err) assert.Equal(t, expectedVersions, versions) } @@ -39,7 +39,7 @@ func TestHttpGeneratorUnknownVersion(t *testing.T) { }, } - generator := NewHttpGenerator(config, nil) + generator := NewHttpGenerator(config, nil, regexp.MustCompile(".*")) metadata, err := generator.MetaData("4.5.6") assert.Nil(t, metadata) @@ -68,7 +68,7 @@ func TestHttpGeneratorSchemas(t *testing.T) { reader, err := crd.NewCrdReader(setupLogger()) assert.Nil(t, err) - generator := NewHttpGenerator(config, reader) + generator := NewHttpGenerator(config, reader, regexp.MustCompile(".*")) defer generator.Close() crds, err := generator.Crds(version) @@ -112,7 +112,7 @@ func TestHttpGeneratorMetadata(t *testing.T) { reader, err := crd.NewCrdReader(setupLogger()) assert.Nil(t, err) - generator := NewHttpGenerator(config, reader) + generator := NewHttpGenerator(config, reader, regexp.MustCompile(".*")) defer generator.Close() metadata, err := generator.MetaData(version) @@ -148,7 +148,7 @@ func TestHttpGeneratorPartialSchemas(t *testing.T) { reader, err := crd.NewCrdReader(setupLogger()) assert.Nil(t, err) - generator := NewHttpGenerator(config, reader) + generator := NewHttpGenerator(config, reader, regexp.MustCompile(".*")) defer generator.Close() crds, err := generator.Crds(version) @@ -194,7 +194,7 @@ func TestHttpGeneratorNoSchemas(t *testing.T) { reader, err := crd.NewCrdReader(setupLogger()) assert.Nil(t, err) - generator := NewHttpGenerator(config, reader) + generator := NewHttpGenerator(config, reader, regexp.MustCompile(".*")) defer generator.Close() crds, err := generator.Crds(version) @@ -222,10 +222,6 @@ func TestHttpGeneratorVersionsFiltering(t *testing.T) { versions: []string{"2.0.0", "1.3.0", "1.0.0"}, expectedVersions: []string{"2.0.0", "1.3.0", "1.0.0"}, }, - { - versions: []string{"v2.0.0", "v1.3.0", "v1.0.0"}, - expectedVersions: []string{}, - }, { versions: []string{"v2.0.0", "v1.3.0", "v1.0.0"}, expectedVersions: []string{"v2.0.0", "v1.3.0", "v1.0.0"}, @@ -273,9 +269,6 @@ func TestHttpGeneratorVersionsFiltering(t *testing.T) { Downloads: downloads, } - generator := NewHttpGenerator(config, nil) - defer generator.Close() - var filter *regexp.Regexp if test.pattern != "" { filter = regexp.MustCompile(test.pattern) @@ -283,7 +276,10 @@ func TestHttpGeneratorVersionsFiltering(t *testing.T) { filter = regexp.MustCompile(".*") } - versions, err := generator.Versions(filter) + generator := NewHttpGenerator(config, nil, filter) + defer generator.Close() + + versions, err := generator.Versions() assert.Nil(t, err, "index %d failed", i) assert.Equal(t, test.expectedVersions, versions, "index %d failed", i) } diff --git a/internal/generator/oci.go b/internal/generator/oci.go index 9a29a08c8..aaff82281 100644 --- a/internal/generator/oci.go +++ b/internal/generator/oci.go @@ -19,6 +19,7 @@ type OciGenerator struct { realmClient realmClient config configuration.Configuration reader crd.CrdReader + filter *regexp.Regexp tmpDir string downloader downloader.ChartDownloader plainHttp bool @@ -26,7 +27,7 @@ type OciGenerator struct { const HELM_OCI_PLAIN_HTTP = "HELM_OCI_PLAIN_HTTP" -func NewOciGenerator(config configuration.Configuration, reader crd.CrdReader) Generator { +func NewOciGenerator(config configuration.Configuration, reader crd.CrdReader, filter *regexp.Regexp) Generator { plainHttp := false env, found := os.LookupEnv(HELM_OCI_PLAIN_HTTP) value, err := strconv.ParseBool(env) @@ -38,6 +39,7 @@ func NewOciGenerator(config configuration.Configuration, reader crd.CrdReader) G realmClient: newRealmClient(plainHttp), config: config, reader: reader, + filter: filter, plainHttp: plainHttp, } } @@ -78,13 +80,11 @@ func (generator *OciGenerator) Crds(version string) ([]crd.Crd, error) { } if len(version) == 0 { - return nil, fmt.Errorf("no version was provided") - // FIXME: verify - // versions, err := generator.Versions() - // if err != nil { - // return nil, err - // } - // version = versions[0] + versions, err := generator.Versions() + if err != nil { + return nil, err + } + version = versions[0] } savedPath, _, err := generator.downloader.DownloadTo(generator.config.Repository, version, generator.tmpDir) @@ -110,15 +110,15 @@ func (generator *OciGenerator) Crds(version string) ([]crd.Crd, error) { return crds, nil } -func (generator *OciGenerator) LatestVersion(filter *regexp.Regexp) (string, error) { - versions, err := generator.Versions(filter) +func (generator *OciGenerator) LatestVersion() (string, error) { + versions, err := generator.Versions() if err != nil { return "", err } return generator.latest(versions) } -func (generator *OciGenerator) Versions(filter *regexp.Regexp) ([]string, error) { +func (generator *OciGenerator) Versions() ([]string, error) { if err := generator.ensureLoaded(); err != nil { return nil, err } @@ -128,7 +128,7 @@ func (generator *OciGenerator) Versions(filter *regexp.Regexp) ([]string, error) return nil, err } - return generator.semverSort(versions, filter) + return generator.semverSort(versions, generator.filter) } func (generator *OciGenerator) ensureLoaded() error { diff --git a/internal/generator/oci_test.go b/internal/generator/oci_test.go index d4142011d..05b903d41 100644 --- a/internal/generator/oci_test.go +++ b/internal/generator/oci_test.go @@ -26,10 +26,10 @@ func TestOciGeneratorVersions(t *testing.T) { Repository: fmt.Sprintf("%s%s", server.URL, "/helm/connect"), } - generator := NewOciGenerator(config, nil) + generator := NewOciGenerator(config, nil, regexp.MustCompile(".*")) defer generator.Close() - versions, err := generator.Versions(regexp.MustCompile(".*")) + versions, err := generator.Versions() assert.Nil(t, err) assert.Equal(t, []string{"2.0.0"}, versions) } @@ -51,7 +51,7 @@ func TestOciGeneratorUnknownVersion(t *testing.T) { Repository: fmt.Sprintf("%s%s", server.URL, "/helm/connect"), } - generator := NewOciGenerator(config, nil) + generator := NewOciGenerator(config, nil, regexp.MustCompile(".*")) defer generator.Close() metadata, err := generator.MetaData("4.5.6") @@ -79,7 +79,7 @@ func TestOciGeneratorMetadata(t *testing.T) { reader, err := crd.NewCrdReader(setupLogger()) assert.Nil(t, err) - generator := NewOciGenerator(config, reader) + generator := NewOciGenerator(config, reader, regexp.MustCompile(".*")) defer generator.Close() metadata, err := generator.MetaData("") diff --git a/internal/generator/preparedGit.go b/internal/generator/preparedGit.go index 2b759883c..1d7072a99 100644 --- a/internal/generator/preparedGit.go +++ b/internal/generator/preparedGit.go @@ -11,6 +11,7 @@ import ( type PreparedGitGenerator struct { gitGenerator *GitGenerator versions []versionInfo + filter *regexp.Regexp } type versionInfo struct { @@ -18,17 +19,18 @@ type versionInfo struct { timestamp int64 } -func NewPreparedGitGenerator(gitGenerator *GitGenerator, versions []versionInfo) Generator { +func NewPreparedGitGenerator(gitGenerator *GitGenerator, versions []versionInfo, filter *regexp.Regexp) Generator { return &PreparedGitGenerator{ gitGenerator: gitGenerator, versions: versions, + filter: filter, } } -func (g *PreparedGitGenerator) LatestVersion(filter *regexp.Regexp) (string, error) { +func (g *PreparedGitGenerator) LatestVersion() (string, error) { filtered := make([]versionInfo, 0) for _, v := range g.versions { - if filter.MatchString(v.name) { + if g.filter.MatchString(v.name) { filtered = append(filtered, v) } } @@ -44,8 +46,8 @@ func (g *PreparedGitGenerator) LatestVersion(filter *regexp.Regexp) (string, err return filtered[0].name, nil } -func (g *PreparedGitGenerator) Versions(filter *regexp.Regexp) ([]string, error) { - return g.gitGenerator.Versions(filter) +func (g *PreparedGitGenerator) Versions() ([]string, error) { + return g.gitGenerator.Versions() } func (g *PreparedGitGenerator) MetaData(version string) ([]crd.CrdMetaSchema, error) { diff --git a/internal/generator/preparedGit_test.go b/internal/generator/preparedGit_test.go index ebb84294b..30aa91508 100644 --- a/internal/generator/preparedGit_test.go +++ b/internal/generator/preparedGit_test.go @@ -7,20 +7,6 @@ import ( "github.com/stretchr/testify/assert" ) -func TestPreparedGitGeneratorVersions(t *testing.T) { - versions := []versionInfo{ - {name: "v1.0.0", timestamp: 1705317600}, - {name: "main", timestamp: 1705749600}, - {name: "develop", timestamp: 1705569600}, - } - - generator := NewPreparedGitGenerator(nil, versions) - - result, err := generator.Versions(regexp.MustCompile(".*")) - assert.Nil(t, err) - assert.Equal(t, []string{"v1.0.0", "main", "develop"}, result) -} - func TestPreparedGitGeneratorLatestVersionByTimestamp(t *testing.T) { versions := []versionInfo{ {name: "v1.0.0", timestamp: 1705317600}, @@ -28,9 +14,9 @@ func TestPreparedGitGeneratorLatestVersionByTimestamp(t *testing.T) { {name: "main", timestamp: 1705749600}, } - generator := NewPreparedGitGenerator(nil, versions) + generator := NewPreparedGitGenerator(nil, versions, regexp.MustCompile(".*")) - result, err := generator.LatestVersion(regexp.MustCompile(".*")) + result, err := generator.LatestVersion() assert.Nil(t, err) assert.Equal(t, "v2.0.0", result) } From 1c19a765191cd87e725f7d7548c256e267632a65 Mon Sep 17 00:00:00 2001 From: Jakob Jensen Date: Fri, 6 Mar 2026 20:50:24 +0100 Subject: [PATCH 4/8] tmp --- internal/generator/http_test.go | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/internal/generator/http_test.go b/internal/generator/http_test.go index 9142e9626..3485f9260 100644 --- a/internal/generator/http_test.go +++ b/internal/generator/http_test.go @@ -10,14 +10,14 @@ import ( ) func TestHttpGeneratorVersions(t *testing.T) { - expectedVersions := []string{"1.0.0", "1.3.0", "2.0.0"} + expectedVersions := []string{"2.0.0", "1.3.0", "1.0.0"} config := configuration.Configuration{ Kind: configuration.Http, Downloads: []configuration.ConfigurationDownload{ - {Version: expectedVersions[0]}, - {Version: expectedVersions[1]}, {Version: expectedVersions[2]}, + {Version: expectedVersions[1]}, + {Version: expectedVersions[0]}, }, } @@ -221,6 +221,7 @@ func TestHttpGeneratorVersionsFiltering(t *testing.T) { { versions: []string{"2.0.0", "1.3.0", "1.0.0"}, expectedVersions: []string{"2.0.0", "1.3.0", "1.0.0"}, + pattern: `.*`, }, { versions: []string{"v2.0.0", "v1.3.0", "v1.0.0"}, @@ -269,14 +270,7 @@ func TestHttpGeneratorVersionsFiltering(t *testing.T) { Downloads: downloads, } - var filter *regexp.Regexp - if test.pattern != "" { - filter = regexp.MustCompile(test.pattern) - } else { - filter = regexp.MustCompile(".*") - } - - generator := NewHttpGenerator(config, nil, filter) + generator := NewHttpGenerator(config, nil, regexp.MustCompile(test.pattern)) defer generator.Close() versions, err := generator.Versions() From 879795db2becc76a6880a1eed909a974ab02f27c Mon Sep 17 00:00:00 2001 From: Jakob Jensen Date: Fri, 6 Mar 2026 21:18:17 +0100 Subject: [PATCH 5/8] tmp --- internal/generator/generatorVersions_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/generator/generatorVersions_test.go b/internal/generator/generatorVersions_test.go index 93265568d..8304bcf0d 100644 --- a/internal/generator/generatorVersions_test.go +++ b/internal/generator/generatorVersions_test.go @@ -54,7 +54,7 @@ func TestGeneratorVersionsFiltering(t *testing.T) { name: "filter matches all", versions: []string{"2.0.0", "1.3.0", "1.0.0"}, expectedVersions: []string{"2.0.0", "1.3.0", "1.0.0"}, - pattern: ".*", + pattern: `.*`, }, { name: "v prefix with pattern", From fb50ff1666d5b69d9a43f3e9a9979495754515d9 Mon Sep 17 00:00:00 2001 From: Jakob Jensen Date: Fri, 6 Mar 2026 23:19:44 +0100 Subject: [PATCH 6/8] tmp --- internal/generator/factory_test.go | 33 +++++++++++++++++++++++ internal/generator/preparedGit_test.go | 36 +++++++++++++++++++++++--- 2 files changed, 65 insertions(+), 4 deletions(-) diff --git a/internal/generator/factory_test.go b/internal/generator/factory_test.go index 6872e541b..6f03faccf 100644 --- a/internal/generator/factory_test.go +++ b/internal/generator/factory_test.go @@ -13,6 +13,39 @@ import ( "github.com/stretchr/testify/assert" ) +func TestBuildWithVersionPatternFiltering(t *testing.T) { + config := configuration.Configuration{ + Kind: configuration.Http, + Name: "test", + ApiGroups: []string{"chart.uri"}, + VersionPattern: `^v([0-9]+\.[0-9]+\.[0-9]+)$`, + Downloads: []configuration.ConfigurationDownload{ + { + Version: "v1.0.0", + }, + { + Version: "v2.0.0", + }, + { + Version: "3.0.0", + }, + }, + } + + reader, err := crd.NewCrdReader(setupLogger()) + assert.Nil(t, err) + + tmpDir := t.TempDir() + + builder, err := NewBuilder(config, reader, tmpDir, tmpDir, tmpDir, setupLogger(), nil) + assert.Nil(t, err) + + version, result, err := builder.registryStatus() + assert.Nil(t, err) + assert.False(t, result) + assert.Equal(t, "v2.0.0", version) +} + func TestResolveGenerator(t *testing.T) { invalidConfigs := []configuration.Configuration{ { diff --git a/internal/generator/preparedGit_test.go b/internal/generator/preparedGit_test.go index 30aa91508..6cdacecbc 100644 --- a/internal/generator/preparedGit_test.go +++ b/internal/generator/preparedGit_test.go @@ -9,14 +9,42 @@ import ( func TestPreparedGitGeneratorLatestVersionByTimestamp(t *testing.T) { versions := []versionInfo{ - {name: "v1.0.0", timestamp: 1705317600}, - {name: "v2.0.0", timestamp: 1706000000}, - {name: "main", timestamp: 1705749600}, + {name: "a", timestamp: 1705317600}, + {name: "b", timestamp: 1706000000}, + {name: "c", timestamp: 1705749600}, } generator := NewPreparedGitGenerator(nil, versions, regexp.MustCompile(".*")) result, err := generator.LatestVersion() assert.Nil(t, err) - assert.Equal(t, "v2.0.0", result) + assert.Equal(t, "b", result) +} + +func TestPreparedGitGeneratorLatestVersionByTimestampNotSemver(t *testing.T) { + versions := []versionInfo{ + {name: "10.0.0", timestamp: 1704000000}, + {name: "1.0.0", timestamp: 1705000000}, + {name: "2.0.0", timestamp: 1706000000}, + } + + generator := NewPreparedGitGenerator(nil, versions, regexp.MustCompile(".*")) + + result, err := generator.LatestVersion() + assert.Nil(t, err) + assert.Equal(t, "2.0.0", result) +} + +func TestPreparedGitGeneratorLatestVersionNoMatchingFilter(t *testing.T) { + versions := []versionInfo{ + {name: "v1.0.0", timestamp: 1705317600}, + {name: "v2.0.0", timestamp: 1706000000}, + } + + filter := regexp.MustCompile(`^main$`) + generator := NewPreparedGitGenerator(nil, versions, filter) + + _, err := generator.LatestVersion() + assert.NotNil(t, err) + assert.Contains(t, err.Error(), "no versions are available") } From 17d2f084bf188e838398bab123b6da1bdcb4a77a Mon Sep 17 00:00:00 2001 From: Jakob Jensen Date: Fri, 6 Mar 2026 23:36:18 +0100 Subject: [PATCH 7/8] tmp --- internal/generator/factory.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/internal/generator/factory.go b/internal/generator/factory.go index 7e28b31b4..a4b583726 100644 --- a/internal/generator/factory.go +++ b/internal/generator/factory.go @@ -183,21 +183,21 @@ func resolveGenerator(config configuration.Configuration, reader crd.CrdReader, pattern = config.VersionPattern } - re, err := regexp.Compile(pattern) + filter, err := regexp.Compile(pattern) if err != nil { return nil, err } switch config.Kind { case configuration.Git: - return NewGitGeneratorFactory(config, reader, re, logger).Build() + return NewGitGeneratorFactory(config, reader, filter, logger).Build() case configuration.Http: - return NewHttpGenerator(config, reader, re), nil + return NewHttpGenerator(config, reader, filter), nil case configuration.Helm: target := config.Entries[len(config.Entries)-1] - return NewHelmGenerator(target, config, reader, re), nil + return NewHelmGenerator(target, config, reader, filter), nil case configuration.HelmOci: - return NewOciGenerator(config, reader, re), nil + return NewOciGenerator(config, reader, filter), nil default: return nil, fmt.Errorf("no generators matched for kind '%s'", config.Kind) } From f366d0b28ef281b728723c3e0d6c090ef2166042 Mon Sep 17 00:00:00 2001 From: Jakob Jensen Date: Fri, 6 Mar 2026 23:52:43 +0100 Subject: [PATCH 8/8] tmp --- internal/generator/factory.go | 4 ++++ internal/generator/preparedGit_test.go | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/internal/generator/factory.go b/internal/generator/factory.go index a4b583726..06c7eeca6 100644 --- a/internal/generator/factory.go +++ b/internal/generator/factory.go @@ -64,6 +64,10 @@ func (builder Builder) Build() error { fmt.Fprintf(logger, "Producing for %s@%s:\n", builder.config.Name, builder.config.Kind) defer fmt.Fprintf(logger, "End.\n") + if _, ok := builder.generator.(*PreparedGitGenerator); ok { + fmt.Fprintf(logger, " - using prepared git generator\n") + } + latestVersion, isUpdated, err := builder.registryStatus() if err != nil { return err diff --git a/internal/generator/preparedGit_test.go b/internal/generator/preparedGit_test.go index 6cdacecbc..be35f74aa 100644 --- a/internal/generator/preparedGit_test.go +++ b/internal/generator/preparedGit_test.go @@ -23,9 +23,9 @@ func TestPreparedGitGeneratorLatestVersionByTimestamp(t *testing.T) { func TestPreparedGitGeneratorLatestVersionByTimestampNotSemver(t *testing.T) { versions := []versionInfo{ - {name: "10.0.0", timestamp: 1704000000}, {name: "1.0.0", timestamp: 1705000000}, {name: "2.0.0", timestamp: 1706000000}, + {name: "10.0.0", timestamp: 1704000000}, } generator := NewPreparedGitGenerator(nil, versions, regexp.MustCompile(".*"))