Merge pull request #1663 from entireio/soph/loosen-repo-list-enums · Entire
Merge pull request #1663 from entireio/soph/loosen-repo-list-enums
21a7b10→main · gtrrz-victor · 1w ago · 10 files · +160 added/-720 removed
fix(coreapi): loosen display-only Repo read enums for forward-compat
Changes
10
cmd/entire/cli
Mrepo.go +1/-5
Mrepo_test.go +1/-1
internal/coreapi
MUPSTREAM.md +22
Mclient_test.go +45
Moas_json_gen.go -221
Moas_response_decoders_gen.go -27
Moas_schemas_gen.go +20/-288
Moas_validators_gen.go -156
spec
Mcore.gen.json -13
Mnormalize.go +71/-9
var repoColumns = []string{"ID", "NAME", "PROJECT", "CLUSTER", "STATE"}
func repoRow(r coreapi.Repo) []string {
state := ""
if v, ok := r.State.Get(); ok {
state = string(v)
}
return []string{r.ID, r.Name, r.OwningProjectId, r.ClusterHost.Or("-"), state}
}
return []string{r.ID, r.Name, r.OwningProjectId, r.ClusterHost.Or("-"), r.State.Or("-")}
// repoDetailColumns / repoDetailRow extend the shared repo view with the
2. Display-only read enums hard-fail on unknown values
Symptom: read-model string fields the CLI only displays (Repo.state, Repo.visibility, Repo.objectFormat) are declared as enum. ogen turns each into a named type with a strict Validate() that the response decoder calls unconditionally, so the day the server adds a new value (a new repo lifecycle state, say) the whole repo list / repo-get request fails to decode — even though the client never branches on the value.
Fix upstream: model client-display fields that may grow new values as plain strings (drop enum), or have ogen treat them as open enums. Enums the client sends (request bodies like SetRepoVisibilityInputBody) should stay strict.
Workaround: spec/normalize.go (loosenReadModelEnums, allowlist readModelEnumFields) deletes the enum constraint from those response read-model fields, so ogen emits plain strings with no Validate() and unknown values pass through for display. Only response read models are loosened; request-body enums stay strict. Locked in by TestListProjectRepos_UnknownEnumValuesPassThrough in client_test.go.
Test Function Example
func TestListProjectRepos_UnknownEnumValuesPassThrough(t *testing.T) {
t.Parallel()
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
// Values the current spec's enums did NOT allow.
if _, err := w.Write([]byte(`{"repos":[{"id":"01H000000000000000000000A1","owningProjectId":"01H000000000000000000000P1","name":"demo","state":"archiving","visibility":"internal","objectFormat":"sha512"}]}`)); err != nil {
t.Errorf("writing test response: %v", err)
}
}))
t.Cleanup(srv.Close)
c, err := NewClient(srv.URL, bearerOnlySource{})
if err != nil {
t.Fatalf("NewClient: %v", err)
}
out, err := c.ListProjectRepos(context.Background(), ListProjectReposParams{ProjectId: "01H000000000000000000000P1"})
if err != nil {
t.Fatalf("ListProjectRepos with unknown enum values must not fail (forward-compat), got: %v", err)
}
if len(out.Repos) != 1 {
t.Fatalf("Repos len = %d, want 1", len(out.Repos))
}
repo := out.Repos[0]
if got := repo.State.Or(""); got != "archiving" {
t.Errorf("State = %q, want the unknown value %q passed through verbatim", got, "archiving")
}
if got := repo.Visibility.Or(""); got != "internal" {
t.Errorf("Visibility = %q, want the unknown value %q passed through verbatim", got, "internal")
}
if got := repo.ObjectFormat.Or(""); got != "sha512" {
t.Errorf("ObjectFormat = %q, want the unknown value %q passed through verbatim", got, "sha512")
}
}
File Modifications
internal/coreapi/UPSTREAM.md +22
internal/coreapi/client_test.go +45
internal/coreapi/oas_json_gen.go -221
internal/coreapi/oas_response_decoders_gen.go -27
internal/coreapi/oas_schemas_gen.go +20/-288
internal/coreapi/oas_validators_gen.go -156
spec/core.gen.json -13
spec/normalize.go +71/-9