mesh-delivery-contracts, sdk buildstep: the check job carries the toolchain the checker agreed (ADR 0584 clause 2) and the node names, so a node on another toolchain declines the check; the part had neither, the sdk's CheckJob lacked the toolchain (B2g; issue 1966)
Claude-Session: https://claude.ai/code/session_01NcbgfFSnn24M3GcqttoU7i
This commit is contained in:
@@ -361,13 +361,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.
|
||||
|
||||
@@ -39,7 +39,7 @@ 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},
|
||||
|
||||
@@ -361,13 +361,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.
|
||||
|
||||
@@ -361,13 +361,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.
|
||||
|
||||
@@ -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": [
|
||||
|
||||
@@ -91,7 +91,16 @@
|
||||
"unit",
|
||||
"integration"
|
||||
],
|
||||
"kept": true
|
||||
"kept": true,
|
||||
"toolchain": {
|
||||
"language": "go",
|
||||
"version": "1.26.0",
|
||||
"recipe": "2"
|
||||
},
|
||||
"node-names": [
|
||||
"ace",
|
||||
"g14"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -173,10 +173,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 {
|
||||
|
||||
@@ -173,10 +173,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 {
|
||||
|
||||
@@ -173,10 +173,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 {
|
||||
|
||||
@@ -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] {
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user