Merge branch 'b2/registry' into b7l/registry
This commit is contained in:
@@ -233,7 +233,7 @@ type Capacity struct {
|
||||
|
||||
// CheckAnswer is a type of the contract.
|
||||
type CheckAnswer struct {
|
||||
Fetch Fetch `json:"fetch"`
|
||||
Fetch FetchAnswer `json:"fetch"`
|
||||
Levels []LevelAnswer `json:"levels,omitempty"`
|
||||
}
|
||||
|
||||
@@ -271,6 +271,30 @@ type Fetch struct {
|
||||
Repository string `json:"repository"`
|
||||
}
|
||||
|
||||
// FetchAnswer is what a build module's fetch tool answers, whole: the workspace it made, the commit in it, the module directories found; and, when the call gave a base, the merge preview (the trunk commit, the merge commit, the files that conflict, the paths the merge changes, the compiled programs among them, the tree of each module directory). A head that does not merge cleanly is an answer, not an error: merge is empty and conflicts names the files. The Go module adds the sibling repositories placed and the package versions taken; the TypeScript module the directories installed and refused and the group's package.
|
||||
type FetchAnswer struct {
|
||||
Base string `json:"base,omitempty"`
|
||||
Beside []PlacedBeside `json:"beside,omitempty"`
|
||||
Changed []string `json:"changed,omitempty"`
|
||||
Commit string `json:"commit"`
|
||||
Conflicts []string `json:"conflicts,omitempty"`
|
||||
Group string `json:"group,omitempty"`
|
||||
Installed []string `json:"installed,omitempty"`
|
||||
Merge string `json:"merge,omitempty"`
|
||||
Modules []string `json:"modules"`
|
||||
Packages []TakenVersion `json:"packages,omitempty"`
|
||||
Programs []Program `json:"programs,omitempty"`
|
||||
Refused []FetchRefusal `json:"refused,omitempty"`
|
||||
Trees map[string]ModuleTree `json:"trees,omitempty"`
|
||||
Workspace string `json:"workspace"`
|
||||
}
|
||||
|
||||
// FetchRefusal is a TypeScript module whose packages the fetch did not install, with why.
|
||||
type FetchRefusal struct {
|
||||
Module string `json:"module"`
|
||||
Reason string `json:"reason"`
|
||||
}
|
||||
|
||||
// LevelAnswerDigestNeedsItem is a type of the contract.
|
||||
type LevelAnswerDigestNeedsItem struct {
|
||||
Needs []string `json:"needs,omitempty"`
|
||||
@@ -316,6 +340,16 @@ type LevelAnswer struct {
|
||||
Unmet []LevelAnswerUnmetItem `json:"unmet,omitempty"`
|
||||
}
|
||||
|
||||
// ModuleTree is the tree of one module directory in a merge preview: its git tree, the digest of its manifest, the lock files' digests and the digests of the named paths.
|
||||
type ModuleTree struct {
|
||||
Locks map[string]string `json:"locks,omitempty"`
|
||||
Manifest string `json:"manifest"`
|
||||
// no longer filled (ADR 0593 section 2); kept so a preview written before still reads
|
||||
Packages []string `json:"packages,omitempty"`
|
||||
Paths map[string]string `json:"paths,omitempty"`
|
||||
Tree string `json:"tree"`
|
||||
}
|
||||
|
||||
// Pause is whether the node takes no new ask.
|
||||
type Pause struct {
|
||||
// when (RFC 3339 time)
|
||||
@@ -326,6 +360,21 @@ type Pause struct {
|
||||
V int64 `json:"v,omitempty"`
|
||||
}
|
||||
|
||||
// PlacedBeside is a sibling repository placed as a plain directory under the workspace's beside directory.
|
||||
type PlacedBeside struct {
|
||||
Commit string `json:"commit"`
|
||||
Dir string `json:"dir"`
|
||||
Repository string `json:"repository"`
|
||||
}
|
||||
|
||||
// Program is a changed file that is a compiled program (issue 1577): its path, its executable format, and the commit of the branch that added it when the merge's tree no longer holds it.
|
||||
type Program struct {
|
||||
Commit string `json:"commit,omitempty"`
|
||||
// ELF, Mach-O or PE
|
||||
Kind string `json:"kind"`
|
||||
Path string `json:"path"`
|
||||
}
|
||||
|
||||
// Step is one step a build module runs on a node.
|
||||
type Step struct {
|
||||
// when (RFC 3339 time)
|
||||
@@ -361,13 +410,17 @@ type StepAskBuild struct {
|
||||
|
||||
// StepAskCheck is a type of the contract.
|
||||
type StepAskCheck struct {
|
||||
Fetch Fetch `json:"fetch"`
|
||||
Kept bool `json:"kept,omitempty"`
|
||||
Levels []string `json:"levels"`
|
||||
Fetch Fetch `json:"fetch"`
|
||||
Kept bool `json:"kept,omitempty"`
|
||||
Levels []string `json:"levels"`
|
||||
// the node names the check's tests run against
|
||||
NodeNames []string `json:"node-names,omitempty"`
|
||||
Packages []string `json:"packages,omitempty"`
|
||||
Run string `json:"run,omitempty"`
|
||||
Runner string `json:"runner,omitempty"`
|
||||
RunnerWhen string `json:"runner_when,omitempty"`
|
||||
// the toolchain the checker agreed for the language (ADR 0584 clause 2): a node on another declines the check
|
||||
Toolchain *ToolchainUsed `json:"toolchain,omitempty"`
|
||||
}
|
||||
|
||||
// StepAskCompose is a type of the contract.
|
||||
@@ -405,10 +458,10 @@ type StepResult struct {
|
||||
Artifacts []BuiltArtifact `json:"artifacts,omitempty"`
|
||||
Built bool `json:"built,omitempty"`
|
||||
// the holder declined the ask: its node lacks what the ask needs
|
||||
Declined bool `json:"declined,omitempty"`
|
||||
Fetch *Fetch `json:"fetch,omitempty"`
|
||||
Imports []string `json:"imports,omitempty"`
|
||||
Key string `json:"key,omitempty"`
|
||||
Declined bool `json:"declined,omitempty"`
|
||||
Fetch *FetchAnswer `json:"fetch,omitempty"`
|
||||
Imports []string `json:"imports,omitempty"`
|
||||
Key string `json:"key,omitempty"`
|
||||
// what the holder's node lacks of it
|
||||
Lacks []string `json:"lacks,omitempty"`
|
||||
Levels []LevelAnswer `json:"levels,omitempty"`
|
||||
@@ -420,6 +473,17 @@ type StepResult struct {
|
||||
Verdict any `json:"verdict,omitempty"`
|
||||
}
|
||||
|
||||
// TakenVersion is of a directory whose go.mod requires an asked mesh package, the version it is built against: the asked one, or go.mod's when it names a newer one, said.
|
||||
type TakenVersion struct {
|
||||
Asked string `json:"asked"`
|
||||
Built string `json:"built"`
|
||||
Dir string `json:"dir"`
|
||||
Named string `json:"named"`
|
||||
Package string `json:"package"`
|
||||
Said string `json:"said,omitempty"`
|
||||
Sum string `json:"sum,omitempty"`
|
||||
}
|
||||
|
||||
// Toolchain is the toolchain a node reports.
|
||||
type Toolchain struct {
|
||||
// when (RFC 3339 time)
|
||||
|
||||
@@ -39,14 +39,16 @@ func TestFixtures(t *testing.T) {
|
||||
}, subjectIs: nil},
|
||||
{name: "a build ask", subject: "mesh.seat.node-build-go.accept.delivery", given: "{\"asker\":\"mesh-delivery-builder\",\"build\":{\"artifacts\":[{\"artifact\":\"go\"}],\"module\":\"nats\"},\"id\":\"a1b2\",\"kind\":\"build\",\"language\":\"go\"}", wire: "{\"asker\":\"mesh-delivery-builder\",\"build\":{\"artifacts\":[{\"artifact\":\"go\"}],\"module\":\"nats\"},\"id\":\"a1b2\",\"kind\":\"build\",\"language\":\"go\"}",
|
||||
decode: func(b []byte) (any, error) { var v DeliveryAccept; err := json.Unmarshal(b, &v); return v, err }, subjectIs: regexp.MustCompile("^mesh\\.seat\\.node-build-go\\.accept\\.delivery$")},
|
||||
{name: "a check ask with its fetch, siblings and levels", subject: "mesh.seat.node-build-go.accept.check", given: "{\"asker\":\"mesh-delivery-checker\",\"at\":\"2026-11-05T10:00:00Z\",\"check\":{\"fetch\":{\"base\":\"89abcdef0123456789abcdef0123456789abcdef\",\"beside\":[{\"commit\":\"fedcba9876543210fedcba9876543210fedcba98\",\"repository\":\"novox/mesh-sdk\"}],\"commit\":\"0123456789abcdef0123456789abcdef01234567\",\"packages\":{\"git.novox.be/novox/mesh-sdk/go\":\"fedcba9876543210fedcba9876543210fedcba98\"},\"ref\":\"refs/pull/7/head\",\"repository\":\"novox/mesh-catalog\"},\"kept\":true,\"levels\":[\"unit\",\"integration\"]},\"id\":\"c3d4\",\"kind\":\"check\",\"language\":\"go\",\"v\":1}", wire: "{\"asker\":\"mesh-delivery-checker\",\"at\":\"2026-11-05T10:00:00Z\",\"check\":{\"fetch\":{\"base\":\"89abcdef0123456789abcdef0123456789abcdef\",\"beside\":[{\"commit\":\"fedcba9876543210fedcba9876543210fedcba98\",\"repository\":\"novox/mesh-sdk\"}],\"commit\":\"0123456789abcdef0123456789abcdef01234567\",\"packages\":{\"git.novox.be/novox/mesh-sdk/go\":\"fedcba9876543210fedcba9876543210fedcba98\"},\"ref\":\"refs/pull/7/head\",\"repository\":\"novox/mesh-catalog\"},\"kept\":true,\"levels\":[\"unit\",\"integration\"]},\"id\":\"c3d4\",\"kind\":\"check\",\"language\":\"go\",\"v\":1}",
|
||||
{name: "a check ask with its fetch, siblings and levels", subject: "mesh.seat.node-build-go.accept.check", given: "{\"asker\":\"mesh-delivery-checker\",\"at\":\"2026-11-05T10:00:00Z\",\"check\":{\"fetch\":{\"base\":\"89abcdef0123456789abcdef0123456789abcdef\",\"beside\":[{\"commit\":\"fedcba9876543210fedcba9876543210fedcba98\",\"repository\":\"novox/mesh-sdk\"}],\"commit\":\"0123456789abcdef0123456789abcdef01234567\",\"packages\":{\"git.novox.be/novox/mesh-sdk/go\":\"fedcba9876543210fedcba9876543210fedcba98\"},\"ref\":\"refs/pull/7/head\",\"repository\":\"novox/mesh-catalog\"},\"kept\":true,\"levels\":[\"unit\",\"integration\"],\"node-names\":[\"ace\",\"g14\"],\"toolchain\":{\"language\":\"go\",\"recipe\":\"2\",\"version\":\"1.26.0\"}},\"id\":\"c3d4\",\"kind\":\"check\",\"language\":\"go\",\"v\":1}", wire: "{\"asker\":\"mesh-delivery-checker\",\"at\":\"2026-11-05T10:00:00Z\",\"check\":{\"fetch\":{\"base\":\"89abcdef0123456789abcdef0123456789abcdef\",\"beside\":[{\"commit\":\"fedcba9876543210fedcba9876543210fedcba98\",\"repository\":\"novox/mesh-sdk\"}],\"commit\":\"0123456789abcdef0123456789abcdef01234567\",\"packages\":{\"git.novox.be/novox/mesh-sdk/go\":\"fedcba9876543210fedcba9876543210fedcba98\"},\"ref\":\"refs/pull/7/head\",\"repository\":\"novox/mesh-catalog\"},\"kept\":true,\"levels\":[\"unit\",\"integration\"],\"node-names\":[\"ace\",\"g14\"],\"toolchain\":{\"language\":\"go\",\"recipe\":\"2\",\"version\":\"1.26.0\"}},\"id\":\"c3d4\",\"kind\":\"check\",\"language\":\"go\",\"v\":1}",
|
||||
decode: func(b []byte) (any, error) { var v CheckAccept; err := json.Unmarshal(b, &v); return v, err }, subjectIs: regexp.MustCompile("^mesh\\.seat\\.node-build-go\\.accept\\.check$")},
|
||||
{name: "a finished build step with its artifacts", subject: "", given: "{\"ended\":\"2026-11-05T10:03:00Z\",\"id\":\"a1b2\",\"node\":\"ace\",\"result\":{\"artifacts\":[{\"artifact\":\"go\",\"digest\":\"sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"reference\":\"container-image-registry/nats/go@sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\"}],\"imports\":[\"git.novox.be/novox/mesh-sdk/go\"],\"toolchain\":{\"language\":\"go\",\"recipe\":\"1\",\"version\":\"1.26.0\"}},\"started\":\"2026-11-05T10:00:00Z\",\"state\":\"passed\",\"tool\":\"build\",\"v\":1}", wire: "{\"ended\":\"2026-11-05T10:03:00Z\",\"id\":\"a1b2\",\"node\":\"ace\",\"result\":{\"artifacts\":[{\"artifact\":\"go\",\"digest\":\"sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"reference\":\"container-image-registry/nats/go@sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\"}],\"imports\":[\"git.novox.be/novox/mesh-sdk/go\"],\"toolchain\":{\"language\":\"go\",\"recipe\":\"1\",\"version\":\"1.26.0\"}},\"started\":\"2026-11-05T10:00:00Z\",\"state\":\"passed\",\"tool\":\"build\",\"v\":1}",
|
||||
decode: func(b []byte) (any, error) { var v StepsByNodeIDValue; err := json.Unmarshal(b, &v); return v, err }, subjectIs: nil},
|
||||
{name: "a finished check step with its levels", subject: "", given: "{\"ended\":\"2026-11-05T10:06:00Z\",\"id\":\"c3d4\",\"node\":\"ace\",\"result\":{\"fetch\":{\"commit\":\"0123456789abcdef0123456789abcdef01234567\",\"repository\":\"novox/mesh-catalog\"},\"levels\":[{\"digest\":{\"level\":\"unit\",\"packages\":[{\"digest\":\"sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\",\"package\":\"./modules/a\"}]},\"kept\":[{\"digest\":\"sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\",\"package\":\"./modules/a\",\"tests\":12}],\"level\":\"unit\",\"tests\":[{\"package\":\"./modules/b\",\"pass\":true}],\"unmet\":[{\"needs\":[\"docker\"],\"package\":\"./modules/c\"}]}]},\"started\":\"2026-11-05T10:00:00Z\",\"state\":\"passed\",\"tool\":\"check\",\"v\":1}", wire: "{\"ended\":\"2026-11-05T10:06:00Z\",\"id\":\"c3d4\",\"node\":\"ace\",\"result\":{\"fetch\":{\"commit\":\"0123456789abcdef0123456789abcdef01234567\",\"repository\":\"novox/mesh-catalog\"},\"levels\":[{\"digest\":{\"level\":\"unit\",\"packages\":[{\"digest\":\"sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\",\"package\":\"./modules/a\"}]},\"kept\":[{\"digest\":\"sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\",\"package\":\"./modules/a\",\"tests\":12}],\"level\":\"unit\",\"tests\":[{\"package\":\"./modules/b\",\"pass\":true}],\"unmet\":[{\"needs\":[\"docker\"],\"package\":\"./modules/c\"}]}]},\"started\":\"2026-11-05T10:00:00Z\",\"state\":\"passed\",\"tool\":\"check\",\"v\":1}",
|
||||
{name: "a finished check step with its levels", subject: "", given: "{\"ended\":\"2026-11-05T10:06:00Z\",\"id\":\"c3d4\",\"node\":\"ace\",\"result\":{\"fetch\":{\"base\":\"abcdef0123456789abcdef0123456789abcdef01\",\"changed\":[\"a.go\",\"modules/m/main.go\"],\"commit\":\"0123456789abcdef0123456789abcdef01234567\",\"merge\":\"fedcba9876543210fedcba9876543210fedcba98\",\"modules\":[\".\"],\"trees\":{\"modules/m\":{\"locks\":{\"go.sum\":\"c5fc83c01e92404452b986527d239140ccf9a48b88e0c268fbf38c2e1429e9c9\"},\"manifest\":\"ca3d163bab055381827226140568f3bef7eaac187cebd76878e0b63e9e442356\",\"tree\":\"1111111111111111111111111111111111111111\"}},\"workspace\":\"mvii1iwu5414e4\"},\"levels\":[{\"digest\":{\"level\":\"unit\",\"packages\":[{\"digest\":\"sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\",\"package\":\"./modules/a\"}]},\"kept\":[{\"digest\":\"sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\",\"package\":\"./modules/a\",\"tests\":12}],\"level\":\"unit\",\"tests\":[{\"package\":\"./modules/b\",\"pass\":true}],\"unmet\":[{\"needs\":[\"docker\"],\"package\":\"./modules/c\"}]}]},\"started\":\"2026-11-05T10:00:00Z\",\"state\":\"passed\",\"tool\":\"check\",\"v\":1}", wire: "{\"ended\":\"2026-11-05T10:06:00Z\",\"id\":\"c3d4\",\"node\":\"ace\",\"result\":{\"fetch\":{\"base\":\"abcdef0123456789abcdef0123456789abcdef01\",\"changed\":[\"a.go\",\"modules/m/main.go\"],\"commit\":\"0123456789abcdef0123456789abcdef01234567\",\"merge\":\"fedcba9876543210fedcba9876543210fedcba98\",\"modules\":[\".\"],\"trees\":{\"modules/m\":{\"locks\":{\"go.sum\":\"c5fc83c01e92404452b986527d239140ccf9a48b88e0c268fbf38c2e1429e9c9\"},\"manifest\":\"ca3d163bab055381827226140568f3bef7eaac187cebd76878e0b63e9e442356\",\"tree\":\"1111111111111111111111111111111111111111\"}},\"workspace\":\"mvii1iwu5414e4\"},\"levels\":[{\"digest\":{\"level\":\"unit\",\"packages\":[{\"digest\":\"sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\",\"package\":\"./modules/a\"}]},\"kept\":[{\"digest\":\"sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\",\"package\":\"./modules/a\",\"tests\":12}],\"level\":\"unit\",\"tests\":[{\"package\":\"./modules/b\",\"pass\":true}],\"unmet\":[{\"needs\":[\"docker\"],\"package\":\"./modules/c\"}]}]},\"started\":\"2026-11-05T10:00:00Z\",\"state\":\"passed\",\"tool\":\"check\",\"v\":1}",
|
||||
decode: func(b []byte) (any, error) { var v StepsByNodeIDValue; err := json.Unmarshal(b, &v); return v, err }, subjectIs: nil},
|
||||
{name: "a declined step", subject: "", given: "{\"id\":\"c3d5\",\"node\":\"ace\",\"result\":{\"declined\":true,\"lacks\":[\"docker\"],\"needs\":[\"docker\"]},\"started\":\"2026-11-05T10:00:00Z\",\"state\":\"refused\",\"tool\":\"check\",\"v\":1}", wire: "{\"id\":\"c3d5\",\"node\":\"ace\",\"result\":{\"declined\":true,\"lacks\":[\"docker\"],\"needs\":[\"docker\"]},\"started\":\"2026-11-05T10:00:00Z\",\"state\":\"refused\",\"tool\":\"check\",\"v\":1}",
|
||||
decode: func(b []byte) (any, error) { var v StepsByNodeIDValue; err := json.Unmarshal(b, &v); return v, err }, subjectIs: nil},
|
||||
{name: "a finished check step whose head does not merge", subject: "", given: "{\"ended\":\"2026-11-05T10:01:00Z\",\"id\":\"c3d5\",\"node\":\"ace\",\"result\":{\"fetch\":{\"base\":\"abcdef0123456789abcdef0123456789abcdef01\",\"commit\":\"0123456789abcdef0123456789abcdef01234567\",\"conflicts\":[\"a.go\",\"sub/b.go\"],\"modules\":[\".\"],\"workspace\":\"mvii1iwz5050eb\"}},\"started\":\"2026-11-05T10:00:00Z\",\"state\":\"passed\",\"tool\":\"check\",\"v\":1}", wire: "{\"ended\":\"2026-11-05T10:01:00Z\",\"id\":\"c3d5\",\"node\":\"ace\",\"result\":{\"fetch\":{\"base\":\"abcdef0123456789abcdef0123456789abcdef01\",\"commit\":\"0123456789abcdef0123456789abcdef01234567\",\"conflicts\":[\"a.go\",\"sub/b.go\"],\"modules\":[\".\"],\"workspace\":\"mvii1iwz5050eb\"}},\"started\":\"2026-11-05T10:00:00Z\",\"state\":\"passed\",\"tool\":\"check\",\"v\":1}",
|
||||
decode: func(b []byte) (any, error) { var v StepsByNodeIDValue; err := json.Unmarshal(b, &v); return v, err }, subjectIs: nil},
|
||||
}
|
||||
for _, c := range cases {
|
||||
v, err := c.decode([]byte(c.given))
|
||||
|
||||
@@ -233,7 +233,7 @@ type Capacity struct {
|
||||
|
||||
// CheckAnswer is a type of the contract.
|
||||
type CheckAnswer struct {
|
||||
Fetch Fetch `json:"fetch"`
|
||||
Fetch FetchAnswer `json:"fetch"`
|
||||
Levels []LevelAnswer `json:"levels,omitempty"`
|
||||
}
|
||||
|
||||
@@ -271,6 +271,30 @@ type Fetch struct {
|
||||
Repository string `json:"repository"`
|
||||
}
|
||||
|
||||
// FetchAnswer is what a build module's fetch tool answers, whole: the workspace it made, the commit in it, the module directories found; and, when the call gave a base, the merge preview (the trunk commit, the merge commit, the files that conflict, the paths the merge changes, the compiled programs among them, the tree of each module directory). A head that does not merge cleanly is an answer, not an error: merge is empty and conflicts names the files. The Go module adds the sibling repositories placed and the package versions taken; the TypeScript module the directories installed and refused and the group's package.
|
||||
type FetchAnswer struct {
|
||||
Base string `json:"base,omitempty"`
|
||||
Beside []PlacedBeside `json:"beside,omitempty"`
|
||||
Changed []string `json:"changed,omitempty"`
|
||||
Commit string `json:"commit"`
|
||||
Conflicts []string `json:"conflicts,omitempty"`
|
||||
Group string `json:"group,omitempty"`
|
||||
Installed []string `json:"installed,omitempty"`
|
||||
Merge string `json:"merge,omitempty"`
|
||||
Modules []string `json:"modules"`
|
||||
Packages []TakenVersion `json:"packages,omitempty"`
|
||||
Programs []Program `json:"programs,omitempty"`
|
||||
Refused []FetchRefusal `json:"refused,omitempty"`
|
||||
Trees map[string]ModuleTree `json:"trees,omitempty"`
|
||||
Workspace string `json:"workspace"`
|
||||
}
|
||||
|
||||
// FetchRefusal is a TypeScript module whose packages the fetch did not install, with why.
|
||||
type FetchRefusal struct {
|
||||
Module string `json:"module"`
|
||||
Reason string `json:"reason"`
|
||||
}
|
||||
|
||||
// LevelAnswerDigestNeedsItem is a type of the contract.
|
||||
type LevelAnswerDigestNeedsItem struct {
|
||||
Needs []string `json:"needs,omitempty"`
|
||||
@@ -316,6 +340,16 @@ type LevelAnswer struct {
|
||||
Unmet []LevelAnswerUnmetItem `json:"unmet,omitempty"`
|
||||
}
|
||||
|
||||
// ModuleTree is the tree of one module directory in a merge preview: its git tree, the digest of its manifest, the lock files' digests and the digests of the named paths.
|
||||
type ModuleTree struct {
|
||||
Locks map[string]string `json:"locks,omitempty"`
|
||||
Manifest string `json:"manifest"`
|
||||
// no longer filled (ADR 0593 section 2); kept so a preview written before still reads
|
||||
Packages []string `json:"packages,omitempty"`
|
||||
Paths map[string]string `json:"paths,omitempty"`
|
||||
Tree string `json:"tree"`
|
||||
}
|
||||
|
||||
// Pause is whether the node takes no new ask.
|
||||
type Pause struct {
|
||||
// when (RFC 3339 time)
|
||||
@@ -326,6 +360,21 @@ type Pause struct {
|
||||
V int64 `json:"v,omitempty"`
|
||||
}
|
||||
|
||||
// PlacedBeside is a sibling repository placed as a plain directory under the workspace's beside directory.
|
||||
type PlacedBeside struct {
|
||||
Commit string `json:"commit"`
|
||||
Dir string `json:"dir"`
|
||||
Repository string `json:"repository"`
|
||||
}
|
||||
|
||||
// Program is a changed file that is a compiled program (issue 1577): its path, its executable format, and the commit of the branch that added it when the merge's tree no longer holds it.
|
||||
type Program struct {
|
||||
Commit string `json:"commit,omitempty"`
|
||||
// ELF, Mach-O or PE
|
||||
Kind string `json:"kind"`
|
||||
Path string `json:"path"`
|
||||
}
|
||||
|
||||
// Step is one step a build module runs on a node.
|
||||
type Step struct {
|
||||
// when (RFC 3339 time)
|
||||
@@ -361,13 +410,17 @@ type StepAskBuild struct {
|
||||
|
||||
// StepAskCheck is a type of the contract.
|
||||
type StepAskCheck struct {
|
||||
Fetch Fetch `json:"fetch"`
|
||||
Kept bool `json:"kept,omitempty"`
|
||||
Levels []string `json:"levels"`
|
||||
Fetch Fetch `json:"fetch"`
|
||||
Kept bool `json:"kept,omitempty"`
|
||||
Levels []string `json:"levels"`
|
||||
// the node names the check's tests run against
|
||||
NodeNames []string `json:"node-names,omitempty"`
|
||||
Packages []string `json:"packages,omitempty"`
|
||||
Run string `json:"run,omitempty"`
|
||||
Runner string `json:"runner,omitempty"`
|
||||
RunnerWhen string `json:"runner_when,omitempty"`
|
||||
// the toolchain the checker agreed for the language (ADR 0584 clause 2): a node on another declines the check
|
||||
Toolchain *ToolchainUsed `json:"toolchain,omitempty"`
|
||||
}
|
||||
|
||||
// StepAskCompose is a type of the contract.
|
||||
@@ -405,10 +458,10 @@ type StepResult struct {
|
||||
Artifacts []BuiltArtifact `json:"artifacts,omitempty"`
|
||||
Built bool `json:"built,omitempty"`
|
||||
// the holder declined the ask: its node lacks what the ask needs
|
||||
Declined bool `json:"declined,omitempty"`
|
||||
Fetch *Fetch `json:"fetch,omitempty"`
|
||||
Imports []string `json:"imports,omitempty"`
|
||||
Key string `json:"key,omitempty"`
|
||||
Declined bool `json:"declined,omitempty"`
|
||||
Fetch *FetchAnswer `json:"fetch,omitempty"`
|
||||
Imports []string `json:"imports,omitempty"`
|
||||
Key string `json:"key,omitempty"`
|
||||
// what the holder's node lacks of it
|
||||
Lacks []string `json:"lacks,omitempty"`
|
||||
Levels []LevelAnswer `json:"levels,omitempty"`
|
||||
@@ -420,6 +473,17 @@ type StepResult struct {
|
||||
Verdict any `json:"verdict,omitempty"`
|
||||
}
|
||||
|
||||
// TakenVersion is of a directory whose go.mod requires an asked mesh package, the version it is built against: the asked one, or go.mod's when it names a newer one, said.
|
||||
type TakenVersion struct {
|
||||
Asked string `json:"asked"`
|
||||
Built string `json:"built"`
|
||||
Dir string `json:"dir"`
|
||||
Named string `json:"named"`
|
||||
Package string `json:"package"`
|
||||
Said string `json:"said,omitempty"`
|
||||
Sum string `json:"sum,omitempty"`
|
||||
}
|
||||
|
||||
// Toolchain is the toolchain a node reports.
|
||||
type Toolchain struct {
|
||||
// when (RFC 3339 time)
|
||||
|
||||
@@ -233,7 +233,7 @@ type Capacity struct {
|
||||
|
||||
// CheckAnswer is a type of the contract.
|
||||
type CheckAnswer struct {
|
||||
Fetch Fetch `json:"fetch"`
|
||||
Fetch FetchAnswer `json:"fetch"`
|
||||
Levels []LevelAnswer `json:"levels,omitempty"`
|
||||
}
|
||||
|
||||
@@ -271,6 +271,30 @@ type Fetch struct {
|
||||
Repository string `json:"repository"`
|
||||
}
|
||||
|
||||
// FetchAnswer is what a build module's fetch tool answers, whole: the workspace it made, the commit in it, the module directories found; and, when the call gave a base, the merge preview (the trunk commit, the merge commit, the files that conflict, the paths the merge changes, the compiled programs among them, the tree of each module directory). A head that does not merge cleanly is an answer, not an error: merge is empty and conflicts names the files. The Go module adds the sibling repositories placed and the package versions taken; the TypeScript module the directories installed and refused and the group's package.
|
||||
type FetchAnswer struct {
|
||||
Base string `json:"base,omitempty"`
|
||||
Beside []PlacedBeside `json:"beside,omitempty"`
|
||||
Changed []string `json:"changed,omitempty"`
|
||||
Commit string `json:"commit"`
|
||||
Conflicts []string `json:"conflicts,omitempty"`
|
||||
Group string `json:"group,omitempty"`
|
||||
Installed []string `json:"installed,omitempty"`
|
||||
Merge string `json:"merge,omitempty"`
|
||||
Modules []string `json:"modules"`
|
||||
Packages []TakenVersion `json:"packages,omitempty"`
|
||||
Programs []Program `json:"programs,omitempty"`
|
||||
Refused []FetchRefusal `json:"refused,omitempty"`
|
||||
Trees map[string]ModuleTree `json:"trees,omitempty"`
|
||||
Workspace string `json:"workspace"`
|
||||
}
|
||||
|
||||
// FetchRefusal is a TypeScript module whose packages the fetch did not install, with why.
|
||||
type FetchRefusal struct {
|
||||
Module string `json:"module"`
|
||||
Reason string `json:"reason"`
|
||||
}
|
||||
|
||||
// LevelAnswerDigestNeedsItem is a type of the contract.
|
||||
type LevelAnswerDigestNeedsItem struct {
|
||||
Needs []string `json:"needs,omitempty"`
|
||||
@@ -316,6 +340,16 @@ type LevelAnswer struct {
|
||||
Unmet []LevelAnswerUnmetItem `json:"unmet,omitempty"`
|
||||
}
|
||||
|
||||
// ModuleTree is the tree of one module directory in a merge preview: its git tree, the digest of its manifest, the lock files' digests and the digests of the named paths.
|
||||
type ModuleTree struct {
|
||||
Locks map[string]string `json:"locks,omitempty"`
|
||||
Manifest string `json:"manifest"`
|
||||
// no longer filled (ADR 0593 section 2); kept so a preview written before still reads
|
||||
Packages []string `json:"packages,omitempty"`
|
||||
Paths map[string]string `json:"paths,omitempty"`
|
||||
Tree string `json:"tree"`
|
||||
}
|
||||
|
||||
// Pause is whether the node takes no new ask.
|
||||
type Pause struct {
|
||||
// when (RFC 3339 time)
|
||||
@@ -326,6 +360,21 @@ type Pause struct {
|
||||
V int64 `json:"v,omitempty"`
|
||||
}
|
||||
|
||||
// PlacedBeside is a sibling repository placed as a plain directory under the workspace's beside directory.
|
||||
type PlacedBeside struct {
|
||||
Commit string `json:"commit"`
|
||||
Dir string `json:"dir"`
|
||||
Repository string `json:"repository"`
|
||||
}
|
||||
|
||||
// Program is a changed file that is a compiled program (issue 1577): its path, its executable format, and the commit of the branch that added it when the merge's tree no longer holds it.
|
||||
type Program struct {
|
||||
Commit string `json:"commit,omitempty"`
|
||||
// ELF, Mach-O or PE
|
||||
Kind string `json:"kind"`
|
||||
Path string `json:"path"`
|
||||
}
|
||||
|
||||
// Step is one step a build module runs on a node.
|
||||
type Step struct {
|
||||
// when (RFC 3339 time)
|
||||
@@ -361,13 +410,17 @@ type StepAskBuild struct {
|
||||
|
||||
// StepAskCheck is a type of the contract.
|
||||
type StepAskCheck struct {
|
||||
Fetch Fetch `json:"fetch"`
|
||||
Kept bool `json:"kept,omitempty"`
|
||||
Levels []string `json:"levels"`
|
||||
Fetch Fetch `json:"fetch"`
|
||||
Kept bool `json:"kept,omitempty"`
|
||||
Levels []string `json:"levels"`
|
||||
// the node names the check's tests run against
|
||||
NodeNames []string `json:"node-names,omitempty"`
|
||||
Packages []string `json:"packages,omitempty"`
|
||||
Run string `json:"run,omitempty"`
|
||||
Runner string `json:"runner,omitempty"`
|
||||
RunnerWhen string `json:"runner_when,omitempty"`
|
||||
// the toolchain the checker agreed for the language (ADR 0584 clause 2): a node on another declines the check
|
||||
Toolchain *ToolchainUsed `json:"toolchain,omitempty"`
|
||||
}
|
||||
|
||||
// StepAskCompose is a type of the contract.
|
||||
@@ -405,10 +458,10 @@ type StepResult struct {
|
||||
Artifacts []BuiltArtifact `json:"artifacts,omitempty"`
|
||||
Built bool `json:"built,omitempty"`
|
||||
// the holder declined the ask: its node lacks what the ask needs
|
||||
Declined bool `json:"declined,omitempty"`
|
||||
Fetch *Fetch `json:"fetch,omitempty"`
|
||||
Imports []string `json:"imports,omitempty"`
|
||||
Key string `json:"key,omitempty"`
|
||||
Declined bool `json:"declined,omitempty"`
|
||||
Fetch *FetchAnswer `json:"fetch,omitempty"`
|
||||
Imports []string `json:"imports,omitempty"`
|
||||
Key string `json:"key,omitempty"`
|
||||
// what the holder's node lacks of it
|
||||
Lacks []string `json:"lacks,omitempty"`
|
||||
Levels []LevelAnswer `json:"levels,omitempty"`
|
||||
@@ -420,6 +473,17 @@ type StepResult struct {
|
||||
Verdict any `json:"verdict,omitempty"`
|
||||
}
|
||||
|
||||
// TakenVersion is of a directory whose go.mod requires an asked mesh package, the version it is built against: the asked one, or go.mod's when it names a newer one, said.
|
||||
type TakenVersion struct {
|
||||
Asked string `json:"asked"`
|
||||
Built string `json:"built"`
|
||||
Dir string `json:"dir"`
|
||||
Named string `json:"named"`
|
||||
Package string `json:"package"`
|
||||
Said string `json:"said,omitempty"`
|
||||
Sum string `json:"sum,omitempty"`
|
||||
}
|
||||
|
||||
// Toolchain is the toolchain a node reports.
|
||||
type Toolchain struct {
|
||||
// when (RFC 3339 time)
|
||||
|
||||
@@ -39,6 +39,8 @@ func TestFixtures(t *testing.T) {
|
||||
}, subjectIs: nil},
|
||||
{name: "a build ask", subject: "mesh.seat.node-build-node.accept.delivery", given: "{\"asker\":\"mesh-delivery-builder\",\"build\":{\"artifacts\":[{\"artifact\":\"go\"}],\"module\":\"nats\"},\"id\":\"a1b2\",\"kind\":\"build\",\"language\":\"go\"}", wire: "{\"asker\":\"mesh-delivery-builder\",\"build\":{\"artifacts\":[{\"artifact\":\"go\"}],\"module\":\"nats\"},\"id\":\"a1b2\",\"kind\":\"build\",\"language\":\"go\"}",
|
||||
decode: func(b []byte) (any, error) { var v DeliveryAccept; err := json.Unmarshal(b, &v); return v, err }, subjectIs: regexp.MustCompile("^mesh\\.seat\\.node-build-node\\.accept\\.delivery$")},
|
||||
{name: "a finished check step of a TypeScript merge preview", subject: "", given: "{\"ended\":\"2026-11-05T10:01:00Z\",\"id\":\"c3d6\",\"node\":\"ace\",\"result\":{\"fetch\":{\"base\":\"abcdef0123456789abcdef0123456789abcdef01\",\"changed\":[\"modules/m/package.json\"],\"commit\":\"0123456789abcdef0123456789abcdef01234567\",\"merge\":\"0123456789abcdef0123456789abcdef01234567\",\"modules\":[\"modules/m\"],\"trees\":{\"modules/m\":{\"manifest\":\"0581b699d9d05517e69b21f5cedbeb2eee8aba2b205280b561be731594d7feef\",\"tree\":\"0123456789abcdef0123456789abcdef01234567\"}},\"workspace\":\"mvii1sxt979f67\"}},\"started\":\"2026-11-05T10:00:00Z\",\"state\":\"passed\",\"tool\":\"check\",\"v\":1}", wire: "{\"ended\":\"2026-11-05T10:01:00Z\",\"id\":\"c3d6\",\"node\":\"ace\",\"result\":{\"fetch\":{\"base\":\"abcdef0123456789abcdef0123456789abcdef01\",\"changed\":[\"modules/m/package.json\"],\"commit\":\"0123456789abcdef0123456789abcdef01234567\",\"merge\":\"0123456789abcdef0123456789abcdef01234567\",\"modules\":[\"modules/m\"],\"trees\":{\"modules/m\":{\"manifest\":\"0581b699d9d05517e69b21f5cedbeb2eee8aba2b205280b561be731594d7feef\",\"tree\":\"0123456789abcdef0123456789abcdef01234567\"}},\"workspace\":\"mvii1sxt979f67\"}},\"started\":\"2026-11-05T10:00:00Z\",\"state\":\"passed\",\"tool\":\"check\",\"v\":1}",
|
||||
decode: func(b []byte) (any, error) { var v StepsByNodeIDValue; err := json.Unmarshal(b, &v); return v, err }, subjectIs: nil},
|
||||
}
|
||||
for _, c := range cases {
|
||||
v, err := c.decode([]byte(c.given))
|
||||
|
||||
@@ -130,6 +130,17 @@
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"toolchain": {
|
||||
"$ref": "#/defs/ToolchainUsed",
|
||||
"description": "the toolchain the checker agreed for the language (ADR 0584 clause 2): a node on another declines the check"
|
||||
},
|
||||
"node-names": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": "the node names the check's tests run against"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
@@ -218,7 +229,7 @@
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"fetch": {
|
||||
"$ref": "#/defs/Fetch"
|
||||
"$ref": "#/defs/FetchAnswer"
|
||||
},
|
||||
"levels": {
|
||||
"type": "array",
|
||||
@@ -680,7 +691,7 @@
|
||||
}
|
||||
},
|
||||
"fetch": {
|
||||
"$ref": "#/defs/Fetch"
|
||||
"$ref": "#/defs/FetchAnswer"
|
||||
},
|
||||
"levels": {
|
||||
"type": "array",
|
||||
@@ -716,6 +727,211 @@
|
||||
"description": "what the holder's node lacks of it"
|
||||
}
|
||||
}
|
||||
},
|
||||
"ModuleTree": {
|
||||
"type": "object",
|
||||
"description": "the tree of one module directory in a merge preview: its git tree, the digest of its manifest, the lock files' digests and the digests of the named paths",
|
||||
"properties": {
|
||||
"tree": {
|
||||
"type": "string"
|
||||
},
|
||||
"manifest": {
|
||||
"type": "string"
|
||||
},
|
||||
"locks": {
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"paths": {
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"packages": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": "no longer filled (ADR 0593 section 2); kept so a preview written before still reads"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"tree",
|
||||
"manifest"
|
||||
]
|
||||
},
|
||||
"Program": {
|
||||
"type": "object",
|
||||
"description": "a changed file that is a compiled program (issue 1577): its path, its executable format, and the commit of the branch that added it when the merge's tree no longer holds it",
|
||||
"properties": {
|
||||
"path": {
|
||||
"type": "string"
|
||||
},
|
||||
"kind": {
|
||||
"type": "string",
|
||||
"description": "ELF, Mach-O or PE"
|
||||
},
|
||||
"commit": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"path",
|
||||
"kind"
|
||||
]
|
||||
},
|
||||
"PlacedBeside": {
|
||||
"type": "object",
|
||||
"description": "a sibling repository placed as a plain directory under the workspace's beside directory",
|
||||
"properties": {
|
||||
"repository": {
|
||||
"type": "string"
|
||||
},
|
||||
"commit": {
|
||||
"type": "string"
|
||||
},
|
||||
"dir": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"repository",
|
||||
"commit",
|
||||
"dir"
|
||||
]
|
||||
},
|
||||
"TakenVersion": {
|
||||
"type": "object",
|
||||
"description": "of a directory whose go.mod requires an asked mesh package, the version it is built against: the asked one, or go.mod's when it names a newer one, said",
|
||||
"properties": {
|
||||
"dir": {
|
||||
"type": "string"
|
||||
},
|
||||
"package": {
|
||||
"type": "string"
|
||||
},
|
||||
"asked": {
|
||||
"type": "string"
|
||||
},
|
||||
"named": {
|
||||
"type": "string"
|
||||
},
|
||||
"built": {
|
||||
"type": "string"
|
||||
},
|
||||
"sum": {
|
||||
"type": "string"
|
||||
},
|
||||
"said": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"dir",
|
||||
"package",
|
||||
"asked",
|
||||
"named",
|
||||
"built"
|
||||
]
|
||||
},
|
||||
"FetchRefusal": {
|
||||
"type": "object",
|
||||
"description": "a TypeScript module whose packages the fetch did not install, with why",
|
||||
"properties": {
|
||||
"module": {
|
||||
"type": "string"
|
||||
},
|
||||
"reason": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"module",
|
||||
"reason"
|
||||
]
|
||||
},
|
||||
"FetchAnswer": {
|
||||
"type": "object",
|
||||
"description": "what a build module's fetch tool answers, whole: the workspace it made, the commit in it, the module directories found; and, when the call gave a base, the merge preview (the trunk commit, the merge commit, the files that conflict, the paths the merge changes, the compiled programs among them, the tree of each module directory). A head that does not merge cleanly is an answer, not an error: merge is empty and conflicts names the files. The Go module adds the sibling repositories placed and the package versions taken; the TypeScript module the directories installed and refused and the group's package",
|
||||
"properties": {
|
||||
"workspace": {
|
||||
"type": "string"
|
||||
},
|
||||
"commit": {
|
||||
"type": "string"
|
||||
},
|
||||
"modules": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"base": {
|
||||
"type": "string"
|
||||
},
|
||||
"merge": {
|
||||
"type": "string"
|
||||
},
|
||||
"conflicts": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"changed": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"programs": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/defs/Program"
|
||||
}
|
||||
},
|
||||
"trees": {
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"$ref": "#/defs/ModuleTree"
|
||||
}
|
||||
},
|
||||
"beside": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/defs/PlacedBeside"
|
||||
}
|
||||
},
|
||||
"packages": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/defs/TakenVersion"
|
||||
}
|
||||
},
|
||||
"installed": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"refused": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/defs/FetchRefusal"
|
||||
}
|
||||
},
|
||||
"group": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"workspace",
|
||||
"commit",
|
||||
"modules"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -91,7 +91,16 @@
|
||||
"unit",
|
||||
"integration"
|
||||
],
|
||||
"kept": true
|
||||
"kept": true,
|
||||
"toolchain": {
|
||||
"language": "go",
|
||||
"version": "1.26.0",
|
||||
"recipe": "2"
|
||||
},
|
||||
"node-names": [
|
||||
"ace",
|
||||
"g14"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -138,8 +147,26 @@
|
||||
"ended": "2026-11-05T10:06:00Z",
|
||||
"result": {
|
||||
"fetch": {
|
||||
"repository": "novox/mesh-catalog",
|
||||
"commit": "0123456789abcdef0123456789abcdef01234567"
|
||||
"workspace": "mvii1iwu5414e4",
|
||||
"commit": "0123456789abcdef0123456789abcdef01234567",
|
||||
"modules": [
|
||||
"."
|
||||
],
|
||||
"base": "abcdef0123456789abcdef0123456789abcdef01",
|
||||
"merge": "fedcba9876543210fedcba9876543210fedcba98",
|
||||
"changed": [
|
||||
"a.go",
|
||||
"modules/m/main.go"
|
||||
],
|
||||
"trees": {
|
||||
"modules/m": {
|
||||
"tree": "1111111111111111111111111111111111111111",
|
||||
"manifest": "ca3d163bab055381827226140568f3bef7eaac187cebd76878e0b63e9e442356",
|
||||
"locks": {
|
||||
"go.sum": "c5fc83c01e92404452b986527d239140ccf9a48b88e0c268fbf38c2e1429e9c9"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"levels": [
|
||||
{
|
||||
@@ -199,5 +226,32 @@
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "a finished check step whose head does not merge",
|
||||
"of": "state:steps/<node>.<id>",
|
||||
"given": {
|
||||
"v": 1,
|
||||
"id": "c3d5",
|
||||
"tool": "check",
|
||||
"node": "ace",
|
||||
"state": "passed",
|
||||
"started": "2026-11-05T10:00:00Z",
|
||||
"ended": "2026-11-05T10:01:00Z",
|
||||
"result": {
|
||||
"fetch": {
|
||||
"workspace": "mvii1iwz5050eb",
|
||||
"commit": "0123456789abcdef0123456789abcdef01234567",
|
||||
"modules": [
|
||||
"."
|
||||
],
|
||||
"base": "abcdef0123456789abcdef0123456789abcdef01",
|
||||
"conflicts": [
|
||||
"a.go",
|
||||
"sub/b.go"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
@@ -59,5 +59,38 @@
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "a finished check step of a TypeScript merge preview",
|
||||
"of": "state:steps/<node>.<id>",
|
||||
"given": {
|
||||
"v": 1,
|
||||
"id": "c3d6",
|
||||
"tool": "check",
|
||||
"node": "ace",
|
||||
"state": "passed",
|
||||
"started": "2026-11-05T10:00:00Z",
|
||||
"ended": "2026-11-05T10:01:00Z",
|
||||
"result": {
|
||||
"fetch": {
|
||||
"workspace": "mvii1sxt979f67",
|
||||
"commit": "0123456789abcdef0123456789abcdef01234567",
|
||||
"modules": [
|
||||
"modules/m"
|
||||
],
|
||||
"base": "abcdef0123456789abcdef0123456789abcdef01",
|
||||
"merge": "0123456789abcdef0123456789abcdef01234567",
|
||||
"changed": [
|
||||
"modules/m/package.json"
|
||||
],
|
||||
"trees": {
|
||||
"modules/m": {
|
||||
"tree": "0123456789abcdef0123456789abcdef01234567",
|
||||
"manifest": "0581b699d9d05517e69b21f5cedbeb2eee8aba2b205280b561be731594d7feef"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
@@ -111,16 +111,21 @@ export type ComposeAnswer = buildStep.ComposeAnswer;
|
||||
export type CurrentAnswer = buildStep.CurrentAnswer;
|
||||
export type CurrentInput = buildStep.CurrentInput;
|
||||
export type Fetch = buildStep.Fetch;
|
||||
export type FetchAnswer = buildStep.FetchAnswer;
|
||||
export type FetchBesideItem = buildStep.FetchBesideItem;
|
||||
export type FetchRefusal = buildStep.FetchRefusal;
|
||||
export type LevelAnswer = buildStep.LevelAnswer;
|
||||
export type LevelAnswerDigest = buildStep.LevelAnswerDigest;
|
||||
export type LevelAnswerDigestNeedsItem = buildStep.LevelAnswerDigestNeedsItem;
|
||||
export type LevelAnswerDigestPackagesItem = buildStep.LevelAnswerDigestPackagesItem;
|
||||
export type LevelAnswerKeptItem = buildStep.LevelAnswerKeptItem;
|
||||
export type LevelAnswerUnmetItem = buildStep.LevelAnswerUnmetItem;
|
||||
export type ModuleTree = buildStep.ModuleTree;
|
||||
export type Pause = buildStep.Pause;
|
||||
export type PauseAnswer = buildStep.PauseAnswer;
|
||||
export type PauseInput = buildStep.PauseInput;
|
||||
export type PlacedBeside = buildStep.PlacedBeside;
|
||||
export type Program = buildStep.Program;
|
||||
export type ResumeAnswer = buildStep.ResumeAnswer;
|
||||
export type ResumeInput = buildStep.ResumeInput;
|
||||
export type Step = buildStep.Step;
|
||||
@@ -129,6 +134,7 @@ export type StepAskBuild = buildStep.StepAskBuild;
|
||||
export type StepAskCheck = buildStep.StepAskCheck;
|
||||
export type StepAskCompose = buildStep.StepAskCompose;
|
||||
export type StepResult = buildStep.StepResult;
|
||||
export type TakenVersion = buildStep.TakenVersion;
|
||||
export type Toolchain = buildStep.Toolchain;
|
||||
export type ToolchainUsed = buildStep.ToolchainUsed;
|
||||
|
||||
|
||||
@@ -51,7 +51,7 @@ export interface Capacity {
|
||||
}
|
||||
|
||||
export interface CheckAnswer {
|
||||
"fetch": Fetch;
|
||||
"fetch": FetchAnswer;
|
||||
"levels"?: LevelAnswer[];
|
||||
}
|
||||
|
||||
@@ -87,6 +87,30 @@ export interface Fetch {
|
||||
"repository": string;
|
||||
}
|
||||
|
||||
/** what a build module's fetch tool answers, whole: the workspace it made, the commit in it, the module directories found; and, when the call gave a base, the merge preview (the trunk commit, the merge commit, the files that conflict, the paths the merge changes, the compiled programs among them, the tree of each module directory). A head that does not merge cleanly is an answer, not an error: merge is empty and conflicts names the files. The Go module adds the sibling repositories placed and the package versions taken; the TypeScript module the directories installed and refused and the group's package */
|
||||
export interface FetchAnswer {
|
||||
"base"?: string;
|
||||
"beside"?: PlacedBeside[];
|
||||
"changed"?: string[];
|
||||
"commit": string;
|
||||
"conflicts"?: string[];
|
||||
"group"?: string;
|
||||
"installed"?: string[];
|
||||
"merge"?: string;
|
||||
"modules": string[];
|
||||
"packages"?: TakenVersion[];
|
||||
"programs"?: Program[];
|
||||
"refused"?: FetchRefusal[];
|
||||
"trees"?: Record<string, ModuleTree>;
|
||||
"workspace": string;
|
||||
}
|
||||
|
||||
/** a TypeScript module whose packages the fetch did not install, with why */
|
||||
export interface FetchRefusal {
|
||||
"module": string;
|
||||
"reason": string;
|
||||
}
|
||||
|
||||
export interface LevelAnswerDigestNeedsItem {
|
||||
"needs"?: string[];
|
||||
"package"?: string;
|
||||
@@ -127,6 +151,16 @@ export interface LevelAnswer {
|
||||
"unmet"?: LevelAnswerUnmetItem[];
|
||||
}
|
||||
|
||||
/** the tree of one module directory in a merge preview: its git tree, the digest of its manifest, the lock files' digests and the digests of the named paths */
|
||||
export interface ModuleTree {
|
||||
"locks"?: Record<string, string>;
|
||||
"manifest": string;
|
||||
/** no longer filled (ADR 0593 section 2); kept so a preview written before still reads */
|
||||
"packages"?: string[];
|
||||
"paths"?: Record<string, string>;
|
||||
"tree": string;
|
||||
}
|
||||
|
||||
/** whether the node takes no new ask */
|
||||
export interface Pause {
|
||||
/** when (RFC 3339 time) */
|
||||
@@ -137,6 +171,21 @@ export interface Pause {
|
||||
"v"?: number;
|
||||
}
|
||||
|
||||
/** a sibling repository placed as a plain directory under the workspace's beside directory */
|
||||
export interface PlacedBeside {
|
||||
"commit": string;
|
||||
"dir": string;
|
||||
"repository": string;
|
||||
}
|
||||
|
||||
/** a changed file that is a compiled program (issue 1577): its path, its executable format, and the commit of the branch that added it when the merge's tree no longer holds it */
|
||||
export interface Program {
|
||||
"commit"?: string;
|
||||
/** ELF, Mach-O or PE */
|
||||
"kind": string;
|
||||
"path": string;
|
||||
}
|
||||
|
||||
/** one step a build module runs on a node */
|
||||
export interface Step {
|
||||
/** when (RFC 3339 time) */
|
||||
@@ -173,10 +222,14 @@ export interface StepAskCheck {
|
||||
"fetch": Fetch;
|
||||
"kept"?: boolean;
|
||||
"levels": string[];
|
||||
/** the node names the check's tests run against */
|
||||
"node-names"?: string[];
|
||||
"packages"?: string[];
|
||||
"run"?: string;
|
||||
"runner"?: string;
|
||||
"runner_when"?: string;
|
||||
/** the toolchain the checker agreed for the language (ADR 0584 clause 2): a node on another declines the check */
|
||||
"toolchain"?: ToolchainUsed;
|
||||
}
|
||||
|
||||
export interface StepAskCompose {
|
||||
@@ -214,7 +267,7 @@ export interface StepResult {
|
||||
"built"?: boolean;
|
||||
/** the holder declined the ask: its node lacks what the ask needs */
|
||||
"declined"?: boolean;
|
||||
"fetch"?: Fetch;
|
||||
"fetch"?: FetchAnswer;
|
||||
"imports"?: string[];
|
||||
"key"?: string;
|
||||
/** what the holder's node lacks of it */
|
||||
@@ -228,6 +281,17 @@ export interface StepResult {
|
||||
"verdict"?: unknown;
|
||||
}
|
||||
|
||||
/** of a directory whose go.mod requires an asked mesh package, the version it is built against: the asked one, or go.mod's when it names a newer one, said */
|
||||
export interface TakenVersion {
|
||||
"asked": string;
|
||||
"built": string;
|
||||
"dir": string;
|
||||
"named": string;
|
||||
"package": string;
|
||||
"said"?: string;
|
||||
"sum"?: string;
|
||||
}
|
||||
|
||||
/** the toolchain a node reports */
|
||||
export interface Toolchain {
|
||||
/** when (RFC 3339 time) */
|
||||
|
||||
@@ -111,16 +111,21 @@ export type ComposeAnswer = buildStep.ComposeAnswer;
|
||||
export type CurrentAnswer = buildStep.CurrentAnswer;
|
||||
export type CurrentInput = buildStep.CurrentInput;
|
||||
export type Fetch = buildStep.Fetch;
|
||||
export type FetchAnswer = buildStep.FetchAnswer;
|
||||
export type FetchBesideItem = buildStep.FetchBesideItem;
|
||||
export type FetchRefusal = buildStep.FetchRefusal;
|
||||
export type LevelAnswer = buildStep.LevelAnswer;
|
||||
export type LevelAnswerDigest = buildStep.LevelAnswerDigest;
|
||||
export type LevelAnswerDigestNeedsItem = buildStep.LevelAnswerDigestNeedsItem;
|
||||
export type LevelAnswerDigestPackagesItem = buildStep.LevelAnswerDigestPackagesItem;
|
||||
export type LevelAnswerKeptItem = buildStep.LevelAnswerKeptItem;
|
||||
export type LevelAnswerUnmetItem = buildStep.LevelAnswerUnmetItem;
|
||||
export type ModuleTree = buildStep.ModuleTree;
|
||||
export type Pause = buildStep.Pause;
|
||||
export type PauseAnswer = buildStep.PauseAnswer;
|
||||
export type PauseInput = buildStep.PauseInput;
|
||||
export type PlacedBeside = buildStep.PlacedBeside;
|
||||
export type Program = buildStep.Program;
|
||||
export type ResumeAnswer = buildStep.ResumeAnswer;
|
||||
export type ResumeInput = buildStep.ResumeInput;
|
||||
export type Step = buildStep.Step;
|
||||
@@ -129,6 +134,7 @@ export type StepAskBuild = buildStep.StepAskBuild;
|
||||
export type StepAskCheck = buildStep.StepAskCheck;
|
||||
export type StepAskCompose = buildStep.StepAskCompose;
|
||||
export type StepResult = buildStep.StepResult;
|
||||
export type TakenVersion = buildStep.TakenVersion;
|
||||
export type Toolchain = buildStep.Toolchain;
|
||||
export type ToolchainUsed = buildStep.ToolchainUsed;
|
||||
|
||||
|
||||
@@ -51,7 +51,7 @@ export interface Capacity {
|
||||
}
|
||||
|
||||
export interface CheckAnswer {
|
||||
"fetch": Fetch;
|
||||
"fetch": FetchAnswer;
|
||||
"levels"?: LevelAnswer[];
|
||||
}
|
||||
|
||||
@@ -87,6 +87,30 @@ export interface Fetch {
|
||||
"repository": string;
|
||||
}
|
||||
|
||||
/** what a build module's fetch tool answers, whole: the workspace it made, the commit in it, the module directories found; and, when the call gave a base, the merge preview (the trunk commit, the merge commit, the files that conflict, the paths the merge changes, the compiled programs among them, the tree of each module directory). A head that does not merge cleanly is an answer, not an error: merge is empty and conflicts names the files. The Go module adds the sibling repositories placed and the package versions taken; the TypeScript module the directories installed and refused and the group's package */
|
||||
export interface FetchAnswer {
|
||||
"base"?: string;
|
||||
"beside"?: PlacedBeside[];
|
||||
"changed"?: string[];
|
||||
"commit": string;
|
||||
"conflicts"?: string[];
|
||||
"group"?: string;
|
||||
"installed"?: string[];
|
||||
"merge"?: string;
|
||||
"modules": string[];
|
||||
"packages"?: TakenVersion[];
|
||||
"programs"?: Program[];
|
||||
"refused"?: FetchRefusal[];
|
||||
"trees"?: Record<string, ModuleTree>;
|
||||
"workspace": string;
|
||||
}
|
||||
|
||||
/** a TypeScript module whose packages the fetch did not install, with why */
|
||||
export interface FetchRefusal {
|
||||
"module": string;
|
||||
"reason": string;
|
||||
}
|
||||
|
||||
export interface LevelAnswerDigestNeedsItem {
|
||||
"needs"?: string[];
|
||||
"package"?: string;
|
||||
@@ -127,6 +151,16 @@ export interface LevelAnswer {
|
||||
"unmet"?: LevelAnswerUnmetItem[];
|
||||
}
|
||||
|
||||
/** the tree of one module directory in a merge preview: its git tree, the digest of its manifest, the lock files' digests and the digests of the named paths */
|
||||
export interface ModuleTree {
|
||||
"locks"?: Record<string, string>;
|
||||
"manifest": string;
|
||||
/** no longer filled (ADR 0593 section 2); kept so a preview written before still reads */
|
||||
"packages"?: string[];
|
||||
"paths"?: Record<string, string>;
|
||||
"tree": string;
|
||||
}
|
||||
|
||||
/** whether the node takes no new ask */
|
||||
export interface Pause {
|
||||
/** when (RFC 3339 time) */
|
||||
@@ -137,6 +171,21 @@ export interface Pause {
|
||||
"v"?: number;
|
||||
}
|
||||
|
||||
/** a sibling repository placed as a plain directory under the workspace's beside directory */
|
||||
export interface PlacedBeside {
|
||||
"commit": string;
|
||||
"dir": string;
|
||||
"repository": string;
|
||||
}
|
||||
|
||||
/** a changed file that is a compiled program (issue 1577): its path, its executable format, and the commit of the branch that added it when the merge's tree no longer holds it */
|
||||
export interface Program {
|
||||
"commit"?: string;
|
||||
/** ELF, Mach-O or PE */
|
||||
"kind": string;
|
||||
"path": string;
|
||||
}
|
||||
|
||||
/** one step a build module runs on a node */
|
||||
export interface Step {
|
||||
/** when (RFC 3339 time) */
|
||||
@@ -173,10 +222,14 @@ export interface StepAskCheck {
|
||||
"fetch": Fetch;
|
||||
"kept"?: boolean;
|
||||
"levels": string[];
|
||||
/** the node names the check's tests run against */
|
||||
"node-names"?: string[];
|
||||
"packages"?: string[];
|
||||
"run"?: string;
|
||||
"runner"?: string;
|
||||
"runner_when"?: string;
|
||||
/** the toolchain the checker agreed for the language (ADR 0584 clause 2): a node on another declines the check */
|
||||
"toolchain"?: ToolchainUsed;
|
||||
}
|
||||
|
||||
export interface StepAskCompose {
|
||||
@@ -214,7 +267,7 @@ export interface StepResult {
|
||||
"built"?: boolean;
|
||||
/** the holder declined the ask: its node lacks what the ask needs */
|
||||
"declined"?: boolean;
|
||||
"fetch"?: Fetch;
|
||||
"fetch"?: FetchAnswer;
|
||||
"imports"?: string[];
|
||||
"key"?: string;
|
||||
/** what the holder's node lacks of it */
|
||||
@@ -228,6 +281,17 @@ export interface StepResult {
|
||||
"verdict"?: unknown;
|
||||
}
|
||||
|
||||
/** of a directory whose go.mod requires an asked mesh package, the version it is built against: the asked one, or go.mod's when it names a newer one, said */
|
||||
export interface TakenVersion {
|
||||
"asked": string;
|
||||
"built": string;
|
||||
"dir": string;
|
||||
"named": string;
|
||||
"package": string;
|
||||
"said"?: string;
|
||||
"sum"?: string;
|
||||
}
|
||||
|
||||
/** the toolchain a node reports */
|
||||
export interface Toolchain {
|
||||
/** when (RFC 3339 time) */
|
||||
|
||||
@@ -111,16 +111,21 @@ export type ComposeAnswer = buildStep.ComposeAnswer;
|
||||
export type CurrentAnswer = buildStep.CurrentAnswer;
|
||||
export type CurrentInput = buildStep.CurrentInput;
|
||||
export type Fetch = buildStep.Fetch;
|
||||
export type FetchAnswer = buildStep.FetchAnswer;
|
||||
export type FetchBesideItem = buildStep.FetchBesideItem;
|
||||
export type FetchRefusal = buildStep.FetchRefusal;
|
||||
export type LevelAnswer = buildStep.LevelAnswer;
|
||||
export type LevelAnswerDigest = buildStep.LevelAnswerDigest;
|
||||
export type LevelAnswerDigestNeedsItem = buildStep.LevelAnswerDigestNeedsItem;
|
||||
export type LevelAnswerDigestPackagesItem = buildStep.LevelAnswerDigestPackagesItem;
|
||||
export type LevelAnswerKeptItem = buildStep.LevelAnswerKeptItem;
|
||||
export type LevelAnswerUnmetItem = buildStep.LevelAnswerUnmetItem;
|
||||
export type ModuleTree = buildStep.ModuleTree;
|
||||
export type Pause = buildStep.Pause;
|
||||
export type PauseAnswer = buildStep.PauseAnswer;
|
||||
export type PauseInput = buildStep.PauseInput;
|
||||
export type PlacedBeside = buildStep.PlacedBeside;
|
||||
export type Program = buildStep.Program;
|
||||
export type ResumeAnswer = buildStep.ResumeAnswer;
|
||||
export type ResumeInput = buildStep.ResumeInput;
|
||||
export type Step = buildStep.Step;
|
||||
@@ -129,6 +134,7 @@ export type StepAskBuild = buildStep.StepAskBuild;
|
||||
export type StepAskCheck = buildStep.StepAskCheck;
|
||||
export type StepAskCompose = buildStep.StepAskCompose;
|
||||
export type StepResult = buildStep.StepResult;
|
||||
export type TakenVersion = buildStep.TakenVersion;
|
||||
export type Toolchain = buildStep.Toolchain;
|
||||
export type ToolchainUsed = buildStep.ToolchainUsed;
|
||||
|
||||
|
||||
@@ -51,7 +51,7 @@ export interface Capacity {
|
||||
}
|
||||
|
||||
export interface CheckAnswer {
|
||||
"fetch": Fetch;
|
||||
"fetch": FetchAnswer;
|
||||
"levels"?: LevelAnswer[];
|
||||
}
|
||||
|
||||
@@ -87,6 +87,30 @@ export interface Fetch {
|
||||
"repository": string;
|
||||
}
|
||||
|
||||
/** what a build module's fetch tool answers, whole: the workspace it made, the commit in it, the module directories found; and, when the call gave a base, the merge preview (the trunk commit, the merge commit, the files that conflict, the paths the merge changes, the compiled programs among them, the tree of each module directory). A head that does not merge cleanly is an answer, not an error: merge is empty and conflicts names the files. The Go module adds the sibling repositories placed and the package versions taken; the TypeScript module the directories installed and refused and the group's package */
|
||||
export interface FetchAnswer {
|
||||
"base"?: string;
|
||||
"beside"?: PlacedBeside[];
|
||||
"changed"?: string[];
|
||||
"commit": string;
|
||||
"conflicts"?: string[];
|
||||
"group"?: string;
|
||||
"installed"?: string[];
|
||||
"merge"?: string;
|
||||
"modules": string[];
|
||||
"packages"?: TakenVersion[];
|
||||
"programs"?: Program[];
|
||||
"refused"?: FetchRefusal[];
|
||||
"trees"?: Record<string, ModuleTree>;
|
||||
"workspace": string;
|
||||
}
|
||||
|
||||
/** a TypeScript module whose packages the fetch did not install, with why */
|
||||
export interface FetchRefusal {
|
||||
"module": string;
|
||||
"reason": string;
|
||||
}
|
||||
|
||||
export interface LevelAnswerDigestNeedsItem {
|
||||
"needs"?: string[];
|
||||
"package"?: string;
|
||||
@@ -127,6 +151,16 @@ export interface LevelAnswer {
|
||||
"unmet"?: LevelAnswerUnmetItem[];
|
||||
}
|
||||
|
||||
/** the tree of one module directory in a merge preview: its git tree, the digest of its manifest, the lock files' digests and the digests of the named paths */
|
||||
export interface ModuleTree {
|
||||
"locks"?: Record<string, string>;
|
||||
"manifest": string;
|
||||
/** no longer filled (ADR 0593 section 2); kept so a preview written before still reads */
|
||||
"packages"?: string[];
|
||||
"paths"?: Record<string, string>;
|
||||
"tree": string;
|
||||
}
|
||||
|
||||
/** whether the node takes no new ask */
|
||||
export interface Pause {
|
||||
/** when (RFC 3339 time) */
|
||||
@@ -137,6 +171,21 @@ export interface Pause {
|
||||
"v"?: number;
|
||||
}
|
||||
|
||||
/** a sibling repository placed as a plain directory under the workspace's beside directory */
|
||||
export interface PlacedBeside {
|
||||
"commit": string;
|
||||
"dir": string;
|
||||
"repository": string;
|
||||
}
|
||||
|
||||
/** a changed file that is a compiled program (issue 1577): its path, its executable format, and the commit of the branch that added it when the merge's tree no longer holds it */
|
||||
export interface Program {
|
||||
"commit"?: string;
|
||||
/** ELF, Mach-O or PE */
|
||||
"kind": string;
|
||||
"path": string;
|
||||
}
|
||||
|
||||
/** one step a build module runs on a node */
|
||||
export interface Step {
|
||||
/** when (RFC 3339 time) */
|
||||
@@ -173,10 +222,14 @@ export interface StepAskCheck {
|
||||
"fetch": Fetch;
|
||||
"kept"?: boolean;
|
||||
"levels": string[];
|
||||
/** the node names the check's tests run against */
|
||||
"node-names"?: string[];
|
||||
"packages"?: string[];
|
||||
"run"?: string;
|
||||
"runner"?: string;
|
||||
"runner_when"?: string;
|
||||
/** the toolchain the checker agreed for the language (ADR 0584 clause 2): a node on another declines the check */
|
||||
"toolchain"?: ToolchainUsed;
|
||||
}
|
||||
|
||||
export interface StepAskCompose {
|
||||
@@ -214,7 +267,7 @@ export interface StepResult {
|
||||
"built"?: boolean;
|
||||
/** the holder declined the ask: its node lacks what the ask needs */
|
||||
"declined"?: boolean;
|
||||
"fetch"?: Fetch;
|
||||
"fetch"?: FetchAnswer;
|
||||
"imports"?: string[];
|
||||
"key"?: string;
|
||||
/** what the holder's node lacks of it */
|
||||
@@ -228,6 +281,17 @@ export interface StepResult {
|
||||
"verdict"?: unknown;
|
||||
}
|
||||
|
||||
/** of a directory whose go.mod requires an asked mesh package, the version it is built against: the asked one, or go.mod's when it names a newer one, said */
|
||||
export interface TakenVersion {
|
||||
"asked": string;
|
||||
"built": string;
|
||||
"dir": string;
|
||||
"named": string;
|
||||
"package": string;
|
||||
"said"?: string;
|
||||
"sum"?: string;
|
||||
}
|
||||
|
||||
/** the toolchain a node reports */
|
||||
export interface Toolchain {
|
||||
/** when (RFC 3339 time) */
|
||||
|
||||
+78
-1
@@ -258,6 +258,9 @@ type CheckJob struct {
|
||||
Run string `json:"run,omitempty"`
|
||||
Packages []string `json:"packages,omitempty"`
|
||||
NodeNames []string `json:"node-names,omitempty"`
|
||||
// Toolchain is the toolchain the checker agreed for the language (ADR 0584 clause 2): a holder whose node reports
|
||||
// another version declines the check.
|
||||
Toolchain *ToolchainUsed `json:"toolchain,omitempty"`
|
||||
}
|
||||
|
||||
// ComposeJob asks one compose-candidate build.
|
||||
@@ -409,6 +412,9 @@ func (c CheckJob) check(id string) error {
|
||||
return fmt.Errorf("buildstep: the check ask %s names a package %q that is no import path", id, p)
|
||||
}
|
||||
}
|
||||
if t := c.Toolchain; t != nil && (t.Language == "" || t.Version == "" || t.Recipe == "") {
|
||||
return fmt.Errorf("buildstep: the check ask %s names a toolchain without its language, version and recipe", id)
|
||||
}
|
||||
seen := map[string]bool{}
|
||||
for _, n := range c.NodeNames {
|
||||
if err := meshkeys.CheckName("node", n); err != nil || strings.Contains(n, ",") || seen[n] {
|
||||
@@ -520,10 +526,81 @@ type AskBuilt struct {
|
||||
|
||||
// CheckAnswer is what a check ask's step answers.
|
||||
type CheckAnswer struct {
|
||||
Fetch Fetch `json:"fetch"`
|
||||
Fetch FetchAnswer `json:"fetch"`
|
||||
Levels []LevelAnswer `json:"levels,omitempty"`
|
||||
}
|
||||
|
||||
// FetchAnswer is what a build module's fetch tool answers, whole: the part's `FetchAnswer`. A check keeps it as the
|
||||
// answer's fetch, so the checker reads a conflict (a head that does not merge is an answer, not an error), the changed
|
||||
// paths, the programs and the trees from it.
|
||||
type FetchAnswer struct {
|
||||
Workspace string `json:"workspace"`
|
||||
Commit string `json:"commit"`
|
||||
Modules []string `json:"modules"`
|
||||
// The merge preview, only when the call gave a base.
|
||||
Base string `json:"base,omitempty"`
|
||||
Merge string `json:"merge,omitempty"`
|
||||
Conflicts []string `json:"conflicts,omitempty"`
|
||||
Changed []string `json:"changed,omitempty"`
|
||||
Programs []Program `json:"programs,omitempty"`
|
||||
Trees map[string]ModuleTree `json:"trees,omitempty"`
|
||||
// The Go module's.
|
||||
Beside []PlacedBeside `json:"beside,omitempty"`
|
||||
Packages []TakenVersion `json:"packages,omitempty"`
|
||||
// The TypeScript module's.
|
||||
Installed []string `json:"installed,omitempty"`
|
||||
Refused []FetchRefusal `json:"refused,omitempty"`
|
||||
Group string `json:"group,omitempty"`
|
||||
}
|
||||
|
||||
// Program is a changed file that is a compiled program (issue 1577).
|
||||
type Program struct {
|
||||
Path string `json:"path"`
|
||||
Kind string `json:"kind"` // ELF, Mach-O or PE
|
||||
Commit string `json:"commit,omitempty"`
|
||||
}
|
||||
|
||||
// PlacedBeside is a sibling repository placed as a plain directory under the workspace's beside directory.
|
||||
type PlacedBeside struct {
|
||||
Repository string `json:"repository"`
|
||||
Commit string `json:"commit"`
|
||||
Dir string `json:"dir"`
|
||||
}
|
||||
|
||||
// TakenVersion is, of a directory whose go.mod requires an asked mesh package, the version it is built against.
|
||||
type TakenVersion struct {
|
||||
Dir string `json:"dir"`
|
||||
Package string `json:"package"`
|
||||
Asked string `json:"asked"`
|
||||
Named string `json:"named"`
|
||||
Built string `json:"built"`
|
||||
Sum string `json:"sum,omitempty"`
|
||||
Said string `json:"said,omitempty"`
|
||||
}
|
||||
|
||||
// FetchRefusal is a TypeScript module whose packages the fetch did not install, with why.
|
||||
type FetchRefusal struct {
|
||||
Module string `json:"module"`
|
||||
Reason string `json:"reason"`
|
||||
}
|
||||
|
||||
// StepResult is what any step answered: one layout for the four kinds, as the seats' `StepResult` (the fields of the
|
||||
// kinds do not meet). A step's result bytes read into it strictly.
|
||||
type StepResult struct {
|
||||
Artifacts []AskBuilt `json:"artifacts,omitempty"`
|
||||
Toolchain *ToolchainUsed `json:"toolchain,omitempty"`
|
||||
Imports []string `json:"imports,omitempty"`
|
||||
OutOfStep []string `json:"out-of-step,omitempty"`
|
||||
Fetch *FetchAnswer `json:"fetch,omitempty"`
|
||||
Levels []LevelAnswer `json:"levels,omitempty"`
|
||||
Built bool `json:"built,omitempty"`
|
||||
Key string `json:"key,omitempty"`
|
||||
Verdict json.RawMessage `json:"verdict,omitempty"`
|
||||
Declined bool `json:"declined,omitempty"`
|
||||
Needs []string `json:"needs,omitempty"`
|
||||
Lacks []string `json:"lacks,omitempty"`
|
||||
}
|
||||
|
||||
// ComposeAnswer is what a compose ask's step answers.
|
||||
type ComposeAnswer struct {
|
||||
Built bool `json:"built"`
|
||||
|
||||
@@ -72,6 +72,19 @@ func TestAskCheckAndRoundTrip(t *testing.T) {
|
||||
t.Errorf("a level: %v", err)
|
||||
}
|
||||
chk = goodCheck()
|
||||
chk.Check.Toolchain = &ToolchainUsed{Language: "go", Version: "1.26.0", Recipe: "2"}
|
||||
raw, err := EncodeStepAsk(chk)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if back, err := DecodeStepAsk(raw); err != nil || back.Check.Toolchain == nil || back.Check.Toolchain.Version != "1.26.0" {
|
||||
t.Errorf("the check's toolchain is lost in a round trip: %+v, %v", back.Check, err)
|
||||
}
|
||||
chk.Check.Toolchain.Recipe = ""
|
||||
if _, err := EncodeStepAsk(chk); err == nil || !strings.Contains(err.Error(), "toolchain") {
|
||||
t.Errorf("a toolchain without a recipe: %v", err)
|
||||
}
|
||||
chk = goodCheck()
|
||||
chk.Language = AskImage
|
||||
if _, err := EncodeStepAsk(chk); err == nil || !strings.Contains(err.Error(), "no tests") {
|
||||
t.Errorf("an image check: %v", err)
|
||||
@@ -251,6 +264,11 @@ func TestTheThreeSeatsFixturesFitTheNeutralForms(t *testing.T) {
|
||||
case strings.HasPrefix(f.Of, "state:steps/"):
|
||||
seen++
|
||||
strict(t, f.Given, &Step{})
|
||||
var st Step
|
||||
if err := json.Unmarshal(f.Given, &st); err == nil && len(st.Result) > 0 {
|
||||
// a step's result keeps what the tool answered, whole (the fetch tool's answer too)
|
||||
strict(t, st.Result, &StepResult{})
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
package buildstep
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// ToolchainVersion is the layout version of a toolchains value.
|
||||
const ToolchainVersion = 1
|
||||
|
||||
// Toolchain is the value of a build module's state toolchains under the key <node>.<language>: the version of the
|
||||
// language's toolchain installed on the node, the build module's recipe version, and when the module saw them. It is
|
||||
// the part build-step's `Toolchain`, the layout every node-build seat gives that state; the three build modules share
|
||||
// this neutral form (a seat's generated type is one package per seat). A test reads each seat's fixture strictly into it.
|
||||
type Toolchain struct {
|
||||
V int `json:"v,omitempty"`
|
||||
Language string `json:"language"`
|
||||
Version string `json:"version"`
|
||||
Recipe string `json:"recipe"`
|
||||
At time.Time `json:"at,omitzero"`
|
||||
}
|
||||
|
||||
func checkToolchainLanguage(language string) error {
|
||||
switch language {
|
||||
case "go", "typescript":
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("buildstep: the toolchain language %q is not go or typescript", language)
|
||||
}
|
||||
|
||||
// ToolchainKey is the key of a node's toolchain of one language: <node>.<language>. It refuses an empty node, a node
|
||||
// with a dot and a language other than go or typescript.
|
||||
func ToolchainKey(node, language string) (string, error) {
|
||||
if node == "" || strings.ContainsAny(node, ". ") {
|
||||
return "", fmt.Errorf("buildstep: %q is not a node name", node)
|
||||
}
|
||||
if err := checkToolchainLanguage(language); err != nil {
|
||||
return "", err
|
||||
}
|
||||
return node + "." + language, nil
|
||||
}
|
||||
|
||||
func (t Toolchain) check() error {
|
||||
if err := checkToolchainLanguage(t.Language); err != nil {
|
||||
return err
|
||||
}
|
||||
if t.Version == "" || t.Recipe == "" {
|
||||
return fmt.Errorf("buildstep: a %s toolchain needs its version and its recipe", t.Language)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// EncodeToolchain is t as JSON; it refuses a language other than go or typescript and an empty version or recipe.
|
||||
func EncodeToolchain(t Toolchain) ([]byte, error) {
|
||||
if err := t.check(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
t.V = ToolchainVersion
|
||||
return json.Marshal(t)
|
||||
}
|
||||
|
||||
// DecodeToolchain reads a toolchains value, refusing an unknown field, another layout version and what
|
||||
// EncodeToolchain refuses.
|
||||
func DecodeToolchain(data []byte) (Toolchain, error) {
|
||||
var t Toolchain
|
||||
dec := json.NewDecoder(bytes.NewReader(data))
|
||||
dec.DisallowUnknownFields()
|
||||
if err := dec.Decode(&t); err != nil {
|
||||
return Toolchain{}, fmt.Errorf("buildstep: a toolchain does not read: %w", err)
|
||||
}
|
||||
if t.V != ToolchainVersion {
|
||||
return Toolchain{}, fmt.Errorf("buildstep: a toolchain of version %d, this reads %d", t.V, ToolchainVersion)
|
||||
}
|
||||
if err := t.check(); err != nil {
|
||||
return Toolchain{}, err
|
||||
}
|
||||
return t, nil
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
package buildstep
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
// The toolchains value and key are the layout all three node-build seats generate: each seat's fixture of the state
|
||||
// reads strictly into Toolchain, and the key is the seat's key form <node>.<language>.
|
||||
func TestTheToolchainsValueAndKeyAreTheSeatsLayout(t *testing.T) {
|
||||
read := 0
|
||||
for _, seat := range []string{"node-build-go", "node-build-image", "node-build-node"} {
|
||||
raw, err := os.ReadFile(filepath.Join("..", "..", "contracts", "seats", seat, "fixtures", "states.json"))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
var fixtures []struct {
|
||||
Of string `json:"of"`
|
||||
Given json.RawMessage `json:"given"`
|
||||
}
|
||||
if err := json.Unmarshal(raw, &fixtures); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
for _, f := range fixtures {
|
||||
if f.Of != "state:toolchains/<node>.<language>" {
|
||||
continue
|
||||
}
|
||||
if back, err := DecodeToolchain(f.Given); err != nil || back.Version == "" {
|
||||
t.Errorf("%s: the fixture reads as %+v, %v", seat, back, err)
|
||||
}
|
||||
if _, err := EncodeToolchain(mustToolchain(t, f.Given)); err != nil {
|
||||
t.Errorf("%s: %v", seat, err)
|
||||
}
|
||||
dec := json.NewDecoder(bytes.NewReader(f.Given))
|
||||
dec.DisallowUnknownFields()
|
||||
if err := dec.Decode(&Toolchain{}); err != nil {
|
||||
t.Errorf("%s: %v", seat, err)
|
||||
}
|
||||
read++
|
||||
}
|
||||
}
|
||||
if read != 3 {
|
||||
t.Errorf("%d toolchain fixtures read, want 3", read)
|
||||
}
|
||||
raw, err := EncodeToolchain(Toolchain{Language: "go", Version: "go1.27.1", Recipe: "3", At: time.Date(2026, 11, 5, 10, 0, 0, 0, time.UTC)})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if back, err := DecodeToolchain(raw); err != nil || back.Version != "go1.27.1" || back.At.IsZero() {
|
||||
t.Errorf("the value reads back as %+v, %v", back, err)
|
||||
}
|
||||
if key, err := ToolchainKey("ace", "typescript"); err != nil || key != "ace.typescript" {
|
||||
t.Errorf("key %q, %v", key, err)
|
||||
}
|
||||
for _, bad := range [][2]string{{"", "go"}, {"a.b", "go"}, {"ace", "rust"}} {
|
||||
if _, err := ToolchainKey(bad[0], bad[1]); err == nil {
|
||||
t.Errorf("the key of %v was made", bad)
|
||||
}
|
||||
}
|
||||
if _, err := EncodeToolchain(Toolchain{Language: "go", Version: "go1.27"}); err == nil {
|
||||
t.Error("a toolchain without its recipe was written")
|
||||
}
|
||||
if _, err := DecodeToolchain([]byte(`{"v":1,"language":"go","version":"x","recipe":"1","extra":1}`)); err == nil || !strings.Contains(err.Error(), "extra") {
|
||||
t.Errorf("a field the layout lacks was read: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func mustToolchain(t *testing.T, raw []byte) Toolchain {
|
||||
t.Helper()
|
||||
var tc Toolchain
|
||||
if err := json.Unmarshal(raw, &tc); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
return tc
|
||||
}
|
||||
Reference in New Issue
Block a user