diff --git a/go/delivery/history_records.go b/go/delivery/history_records.go index 8f8f23a..fd4b5bd 100644 --- a/go/delivery/history_records.go +++ b/go/delivery/history_records.go @@ -179,6 +179,10 @@ type BuildLogEntry struct { // sorted and each once, as the build module answered them (BuildAnswer.Imports; novox/hq ADR 0593 ยง2): the indexer // keeps them on the module (KeptInputs2.Imports) when the build's fingerprint is the module's. Imports []string `json:"imports,omitempty"` + // OutOfStep are, at a build's end, the generated files its test step found out of step with what their generator + // writes, as the build module answered them (its test step's `out-of-step`): the indexer raises a finding naming them + // for a trunk build, and only a clean build of the same module clears it. A start or a narration names none. + OutOfStep []string `json:"out-of-step,omitempty"` // Line is a narration's words, Why what it narrates (asked, waiting, stored, refused): a build.said entry's alone. Line string `json:"line,omitempty"` Why string `json:"why,omitempty"` @@ -225,8 +229,8 @@ func EncodeBuildLogEntry(e BuildLogEntry) ([]byte, error) { switch { case e.Module == "" || e.FP == "" || e.At.IsZero() || e.Line == "": return nil, fmt.Errorf("delivery: a build's narration names its module, fingerprint, line and time") - case e.Outcome != "" || len(e.Made) > 0 || e.Manifest != "" || len(e.Against) > 0 || len(e.Imports) > 0: - return nil, fmt.Errorf("delivery: a build's narration names no outcome, manifest, base, artifact or import") + case e.Outcome != "" || len(e.Made) > 0 || e.Manifest != "" || len(e.Against) > 0 || len(e.Imports) > 0 || len(e.OutOfStep) > 0: + return nil, fmt.Errorf("delivery: a build's narration names no outcome, manifest, base, artifact, import or file out of step") } return json.Marshal(e) case e.Event != BuildStartedEvent && e.Event != BuildEndedEvent: @@ -237,8 +241,9 @@ func EncodeBuildLogEntry(e BuildLogEntry) ([]byte, error) { return nil, fmt.Errorf("delivery: a build log entry names its module, fingerprint, repository, commit, node and time") case e.Event == BuildEndedEvent && e.Outcome == "": return nil, fmt.Errorf("delivery: a build's end names its outcome") - case e.Event == BuildStartedEvent && (e.Outcome != "" || len(e.Made) > 0 || e.Manifest != "" || len(e.Against) > 0 || len(e.Imports) > 0): - return nil, fmt.Errorf("delivery: a build's start names no outcome, manifest, base, artifact or import") + case e.Event == BuildStartedEvent && (e.Outcome != "" || len(e.Made) > 0 || e.Manifest != "" || len(e.Against) > 0 || len(e.Imports) > 0 || + len(e.OutOfStep) > 0): + return nil, fmt.Errorf("delivery: a build's start names no outcome, manifest, base, artifact, import or file out of step") } if err := CheckImports(e.Imports); err != nil { return nil, err diff --git a/go/delivery/published_packages_test.go b/go/delivery/published_packages_test.go index bd44b58..773f022 100644 --- a/go/delivery/published_packages_test.go +++ b/go/delivery/published_packages_test.go @@ -57,17 +57,23 @@ func TestPublishedPackagesAndImportsRoundTripAndRefuse(t *testing.T) { } imports := []string{sdk, sdk + "/announce"} + outOfStep := []string{"go/seats/meshbroker/contract.go", "ts/seats/meshbroker/src/index.ts"} end := BuildLogEntry{Event: BuildEndedEvent, Module: "netcheck", FP: "src2:x", Repository: "novox/mesh-catalog", Commit: commit, - Node: "ace", At: good.At, Outcome: "done", Imports: imports} + Node: "ace", At: good.At, Outcome: "done", Imports: imports, OutOfStep: outOfStep} raw, err = EncodeBuildLogEntry(end) if err != nil { t.Fatal(err) } - if e, err := DecodeBuildLogEntry(raw); err != nil || !reflect.DeepEqual(e.Imports, imports) { - t.Fatalf("build end round trip: %v, %v", err, e.Imports) + if e, err := DecodeBuildLogEntry(raw); err != nil || !reflect.DeepEqual(e.Imports, imports) || !reflect.DeepEqual(e.OutOfStep, outOfStep) || + !strings.Contains(string(raw), `"out-of-step":["go/seats/meshbroker/contract.go",`) { + t.Fatalf("build end round trip: %v, %v, %v in %s", err, e.Imports, e.OutOfStep, raw) } start := end - start.Event, start.Outcome = BuildStartedEvent, "" + start.Event, start.Outcome, start.Imports = BuildStartedEvent, "", nil + if _, err := EncodeBuildLogEntry(start); err == nil { + t.Error("a build's start with files out of step encoded") + } + start.Imports, start.OutOfStep = imports, nil if _, err := EncodeBuildLogEntry(start); err == nil { t.Error("a build's start with imports encoded") } @@ -87,6 +93,7 @@ func TestPublishedPackagesAndImportsRoundTripAndRefuse(t *testing.T) { for name, mutate := range map[string]func(e *BuildLogEntry){ "a narration with no line": func(e *BuildLogEntry) { e.Line = "" }, "a narration with an outcome": func(e *BuildLogEntry) { e.Outcome = "done" }, + "a narration out of step": func(e *BuildLogEntry) { e.OutOfStep = outOfStep }, "an end with a line": func(e *BuildLogEntry) { e.Event, e.Outcome, e.Node, e.Repository, e.Commit = BuildEndedEvent, "done", "ace", "novox/mesh-catalog", commit },