diff --git a/contracts/go/clients/containerimageregistryclient/reference/reference_test.go b/contracts/go/clients/containerimageregistryclient/reference/reference_test.go index d707c9e4..60823b7d 100644 --- a/contracts/go/clients/containerimageregistryclient/reference/reference_test.go +++ b/contracts/go/clients/containerimageregistryclient/reference/reference_test.go @@ -7,7 +7,7 @@ import ( var digest = "sha256:" + strings.Repeat("d", 64) -var seats = Seats{Image: "container-image-registry", Object: "oci-artifact-registry"} +var seats = Seats{Image: "container-image-registry", Object: "object-registry"} func TestAReferenceIsRecordedWithoutTheStoresAddress(t *testing.T) { cases := map[string]string{ @@ -21,7 +21,7 @@ func TestAReferenceIsRecordedWithoutTheStoresAddress(t *testing.T) { "https://registry.example/v2/gitea/config/blobs/" + digest: "https://registry.example/v2/gitea/config/blobs/" + digest, // The form a registry seat answers is recorded as it is (ADR 0605 ยง9). "container-image-registry/gitea/server@" + digest: "container-image-registry/gitea/server@" + digest, - "oci-artifact-registry/gitea/config@" + digest: "oci-artifact-registry/gitea/config@" + digest, + "object-registry/gitea/config@" + digest: "object-registry/gitea/config@" + digest, } for announced, want := range cases { if got := seats.Recorded(announced); got != want { @@ -33,7 +33,7 @@ func TestAReferenceIsRecordedWithoutTheStoresAddress(t *testing.T) { ArtifactStoreScheme + "gitea/server@" + digest: "10.0.0.1:5000/gitea/server@" + digest, "container-image-registry/gitea/server@" + digest: "10.0.0.1:5000/gitea/server@" + digest, ArtifactStoreScheme + "gitea/config/blobs/" + digest: "http://10.0.0.1:5000/v2/gitea/config/blobs/" + digest, - "oci-artifact-registry/gitea/config@" + digest: "http://10.0.0.1:5000/v2/gitea/config/blobs/" + digest, + "object-registry/gitea/config@" + digest: "http://10.0.0.1:5000/v2/gitea/config/blobs/" + digest, "registry.example/gitea/server@" + digest: "registry.example/gitea/server@" + digest, "mesh-artifact-store/gitea/server@" + digest: "mesh-artifact-store/gitea/server@" + digest, // An upstream copy under the holder's own naming, in both forms. @@ -54,7 +54,7 @@ func TestAReferenceIsRecordedWithoutTheStoresAddress(t *testing.T) { // The holder's naming of an upstream copy reads through the image seat only, and InUpstream reads its host and path. for reference, want := range map[string]bool{ "container-image-registry/upstream/quay.io:443/org/app@" + digest: true, - "oci-artifact-registry/upstream/quay.io:443/org/app@" + digest: false, + "object-registry/upstream/quay.io:443/org/app@" + digest: false, "container-image-registry/upstream/org/app@" + digest: false, "container-image-registry/upstream/quay.io/app": false, } { diff --git a/contracts/go/seats/nodebuildgo/contract.go b/contracts/go/seats/nodebuildgo/contract.go index 59b72a28..a734103f 100644 --- a/contracts/go/seats/nodebuildgo/contract.go +++ b/contracts/go/seats/nodebuildgo/contract.go @@ -187,26 +187,27 @@ func DecodeToolchainsByNodeLanguageValue(raw []byte) (ToolchainsByNodeLanguageVa return v, nil } -// BuildAnswerArtifactsItem is a type of the contract. -type BuildAnswerArtifactsItem struct { - Artifact string `json:"artifact"` - Digest string `json:"digest"` - Reference string `json:"reference,omitempty"` -} - -// BuildAnswerToolchain is a type of the contract. -type BuildAnswerToolchain struct { - Language string `json:"language"` - Recipe string `json:"recipe"` - Version string `json:"version"` +// AskArtifact is one artifact of a build ask: built from the fetched tree, or copied from an upstream pin. +type AskArtifact struct { + Artifact string `json:"artifact"` + From string `json:"from,omitempty"` + Seat string `json:"seat,omitempty"` + Version string `json:"version,omitempty"` } // BuildAnswer is a type of the contract. type BuildAnswer struct { - Artifacts []BuildAnswerArtifactsItem `json:"artifacts"` - Imports []string `json:"imports,omitempty"` - OutOfStep []string `json:"out-of-step,omitempty"` - Toolchain *BuildAnswerToolchain `json:"toolchain,omitempty"` + Artifacts []BuiltArtifact `json:"artifacts"` + Imports []string `json:"imports,omitempty"` + OutOfStep []string `json:"out-of-step,omitempty"` + Toolchain *ToolchainUsed `json:"toolchain,omitempty"` +} + +// BuiltArtifact is one artifact a build made: its digest and the reference it was published under. +type BuiltArtifact struct { + Artifact string `json:"artifact"` + Digest string `json:"digest"` + Reference string `json:"reference,omitempty"` } // Capacity is how many steps the node runs at once. @@ -229,56 +230,10 @@ type Capacity struct { Why string `json:"why"` } -// CheckAnswerLevelsItemDigestNeedsItem is a type of the contract. -type CheckAnswerLevelsItemDigestNeedsItem struct { - Needs []string `json:"needs,omitempty"` - Package string `json:"package,omitempty"` -} - -// CheckAnswerLevelsItemDigestPackagesItem is a type of the contract. -type CheckAnswerLevelsItemDigestPackagesItem struct { - Digest string `json:"digest"` - Package string `json:"package"` -} - -// CheckAnswerLevelsItemDigest is a type of the contract. -type CheckAnswerLevelsItemDigest struct { - Beside []string `json:"beside,omitempty"` - JudgedBy string `json:"judged_by,omitempty"` - Level string `json:"level,omitempty"` - Needs []CheckAnswerLevelsItemDigestNeedsItem `json:"needs,omitempty"` - Packages []CheckAnswerLevelsItemDigestPackagesItem `json:"packages,omitempty"` - WithoutTests []string `json:"without_tests,omitempty"` -} - -// CheckAnswerLevelsItemKeptItem is a type of the contract. -type CheckAnswerLevelsItemKeptItem struct { - Digest string `json:"digest,omitempty"` - Package string `json:"package,omitempty"` - Tests int64 `json:"tests,omitempty"` -} - -// CheckAnswerLevelsItemUnmetItem is a type of the contract. -type CheckAnswerLevelsItemUnmetItem struct { - Needs []string `json:"needs,omitempty"` - Package string `json:"package,omitempty"` -} - -// CheckAnswerLevelsItem is a type of the contract. -type CheckAnswerLevelsItem struct { - Digest *CheckAnswerLevelsItemDigest `json:"digest,omitempty"` - Judged string `json:"judged,omitempty"` - Kept []CheckAnswerLevelsItemKeptItem `json:"kept,omitempty"` - Level string `json:"level"` - Tests []any `json:"tests,omitempty"` - Unmet []CheckAnswerLevelsItemUnmetItem `json:"unmet,omitempty"` -} - // CheckAnswer is a type of the contract. type CheckAnswer struct { - // what the build module fetches: the repository, commit and directory, as the indexer states it - Fetch any `json:"fetch"` - Levels []CheckAnswerLevelsItem `json:"levels,omitempty"` + Fetch Fetch `json:"fetch"` + Levels []LevelAnswer `json:"levels,omitempty"` } // ComposeAnswer is a type of the contract. @@ -289,6 +244,77 @@ type ComposeAnswer struct { Verdict any `json:"verdict,omitempty"` } +// FetchBesideItem is a type of the contract. +type FetchBesideItem struct { + Commit string `json:"commit"` + Repository string `json:"repository"` +} + +// Fetch is what a build module's fetch tool is asked: the repository and the full commit, the pull request's ref when only its head carries the commit, the trunk commit to merge onto for a merge preview, the module's directory and named paths, the mesh packages to build against, and the sibling repositories placed beside. +type Fetch struct { + // the trunk commit a merge preview merges onto + Base string `json:"base,omitempty"` + // the sibling repositories placed beside the fetched tree + Beside []FetchBesideItem `json:"beside,omitempty"` + // the full commit + Commit string `json:"commit"` + // the module's directory in the repository ("." for its root), with paths + Dir string `json:"dir,omitempty"` + // the version (a full commit) of each mesh package to build against, by its module path + Packages map[string]string `json:"packages,omitempty"` + // the paths the module names, relative to dir + Paths []string `json:"paths,omitempty"` + // the pull request's ref, when only its head carries the commit + Ref string `json:"ref,omitempty"` + // / + Repository string `json:"repository"` +} + +// LevelAnswerDigestNeedsItem is a type of the contract. +type LevelAnswerDigestNeedsItem struct { + Needs []string `json:"needs,omitempty"` + Package string `json:"package,omitempty"` +} + +// LevelAnswerDigestPackagesItem is a type of the contract. +type LevelAnswerDigestPackagesItem struct { + Digest string `json:"digest"` + Package string `json:"package"` +} + +// LevelAnswerDigest is a type of the contract. +type LevelAnswerDigest struct { + Beside []string `json:"beside,omitempty"` + JudgedBy string `json:"judged_by,omitempty"` + Level string `json:"level,omitempty"` + Needs []LevelAnswerDigestNeedsItem `json:"needs,omitempty"` + Packages []LevelAnswerDigestPackagesItem `json:"packages,omitempty"` + WithoutTests []string `json:"without_tests,omitempty"` +} + +// LevelAnswerKeptItem is a type of the contract. +type LevelAnswerKeptItem struct { + Digest string `json:"digest,omitempty"` + Package string `json:"package,omitempty"` + Tests int64 `json:"tests,omitempty"` +} + +// LevelAnswerUnmetItem is a type of the contract. +type LevelAnswerUnmetItem struct { + Needs []string `json:"needs,omitempty"` + Package string `json:"package,omitempty"` +} + +// LevelAnswer is one level of a check ask: the digest's answer, the kept verdicts taken, one test result per test step run, and the packages the node could not test. +type LevelAnswer struct { + Digest *LevelAnswerDigest `json:"digest,omitempty"` + Judged string `json:"judged,omitempty"` + Kept []LevelAnswerKeptItem `json:"kept,omitempty"` + Level string `json:"level"` + Tests []any `json:"tests,omitempty"` + Unmet []LevelAnswerUnmetItem `json:"unmet,omitempty"` +} + // Pause is whether the node takes no new ask. type Pause struct { // when (RFC 3339 time) @@ -308,10 +334,9 @@ type Step struct { Owner string `json:"owner,omitempty"` Phase string `json:"phase,omitempty"` // when (RFC 3339 time) - PhaseAt string `json:"phase-at,omitempty"` - Reason string `json:"reason,omitempty"` - // what the step answered - Result any `json:"result,omitempty"` + PhaseAt string `json:"phase-at,omitempty"` + Reason string `json:"reason,omitempty"` + Result *StepResult `json:"result,omitempty"` // when (RFC 3339 time) Started string `json:"started"` // running, passed, failed or refused @@ -322,37 +347,20 @@ type Step struct { What string `json:"what,omitempty"` } -// StepAskBuildArtifactsItem is a type of the contract. -type StepAskBuildArtifactsItem struct { - Artifact string `json:"artifact"` - From string `json:"from,omitempty"` - Seat string `json:"seat,omitempty"` - Version string `json:"version,omitempty"` -} - -// StepAskBuildToolchain is a type of the contract. -type StepAskBuildToolchain struct { - Language string `json:"language"` - Recipe string `json:"recipe"` - Version string `json:"version"` -} - // StepAskBuild is a type of the contract. type StepAskBuild struct { - Artifacts []StepAskBuildArtifactsItem `json:"artifacts"` - // what the build module fetches: the repository, commit and directory, as the indexer states it - Fetch any `json:"fetch,omitempty"` - Fp string `json:"fp,omitempty"` - Module string `json:"module"` - Path string `json:"path,omitempty"` - Publish bool `json:"publish,omitempty"` - Toolchain *StepAskBuildToolchain `json:"toolchain,omitempty"` + Artifacts []AskArtifact `json:"artifacts"` + Fetch *Fetch `json:"fetch,omitempty"` + Fp string `json:"fp,omitempty"` + Module string `json:"module"` + Path string `json:"path,omitempty"` + Publish bool `json:"publish,omitempty"` + Toolchain *ToolchainUsed `json:"toolchain,omitempty"` } // StepAskCheck is a type of the contract. type StepAskCheck struct { - // what the build module fetches: the repository, commit and directory, as the indexer states it - Fetch any `json:"fetch"` + Fetch Fetch `json:"fetch"` Kept bool `json:"kept,omitempty"` Levels []string `json:"levels"` Packages []string `json:"packages,omitempty"` @@ -363,9 +371,8 @@ type StepAskCheck struct { // StepAskCompose is a type of the contract. type StepAskCompose struct { - Dir string `json:"dir"` - // what the build module fetches: the repository, commit and directory, as the indexer states it - Fetch any `json:"fetch"` + Dir string `json:"dir"` + Fetch Fetch `json:"fetch"` Package string `json:"package"` Reader string `json:"reader,omitempty"` // the compose-candidate request @@ -392,6 +399,26 @@ type StepAsk struct { V int64 `json:"v,omitempty"` } +// StepResult is what a step answered, by the kind of ask: a build's artifacts, toolchain, imports and out-of-step modules; a check's fetch and levels; a compose's built, key and verdict; a declined ask's declined, needs and lacks. The fields of the kinds do not meet, so one layout holds the four. +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"` + // what the holder's node lacks of it + Lacks []string `json:"lacks,omitempty"` + Levels []LevelAnswer `json:"levels,omitempty"` + // what the declined ask needs + Needs []string `json:"needs,omitempty"` + OutOfStep []string `json:"out-of-step,omitempty"` + Toolchain *ToolchainUsed `json:"toolchain,omitempty"` + // the compose-candidate verdict (the composer's own layout) + Verdict any `json:"verdict,omitempty"` +} + // Toolchain is the toolchain a node reports. type Toolchain struct { // when (RFC 3339 time) @@ -404,6 +431,13 @@ type Toolchain struct { Version string `json:"version"` } +// ToolchainUsed is the toolchain a build was made with: the language, the installed version and the build module's recipe. +type ToolchainUsed struct { + Language string `json:"language"` + Recipe string `json:"recipe"` + Version string `json:"version"` +} + // CurrentInput is what current takes. type CurrentInput struct { } diff --git a/contracts/go/seats/nodebuildgo/contract_test.go b/contracts/go/seats/nodebuildgo/contract_test.go index e7dd00cc..4aabcc73 100644 --- a/contracts/go/seats/nodebuildgo/contract_test.go +++ b/contracts/go/seats/nodebuildgo/contract_test.go @@ -39,6 +39,14 @@ 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}", + 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}", + 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}, } for _, c := range cases { v, err := c.decode([]byte(c.given)) diff --git a/contracts/go/seats/nodebuildimage/contract.go b/contracts/go/seats/nodebuildimage/contract.go index 843c04ae..db640ee3 100644 --- a/contracts/go/seats/nodebuildimage/contract.go +++ b/contracts/go/seats/nodebuildimage/contract.go @@ -187,26 +187,27 @@ func DecodeToolchainsByNodeLanguageValue(raw []byte) (ToolchainsByNodeLanguageVa return v, nil } -// BuildAnswerArtifactsItem is a type of the contract. -type BuildAnswerArtifactsItem struct { - Artifact string `json:"artifact"` - Digest string `json:"digest"` - Reference string `json:"reference,omitempty"` -} - -// BuildAnswerToolchain is a type of the contract. -type BuildAnswerToolchain struct { - Language string `json:"language"` - Recipe string `json:"recipe"` - Version string `json:"version"` +// AskArtifact is one artifact of a build ask: built from the fetched tree, or copied from an upstream pin. +type AskArtifact struct { + Artifact string `json:"artifact"` + From string `json:"from,omitempty"` + Seat string `json:"seat,omitempty"` + Version string `json:"version,omitempty"` } // BuildAnswer is a type of the contract. type BuildAnswer struct { - Artifacts []BuildAnswerArtifactsItem `json:"artifacts"` - Imports []string `json:"imports,omitempty"` - OutOfStep []string `json:"out-of-step,omitempty"` - Toolchain *BuildAnswerToolchain `json:"toolchain,omitempty"` + Artifacts []BuiltArtifact `json:"artifacts"` + Imports []string `json:"imports,omitempty"` + OutOfStep []string `json:"out-of-step,omitempty"` + Toolchain *ToolchainUsed `json:"toolchain,omitempty"` +} + +// BuiltArtifact is one artifact a build made: its digest and the reference it was published under. +type BuiltArtifact struct { + Artifact string `json:"artifact"` + Digest string `json:"digest"` + Reference string `json:"reference,omitempty"` } // Capacity is how many steps the node runs at once. @@ -229,56 +230,10 @@ type Capacity struct { Why string `json:"why"` } -// CheckAnswerLevelsItemDigestNeedsItem is a type of the contract. -type CheckAnswerLevelsItemDigestNeedsItem struct { - Needs []string `json:"needs,omitempty"` - Package string `json:"package,omitempty"` -} - -// CheckAnswerLevelsItemDigestPackagesItem is a type of the contract. -type CheckAnswerLevelsItemDigestPackagesItem struct { - Digest string `json:"digest"` - Package string `json:"package"` -} - -// CheckAnswerLevelsItemDigest is a type of the contract. -type CheckAnswerLevelsItemDigest struct { - Beside []string `json:"beside,omitempty"` - JudgedBy string `json:"judged_by,omitempty"` - Level string `json:"level,omitempty"` - Needs []CheckAnswerLevelsItemDigestNeedsItem `json:"needs,omitempty"` - Packages []CheckAnswerLevelsItemDigestPackagesItem `json:"packages,omitempty"` - WithoutTests []string `json:"without_tests,omitempty"` -} - -// CheckAnswerLevelsItemKeptItem is a type of the contract. -type CheckAnswerLevelsItemKeptItem struct { - Digest string `json:"digest,omitempty"` - Package string `json:"package,omitempty"` - Tests int64 `json:"tests,omitempty"` -} - -// CheckAnswerLevelsItemUnmetItem is a type of the contract. -type CheckAnswerLevelsItemUnmetItem struct { - Needs []string `json:"needs,omitempty"` - Package string `json:"package,omitempty"` -} - -// CheckAnswerLevelsItem is a type of the contract. -type CheckAnswerLevelsItem struct { - Digest *CheckAnswerLevelsItemDigest `json:"digest,omitempty"` - Judged string `json:"judged,omitempty"` - Kept []CheckAnswerLevelsItemKeptItem `json:"kept,omitempty"` - Level string `json:"level"` - Tests []any `json:"tests,omitempty"` - Unmet []CheckAnswerLevelsItemUnmetItem `json:"unmet,omitempty"` -} - // CheckAnswer is a type of the contract. type CheckAnswer struct { - // what the build module fetches: the repository, commit and directory, as the indexer states it - Fetch any `json:"fetch"` - Levels []CheckAnswerLevelsItem `json:"levels,omitempty"` + Fetch Fetch `json:"fetch"` + Levels []LevelAnswer `json:"levels,omitempty"` } // ComposeAnswer is a type of the contract. @@ -289,6 +244,77 @@ type ComposeAnswer struct { Verdict any `json:"verdict,omitempty"` } +// FetchBesideItem is a type of the contract. +type FetchBesideItem struct { + Commit string `json:"commit"` + Repository string `json:"repository"` +} + +// Fetch is what a build module's fetch tool is asked: the repository and the full commit, the pull request's ref when only its head carries the commit, the trunk commit to merge onto for a merge preview, the module's directory and named paths, the mesh packages to build against, and the sibling repositories placed beside. +type Fetch struct { + // the trunk commit a merge preview merges onto + Base string `json:"base,omitempty"` + // the sibling repositories placed beside the fetched tree + Beside []FetchBesideItem `json:"beside,omitempty"` + // the full commit + Commit string `json:"commit"` + // the module's directory in the repository ("." for its root), with paths + Dir string `json:"dir,omitempty"` + // the version (a full commit) of each mesh package to build against, by its module path + Packages map[string]string `json:"packages,omitempty"` + // the paths the module names, relative to dir + Paths []string `json:"paths,omitempty"` + // the pull request's ref, when only its head carries the commit + Ref string `json:"ref,omitempty"` + // / + Repository string `json:"repository"` +} + +// LevelAnswerDigestNeedsItem is a type of the contract. +type LevelAnswerDigestNeedsItem struct { + Needs []string `json:"needs,omitempty"` + Package string `json:"package,omitempty"` +} + +// LevelAnswerDigestPackagesItem is a type of the contract. +type LevelAnswerDigestPackagesItem struct { + Digest string `json:"digest"` + Package string `json:"package"` +} + +// LevelAnswerDigest is a type of the contract. +type LevelAnswerDigest struct { + Beside []string `json:"beside,omitempty"` + JudgedBy string `json:"judged_by,omitempty"` + Level string `json:"level,omitempty"` + Needs []LevelAnswerDigestNeedsItem `json:"needs,omitempty"` + Packages []LevelAnswerDigestPackagesItem `json:"packages,omitempty"` + WithoutTests []string `json:"without_tests,omitempty"` +} + +// LevelAnswerKeptItem is a type of the contract. +type LevelAnswerKeptItem struct { + Digest string `json:"digest,omitempty"` + Package string `json:"package,omitempty"` + Tests int64 `json:"tests,omitempty"` +} + +// LevelAnswerUnmetItem is a type of the contract. +type LevelAnswerUnmetItem struct { + Needs []string `json:"needs,omitempty"` + Package string `json:"package,omitempty"` +} + +// LevelAnswer is one level of a check ask: the digest's answer, the kept verdicts taken, one test result per test step run, and the packages the node could not test. +type LevelAnswer struct { + Digest *LevelAnswerDigest `json:"digest,omitempty"` + Judged string `json:"judged,omitempty"` + Kept []LevelAnswerKeptItem `json:"kept,omitempty"` + Level string `json:"level"` + Tests []any `json:"tests,omitempty"` + Unmet []LevelAnswerUnmetItem `json:"unmet,omitempty"` +} + // Pause is whether the node takes no new ask. type Pause struct { // when (RFC 3339 time) @@ -308,10 +334,9 @@ type Step struct { Owner string `json:"owner,omitempty"` Phase string `json:"phase,omitempty"` // when (RFC 3339 time) - PhaseAt string `json:"phase-at,omitempty"` - Reason string `json:"reason,omitempty"` - // what the step answered - Result any `json:"result,omitempty"` + PhaseAt string `json:"phase-at,omitempty"` + Reason string `json:"reason,omitempty"` + Result *StepResult `json:"result,omitempty"` // when (RFC 3339 time) Started string `json:"started"` // running, passed, failed or refused @@ -322,37 +347,20 @@ type Step struct { What string `json:"what,omitempty"` } -// StepAskBuildArtifactsItem is a type of the contract. -type StepAskBuildArtifactsItem struct { - Artifact string `json:"artifact"` - From string `json:"from,omitempty"` - Seat string `json:"seat,omitempty"` - Version string `json:"version,omitempty"` -} - -// StepAskBuildToolchain is a type of the contract. -type StepAskBuildToolchain struct { - Language string `json:"language"` - Recipe string `json:"recipe"` - Version string `json:"version"` -} - // StepAskBuild is a type of the contract. type StepAskBuild struct { - Artifacts []StepAskBuildArtifactsItem `json:"artifacts"` - // what the build module fetches: the repository, commit and directory, as the indexer states it - Fetch any `json:"fetch,omitempty"` - Fp string `json:"fp,omitempty"` - Module string `json:"module"` - Path string `json:"path,omitempty"` - Publish bool `json:"publish,omitempty"` - Toolchain *StepAskBuildToolchain `json:"toolchain,omitempty"` + Artifacts []AskArtifact `json:"artifacts"` + Fetch *Fetch `json:"fetch,omitempty"` + Fp string `json:"fp,omitempty"` + Module string `json:"module"` + Path string `json:"path,omitempty"` + Publish bool `json:"publish,omitempty"` + Toolchain *ToolchainUsed `json:"toolchain,omitempty"` } // StepAskCheck is a type of the contract. type StepAskCheck struct { - // what the build module fetches: the repository, commit and directory, as the indexer states it - Fetch any `json:"fetch"` + Fetch Fetch `json:"fetch"` Kept bool `json:"kept,omitempty"` Levels []string `json:"levels"` Packages []string `json:"packages,omitempty"` @@ -363,9 +371,8 @@ type StepAskCheck struct { // StepAskCompose is a type of the contract. type StepAskCompose struct { - Dir string `json:"dir"` - // what the build module fetches: the repository, commit and directory, as the indexer states it - Fetch any `json:"fetch"` + Dir string `json:"dir"` + Fetch Fetch `json:"fetch"` Package string `json:"package"` Reader string `json:"reader,omitempty"` // the compose-candidate request @@ -392,6 +399,26 @@ type StepAsk struct { V int64 `json:"v,omitempty"` } +// StepResult is what a step answered, by the kind of ask: a build's artifacts, toolchain, imports and out-of-step modules; a check's fetch and levels; a compose's built, key and verdict; a declined ask's declined, needs and lacks. The fields of the kinds do not meet, so one layout holds the four. +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"` + // what the holder's node lacks of it + Lacks []string `json:"lacks,omitempty"` + Levels []LevelAnswer `json:"levels,omitempty"` + // what the declined ask needs + Needs []string `json:"needs,omitempty"` + OutOfStep []string `json:"out-of-step,omitempty"` + Toolchain *ToolchainUsed `json:"toolchain,omitempty"` + // the compose-candidate verdict (the composer's own layout) + Verdict any `json:"verdict,omitempty"` +} + // Toolchain is the toolchain a node reports. type Toolchain struct { // when (RFC 3339 time) @@ -404,6 +431,13 @@ type Toolchain struct { Version string `json:"version"` } +// ToolchainUsed is the toolchain a build was made with: the language, the installed version and the build module's recipe. +type ToolchainUsed struct { + Language string `json:"language"` + Recipe string `json:"recipe"` + Version string `json:"version"` +} + // CurrentInput is what current takes. type CurrentInput struct { } diff --git a/contracts/go/seats/nodebuildnode/contract.go b/contracts/go/seats/nodebuildnode/contract.go index 8e3e0448..9b0c7ff8 100644 --- a/contracts/go/seats/nodebuildnode/contract.go +++ b/contracts/go/seats/nodebuildnode/contract.go @@ -187,26 +187,27 @@ func DecodeToolchainsByNodeLanguageValue(raw []byte) (ToolchainsByNodeLanguageVa return v, nil } -// BuildAnswerArtifactsItem is a type of the contract. -type BuildAnswerArtifactsItem struct { - Artifact string `json:"artifact"` - Digest string `json:"digest"` - Reference string `json:"reference,omitempty"` -} - -// BuildAnswerToolchain is a type of the contract. -type BuildAnswerToolchain struct { - Language string `json:"language"` - Recipe string `json:"recipe"` - Version string `json:"version"` +// AskArtifact is one artifact of a build ask: built from the fetched tree, or copied from an upstream pin. +type AskArtifact struct { + Artifact string `json:"artifact"` + From string `json:"from,omitempty"` + Seat string `json:"seat,omitempty"` + Version string `json:"version,omitempty"` } // BuildAnswer is a type of the contract. type BuildAnswer struct { - Artifacts []BuildAnswerArtifactsItem `json:"artifacts"` - Imports []string `json:"imports,omitempty"` - OutOfStep []string `json:"out-of-step,omitempty"` - Toolchain *BuildAnswerToolchain `json:"toolchain,omitempty"` + Artifacts []BuiltArtifact `json:"artifacts"` + Imports []string `json:"imports,omitempty"` + OutOfStep []string `json:"out-of-step,omitempty"` + Toolchain *ToolchainUsed `json:"toolchain,omitempty"` +} + +// BuiltArtifact is one artifact a build made: its digest and the reference it was published under. +type BuiltArtifact struct { + Artifact string `json:"artifact"` + Digest string `json:"digest"` + Reference string `json:"reference,omitempty"` } // Capacity is how many steps the node runs at once. @@ -229,56 +230,10 @@ type Capacity struct { Why string `json:"why"` } -// CheckAnswerLevelsItemDigestNeedsItem is a type of the contract. -type CheckAnswerLevelsItemDigestNeedsItem struct { - Needs []string `json:"needs,omitempty"` - Package string `json:"package,omitempty"` -} - -// CheckAnswerLevelsItemDigestPackagesItem is a type of the contract. -type CheckAnswerLevelsItemDigestPackagesItem struct { - Digest string `json:"digest"` - Package string `json:"package"` -} - -// CheckAnswerLevelsItemDigest is a type of the contract. -type CheckAnswerLevelsItemDigest struct { - Beside []string `json:"beside,omitempty"` - JudgedBy string `json:"judged_by,omitempty"` - Level string `json:"level,omitempty"` - Needs []CheckAnswerLevelsItemDigestNeedsItem `json:"needs,omitempty"` - Packages []CheckAnswerLevelsItemDigestPackagesItem `json:"packages,omitempty"` - WithoutTests []string `json:"without_tests,omitempty"` -} - -// CheckAnswerLevelsItemKeptItem is a type of the contract. -type CheckAnswerLevelsItemKeptItem struct { - Digest string `json:"digest,omitempty"` - Package string `json:"package,omitempty"` - Tests int64 `json:"tests,omitempty"` -} - -// CheckAnswerLevelsItemUnmetItem is a type of the contract. -type CheckAnswerLevelsItemUnmetItem struct { - Needs []string `json:"needs,omitempty"` - Package string `json:"package,omitempty"` -} - -// CheckAnswerLevelsItem is a type of the contract. -type CheckAnswerLevelsItem struct { - Digest *CheckAnswerLevelsItemDigest `json:"digest,omitempty"` - Judged string `json:"judged,omitempty"` - Kept []CheckAnswerLevelsItemKeptItem `json:"kept,omitempty"` - Level string `json:"level"` - Tests []any `json:"tests,omitempty"` - Unmet []CheckAnswerLevelsItemUnmetItem `json:"unmet,omitempty"` -} - // CheckAnswer is a type of the contract. type CheckAnswer struct { - // what the build module fetches: the repository, commit and directory, as the indexer states it - Fetch any `json:"fetch"` - Levels []CheckAnswerLevelsItem `json:"levels,omitempty"` + Fetch Fetch `json:"fetch"` + Levels []LevelAnswer `json:"levels,omitempty"` } // ComposeAnswer is a type of the contract. @@ -289,6 +244,77 @@ type ComposeAnswer struct { Verdict any `json:"verdict,omitempty"` } +// FetchBesideItem is a type of the contract. +type FetchBesideItem struct { + Commit string `json:"commit"` + Repository string `json:"repository"` +} + +// Fetch is what a build module's fetch tool is asked: the repository and the full commit, the pull request's ref when only its head carries the commit, the trunk commit to merge onto for a merge preview, the module's directory and named paths, the mesh packages to build against, and the sibling repositories placed beside. +type Fetch struct { + // the trunk commit a merge preview merges onto + Base string `json:"base,omitempty"` + // the sibling repositories placed beside the fetched tree + Beside []FetchBesideItem `json:"beside,omitempty"` + // the full commit + Commit string `json:"commit"` + // the module's directory in the repository ("." for its root), with paths + Dir string `json:"dir,omitempty"` + // the version (a full commit) of each mesh package to build against, by its module path + Packages map[string]string `json:"packages,omitempty"` + // the paths the module names, relative to dir + Paths []string `json:"paths,omitempty"` + // the pull request's ref, when only its head carries the commit + Ref string `json:"ref,omitempty"` + // / + Repository string `json:"repository"` +} + +// LevelAnswerDigestNeedsItem is a type of the contract. +type LevelAnswerDigestNeedsItem struct { + Needs []string `json:"needs,omitempty"` + Package string `json:"package,omitempty"` +} + +// LevelAnswerDigestPackagesItem is a type of the contract. +type LevelAnswerDigestPackagesItem struct { + Digest string `json:"digest"` + Package string `json:"package"` +} + +// LevelAnswerDigest is a type of the contract. +type LevelAnswerDigest struct { + Beside []string `json:"beside,omitempty"` + JudgedBy string `json:"judged_by,omitempty"` + Level string `json:"level,omitempty"` + Needs []LevelAnswerDigestNeedsItem `json:"needs,omitempty"` + Packages []LevelAnswerDigestPackagesItem `json:"packages,omitempty"` + WithoutTests []string `json:"without_tests,omitempty"` +} + +// LevelAnswerKeptItem is a type of the contract. +type LevelAnswerKeptItem struct { + Digest string `json:"digest,omitempty"` + Package string `json:"package,omitempty"` + Tests int64 `json:"tests,omitempty"` +} + +// LevelAnswerUnmetItem is a type of the contract. +type LevelAnswerUnmetItem struct { + Needs []string `json:"needs,omitempty"` + Package string `json:"package,omitempty"` +} + +// LevelAnswer is one level of a check ask: the digest's answer, the kept verdicts taken, one test result per test step run, and the packages the node could not test. +type LevelAnswer struct { + Digest *LevelAnswerDigest `json:"digest,omitempty"` + Judged string `json:"judged,omitempty"` + Kept []LevelAnswerKeptItem `json:"kept,omitempty"` + Level string `json:"level"` + Tests []any `json:"tests,omitempty"` + Unmet []LevelAnswerUnmetItem `json:"unmet,omitempty"` +} + // Pause is whether the node takes no new ask. type Pause struct { // when (RFC 3339 time) @@ -308,10 +334,9 @@ type Step struct { Owner string `json:"owner,omitempty"` Phase string `json:"phase,omitempty"` // when (RFC 3339 time) - PhaseAt string `json:"phase-at,omitempty"` - Reason string `json:"reason,omitempty"` - // what the step answered - Result any `json:"result,omitempty"` + PhaseAt string `json:"phase-at,omitempty"` + Reason string `json:"reason,omitempty"` + Result *StepResult `json:"result,omitempty"` // when (RFC 3339 time) Started string `json:"started"` // running, passed, failed or refused @@ -322,37 +347,20 @@ type Step struct { What string `json:"what,omitempty"` } -// StepAskBuildArtifactsItem is a type of the contract. -type StepAskBuildArtifactsItem struct { - Artifact string `json:"artifact"` - From string `json:"from,omitempty"` - Seat string `json:"seat,omitempty"` - Version string `json:"version,omitempty"` -} - -// StepAskBuildToolchain is a type of the contract. -type StepAskBuildToolchain struct { - Language string `json:"language"` - Recipe string `json:"recipe"` - Version string `json:"version"` -} - // StepAskBuild is a type of the contract. type StepAskBuild struct { - Artifacts []StepAskBuildArtifactsItem `json:"artifacts"` - // what the build module fetches: the repository, commit and directory, as the indexer states it - Fetch any `json:"fetch,omitempty"` - Fp string `json:"fp,omitempty"` - Module string `json:"module"` - Path string `json:"path,omitempty"` - Publish bool `json:"publish,omitempty"` - Toolchain *StepAskBuildToolchain `json:"toolchain,omitempty"` + Artifacts []AskArtifact `json:"artifacts"` + Fetch *Fetch `json:"fetch,omitempty"` + Fp string `json:"fp,omitempty"` + Module string `json:"module"` + Path string `json:"path,omitempty"` + Publish bool `json:"publish,omitempty"` + Toolchain *ToolchainUsed `json:"toolchain,omitempty"` } // StepAskCheck is a type of the contract. type StepAskCheck struct { - // what the build module fetches: the repository, commit and directory, as the indexer states it - Fetch any `json:"fetch"` + Fetch Fetch `json:"fetch"` Kept bool `json:"kept,omitempty"` Levels []string `json:"levels"` Packages []string `json:"packages,omitempty"` @@ -363,9 +371,8 @@ type StepAskCheck struct { // StepAskCompose is a type of the contract. type StepAskCompose struct { - Dir string `json:"dir"` - // what the build module fetches: the repository, commit and directory, as the indexer states it - Fetch any `json:"fetch"` + Dir string `json:"dir"` + Fetch Fetch `json:"fetch"` Package string `json:"package"` Reader string `json:"reader,omitempty"` // the compose-candidate request @@ -392,6 +399,26 @@ type StepAsk struct { V int64 `json:"v,omitempty"` } +// StepResult is what a step answered, by the kind of ask: a build's artifacts, toolchain, imports and out-of-step modules; a check's fetch and levels; a compose's built, key and verdict; a declined ask's declined, needs and lacks. The fields of the kinds do not meet, so one layout holds the four. +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"` + // what the holder's node lacks of it + Lacks []string `json:"lacks,omitempty"` + Levels []LevelAnswer `json:"levels,omitempty"` + // what the declined ask needs + Needs []string `json:"needs,omitempty"` + OutOfStep []string `json:"out-of-step,omitempty"` + Toolchain *ToolchainUsed `json:"toolchain,omitempty"` + // the compose-candidate verdict (the composer's own layout) + Verdict any `json:"verdict,omitempty"` +} + // Toolchain is the toolchain a node reports. type Toolchain struct { // when (RFC 3339 time) @@ -404,6 +431,13 @@ type Toolchain struct { Version string `json:"version"` } +// ToolchainUsed is the toolchain a build was made with: the language, the installed version and the build module's recipe. +type ToolchainUsed struct { + Language string `json:"language"` + Recipe string `json:"recipe"` + Version string `json:"version"` +} + // CurrentInput is what current takes. type CurrentInput struct { } diff --git a/contracts/parts/build-step.json b/contracts/parts/build-step.json index dfc809f6..55920376 100644 --- a/contracts/parts/build-step.json +++ b/contracts/parts/build-step.json @@ -64,7 +64,8 @@ }, "at": { "type": "string", - "description": "when (RFC 3339 time)" + "description": "when (RFC 3339 time)", + "format": "date-time" }, "build": { "type": "object", @@ -79,52 +80,19 @@ "type": "string" }, "fetch": { - "description": "what the build module fetches: the repository, commit and directory, as the indexer states it" + "$ref": "#/defs/Fetch" }, "artifacts": { "type": "array", "items": { - "type": "object", - "properties": { - "artifact": { - "type": "string" - }, - "from": { - "type": "string" - }, - "seat": { - "type": "string" - }, - "version": { - "type": "string" - } - }, - "required": [ - "artifact" - ] + "$ref": "#/defs/AskArtifact" } }, "publish": { "type": "boolean" }, "toolchain": { - "type": "object", - "properties": { - "language": { - "type": "string" - }, - "version": { - "type": "string" - }, - "recipe": { - "type": "string" - } - }, - "required": [ - "language", - "version", - "recipe" - ] + "$ref": "#/defs/ToolchainUsed" } }, "required": [ @@ -136,7 +104,7 @@ "type": "object", "properties": { "fetch": { - "description": "what the build module fetches: the repository, commit and directory, as the indexer states it" + "$ref": "#/defs/Fetch" }, "levels": { "type": "array", @@ -173,7 +141,7 @@ "type": "object", "properties": { "fetch": { - "description": "what the build module fetches: the repository, commit and directory, as the indexer states it" + "$ref": "#/defs/Fetch" }, "dir": { "type": "string" @@ -223,42 +191,11 @@ "artifacts": { "type": "array", "items": { - "type": "object", - "properties": { - "artifact": { - "type": "string" - }, - "digest": { - "type": "string" - }, - "reference": { - "type": "string" - } - }, - "required": [ - "artifact", - "digest" - ] + "$ref": "#/defs/BuiltArtifact" } }, "toolchain": { - "type": "object", - "properties": { - "language": { - "type": "string" - }, - "version": { - "type": "string" - }, - "recipe": { - "type": "string" - } - }, - "required": [ - "language", - "version", - "recipe" - ] + "$ref": "#/defs/ToolchainUsed" }, "imports": { "type": "array", @@ -281,121 +218,12 @@ "type": "object", "properties": { "fetch": { - "description": "what the build module fetches: the repository, commit and directory, as the indexer states it" + "$ref": "#/defs/Fetch" }, "levels": { "type": "array", "items": { - "type": "object", - "properties": { - "level": { - "type": "string" - }, - "judged": { - "type": "string" - }, - "digest": { - "type": "object", - "properties": { - "level": { - "type": "string" - }, - "packages": { - "type": "array", - "items": { - "type": "object", - "properties": { - "package": { - "type": "string" - }, - "digest": { - "type": "string" - } - }, - "required": [ - "package", - "digest" - ] - } - }, - "beside": { - "type": "array", - "items": { - "type": "string" - } - }, - "without_tests": { - "type": "array", - "items": { - "type": "string" - } - }, - "judged_by": { - "type": "string" - }, - "needs": { - "type": "array", - "items": { - "type": "object", - "properties": { - "package": { - "type": "string" - }, - "needs": { - "type": "array", - "items": { - "type": "string" - } - } - } - } - } - } - }, - "kept": { - "type": "array", - "items": { - "type": "object", - "properties": { - "package": { - "type": "string" - }, - "digest": { - "type": "string" - }, - "tests": { - "type": "integer" - } - } - } - }, - "tests": { - "type": "array", - "items": { - "description": "one test's result" - } - }, - "unmet": { - "type": "array", - "items": { - "type": "object", - "properties": { - "package": { - "type": "string" - }, - "needs": { - "type": "array", - "items": { - "type": "string" - } - } - } - } - } - }, - "required": [ - "level" - ] + "$ref": "#/defs/LevelAnswer" } } }, @@ -442,17 +270,19 @@ }, "started": { "type": "string", - "description": "when (RFC 3339 time)" + "description": "when (RFC 3339 time)", + "format": "date-time" }, "ended": { "type": "string", - "description": "when (RFC 3339 time)" + "description": "when (RFC 3339 time)", + "format": "date-time" }, "reason": { "type": "string" }, "result": { - "description": "what the step answered" + "$ref": "#/defs/StepResult" }, "what": { "type": "string" @@ -462,7 +292,8 @@ }, "phase-at": { "type": "string", - "description": "when (RFC 3339 time)" + "description": "when (RFC 3339 time)", + "format": "date-time" }, "owner": { "type": "string" @@ -496,7 +327,8 @@ }, "at": { "type": "string", - "description": "when (RFC 3339 time)" + "description": "when (RFC 3339 time)", + "format": "date-time" } }, "required": [ @@ -521,7 +353,8 @@ }, "at": { "type": "string", - "description": "when (RFC 3339 time)" + "description": "when (RFC 3339 time)", + "format": "date-time" } }, "required": [ @@ -574,7 +407,8 @@ }, "at": { "type": "string", - "description": "when (RFC 3339 time)" + "description": "when (RFC 3339 time)", + "format": "date-time" } }, "required": [ @@ -583,6 +417,305 @@ "why" ], "description": "how many steps the node runs at once" + }, + "Fetch": { + "type": "object", + "description": "what a build module's fetch tool is asked: the repository and the full commit, the pull request's ref when only its head carries the commit, the trunk commit to merge onto for a merge preview, the module's directory and named paths, the mesh packages to build against, and the sibling repositories placed beside", + "properties": { + "repository": { + "type": "string", + "description": "/" + }, + "commit": { + "type": "string", + "description": "the full commit" + }, + "ref": { + "type": "string", + "description": "the pull request's ref, when only its head carries the commit" + }, + "base": { + "type": "string", + "description": "the trunk commit a merge preview merges onto" + }, + "dir": { + "type": "string", + "description": "the module's directory in the repository (\".\" for its root), with paths" + }, + "paths": { + "type": "array", + "items": { + "type": "string" + }, + "description": "the paths the module names, relative to dir" + }, + "packages": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "the version (a full commit) of each mesh package to build against, by its module path" + }, + "beside": { + "type": "array", + "items": { + "type": "object", + "properties": { + "repository": { + "type": "string" + }, + "commit": { + "type": "string" + } + }, + "required": [ + "repository", + "commit" + ] + }, + "description": "the sibling repositories placed beside the fetched tree" + } + }, + "required": [ + "repository", + "commit" + ] + }, + "ToolchainUsed": { + "type": "object", + "properties": { + "language": { + "type": "string" + }, + "version": { + "type": "string" + }, + "recipe": { + "type": "string" + } + }, + "required": [ + "language", + "version", + "recipe" + ], + "description": "the toolchain a build was made with: the language, the installed version and the build module's recipe" + }, + "AskArtifact": { + "type": "object", + "properties": { + "artifact": { + "type": "string" + }, + "from": { + "type": "string" + }, + "seat": { + "type": "string" + }, + "version": { + "type": "string" + } + }, + "required": [ + "artifact" + ], + "description": "one artifact of a build ask: built from the fetched tree, or copied from an upstream pin" + }, + "BuiltArtifact": { + "type": "object", + "properties": { + "artifact": { + "type": "string" + }, + "digest": { + "type": "string" + }, + "reference": { + "type": "string" + } + }, + "required": [ + "artifact", + "digest" + ], + "description": "one artifact a build made: its digest and the reference it was published under" + }, + "LevelAnswer": { + "type": "object", + "properties": { + "level": { + "type": "string" + }, + "judged": { + "type": "string" + }, + "digest": { + "type": "object", + "properties": { + "level": { + "type": "string" + }, + "packages": { + "type": "array", + "items": { + "type": "object", + "properties": { + "package": { + "type": "string" + }, + "digest": { + "type": "string" + } + }, + "required": [ + "package", + "digest" + ] + } + }, + "beside": { + "type": "array", + "items": { + "type": "string" + } + }, + "without_tests": { + "type": "array", + "items": { + "type": "string" + } + }, + "judged_by": { + "type": "string" + }, + "needs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "package": { + "type": "string" + }, + "needs": { + "type": "array", + "items": { + "type": "string" + } + } + } + } + } + } + }, + "kept": { + "type": "array", + "items": { + "type": "object", + "properties": { + "package": { + "type": "string" + }, + "digest": { + "type": "string" + }, + "tests": { + "type": "integer" + } + } + } + }, + "tests": { + "type": "array", + "items": { + "description": "one test's result" + } + }, + "unmet": { + "type": "array", + "items": { + "type": "object", + "properties": { + "package": { + "type": "string" + }, + "needs": { + "type": "array", + "items": { + "type": "string" + } + } + } + } + } + }, + "required": [ + "level" + ], + "description": "one level of a check ask: the digest's answer, the kept verdicts taken, one test result per test step run, and the packages the node could not test" + }, + "StepResult": { + "type": "object", + "description": "what a step answered, by the kind of ask: a build's artifacts, toolchain, imports and out-of-step modules; a check's fetch and levels; a compose's built, key and verdict; a declined ask's declined, needs and lacks. The fields of the kinds do not meet, so one layout holds the four", + "properties": { + "artifacts": { + "type": "array", + "items": { + "$ref": "#/defs/BuiltArtifact" + } + }, + "toolchain": { + "$ref": "#/defs/ToolchainUsed" + }, + "imports": { + "type": "array", + "items": { + "type": "string" + } + }, + "out-of-step": { + "type": "array", + "items": { + "type": "string" + } + }, + "fetch": { + "$ref": "#/defs/Fetch" + }, + "levels": { + "type": "array", + "items": { + "$ref": "#/defs/LevelAnswer" + } + }, + "built": { + "type": "boolean" + }, + "key": { + "type": "string" + }, + "verdict": { + "description": "the compose-candidate verdict (the composer's own layout)" + }, + "declined": { + "type": "boolean", + "description": "the holder declined the ask: its node lacks what the ask needs" + }, + "needs": { + "type": "array", + "items": { + "type": "string" + }, + "description": "what the declined ask needs" + }, + "lacks": { + "type": "array", + "items": { + "type": "string" + }, + "description": "what the holder's node lacks of it" + } + } } } } diff --git a/contracts/seats/node-build-go/fixtures/states.json b/contracts/seats/node-build-go/fixtures/states.json index 1988c3d4..5193a6af 100644 --- a/contracts/seats/node-build-go/fixtures/states.json +++ b/contracts/seats/node-build-go/fixtures/states.json @@ -59,5 +59,145 @@ ] } } + }, + { + "name": "a check ask with its fetch, siblings and levels", + "of": "accept:check", + "subject": "mesh.seat.node-build-go.accept.check", + "given": { + "v": 1, + "id": "c3d4", + "kind": "check", + "language": "go", + "asker": "mesh-delivery-checker", + "at": "2026-11-05T10:00:00Z", + "check": { + "fetch": { + "repository": "novox/mesh-catalog", + "commit": "0123456789abcdef0123456789abcdef01234567", + "ref": "refs/pull/7/head", + "base": "89abcdef0123456789abcdef0123456789abcdef", + "beside": [ + { + "repository": "novox/mesh-sdk", + "commit": "fedcba9876543210fedcba9876543210fedcba98" + } + ], + "packages": { + "git.novox.be/novox/mesh-sdk/go": "fedcba9876543210fedcba9876543210fedcba98" + } + }, + "levels": [ + "unit", + "integration" + ], + "kept": true + } + } + }, + { + "name": "a finished build step with its artifacts", + "of": "state:steps/.", + "given": { + "v": 1, + "id": "a1b2", + "tool": "build", + "node": "ace", + "state": "passed", + "started": "2026-11-05T10:00:00Z", + "ended": "2026-11-05T10:03:00Z", + "result": { + "artifacts": [ + { + "artifact": "go", + "digest": "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "reference": "container-image-registry/nats/go@sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + } + ], + "toolchain": { + "language": "go", + "version": "1.26.0", + "recipe": "1" + }, + "imports": [ + "git.novox.be/novox/mesh-sdk/go" + ] + } + } + }, + { + "name": "a finished check step with its levels", + "of": "state:steps/.", + "given": { + "v": 1, + "id": "c3d4", + "tool": "check", + "node": "ace", + "state": "passed", + "started": "2026-11-05T10:00:00Z", + "ended": "2026-11-05T10:06:00Z", + "result": { + "fetch": { + "repository": "novox/mesh-catalog", + "commit": "0123456789abcdef0123456789abcdef01234567" + }, + "levels": [ + { + "level": "unit", + "digest": { + "level": "unit", + "packages": [ + { + "package": "./modules/a", + "digest": "sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" + } + ] + }, + "kept": [ + { + "package": "./modules/a", + "digest": "sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "tests": 12 + } + ], + "tests": [ + { + "package": "./modules/b", + "pass": true + } + ], + "unmet": [ + { + "package": "./modules/c", + "needs": [ + "docker" + ] + } + ] + } + ] + } + } + }, + { + "name": "a declined step", + "of": "state:steps/.", + "given": { + "v": 1, + "id": "c3d5", + "tool": "check", + "node": "ace", + "state": "refused", + "started": "2026-11-05T10:00:00Z", + "result": { + "declined": true, + "needs": [ + "docker" + ], + "lacks": [ + "docker" + ] + } + } } ] diff --git a/contracts/ts/seats/nodebuildgo/src/index.ts b/contracts/ts/seats/nodebuildgo/src/index.ts index 24fa95b4..48102965 100644 --- a/contracts/ts/seats/nodebuildgo/src/index.ts +++ b/contracts/ts/seats/nodebuildgo/src/index.ts @@ -102,20 +102,22 @@ export function parseToolchainsByNodeLanguageKey(key: string): { node: string; l return { node, language }; } +export type AskArtifact = buildStep.AskArtifact; export type BuildAnswer = buildStep.BuildAnswer; -export type BuildAnswerArtifactsItem = buildStep.BuildAnswerArtifactsItem; -export type BuildAnswerToolchain = buildStep.BuildAnswerToolchain; +export type BuiltArtifact = buildStep.BuiltArtifact; export type Capacity = buildStep.Capacity; export type CheckAnswer = buildStep.CheckAnswer; -export type CheckAnswerLevelsItem = buildStep.CheckAnswerLevelsItem; -export type CheckAnswerLevelsItemDigest = buildStep.CheckAnswerLevelsItemDigest; -export type CheckAnswerLevelsItemDigestNeedsItem = buildStep.CheckAnswerLevelsItemDigestNeedsItem; -export type CheckAnswerLevelsItemDigestPackagesItem = buildStep.CheckAnswerLevelsItemDigestPackagesItem; -export type CheckAnswerLevelsItemKeptItem = buildStep.CheckAnswerLevelsItemKeptItem; -export type CheckAnswerLevelsItemUnmetItem = buildStep.CheckAnswerLevelsItemUnmetItem; export type ComposeAnswer = buildStep.ComposeAnswer; export type CurrentAnswer = buildStep.CurrentAnswer; export type CurrentInput = buildStep.CurrentInput; +export type Fetch = buildStep.Fetch; +export type FetchBesideItem = buildStep.FetchBesideItem; +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 Pause = buildStep.Pause; export type PauseAnswer = buildStep.PauseAnswer; export type PauseInput = buildStep.PauseInput; @@ -124,11 +126,11 @@ export type ResumeInput = buildStep.ResumeInput; export type Step = buildStep.Step; export type StepAsk = buildStep.StepAsk; export type StepAskBuild = buildStep.StepAskBuild; -export type StepAskBuildArtifactsItem = buildStep.StepAskBuildArtifactsItem; -export type StepAskBuildToolchain = buildStep.StepAskBuildToolchain; export type StepAskCheck = buildStep.StepAskCheck; export type StepAskCompose = buildStep.StepAskCompose; +export type StepResult = buildStep.StepResult; export type Toolchain = buildStep.Toolchain; +export type ToolchainUsed = buildStep.ToolchainUsed; /** is the body of delivery. */ export type DeliveryAccept = StepAsk; diff --git a/contracts/ts/seats/nodebuildgo/src/parts/build-step.ts b/contracts/ts/seats/nodebuildgo/src/parts/build-step.ts index fa5146dc..4ca1eb95 100644 --- a/contracts/ts/seats/nodebuildgo/src/parts/build-step.ts +++ b/contracts/ts/seats/nodebuildgo/src/parts/build-step.ts @@ -8,23 +8,26 @@ export const verbs = { resume: "resume", } as const; -export interface BuildAnswerArtifactsItem { +/** one artifact of a build ask: built from the fetched tree, or copied from an upstream pin */ +export interface AskArtifact { "artifact": string; - "digest": string; - "reference"?: string; -} - -export interface BuildAnswerToolchain { - "language": string; - "recipe": string; - "version": string; + "from"?: string; + "seat"?: string; + "version"?: string; } export interface BuildAnswer { - "artifacts": BuildAnswerArtifactsItem[]; + "artifacts": BuiltArtifact[]; "imports"?: string[]; "out-of-step"?: string[]; - "toolchain"?: BuildAnswerToolchain; + "toolchain"?: ToolchainUsed; +} + +/** one artifact a build made: its digest and the reference it was published under */ +export interface BuiltArtifact { + "artifact": string; + "digest": string; + "reference"?: string; } /** how many steps the node runs at once */ @@ -47,49 +50,9 @@ export interface Capacity { "why": string; } -export interface CheckAnswerLevelsItemDigestNeedsItem { - "needs"?: string[]; - "package"?: string; -} - -export interface CheckAnswerLevelsItemDigestPackagesItem { - "digest": string; - "package": string; -} - -export interface CheckAnswerLevelsItemDigest { - "beside"?: string[]; - "judged_by"?: string; - "level"?: string; - "needs"?: CheckAnswerLevelsItemDigestNeedsItem[]; - "packages"?: CheckAnswerLevelsItemDigestPackagesItem[]; - "without_tests"?: string[]; -} - -export interface CheckAnswerLevelsItemKeptItem { - "digest"?: string; - "package"?: string; - "tests"?: number; -} - -export interface CheckAnswerLevelsItemUnmetItem { - "needs"?: string[]; - "package"?: string; -} - -export interface CheckAnswerLevelsItem { - "digest"?: CheckAnswerLevelsItemDigest; - "judged"?: string; - "kept"?: CheckAnswerLevelsItemKeptItem[]; - "level": string; - "tests"?: unknown[]; - "unmet"?: CheckAnswerLevelsItemUnmetItem[]; -} - export interface CheckAnswer { - /** what the build module fetches: the repository, commit and directory, as the indexer states it */ - "fetch": unknown; - "levels"?: CheckAnswerLevelsItem[]; + "fetch": Fetch; + "levels"?: LevelAnswer[]; } export interface ComposeAnswer { @@ -99,6 +62,71 @@ export interface ComposeAnswer { "verdict"?: unknown; } +export interface FetchBesideItem { + "commit": string; + "repository": string; +} + +/** what a build module's fetch tool is asked: the repository and the full commit, the pull request's ref when only its head carries the commit, the trunk commit to merge onto for a merge preview, the module's directory and named paths, the mesh packages to build against, and the sibling repositories placed beside */ +export interface Fetch { + /** the trunk commit a merge preview merges onto */ + "base"?: string; + /** the sibling repositories placed beside the fetched tree */ + "beside"?: FetchBesideItem[]; + /** the full commit */ + "commit": string; + /** the module's directory in the repository ("." for its root), with paths */ + "dir"?: string; + /** the version (a full commit) of each mesh package to build against, by its module path */ + "packages"?: Record; + /** the paths the module names, relative to dir */ + "paths"?: string[]; + /** the pull request's ref, when only its head carries the commit */ + "ref"?: string; + /** / */ + "repository": string; +} + +export interface LevelAnswerDigestNeedsItem { + "needs"?: string[]; + "package"?: string; +} + +export interface LevelAnswerDigestPackagesItem { + "digest": string; + "package": string; +} + +export interface LevelAnswerDigest { + "beside"?: string[]; + "judged_by"?: string; + "level"?: string; + "needs"?: LevelAnswerDigestNeedsItem[]; + "packages"?: LevelAnswerDigestPackagesItem[]; + "without_tests"?: string[]; +} + +export interface LevelAnswerKeptItem { + "digest"?: string; + "package"?: string; + "tests"?: number; +} + +export interface LevelAnswerUnmetItem { + "needs"?: string[]; + "package"?: string; +} + +/** one level of a check ask: the digest's answer, the kept verdicts taken, one test result per test step run, and the packages the node could not test */ +export interface LevelAnswer { + "digest"?: LevelAnswerDigest; + "judged"?: string; + "kept"?: LevelAnswerKeptItem[]; + "level": string; + "tests"?: unknown[]; + "unmet"?: LevelAnswerUnmetItem[]; +} + /** whether the node takes no new ask */ export interface Pause { /** when (RFC 3339 time) */ @@ -120,8 +148,7 @@ export interface Step { /** when (RFC 3339 time) */ "phase-at"?: string; "reason"?: string; - /** what the step answered */ - "result"?: unknown; + "result"?: StepResult; /** when (RFC 3339 time) */ "started": string; /** running, passed, failed or refused */ @@ -132,33 +159,18 @@ export interface Step { "what"?: string; } -export interface StepAskBuildArtifactsItem { - "artifact": string; - "from"?: string; - "seat"?: string; - "version"?: string; -} - -export interface StepAskBuildToolchain { - "language": string; - "recipe": string; - "version": string; -} - export interface StepAskBuild { - "artifacts": StepAskBuildArtifactsItem[]; - /** what the build module fetches: the repository, commit and directory, as the indexer states it */ - "fetch"?: unknown; + "artifacts": AskArtifact[]; + "fetch"?: Fetch; "fp"?: string; "module": string; "path"?: string; "publish"?: boolean; - "toolchain"?: StepAskBuildToolchain; + "toolchain"?: ToolchainUsed; } export interface StepAskCheck { - /** what the build module fetches: the repository, commit and directory, as the indexer states it */ - "fetch": unknown; + "fetch": Fetch; "kept"?: boolean; "levels": string[]; "packages"?: string[]; @@ -169,8 +181,7 @@ export interface StepAskCheck { export interface StepAskCompose { "dir": string; - /** what the build module fetches: the repository, commit and directory, as the indexer states it */ - "fetch": unknown; + "fetch": Fetch; "package": string; "reader"?: string; /** the compose-candidate request */ @@ -197,6 +208,26 @@ export interface StepAsk { "v"?: number; } +/** what a step answered, by the kind of ask: a build's artifacts, toolchain, imports and out-of-step modules; a check's fetch and levels; a compose's built, key and verdict; a declined ask's declined, needs and lacks. The fields of the kinds do not meet, so one layout holds the four */ +export interface StepResult { + "artifacts"?: BuiltArtifact[]; + "built"?: boolean; + /** the holder declined the ask: its node lacks what the ask needs */ + "declined"?: boolean; + "fetch"?: Fetch; + "imports"?: string[]; + "key"?: string; + /** what the holder's node lacks of it */ + "lacks"?: string[]; + "levels"?: LevelAnswer[]; + /** what the declined ask needs */ + "needs"?: string[]; + "out-of-step"?: string[]; + "toolchain"?: ToolchainUsed; + /** the compose-candidate verdict (the composer's own layout) */ + "verdict"?: unknown; +} + /** the toolchain a node reports */ export interface Toolchain { /** when (RFC 3339 time) */ @@ -209,6 +240,13 @@ export interface Toolchain { "version": string; } +/** the toolchain a build was made with: the language, the installed version and the build module's recipe */ +export interface ToolchainUsed { + "language": string; + "recipe": string; + "version": string; +} + /** is what current takes. */ export interface CurrentInput { } diff --git a/contracts/ts/seats/nodebuildimage/src/index.ts b/contracts/ts/seats/nodebuildimage/src/index.ts index b289e8f7..f0312a18 100644 --- a/contracts/ts/seats/nodebuildimage/src/index.ts +++ b/contracts/ts/seats/nodebuildimage/src/index.ts @@ -102,20 +102,22 @@ export function parseToolchainsByNodeLanguageKey(key: string): { node: string; l return { node, language }; } +export type AskArtifact = buildStep.AskArtifact; export type BuildAnswer = buildStep.BuildAnswer; -export type BuildAnswerArtifactsItem = buildStep.BuildAnswerArtifactsItem; -export type BuildAnswerToolchain = buildStep.BuildAnswerToolchain; +export type BuiltArtifact = buildStep.BuiltArtifact; export type Capacity = buildStep.Capacity; export type CheckAnswer = buildStep.CheckAnswer; -export type CheckAnswerLevelsItem = buildStep.CheckAnswerLevelsItem; -export type CheckAnswerLevelsItemDigest = buildStep.CheckAnswerLevelsItemDigest; -export type CheckAnswerLevelsItemDigestNeedsItem = buildStep.CheckAnswerLevelsItemDigestNeedsItem; -export type CheckAnswerLevelsItemDigestPackagesItem = buildStep.CheckAnswerLevelsItemDigestPackagesItem; -export type CheckAnswerLevelsItemKeptItem = buildStep.CheckAnswerLevelsItemKeptItem; -export type CheckAnswerLevelsItemUnmetItem = buildStep.CheckAnswerLevelsItemUnmetItem; export type ComposeAnswer = buildStep.ComposeAnswer; export type CurrentAnswer = buildStep.CurrentAnswer; export type CurrentInput = buildStep.CurrentInput; +export type Fetch = buildStep.Fetch; +export type FetchBesideItem = buildStep.FetchBesideItem; +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 Pause = buildStep.Pause; export type PauseAnswer = buildStep.PauseAnswer; export type PauseInput = buildStep.PauseInput; @@ -124,11 +126,11 @@ export type ResumeInput = buildStep.ResumeInput; export type Step = buildStep.Step; export type StepAsk = buildStep.StepAsk; export type StepAskBuild = buildStep.StepAskBuild; -export type StepAskBuildArtifactsItem = buildStep.StepAskBuildArtifactsItem; -export type StepAskBuildToolchain = buildStep.StepAskBuildToolchain; export type StepAskCheck = buildStep.StepAskCheck; export type StepAskCompose = buildStep.StepAskCompose; +export type StepResult = buildStep.StepResult; export type Toolchain = buildStep.Toolchain; +export type ToolchainUsed = buildStep.ToolchainUsed; /** is the body of delivery. */ export type DeliveryAccept = StepAsk; diff --git a/contracts/ts/seats/nodebuildimage/src/parts/build-step.ts b/contracts/ts/seats/nodebuildimage/src/parts/build-step.ts index fa5146dc..4ca1eb95 100644 --- a/contracts/ts/seats/nodebuildimage/src/parts/build-step.ts +++ b/contracts/ts/seats/nodebuildimage/src/parts/build-step.ts @@ -8,23 +8,26 @@ export const verbs = { resume: "resume", } as const; -export interface BuildAnswerArtifactsItem { +/** one artifact of a build ask: built from the fetched tree, or copied from an upstream pin */ +export interface AskArtifact { "artifact": string; - "digest": string; - "reference"?: string; -} - -export interface BuildAnswerToolchain { - "language": string; - "recipe": string; - "version": string; + "from"?: string; + "seat"?: string; + "version"?: string; } export interface BuildAnswer { - "artifacts": BuildAnswerArtifactsItem[]; + "artifacts": BuiltArtifact[]; "imports"?: string[]; "out-of-step"?: string[]; - "toolchain"?: BuildAnswerToolchain; + "toolchain"?: ToolchainUsed; +} + +/** one artifact a build made: its digest and the reference it was published under */ +export interface BuiltArtifact { + "artifact": string; + "digest": string; + "reference"?: string; } /** how many steps the node runs at once */ @@ -47,49 +50,9 @@ export interface Capacity { "why": string; } -export interface CheckAnswerLevelsItemDigestNeedsItem { - "needs"?: string[]; - "package"?: string; -} - -export interface CheckAnswerLevelsItemDigestPackagesItem { - "digest": string; - "package": string; -} - -export interface CheckAnswerLevelsItemDigest { - "beside"?: string[]; - "judged_by"?: string; - "level"?: string; - "needs"?: CheckAnswerLevelsItemDigestNeedsItem[]; - "packages"?: CheckAnswerLevelsItemDigestPackagesItem[]; - "without_tests"?: string[]; -} - -export interface CheckAnswerLevelsItemKeptItem { - "digest"?: string; - "package"?: string; - "tests"?: number; -} - -export interface CheckAnswerLevelsItemUnmetItem { - "needs"?: string[]; - "package"?: string; -} - -export interface CheckAnswerLevelsItem { - "digest"?: CheckAnswerLevelsItemDigest; - "judged"?: string; - "kept"?: CheckAnswerLevelsItemKeptItem[]; - "level": string; - "tests"?: unknown[]; - "unmet"?: CheckAnswerLevelsItemUnmetItem[]; -} - export interface CheckAnswer { - /** what the build module fetches: the repository, commit and directory, as the indexer states it */ - "fetch": unknown; - "levels"?: CheckAnswerLevelsItem[]; + "fetch": Fetch; + "levels"?: LevelAnswer[]; } export interface ComposeAnswer { @@ -99,6 +62,71 @@ export interface ComposeAnswer { "verdict"?: unknown; } +export interface FetchBesideItem { + "commit": string; + "repository": string; +} + +/** what a build module's fetch tool is asked: the repository and the full commit, the pull request's ref when only its head carries the commit, the trunk commit to merge onto for a merge preview, the module's directory and named paths, the mesh packages to build against, and the sibling repositories placed beside */ +export interface Fetch { + /** the trunk commit a merge preview merges onto */ + "base"?: string; + /** the sibling repositories placed beside the fetched tree */ + "beside"?: FetchBesideItem[]; + /** the full commit */ + "commit": string; + /** the module's directory in the repository ("." for its root), with paths */ + "dir"?: string; + /** the version (a full commit) of each mesh package to build against, by its module path */ + "packages"?: Record; + /** the paths the module names, relative to dir */ + "paths"?: string[]; + /** the pull request's ref, when only its head carries the commit */ + "ref"?: string; + /** / */ + "repository": string; +} + +export interface LevelAnswerDigestNeedsItem { + "needs"?: string[]; + "package"?: string; +} + +export interface LevelAnswerDigestPackagesItem { + "digest": string; + "package": string; +} + +export interface LevelAnswerDigest { + "beside"?: string[]; + "judged_by"?: string; + "level"?: string; + "needs"?: LevelAnswerDigestNeedsItem[]; + "packages"?: LevelAnswerDigestPackagesItem[]; + "without_tests"?: string[]; +} + +export interface LevelAnswerKeptItem { + "digest"?: string; + "package"?: string; + "tests"?: number; +} + +export interface LevelAnswerUnmetItem { + "needs"?: string[]; + "package"?: string; +} + +/** one level of a check ask: the digest's answer, the kept verdicts taken, one test result per test step run, and the packages the node could not test */ +export interface LevelAnswer { + "digest"?: LevelAnswerDigest; + "judged"?: string; + "kept"?: LevelAnswerKeptItem[]; + "level": string; + "tests"?: unknown[]; + "unmet"?: LevelAnswerUnmetItem[]; +} + /** whether the node takes no new ask */ export interface Pause { /** when (RFC 3339 time) */ @@ -120,8 +148,7 @@ export interface Step { /** when (RFC 3339 time) */ "phase-at"?: string; "reason"?: string; - /** what the step answered */ - "result"?: unknown; + "result"?: StepResult; /** when (RFC 3339 time) */ "started": string; /** running, passed, failed or refused */ @@ -132,33 +159,18 @@ export interface Step { "what"?: string; } -export interface StepAskBuildArtifactsItem { - "artifact": string; - "from"?: string; - "seat"?: string; - "version"?: string; -} - -export interface StepAskBuildToolchain { - "language": string; - "recipe": string; - "version": string; -} - export interface StepAskBuild { - "artifacts": StepAskBuildArtifactsItem[]; - /** what the build module fetches: the repository, commit and directory, as the indexer states it */ - "fetch"?: unknown; + "artifacts": AskArtifact[]; + "fetch"?: Fetch; "fp"?: string; "module": string; "path"?: string; "publish"?: boolean; - "toolchain"?: StepAskBuildToolchain; + "toolchain"?: ToolchainUsed; } export interface StepAskCheck { - /** what the build module fetches: the repository, commit and directory, as the indexer states it */ - "fetch": unknown; + "fetch": Fetch; "kept"?: boolean; "levels": string[]; "packages"?: string[]; @@ -169,8 +181,7 @@ export interface StepAskCheck { export interface StepAskCompose { "dir": string; - /** what the build module fetches: the repository, commit and directory, as the indexer states it */ - "fetch": unknown; + "fetch": Fetch; "package": string; "reader"?: string; /** the compose-candidate request */ @@ -197,6 +208,26 @@ export interface StepAsk { "v"?: number; } +/** what a step answered, by the kind of ask: a build's artifacts, toolchain, imports and out-of-step modules; a check's fetch and levels; a compose's built, key and verdict; a declined ask's declined, needs and lacks. The fields of the kinds do not meet, so one layout holds the four */ +export interface StepResult { + "artifacts"?: BuiltArtifact[]; + "built"?: boolean; + /** the holder declined the ask: its node lacks what the ask needs */ + "declined"?: boolean; + "fetch"?: Fetch; + "imports"?: string[]; + "key"?: string; + /** what the holder's node lacks of it */ + "lacks"?: string[]; + "levels"?: LevelAnswer[]; + /** what the declined ask needs */ + "needs"?: string[]; + "out-of-step"?: string[]; + "toolchain"?: ToolchainUsed; + /** the compose-candidate verdict (the composer's own layout) */ + "verdict"?: unknown; +} + /** the toolchain a node reports */ export interface Toolchain { /** when (RFC 3339 time) */ @@ -209,6 +240,13 @@ export interface Toolchain { "version": string; } +/** the toolchain a build was made with: the language, the installed version and the build module's recipe */ +export interface ToolchainUsed { + "language": string; + "recipe": string; + "version": string; +} + /** is what current takes. */ export interface CurrentInput { } diff --git a/contracts/ts/seats/nodebuildnode/src/index.ts b/contracts/ts/seats/nodebuildnode/src/index.ts index d84ca0ae..99f5963c 100644 --- a/contracts/ts/seats/nodebuildnode/src/index.ts +++ b/contracts/ts/seats/nodebuildnode/src/index.ts @@ -102,20 +102,22 @@ export function parseToolchainsByNodeLanguageKey(key: string): { node: string; l return { node, language }; } +export type AskArtifact = buildStep.AskArtifact; export type BuildAnswer = buildStep.BuildAnswer; -export type BuildAnswerArtifactsItem = buildStep.BuildAnswerArtifactsItem; -export type BuildAnswerToolchain = buildStep.BuildAnswerToolchain; +export type BuiltArtifact = buildStep.BuiltArtifact; export type Capacity = buildStep.Capacity; export type CheckAnswer = buildStep.CheckAnswer; -export type CheckAnswerLevelsItem = buildStep.CheckAnswerLevelsItem; -export type CheckAnswerLevelsItemDigest = buildStep.CheckAnswerLevelsItemDigest; -export type CheckAnswerLevelsItemDigestNeedsItem = buildStep.CheckAnswerLevelsItemDigestNeedsItem; -export type CheckAnswerLevelsItemDigestPackagesItem = buildStep.CheckAnswerLevelsItemDigestPackagesItem; -export type CheckAnswerLevelsItemKeptItem = buildStep.CheckAnswerLevelsItemKeptItem; -export type CheckAnswerLevelsItemUnmetItem = buildStep.CheckAnswerLevelsItemUnmetItem; export type ComposeAnswer = buildStep.ComposeAnswer; export type CurrentAnswer = buildStep.CurrentAnswer; export type CurrentInput = buildStep.CurrentInput; +export type Fetch = buildStep.Fetch; +export type FetchBesideItem = buildStep.FetchBesideItem; +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 Pause = buildStep.Pause; export type PauseAnswer = buildStep.PauseAnswer; export type PauseInput = buildStep.PauseInput; @@ -124,11 +126,11 @@ export type ResumeInput = buildStep.ResumeInput; export type Step = buildStep.Step; export type StepAsk = buildStep.StepAsk; export type StepAskBuild = buildStep.StepAskBuild; -export type StepAskBuildArtifactsItem = buildStep.StepAskBuildArtifactsItem; -export type StepAskBuildToolchain = buildStep.StepAskBuildToolchain; export type StepAskCheck = buildStep.StepAskCheck; export type StepAskCompose = buildStep.StepAskCompose; +export type StepResult = buildStep.StepResult; export type Toolchain = buildStep.Toolchain; +export type ToolchainUsed = buildStep.ToolchainUsed; /** is the body of delivery. */ export type DeliveryAccept = StepAsk; diff --git a/contracts/ts/seats/nodebuildnode/src/parts/build-step.ts b/contracts/ts/seats/nodebuildnode/src/parts/build-step.ts index fa5146dc..4ca1eb95 100644 --- a/contracts/ts/seats/nodebuildnode/src/parts/build-step.ts +++ b/contracts/ts/seats/nodebuildnode/src/parts/build-step.ts @@ -8,23 +8,26 @@ export const verbs = { resume: "resume", } as const; -export interface BuildAnswerArtifactsItem { +/** one artifact of a build ask: built from the fetched tree, or copied from an upstream pin */ +export interface AskArtifact { "artifact": string; - "digest": string; - "reference"?: string; -} - -export interface BuildAnswerToolchain { - "language": string; - "recipe": string; - "version": string; + "from"?: string; + "seat"?: string; + "version"?: string; } export interface BuildAnswer { - "artifacts": BuildAnswerArtifactsItem[]; + "artifacts": BuiltArtifact[]; "imports"?: string[]; "out-of-step"?: string[]; - "toolchain"?: BuildAnswerToolchain; + "toolchain"?: ToolchainUsed; +} + +/** one artifact a build made: its digest and the reference it was published under */ +export interface BuiltArtifact { + "artifact": string; + "digest": string; + "reference"?: string; } /** how many steps the node runs at once */ @@ -47,49 +50,9 @@ export interface Capacity { "why": string; } -export interface CheckAnswerLevelsItemDigestNeedsItem { - "needs"?: string[]; - "package"?: string; -} - -export interface CheckAnswerLevelsItemDigestPackagesItem { - "digest": string; - "package": string; -} - -export interface CheckAnswerLevelsItemDigest { - "beside"?: string[]; - "judged_by"?: string; - "level"?: string; - "needs"?: CheckAnswerLevelsItemDigestNeedsItem[]; - "packages"?: CheckAnswerLevelsItemDigestPackagesItem[]; - "without_tests"?: string[]; -} - -export interface CheckAnswerLevelsItemKeptItem { - "digest"?: string; - "package"?: string; - "tests"?: number; -} - -export interface CheckAnswerLevelsItemUnmetItem { - "needs"?: string[]; - "package"?: string; -} - -export interface CheckAnswerLevelsItem { - "digest"?: CheckAnswerLevelsItemDigest; - "judged"?: string; - "kept"?: CheckAnswerLevelsItemKeptItem[]; - "level": string; - "tests"?: unknown[]; - "unmet"?: CheckAnswerLevelsItemUnmetItem[]; -} - export interface CheckAnswer { - /** what the build module fetches: the repository, commit and directory, as the indexer states it */ - "fetch": unknown; - "levels"?: CheckAnswerLevelsItem[]; + "fetch": Fetch; + "levels"?: LevelAnswer[]; } export interface ComposeAnswer { @@ -99,6 +62,71 @@ export interface ComposeAnswer { "verdict"?: unknown; } +export interface FetchBesideItem { + "commit": string; + "repository": string; +} + +/** what a build module's fetch tool is asked: the repository and the full commit, the pull request's ref when only its head carries the commit, the trunk commit to merge onto for a merge preview, the module's directory and named paths, the mesh packages to build against, and the sibling repositories placed beside */ +export interface Fetch { + /** the trunk commit a merge preview merges onto */ + "base"?: string; + /** the sibling repositories placed beside the fetched tree */ + "beside"?: FetchBesideItem[]; + /** the full commit */ + "commit": string; + /** the module's directory in the repository ("." for its root), with paths */ + "dir"?: string; + /** the version (a full commit) of each mesh package to build against, by its module path */ + "packages"?: Record; + /** the paths the module names, relative to dir */ + "paths"?: string[]; + /** the pull request's ref, when only its head carries the commit */ + "ref"?: string; + /** / */ + "repository": string; +} + +export interface LevelAnswerDigestNeedsItem { + "needs"?: string[]; + "package"?: string; +} + +export interface LevelAnswerDigestPackagesItem { + "digest": string; + "package": string; +} + +export interface LevelAnswerDigest { + "beside"?: string[]; + "judged_by"?: string; + "level"?: string; + "needs"?: LevelAnswerDigestNeedsItem[]; + "packages"?: LevelAnswerDigestPackagesItem[]; + "without_tests"?: string[]; +} + +export interface LevelAnswerKeptItem { + "digest"?: string; + "package"?: string; + "tests"?: number; +} + +export interface LevelAnswerUnmetItem { + "needs"?: string[]; + "package"?: string; +} + +/** one level of a check ask: the digest's answer, the kept verdicts taken, one test result per test step run, and the packages the node could not test */ +export interface LevelAnswer { + "digest"?: LevelAnswerDigest; + "judged"?: string; + "kept"?: LevelAnswerKeptItem[]; + "level": string; + "tests"?: unknown[]; + "unmet"?: LevelAnswerUnmetItem[]; +} + /** whether the node takes no new ask */ export interface Pause { /** when (RFC 3339 time) */ @@ -120,8 +148,7 @@ export interface Step { /** when (RFC 3339 time) */ "phase-at"?: string; "reason"?: string; - /** what the step answered */ - "result"?: unknown; + "result"?: StepResult; /** when (RFC 3339 time) */ "started": string; /** running, passed, failed or refused */ @@ -132,33 +159,18 @@ export interface Step { "what"?: string; } -export interface StepAskBuildArtifactsItem { - "artifact": string; - "from"?: string; - "seat"?: string; - "version"?: string; -} - -export interface StepAskBuildToolchain { - "language": string; - "recipe": string; - "version": string; -} - export interface StepAskBuild { - "artifacts": StepAskBuildArtifactsItem[]; - /** what the build module fetches: the repository, commit and directory, as the indexer states it */ - "fetch"?: unknown; + "artifacts": AskArtifact[]; + "fetch"?: Fetch; "fp"?: string; "module": string; "path"?: string; "publish"?: boolean; - "toolchain"?: StepAskBuildToolchain; + "toolchain"?: ToolchainUsed; } export interface StepAskCheck { - /** what the build module fetches: the repository, commit and directory, as the indexer states it */ - "fetch": unknown; + "fetch": Fetch; "kept"?: boolean; "levels": string[]; "packages"?: string[]; @@ -169,8 +181,7 @@ export interface StepAskCheck { export interface StepAskCompose { "dir": string; - /** what the build module fetches: the repository, commit and directory, as the indexer states it */ - "fetch": unknown; + "fetch": Fetch; "package": string; "reader"?: string; /** the compose-candidate request */ @@ -197,6 +208,26 @@ export interface StepAsk { "v"?: number; } +/** what a step answered, by the kind of ask: a build's artifacts, toolchain, imports and out-of-step modules; a check's fetch and levels; a compose's built, key and verdict; a declined ask's declined, needs and lacks. The fields of the kinds do not meet, so one layout holds the four */ +export interface StepResult { + "artifacts"?: BuiltArtifact[]; + "built"?: boolean; + /** the holder declined the ask: its node lacks what the ask needs */ + "declined"?: boolean; + "fetch"?: Fetch; + "imports"?: string[]; + "key"?: string; + /** what the holder's node lacks of it */ + "lacks"?: string[]; + "levels"?: LevelAnswer[]; + /** what the declined ask needs */ + "needs"?: string[]; + "out-of-step"?: string[]; + "toolchain"?: ToolchainUsed; + /** the compose-candidate verdict (the composer's own layout) */ + "verdict"?: unknown; +} + /** the toolchain a node reports */ export interface Toolchain { /** when (RFC 3339 time) */ @@ -209,6 +240,13 @@ export interface Toolchain { "version": string; } +/** the toolchain a build was made with: the language, the installed version and the build module's recipe */ +export interface ToolchainUsed { + "language": string; + "recipe": string; + "version": string; +} + /** is what current takes. */ export interface CurrentInput { }