BL7: reserved by name from the catalog half's view, builder_versions calls it
The builder's tools bundle serves reserved given a package's name: it follows the catalog half's packages view itself, finds the module from the name, answers the reserved version, or for a version no reservation holds asks the seat mesh-catalog's versions and answers released with the release's digests; a name no entry carries, two entries carry, or a version neither reserved nor released is answered error. builder_versions by name calls reserved through its invokes. The builder's process serves no call. Builds: design 47 G §572, §582 (A-70) Claude-Session: https://claude.ai/code/session_01NcbgfGKaxw984XyAPfLm4h
This commit is contained in:
@@ -15,6 +15,8 @@ import (
|
||||
"time"
|
||||
|
||||
"git.novox.be/novox/mesh-contracts/health-and-repair/go/clients/meshhandactsclient"
|
||||
"git.novox.be/novox/mesh-delivery/contracts/go/seats/meshbuilds"
|
||||
"git.novox.be/novox/mesh-delivery/contracts/go/seats/meshcatalog"
|
||||
"git.novox.be/novox/mesh-delivery/modules/mesh-delivery-builder/buildrun"
|
||||
"git.novox.be/novox/mesh-delivery/modules/mesh-delivery-builder/builds"
|
||||
"git.novox.be/novox/mesh-delivery/sdk/buildstep"
|
||||
@@ -35,8 +37,11 @@ type queueAsker func(key string, value []byte) (json.RawMessage, error)
|
||||
|
||||
// Tools are the builder's tools: stuck reads, askAgain writes the reasks value, queue writes a queues value and waits for
|
||||
// the builder's read, buildAgain writes a reasks value of mode build and waits for the builder's answer.
|
||||
//
|
||||
// builder_versions, asked by a name, answers also what the verb reserved answers for it (reserve; design 47 G §572): the
|
||||
// bundle calls the seat mesh-builds through its invokes, as any caller does. Nil answers none.
|
||||
func Tools(r build.StuckReader, askAgain func(key string, value []byte) error, queue, buildAgain queueAsker, since build.LogSince, now func() time.Time, vs versions.Reader,
|
||||
fw, of versions.Reader) []stdio.Tool {
|
||||
fw, of versions.Reader, reserve func(name, version string) (meshbuilds.ReservedAnswer, error)) []stdio.Tool {
|
||||
str := func(args map[string]any, k string) string { s, _ := args[k].(string); return strings.TrimSpace(s) }
|
||||
// handAct writes a reasks value of a versions hand act and answers the builder's answer, or its refusal as an error.
|
||||
handAct := func(key string, value []byte, err error) (any, error) {
|
||||
@@ -91,7 +96,16 @@ func Tools(r build.StuckReader, askAgain func(key string, value []byte) error, q
|
||||
"version": map[string]any{"type": "string", "description": "one version, to ask whether it is recorded"},
|
||||
"digest": map[string]any{"type": "string", "description": "with version: the digest the holder received"}}},
|
||||
Run: func(args map[string]any) (any, error) {
|
||||
return versions.AnswerVersions(context.Background(), vs, str(args, "name"), str(args, "version"), str(args, "digest"))
|
||||
out, err := versions.AnswerVersions(context.Background(), vs, str(args, "name"), str(args, "version"), str(args, "digest"))
|
||||
if err != nil || reserve == nil {
|
||||
return out, err
|
||||
}
|
||||
ra, err := reserve(out.Name, str(args, "version"))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("the seat mesh-builds' reserved did not answer for %s: %w", out.Name, err)
|
||||
}
|
||||
out.Reserved = &ra
|
||||
return out, nil
|
||||
}},
|
||||
{Name: build.StuckTool,
|
||||
Description: "Every build key that waits (building or queued), oldest first: its module, fingerprint, step words and since when, and each ask it " +
|
||||
@@ -314,6 +328,26 @@ func written(s stdio.KeptState, key string, revision uint64) time.Time {
|
||||
return time.Time{}
|
||||
}
|
||||
|
||||
// The state the bundle follows, its owner's tool, and the seat verbs it calls (the manifest's invokes).
|
||||
const (
|
||||
indexerModule = "mesh-delivery-indexer"
|
||||
packagesState = "packages"
|
||||
packagesTool = indexerModule + ".indexer_read_packages"
|
||||
catalogVersionsVerb = "seat:mesh-catalog.versions"
|
||||
reservedVerb = "seat:mesh-builds.reserved"
|
||||
)
|
||||
|
||||
// followedPackages is the catalog half's packages state as the bundle's picture of it holds it (versions.PackagesState).
|
||||
type followedPackages struct{ r *views.Reader }
|
||||
|
||||
func (f followedPackages) Keys(context.Context) ([]string, error) {
|
||||
return f.r.Keys(indexerModule + "." + packagesState)
|
||||
}
|
||||
|
||||
func (f followedPackages) Get(_ context.Context, key string) ([]byte, bool, error) {
|
||||
return f.r.Get(indexerModule+"."+packagesState, key)
|
||||
}
|
||||
|
||||
func main() {
|
||||
steps := map[string]build.StateRead{}
|
||||
for _, bm := range build.StuckBuildModules {
|
||||
@@ -370,8 +404,33 @@ func main() {
|
||||
}
|
||||
return e.Value, true, nil
|
||||
}}
|
||||
tools := Tools(r, put, askQueue(stdio.State(build.QueuesState), 25*time.Second), buildAgain, stdio.Log(builds.BuilderLog).Since, time.Now, vr, fr, ofr)
|
||||
tools = append(tools, reservedTools(rr, buildAgain, time.Now, meshhandactsclient.Recorder{Ask: stdio.Ask})...)
|
||||
// The catalog half's view of the packages the bundle follows itself (design 47 G §572, A-70), as other bundles follow views.
|
||||
pk := &views.Reader{Module: builds.BuilderModule, Logf: func(f string, a ...any) { fmt.Fprintf(os.Stderr, "[mesh-delivery-builder-tools] "+f+"\n", a...) },
|
||||
Acts: meshhandactsclient.Recorder{Ask: stdio.Ask}}
|
||||
pk.Follow(indexerModule, packagesState, packagesTool)
|
||||
pk.Start(context.Background())
|
||||
carriers := versions.Carriers(followedPackages{pk})
|
||||
released := func(_ context.Context, module string) ([]meshcatalog.VersionEntry, error) {
|
||||
raw, err := stdio.Ask(catalogVersionsVerb, meshcatalog.VersionsInput{Module: module})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var a meshcatalog.VersionsAnswer
|
||||
if err := json.Unmarshal(raw, &a); err != nil {
|
||||
return nil, fmt.Errorf("the seat mesh-catalog's versions answered what does not read: %w", err)
|
||||
}
|
||||
return a.Versions, nil
|
||||
}
|
||||
reserve := func(name, version string) (meshbuilds.ReservedAnswer, error) {
|
||||
raw, err := stdio.Ask(reservedVerb, meshbuilds.ReservedInput{Name: name, Version: version})
|
||||
if err != nil {
|
||||
return meshbuilds.ReservedAnswer{}, err
|
||||
}
|
||||
var a meshbuilds.ReservedAnswer
|
||||
return a, json.Unmarshal(raw, &a)
|
||||
}
|
||||
tools := Tools(r, put, askQueue(stdio.State(build.QueuesState), 25*time.Second), buildAgain, stdio.Log(builds.BuilderLog).Since, time.Now, vr, fr, ofr, reserve)
|
||||
tools = append(tools, reservedTools(rr, buildAgain, time.Now, meshhandactsclient.Recorder{Ask: stdio.Ask}, carriers, released)...)
|
||||
ws := stdio.State(build.WaitsState)
|
||||
wr := versions.Reader{Keys: ws.Keys, Get: func(key string) (json.RawMessage, bool, error) {
|
||||
e, err := ws.Get(key)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
@@ -16,7 +17,10 @@ import (
|
||||
// reservedTools are builder_reserved, builder_reserved_drop and the seat mesh-builds' verb reserved (design 47 G section
|
||||
// 369), served as tools of the bundle. The drop is a hand act: it is recorded in the hand-act log first, then written to
|
||||
// reasks for the builder, which owns the reservations, to answer.
|
||||
func reservedTools(rr versions.Reader, ask queueAsker, now func() time.Time, acts meshhandactsclient.Recorder) []stdio.Tool {
|
||||
//
|
||||
// The verb reserved given a name finds the module from the catalog half's view the bundle follows (carriers) and, for a version
|
||||
// no reservation holds, asks the seat mesh-catalog's verb versions (released); the builder's process serves no call (A-70).
|
||||
func reservedTools(rr versions.Reader, ask queueAsker, now func() time.Time, acts meshhandactsclient.Recorder, carriers func(context.Context, string) ([]versions.Built, error), released versions.CatalogVersions) []stdio.Tool {
|
||||
str := func(args map[string]any, k string) string { s, _ := args[k].(string); return strings.TrimSpace(s) }
|
||||
return []stdio.Tool{
|
||||
{Name: versions.ReservedTool, Description: versions.ReservedDescription,
|
||||
@@ -25,10 +29,14 @@ func reservedTools(rr versions.Reader, ask queueAsker, now func() time.Time, act
|
||||
Run: func(args map[string]any) (any, error) { return versions.AnswerReserved(rr, str(args, "module")) }},
|
||||
{Name: versions.ReservedVerb, Description: "The seat mesh-builds' verb reserved: a module's reserved version with each artifact's digest once built " +
|
||||
"(design 47 G section 369), for a registry holder deciding whether to publish. Read-only.",
|
||||
Input: map[string]any{"type": "object", "required": []string{"module"}, "properties": map[string]any{
|
||||
"module": map[string]any{"type": "string", "description": "the module"},
|
||||
Input: map[string]any{"type": "object", "properties": map[string]any{
|
||||
"module": map[string]any{"type": "string", "description": "the module; give this or name"},
|
||||
"name": map[string]any{"type": "string", "description": "a package's or an image's name in its ecosystem, in place of module"},
|
||||
"version": map[string]any{"type": "string", "description": "the version, when asked for a particular one"}}},
|
||||
Run: func(args map[string]any) (any, error) {
|
||||
if name := str(args, "name"); name != "" {
|
||||
return versions.AnswerReservedByName(context.Background(), rr, carriers, released, name, str(args, "version"))
|
||||
}
|
||||
return versions.AnswerReservedVerb(rr, str(args, "module"), str(args, "version"))
|
||||
}},
|
||||
{Name: versions.ReservedDropTool, Description: versions.ReservedDropDescription,
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"git.novox.be/novox/mesh-contracts/health-and-repair/go/clients/meshhandactsclient"
|
||||
"git.novox.be/novox/mesh-delivery/contracts/go/seats/meshbuilds"
|
||||
"git.novox.be/novox/mesh-delivery/contracts/go/seats/meshcatalog"
|
||||
|
||||
"mesh-delivery-builder/internal/build"
|
||||
"mesh-delivery-builder/internal/versions"
|
||||
)
|
||||
|
||||
// Design 47 G §572, §582, A-70: the bundle's verb reserved takes a name and answers from the view it follows and the catalog's
|
||||
// versions, and builder_versions, asked by a name, calls reserved and answers what it answers.
|
||||
func TestReservedByNameIsTheBundlesAndBuilderVersionsCallsIt(t *testing.T) {
|
||||
none := versions.Reader{Keys: func() ([]string, error) { return nil, nil }, Get: func(string) (json.RawMessage, bool, error) { return nil, false, nil }}
|
||||
carriers := func(_ context.Context, name string) ([]versions.Built, error) {
|
||||
if name == "@novox/mesh-sdk" {
|
||||
return []versions.Built{{Module: "mesh-sdk", Artifact: "ts"}}, nil
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
released := func(_ context.Context, module string) ([]meshcatalog.VersionEntry, error) {
|
||||
return []meshcatalog.VersionEntry{{Module: module, Version: "0.1.2", Artifacts: []meshcatalog.VersionArtifact{{Artifact: "mesh-sdk:ts", Digest: "sha256:dd"}}}}, nil
|
||||
}
|
||||
acts := meshhandactsclient.Recorder{Ask: func(string, any) (json.RawMessage, error) { return json.RawMessage(`{}`), nil }}
|
||||
byName := map[string]func(map[string]any) (any, error){}
|
||||
for _, tl := range reservedTools(none, nil, time.Now, acts, carriers, released) {
|
||||
byName[tl.Name] = tl.Run
|
||||
}
|
||||
got, err := byName[versions.ReservedVerb](map[string]any{"name": "@novox/mesh-sdk", "version": "0.1.2"})
|
||||
want := meshbuilds.ReservedAnswer{Module: "mesh-sdk", Version: "0.1.2", Released: true, Artifacts: []meshbuilds.ReservedAnswerArtifactsItem{{Artifact: "mesh-sdk:ts", Digest: "sha256:dd"}}}
|
||||
if err != nil || got.(meshbuilds.ReservedAnswer).Released != want.Released || got.(meshbuilds.ReservedAnswer).Artifacts[0] != want.Artifacts[0] {
|
||||
t.Fatalf("reserved by name = %+v (%v), want %+v", got, err, want)
|
||||
}
|
||||
var called []string
|
||||
reserve := func(name, version string) (meshbuilds.ReservedAnswer, error) {
|
||||
called = append(called, name+"@"+version)
|
||||
return want, nil
|
||||
}
|
||||
tools := Tools(build.StuckReader{}, nil, nil, nil, nil, time.Now, none, none, none, reserve)
|
||||
for _, tl := range tools {
|
||||
if tl.Name == versions.VersionsTool {
|
||||
out, err := tl.Run(map[string]any{"name": "@novox/mesh-sdk", "version": "0.1.2"})
|
||||
ans, ok := out.(versions.VersionsAnswer)
|
||||
if err != nil || !ok || ans.Reserved == nil || ans.Reserved.Module != "mesh-sdk" || !ans.Reserved.Released {
|
||||
t.Fatalf("builder_versions by name = %+v (%v), want reserved's answer in it", out, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(called) != 1 || called[0] != "@novox/mesh-sdk@0.1.2" {
|
||||
t.Errorf("reserved was called %v, want once, by the name and version", called)
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,8 @@ package versions
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
@@ -71,22 +73,28 @@ func isSeriesKey(key string) bool {
|
||||
return ok
|
||||
}
|
||||
|
||||
// ModuleOf is the module and artifact a package's name in its ecosystem is built from, as the indexer's packages state holds
|
||||
// them (the inverse of NamesIn; design 47 G §373, §465): the series key whose value names that name.
|
||||
func ModuleOf(s PackagesState) func(ctx context.Context, name string) (module, artifact string, found bool, err error) {
|
||||
return func(ctx context.Context, name string) (string, string, bool, error) {
|
||||
// Built is a module's artifact, which a package's name is the name of.
|
||||
type Built struct{ Module, Artifact string }
|
||||
|
||||
// Carriers are the module artifacts a package's name in its ecosystem is the name of, as the catalog half's packages view
|
||||
// holds them (the inverse of NamesIn; design 47 G §572, §478): each distinct module and artifact of a series key whose value
|
||||
// names that name, sorted. A name no entry carries answers none.
|
||||
func Carriers(s PackagesState) func(ctx context.Context, name string) ([]Built, error) {
|
||||
return func(ctx context.Context, name string) ([]Built, error) {
|
||||
keys, err := s.Keys(ctx)
|
||||
if err != nil {
|
||||
return "", "", false, err
|
||||
return nil, err
|
||||
}
|
||||
sort.Strings(keys)
|
||||
seen := map[Built]bool{}
|
||||
var out []Built
|
||||
for _, key := range keys {
|
||||
if !isSeriesKey(key) {
|
||||
continue
|
||||
}
|
||||
value, found, err := s.Get(ctx, key)
|
||||
if err != nil {
|
||||
return "", "", false, err
|
||||
return nil, err
|
||||
}
|
||||
if !found {
|
||||
continue
|
||||
@@ -95,10 +103,38 @@ func ModuleOf(s PackagesState) func(ctx context.Context, name string) (module, a
|
||||
if err != nil || v.Name != name {
|
||||
continue
|
||||
}
|
||||
if module, artifact, cut := strings.Cut(v.Package, "/"); cut && module != "" && artifact != "" {
|
||||
return module, artifact, true, nil
|
||||
if module, artifact, cut := strings.Cut(v.Package, "/"); cut && module != "" && artifact != "" && !seen[Built{module, artifact}] {
|
||||
seen[Built{module, artifact}] = true
|
||||
out = append(out, Built{module, artifact})
|
||||
}
|
||||
}
|
||||
return "", "", false, nil
|
||||
return out, nil
|
||||
}
|
||||
}
|
||||
|
||||
// ModuleOf is the module and artifact a package's name is built from (Carriers), found false for a name no entry carries; more
|
||||
// than one entry carrying it is an error naming them.
|
||||
func ModuleOf(s PackagesState) func(ctx context.Context, name string) (module, artifact string, found bool, err error) {
|
||||
carriers := Carriers(s)
|
||||
return func(ctx context.Context, name string) (string, string, bool, error) {
|
||||
got, err := carriers(ctx, name)
|
||||
switch {
|
||||
case err != nil:
|
||||
return "", "", false, err
|
||||
case len(got) == 0:
|
||||
return "", "", false, nil
|
||||
case len(got) > 1:
|
||||
return "", "", false, errors.New(MoreThanOne(name, got))
|
||||
}
|
||||
return got[0].Module, got[0].Artifact, true, nil
|
||||
}
|
||||
}
|
||||
|
||||
// MoreThanOne is the words of a name that more than one entry carries.
|
||||
func MoreThanOne(name string, got []Built) string {
|
||||
var refs []string
|
||||
for _, b := range got {
|
||||
refs = append(refs, b.Module+"/"+b.Artifact)
|
||||
}
|
||||
return fmt.Sprintf("the name %s is carried by more than one entry: %s", name, strings.Join(refs, ", "))
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
"time"
|
||||
|
||||
"git.novox.be/novox/mesh-delivery/contracts/go/seats/meshbuilds"
|
||||
"git.novox.be/novox/mesh-delivery/contracts/go/seats/meshcatalog"
|
||||
)
|
||||
|
||||
// **The reservation is one key per module and MAJOR.MINOR** (design 47 G §369, §52): the builder keeps in its old state
|
||||
@@ -436,6 +437,53 @@ func AnswerReservedVerb(r Reader, module, version string) (meshbuilds.ReservedAn
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// CatalogVersions answers a module's released versions, the seat mesh-catalog's verb versions (design 47 G §582).
|
||||
type CatalogVersions func(ctx context.Context, module string) ([]meshcatalog.VersionEntry, error)
|
||||
|
||||
// AnswerReservedByName is the verb reserved given a package's name (design 47 G §572, §582, A-70): the module is found from the
|
||||
// name in the catalog half's view (carriers); that module's reserved version answers as AnswerReservedVerb does. A version
|
||||
// given with no reservation of it (a reservation goes once its version is released) is asked of the catalog, and answers
|
||||
// released with the artifacts and digests the release recorded. A name no entry carries, more than one entry carries, or a
|
||||
// version neither reserved nor released is answered error, naming which, set alone.
|
||||
func AnswerReservedByName(ctx context.Context, r Reader, carriers func(context.Context, string) ([]Built, error), released CatalogVersions, name, version string) (meshbuilds.ReservedAnswer, error) {
|
||||
name, version = strings.TrimSpace(name), strings.TrimSpace(version)
|
||||
got, err := carriers(ctx, name)
|
||||
if err != nil {
|
||||
return meshbuilds.ReservedAnswer{}, fmt.Errorf("the entries of %s cannot be read: %w", name, err)
|
||||
}
|
||||
switch {
|
||||
case len(got) == 0:
|
||||
return meshbuilds.ReservedAnswer{Error: "no entry carries the name " + name}, nil
|
||||
case len(got) > 1:
|
||||
return meshbuilds.ReservedAnswer{Error: MoreThanOne(name, got)}, nil
|
||||
}
|
||||
module := got[0].Module
|
||||
rs := &Reserver{Store: readOnlyReserve{readStore{r}}}
|
||||
if _, found, err := rs.Of(ctx, module, version); err != nil {
|
||||
return meshbuilds.ReservedAnswer{}, err
|
||||
} else if found {
|
||||
return AnswerReservedVerb(r, module, version)
|
||||
}
|
||||
if version != "" {
|
||||
entries, err := released(ctx, module)
|
||||
if err != nil {
|
||||
return meshbuilds.ReservedAnswer{}, fmt.Errorf("the released versions of %s cannot be read: %w", module, err)
|
||||
}
|
||||
for _, e := range entries {
|
||||
if e.Version != version {
|
||||
continue
|
||||
}
|
||||
out := meshbuilds.ReservedAnswer{Module: module, Version: version, Released: true, Artifacts: []meshbuilds.ReservedAnswerArtifactsItem{}}
|
||||
for _, a := range e.Artifacts {
|
||||
out.Artifacts = append(out.Artifacts, meshbuilds.ReservedAnswerArtifactsItem{Artifact: a.Artifact, Digest: a.Digest})
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
return meshbuilds.ReservedAnswer{Error: fmt.Sprintf("%s (%s) has no version %s reserved or released", name, module, version)}, nil
|
||||
}
|
||||
return meshbuilds.ReservedAnswer{Error: fmt.Sprintf("%s (%s) has no reserved version", name, module)}, nil
|
||||
}
|
||||
|
||||
// The descriptions of the reservation's tools.
|
||||
const (
|
||||
ReservedDescription = "The versions the builder reserved (its state reserved, design 47 G section 369): one per module and MAJOR.MINOR, " +
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
package versions
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"git.novox.be/novox/mesh-delivery/contracts/go/seats/meshbuilds"
|
||||
"git.novox.be/novox/mesh-delivery/contracts/go/seats/meshcatalog"
|
||||
)
|
||||
|
||||
// TestReservedByNameAnswersFromTheViewAndTheCatalog: design 47 G §572, §582, A-70 — a package's name (an npm name or a Go
|
||||
// module path) is mapped to its module from the catalog half's view; the reserved version answers as for the module, a version
|
||||
// no reservation holds is asked of the catalog's versions and answers released with the release's digests, and a name no entry
|
||||
// carries, one more than one carries, or a version neither reserved nor released answers error, set alone.
|
||||
func TestReservedByNameAnswersFromTheViewAndTheCatalog(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
view := packagesMem{
|
||||
"git=2enovox=2ebe/novox/mesh-sdk/go.0.1": []byte(`{"v":1,"name":"git.novox.be/novox/mesh-sdk/go","package":"mesh-sdk/go","series":"0.1"}`),
|
||||
"git=2enovox=2ebe/novox/mesh-sdk/go.0.2": []byte(`{"v":1,"name":"git.novox.be/novox/mesh-sdk/go","package":"mesh-sdk/go","series":"0.2"}`),
|
||||
"@novox/mesh-sdk.0.1": []byte(`{"v":1,"name":"@novox/mesh-sdk","package":"mesh-sdk/ts","series":"0.1"}`),
|
||||
"twice.0.1": []byte(`{"v":1,"name":"twice","package":"a/x","series":"0.1"}`),
|
||||
"twice-b.0.1": []byte(`{"v":1,"name":"twice","package":"b/y","series":"0.1"}`),
|
||||
}
|
||||
store := &reserveMem{mem: newMem()}
|
||||
r := &Reserver{Store: store, ReleasedOf: func(context.Context, string) ([]string, error) { return []string{"0.1.3"}, nil }}
|
||||
if _, err := r.Reserve(ctx, "mesh-sdk", "0.1", []string{"mesh-sdk:ts"}, Source{}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
rd := Reader{
|
||||
Keys: func() ([]string, error) { return store.KeysOf(ctx, AllFilter) },
|
||||
Get: func(key string) (json.RawMessage, bool, error) {
|
||||
raw, _, ok, err := store.Get(ctx, key)
|
||||
return raw, ok, err
|
||||
}}
|
||||
var asked []string
|
||||
released := func(_ context.Context, module string) ([]meshcatalog.VersionEntry, error) {
|
||||
asked = append(asked, module)
|
||||
return []meshcatalog.VersionEntry{{Module: module, Version: "0.1.2", Artifacts: []meshcatalog.VersionArtifact{{Artifact: "mesh-sdk:go", Digest: "sha256:dd"}}}}, nil
|
||||
}
|
||||
carriers := Carriers(view)
|
||||
ask := func(name, version string) meshbuilds.ReservedAnswer {
|
||||
t.Helper()
|
||||
got, err := AnswerReservedByName(ctx, rd, carriers, released, name, version)
|
||||
if err != nil {
|
||||
t.Fatalf("%s %s: %v", name, version, err)
|
||||
}
|
||||
return got
|
||||
}
|
||||
if got := ask("@novox/mesh-sdk", ""); got.Module != "mesh-sdk" || got.Version != "0.1.4" || got.Released || got.Error != "" {
|
||||
t.Errorf("an npm name = %+v, want the module's reserved version", got)
|
||||
}
|
||||
if got := ask("git.novox.be/novox/mesh-sdk/go", "0.1.2"); !got.Released || got.Module != "mesh-sdk" || len(got.Artifacts) != 1 || got.Artifacts[0].Digest != "sha256:dd" {
|
||||
t.Errorf("a Go module path = %+v, want the release's artifacts and digests (two series of one entry are one entry)", got)
|
||||
}
|
||||
if len(asked) != 1 || asked[0] != "mesh-sdk" {
|
||||
t.Errorf("the catalog was asked for %v, want the module's versions once, for the version no reservation holds", asked)
|
||||
}
|
||||
for name, c := range map[string]struct{ name, version, want string }{
|
||||
"unknown name": {"nothing", "", "no entry carries"},
|
||||
"two entries": {"twice", "", "more than one entry"},
|
||||
"neither released": {"git.novox.be/novox/mesh-sdk/go", "9.9.9", "reserved or released"},
|
||||
} {
|
||||
if got := ask(c.name, c.version); !strings.Contains(got.Error, c.want) || got.Module != "" || len(got.Artifacts) != 0 {
|
||||
t.Errorf("%s = %+v, want error naming %q alone", name, got, c.want)
|
||||
}
|
||||
}
|
||||
if _, err := AnswerReservedByName(ctx, rd, Carriers(packagesMem(nil)), released, "x", ""); err == nil {
|
||||
t.Error("an unreadable view was answered as if no entry carried the name")
|
||||
}
|
||||
if _, err := AnswerReservedByName(ctx, rd, carriers, func(context.Context, string) ([]meshcatalog.VersionEntry, error) { return nil, errors.New("down") }, "git.novox.be/novox/mesh-sdk/go", "0.1.2"); err == nil {
|
||||
t.Error("an unreadable catalog was answered as if the version were not released")
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,8 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"git.novox.be/novox/mesh-delivery/contracts/go/seats/meshbuilds"
|
||||
)
|
||||
|
||||
// The builder's tools of its versions (design 51 *Events of the builder*, *Tools of the builder*).
|
||||
@@ -64,6 +66,9 @@ type VersionsAnswer struct {
|
||||
Asked string `json:"asked,omitempty"`
|
||||
Recorded *bool `json:"recorded,omitempty"`
|
||||
Why string `json:"why,omitempty"`
|
||||
// Reserved is what the seat mesh-builds' verb reserved answers for the name (and version): the reserved or released version
|
||||
// with each artifact's digest, or its error (design 47 G §572, §582).
|
||||
Reserved *meshbuilds.ReservedAnswer `json:"reserved,omitempty"`
|
||||
}
|
||||
|
||||
// AnswerVersions is builder_versions: a name's versions in order, in one call; with a version (and a digest), whether
|
||||
|
||||
@@ -143,7 +143,7 @@ func TestManifestDeclarations(t *testing.T) { // 1607/AC1
|
||||
if want := []string{"mesh-delivery-assigner.assigner_read_assignments", "mesh-delivery-forge-bridge.bridge_tags", "mesh-delivery-indexer.indexer_read_candidates", "mesh-delivery-indexer.indexer_read_manifests",
|
||||
"mesh-delivery-indexer.indexer_read_modules", "mesh-delivery-indexer.indexer_read_packages", "mesh-delivery-indexer.indexer_requirements", "seat:container-image-registry.remove", "seat:container-image-registry.versions",
|
||||
"seat:git.tag",
|
||||
"seat:go-package-registry.remove", "seat:go-package-registry.versions", "seat:mesh-artifact-sweep.held", "seat:mesh-catalog.versions", "seat:mesh-hand-acts.hand-act", "seat:mesh-watchdogs.presence", "seat:node-build-go.drop", "seat:node-build-image.drop", "seat:node-build-node.drop", "seat:node-engine.manifest-reads", "seat:npm-package-registry.remove",
|
||||
"seat:go-package-registry.remove", "seat:go-package-registry.versions", "seat:mesh-artifact-sweep.held", "seat:mesh-builds.reserved", "seat:mesh-catalog.versions", "seat:mesh-hand-acts.hand-act", "seat:mesh-watchdogs.presence", "seat:node-build-go.drop", "seat:node-build-image.drop", "seat:node-build-node.drop", "seat:node-engine.manifest-reads", "seat:npm-package-registry.remove",
|
||||
"seat:npm-package-registry.versions", "seat:oci-artifact-registry.remove", "seat:oci-artifact-registry.versions"}; !reflect.DeepEqual(sorted(m.Invokes), want) {
|
||||
t.Errorf("invokes = %v, want %v", m.Invokes, want)
|
||||
}
|
||||
|
||||
@@ -82,6 +82,7 @@
|
||||
"seat:go-package-registry.remove",
|
||||
"seat:go-package-registry.versions",
|
||||
"seat:mesh-artifact-sweep.held",
|
||||
"seat:mesh-builds.reserved",
|
||||
"seat:mesh-catalog.versions",
|
||||
"seat:mesh-hand-acts.hand-act",
|
||||
"seat:mesh-watchdogs.presence",
|
||||
|
||||
Reference in New Issue
Block a user