refactor(repos): stabilise registry ordering
Some checks failed
Security Scan / security (push) Failing after 11s
Test / test (push) Successful in 2m21s

Sort registry and provider-registry listings for deterministic output and add coverage for the stable ordering guarantees.

Co-Authored-By: Virgil <virgil@lethean.io>
This commit is contained in:
Virgil 2026-04-02 06:52:45 +00:00
parent 697bfde215
commit 676130ab84
4 changed files with 123 additions and 1 deletions

View file

@ -5,6 +5,7 @@ package marketplace
import (
filepath "dappco.re/go/core/scm/internal/ax/filepathx"
os "dappco.re/go/core/scm/internal/ax/osx"
"sort"
core "dappco.re/go/core"
coreio "dappco.re/go/core/io"
@ -156,6 +157,7 @@ func (r *ProviderRegistryFile) List() []string {
for code := range r.Providers {
codes = append(codes, code)
}
sort.Strings(codes)
return codes
}
@ -168,5 +170,6 @@ func (r *ProviderRegistryFile) AutoStartProviders() []string {
codes = append(codes, code)
}
}
sort.Strings(codes)
return codes
}

View file

@ -258,6 +258,23 @@ func TestProviderRegistry_List_Good(t *testing.T) {
assert.Contains(t, codes, "b")
}
func TestProviderRegistry_List_Good_Sorted_Good(t *testing.T) {
reg := &ProviderRegistryFile{
Version: 1,
Providers: map[string]ProviderRegistryEntry{
"zulu": {Version: "1.0"},
"alpha": {Version: "2.0"},
"mike": {Version: "3.0"},
},
}
codes := reg.List()
require.Len(t, codes, 3)
assert.Equal(t, "alpha", codes[0])
assert.Equal(t, "mike", codes[1])
assert.Equal(t, "zulu", codes[2])
}
func TestProviderRegistry_AutoStartProviders_Good(t *testing.T) {
reg := &ProviderRegistryFile{
Version: 1,
@ -273,3 +290,19 @@ func TestProviderRegistry_AutoStartProviders_Good(t *testing.T) {
assert.Contains(t, auto, "auto-a")
assert.Contains(t, auto, "auto-c")
}
func TestProviderRegistry_AutoStartProviders_Good_Sorted_Good(t *testing.T) {
reg := &ProviderRegistryFile{
Version: 1,
Providers: map[string]ProviderRegistryEntry{
"zulu": {Version: "1.0", AutoStart: true},
"alpha": {Version: "2.0", AutoStart: true},
"mike": {Version: "3.0", AutoStart: false},
},
}
auto := reg.AutoStartProviders()
require.Len(t, auto, 2)
assert.Equal(t, "alpha", auto[0])
assert.Equal(t, "zulu", auto[1])
}

View file

@ -9,6 +9,7 @@ import (
filepath "dappco.re/go/core/scm/internal/ax/filepathx"
os "dappco.re/go/core/scm/internal/ax/osx"
strings "dappco.re/go/core/scm/internal/ax/stringsx"
"sort"
"dappco.re/go/core/io"
coreerr "dappco.re/go/core/log"
@ -266,9 +267,11 @@ func detectOrg(m io.Medium, repoPath string) string {
func (r *Registry) List() []*Repo {
repos := make([]*Repo, 0, len(r.Repos))
for _, repo := range r.Repos {
repos = append(repos, repo)
}
sort.Slice(repos, func(i, j int) bool {
return repos[i].Name < repos[j].Name
})
return repos
}
@ -294,6 +297,9 @@ func (r *Registry) ByType(t string) []*Repo {
repos = append(repos, repo)
}
}
sort.Slice(repos, func(i, j int) bool {
return repos[i].Name < repos[j].Name
})
return repos
}
@ -335,7 +341,13 @@ func (r *Registry) TopologicalOrder() ([]*Repo, error) {
return nil
}
names := make([]string, 0, len(r.Repos))
for name := range r.Repos {
names = append(names, name)
}
sort.Strings(names)
for _, name := range names {
if err := visit(name); err != nil {
return nil, err
}

View file

@ -173,6 +173,32 @@ func TestRegistry_List_Good(t *testing.T) {
assert.Len(t, repos, 4)
}
func TestRegistry_List_Good_SortedByName_Good(t *testing.T) {
m := io.NewMockMedium()
yaml := `
version: 1
org: host-uk
base_path: /tmp/repos
repos:
zulu:
type: module
alpha:
type: module
mike:
type: module
`
_ = m.Write("/tmp/repos.yaml", yaml)
reg, err := LoadRegistry(m, "/tmp/repos.yaml")
require.NoError(t, err)
repos := reg.List()
require.Len(t, repos, 3)
assert.Equal(t, "alpha", repos[0].Name)
assert.Equal(t, "mike", repos[1].Name)
assert.Equal(t, "zulu", repos[2].Name)
}
func TestRegistry_Get_Good(t *testing.T) {
reg := newTestRegistry(t)
repo, ok := reg.Get("core-php")
@ -200,6 +226,31 @@ func TestRegistry_ByType_Good(t *testing.T) {
assert.Len(t, products, 1)
}
func TestRegistry_ByType_Good_SortedByName_Good(t *testing.T) {
m := io.NewMockMedium()
yaml := `
version: 1
org: host-uk
base_path: /tmp/repos
repos:
zulu:
type: module
alpha:
type: module
mike:
type: foundation
`
_ = m.Write("/tmp/repos.yaml", yaml)
reg, err := LoadRegistry(m, "/tmp/repos.yaml")
require.NoError(t, err)
modules := reg.ByType("module")
require.Len(t, modules, 2)
assert.Equal(t, "alpha", modules[0].Name)
assert.Equal(t, "zulu", modules[1].Name)
}
func TestRegistry_ByType_Good_NoMatch_Good(t *testing.T) {
reg := newTestRegistry(t)
templates := reg.ByType("template")
@ -306,6 +357,29 @@ repos:
assert.Len(t, order, 2)
}
func TestTopologicalOrder_Good_NoDeps_Sorted_Good(t *testing.T) {
m := io.NewMockMedium()
yaml := `
version: 1
org: test
base_path: /tmp
repos:
zulu:
type: module
alpha:
type: module
`
_ = m.Write("/tmp/repos.yaml", yaml)
reg, err := LoadRegistry(m, "/tmp/repos.yaml")
require.NoError(t, err)
order, err := reg.TopologicalOrder()
require.NoError(t, err)
require.Len(t, order, 2)
assert.Equal(t, "alpha", order[0].Name)
assert.Equal(t, "zulu", order[1].Name)
}
// ── ScanDirectory ──────────────────────────────────────────────────
func TestScanDirectory_Good(t *testing.T) {