Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 1 addition & 5 deletions pkg/bump.go
Original file line number Diff line number Diff line change
Expand Up @@ -131,11 +131,7 @@ func BumpRegistry(content string, resolve func(name string) (string, bool)) (Bum
for _, b := range reg.Bases {
record(b.Packages)
}
for _, group := range [][]OptionEntry{
reg.CSS, reg.Formatters, reg.Linters, reg.Validation, reg.Form,
reg.Query, reg.State, reg.CMS, reg.Test, reg.Audit, reg.Deployment, reg.CICD,
reg.Desktop,
} {
for _, group := range reg.optionGroups() {
for _, e := range group {
record(e.Packages)
for _, ip := range e.IntegrationPackages {
Expand Down
51 changes: 51 additions & 0 deletions pkg/bump_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package pkg

import (
"encoding/json"
"reflect"
"testing"
"time"
)
Expand Down Expand Up @@ -149,3 +150,53 @@ func TestBumpRegistryDesktop(t *testing.T) {
t.Errorf("content missing %q", want)
}
}

func TestBumpRegistryScansBackendOrmDatabase(t *testing.T) {
// #122: these categories were missing from the pin collection, silently
// freezing hono/drizzle/driver pins out of the freshness policy.
content := `{
"backend": [
{ "value": "hono", "packages": { "dependencies": { "hono": "^4.6.14" } } }
],
"orm": [
{ "value": "drizzle", "packages": { "dependencies": { "drizzle-orm": "^0.38.0" } } }
],
"database": [
{ "value": "postgres", "packages": { "dependencies": { "pg": "^8.13.1" } } }
]
}`
bumped := map[string]string{"hono": "4.7.0", "drizzle-orm": "0.39.0", "pg": "8.14.0"}
resolve := func(name string) (string, bool) {
v, ok := bumped[name]
return v, ok
}
res, err := BumpRegistry(content, resolve)
if err != nil {
t.Fatal(err)
}
if len(res.Changes) != len(bumped) {
t.Fatalf("changes = %+v; want one per backend/orm/database pin", res.Changes)
}
for _, want := range []string{`"hono": "^4.7.0"`, `"drizzle-orm": "^0.39.0"`, `"pg": "^8.14.0"`} {
if !contains(res.Content, want) {
t.Errorf("content missing %q", want)
}
}
}

func TestOptionGroupsCoverRegistry(t *testing.T) {
// Guards the #122 class of bug: every []OptionEntry field of Registry must
// be returned by optionGroups(), so adding a category to the struct without
// wiring it into the all-options scan fails here instead of silently
// freezing its pins.
var fields int
rt := reflect.TypeOf(Registry{})
for i := 0; i < rt.NumField(); i++ {
if rt.Field(i).Type == reflect.TypeOf([]OptionEntry{}) {
fields++
}
}
if groups := (&Registry{}).optionGroups(); len(groups) != fields {
t.Errorf("optionGroups() returns %d groups but Registry has %d []OptionEntry fields — a category is missing from the all-options scan", len(groups), fields)
}
}
12 changes: 12 additions & 0 deletions pkg/registry.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,18 @@ type Registry struct {
Database []OptionEntry `json:"database"`
}

// optionGroups returns every []OptionEntry category of the registry. Anything
// that scans "all options" (e.g. bump's pin collection) must go through this —
// TestOptionGroupsCoverRegistry asserts it stays in sync with the struct, so a
// new category can't silently fall out of the freshness policy again (#122).
func (r *Registry) optionGroups() [][]OptionEntry {
return [][]OptionEntry{
r.CSS, r.Formatters, r.Linters, r.Validation, r.Form,
r.Query, r.State, r.CMS, r.Test, r.Audit, r.Deployment, r.CICD,
r.Desktop, r.Backend, r.ORM, r.Database,
}
}

var globalRegistry *Registry

func InitRegistry(data []byte) error {
Expand Down