Record the inputs of a build's source fingerprint in its build record (issue 1215)
This commit is contained in:
@@ -5,6 +5,7 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"git.novox.be/novox/mesh-sdk/go/delivery"
|
||||
"github.com/novox/mesh-controller/internal/chain"
|
||||
)
|
||||
|
||||
@@ -51,6 +52,8 @@ type Build struct {
|
||||
// SourceFingerprint is what the build was made from, hashed, as its builder said it (novox/hq
|
||||
// issue 280); empty from a builder that predates it, or where the source does not pin the build.
|
||||
SourceFingerprint string
|
||||
// SourceInputs are what it was computed from (novox/hq ADR 0437 §5); nil from a build recorded before they were.
|
||||
SourceInputs *delivery.SourceInputs
|
||||
// Failed is the builder's own words, empty when it worked.
|
||||
Failed string
|
||||
Made []Artifact
|
||||
|
||||
@@ -23,7 +23,7 @@ import (
|
||||
// toChainBuild is a build as the bucket keeps it.
|
||||
func toChainBuild(b Build) chain.Build {
|
||||
c := chain.Build{ID: b.ID, Repository: b.Repository, Ref: b.Ref, Module: b.Module, Commit: b.Commit, On: b.On,
|
||||
Path: b.Path, Against: b.Against, Mirrored: b.Mirrored, SourceFingerprint: b.SourceFingerprint,
|
||||
Path: b.Path, Against: b.Against, Mirrored: b.Mirrored, SourceFingerprint: b.SourceFingerprint, SourceInputs: b.SourceInputs,
|
||||
ManifestDigest: b.ManifestDigest, Failed: b.Failed, Asked: b.Asked.UTC(), At: b.At.UTC(), ReuseKey: b.ReuseKey, Published: b.Published}
|
||||
if len(b.Manifest) > 0 {
|
||||
c.Manifest = json.RawMessage(b.Manifest)
|
||||
@@ -46,7 +46,7 @@ func toChainBuild(b Build) chain.Build {
|
||||
// fromChainBuild is a build as the mesh reads it.
|
||||
func fromChainBuild(c chain.Build) Build {
|
||||
b := Build{ID: c.ID, Repository: c.Repository, Ref: c.Ref, Module: c.Module, Commit: c.Commit, On: c.On, Path: c.Path,
|
||||
Manifest: []byte(c.Manifest), ManifestDigest: c.ManifestDigest, Against: c.Against, Mirrored: c.Mirrored, SourceFingerprint: c.SourceFingerprint,
|
||||
Manifest: []byte(c.Manifest), ManifestDigest: c.ManifestDigest, Against: c.Against, Mirrored: c.Mirrored, SourceFingerprint: c.SourceFingerprint, SourceInputs: c.SourceInputs,
|
||||
Failed: c.Failed, Asked: c.Asked, At: c.At, ReuseKey: c.ReuseKey, Published: c.Published}
|
||||
if len(b.Manifest) == 0 {
|
||||
b.Manifest = nil
|
||||
|
||||
@@ -5,9 +5,11 @@ import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"git.novox.be/novox/mesh-sdk/go/delivery"
|
||||
"github.com/nats-io/nats.go"
|
||||
|
||||
"github.com/novox/mesh-controller/internal/chain"
|
||||
@@ -129,3 +131,55 @@ func TestTheBusBeingAwayIsNotNowLikeTheStoreBeingAway(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 1215/AC1 and AC4: the inputs of a build's fingerprint are kept in the build's record, through the bucket's bytes, unchanged.
|
||||
func TestABuildKeepsTheInputsOfItsSourceFingerprint(t *testing.T) {
|
||||
in := &delivery.SourceInputs{Module: "notes", Tree: "t1", Bases: []string{"r/b@sha256:aa"},
|
||||
Contexts: map[string]string{"server": "narrow:ff"}, Toolchains: map[string]string{"code": "go sha256:cc 0123"}}
|
||||
fp, _ := delivery.SourceFingerprint(*in)
|
||||
b := Build{ID: "build-1", Module: "notes", Commit: "c1", SourceFingerprint: fp, SourceInputs: in}
|
||||
raw, err := json.Marshal(toChainBuild(b))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
var back chain.Build
|
||||
if err := json.Unmarshal(raw, &back); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
got := fromChainBuild(back)
|
||||
if !reflect.DeepEqual(got.SourceInputs, in) {
|
||||
t.Fatalf("the inputs came back as %+v, not %+v", got.SourceInputs, in)
|
||||
}
|
||||
if again, _ := delivery.SourceFingerprint(*got.SourceInputs); again != got.SourceFingerprint {
|
||||
t.Errorf("the inputs read back give %q, the record says %q", again, got.SourceFingerprint)
|
||||
}
|
||||
}
|
||||
|
||||
// 1215/AC3: a build with no fingerprint keeps its inputs, so the reason is visible.
|
||||
func TestABuildWithNoFingerprintKeepsItsInputs(t *testing.T) {
|
||||
in := &delivery.SourceInputs{Module: "notes", Tree: "t1", Unpinned: "it resolves packages when built"}
|
||||
raw, _ := json.Marshal(toChainBuild(Build{ID: "build-1", Module: "notes", SourceInputs: in}))
|
||||
var back chain.Build
|
||||
if err := json.Unmarshal(raw, &back); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if got := fromChainBuild(back); got.SourceFingerprint != "" || !reflect.DeepEqual(got.SourceInputs, in) {
|
||||
t.Errorf("read back as %q with %+v", got.SourceFingerprint, got.SourceInputs)
|
||||
}
|
||||
}
|
||||
|
||||
// 1215/AC2: a record written before the inputs were kept reads as before, with none and no error.
|
||||
func TestABuildRecordFromBeforeTheInputsReadsAsBefore(t *testing.T) {
|
||||
var back chain.Build
|
||||
old := `{"id":"build-1","module":"notes","commit":"c1","source-fingerprint":"src1:aa","reuse-key":"rk"}`
|
||||
if err := json.Unmarshal([]byte(old), &back); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
got := fromChainBuild(back)
|
||||
if got.SourceInputs != nil || got.SourceFingerprint != "src1:aa" || got.ReuseKey != "rk" {
|
||||
t.Errorf("an old record reads as %+v", got)
|
||||
}
|
||||
if raw, _ := json.Marshal(toChainBuild(got)); strings.Contains(string(raw), "source-inputs") {
|
||||
t.Errorf("an old record is written with inputs: %s", raw)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user