issue 1025: a context naming the module's own repository is its own build source (ADR 0420 §4)
This commit is contained in:
@@ -1267,6 +1267,8 @@ func graphOfFacts(f snapshot.Facts) ([]inventory.Entry, map[string][]inventory.R
|
|||||||
read[mod.Name] = append(read[mod.Name], inventory.ReadRepository{Own: true, Paths: s.Paths})
|
read[mod.Name] = append(read[mod.Name], inventory.ReadRepository{Own: true, Paths: s.Paths})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// A context naming the module's own repository is its own build source (novox/hq ADR 0420 §4).
|
||||||
|
read[mod.Name] = inventory.OwnRepositoryAsOwn(read[mod.Name], mod.Repository)
|
||||||
}
|
}
|
||||||
var edges []inventory.Edge
|
var edges []inventory.Edge
|
||||||
for _, e := range f.Edges {
|
for _, e := range f.Edges {
|
||||||
|
|||||||
@@ -680,3 +680,35 @@ func TestAPlanSaysWhyEachModuleIsInIt(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// **A context naming the module's own repository is the module's own build source** (novox/hq ADR 0420 §4,
|
||||||
|
// issue 1025). A module registered from the controller's repository whose image compiles cmd/x through a
|
||||||
|
// context naming that same repository is moved by a change to the program, and by none outside its closure.
|
||||||
|
func TestAContextNamingTheModulesOwnRepositoryIsItsOwnBuildSource(t *testing.T) {
|
||||||
|
const controllerRepo = "http://forge.internal:20000/novox/mesh-controller.git"
|
||||||
|
entries := []inventory.Entry{fromRepo("mover", controllerRepo, "modules/mover")}
|
||||||
|
said := []inventory.ReadRepository{
|
||||||
|
{Repository: "novox/mesh-controller", Ref: "main", Paths: []string{"go.mod", "cmd/x/", "internal/y/"}},
|
||||||
|
{Own: true, Paths: []string{"modules/mover/module.json"}},
|
||||||
|
}
|
||||||
|
read := map[string][]inventory.ReadRepository{"mover": inventory.OwnRepositoryAsOwn(said, controllerRepo)}
|
||||||
|
for _, c := range []struct {
|
||||||
|
what string
|
||||||
|
paths []string
|
||||||
|
want string
|
||||||
|
}{
|
||||||
|
{"the program its image compiles", []string{"cmd/x/main.go"}, "mover"},
|
||||||
|
{"a package the program imports", []string{"internal/y/y.go"}, "mover"},
|
||||||
|
{"its own manifest", []string{"modules/mover/module.json"}, "mover"},
|
||||||
|
{"a file outside its closure", []string{"cmd/other/main.go"}, ""},
|
||||||
|
} {
|
||||||
|
if _, got := planMerge(t, "mesh-controller", c.paths, entries, read, nil); got != c.want {
|
||||||
|
t.Errorf("%s: planned %q, wanted %q", c.what, got, c.want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// A context of another repository stays a context read, and a context of this one that said no paths too.
|
||||||
|
other := []inventory.ReadRepository{{Repository: "novox/mesh-catalog", Paths: []string{"a/"}}, {Repository: "novox/mesh-controller"}}
|
||||||
|
if got := inventory.OwnRepositoryAsOwn(other, controllerRepo); len(got) != 2 || got[0].Own || got[1].Own {
|
||||||
|
t.Errorf("a context that is not this repository's with paths became its own: %+v", got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -428,7 +428,8 @@ func (i *Inventory) ReadRepositories(ctx context.Context) (map[string][]ReadRepo
|
|||||||
}
|
}
|
||||||
|
|
||||||
rows, err := i.store.Pool().Query(ctx,
|
rows, err := i.store.Pool().Query(ctx,
|
||||||
`select distinct on (module) module, built_contexts, build_sources, coalesce(asked, at)
|
`select distinct on (module) module, built_contexts, build_sources, coalesce(asked, at),
|
||||||
|
(select source from module where module.name = build.module)
|
||||||
from build
|
from build
|
||||||
where module is not null and module <> '' and failed = ''
|
where module is not null and module <> '' and failed = ''
|
||||||
order by module, `+newestRequestFirst)
|
order by module, `+newestRequestFirst)
|
||||||
@@ -442,7 +443,8 @@ func (i *Inventory) ReadRepositories(ctx context.Context) (map[string][]ReadRepo
|
|||||||
var module string
|
var module string
|
||||||
var raw, rawSources []byte
|
var raw, rawSources []byte
|
||||||
var built time.Time
|
var built time.Time
|
||||||
if err := rows.Scan(&module, &raw, &rawSources, &built); err != nil {
|
var own *string
|
||||||
|
if err := rows.Scan(&module, &raw, &rawSources, &built, &own); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
var of []ReadRepository
|
var of []ReadRepository
|
||||||
@@ -462,6 +464,9 @@ func (i *Inventory) ReadRepositories(ctx context.Context) (map[string][]ReadRepo
|
|||||||
sources, whole = nil, "a newer build of it failed"
|
sources, whole = nil, "a newer build of it failed"
|
||||||
}
|
}
|
||||||
of = WithBuildSources(of, sources)
|
of = WithBuildSources(of, sources)
|
||||||
|
if own != nil {
|
||||||
|
of = OwnRepositoryAsOwn(of, *own)
|
||||||
|
}
|
||||||
if whole != "" {
|
if whole != "" {
|
||||||
of = append(of, ReadRepository{Own: true, Whole: whole})
|
of = append(of, ReadRepository{Own: true, Whole: whole})
|
||||||
}
|
}
|
||||||
@@ -498,6 +503,57 @@ func WithBuildSources(read []ReadRepository, sources []BuildSource) []ReadReposi
|
|||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// OwnRepositoryAsOwn reads a context that names the module's own registered repository, with the paths its
|
||||||
|
// build read there, as the module's own build source (novox/hq ADR 0420 §4): a change to the program it
|
||||||
|
// compiles moves the module, as one in its own directory does. A context of that repository that said
|
||||||
|
// no paths stays a context read, whole.
|
||||||
|
func OwnRepositoryAsOwn(read []ReadRepository, repository string) []ReadRepository {
|
||||||
|
if repository == "" {
|
||||||
|
return read
|
||||||
|
}
|
||||||
|
out := make([]ReadRepository, 0, len(read))
|
||||||
|
var moved []ReadRepository
|
||||||
|
for _, r := range read {
|
||||||
|
if !r.Own && len(r.Paths) > 0 && r.Repository != "" && namesRepository(repository, r.Repository) {
|
||||||
|
moved = append(moved, r)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
out = append(out, r)
|
||||||
|
}
|
||||||
|
if len(moved) == 0 {
|
||||||
|
return read
|
||||||
|
}
|
||||||
|
// One entry of its own: ownSource reads the first that has paths.
|
||||||
|
at := -1
|
||||||
|
for k := range out {
|
||||||
|
if out[k].Own && len(out[k].Paths) > 0 {
|
||||||
|
at = k
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if at < 0 {
|
||||||
|
out = append(out, ReadRepository{Own: true})
|
||||||
|
at = len(out) - 1
|
||||||
|
}
|
||||||
|
for _, r := range moved {
|
||||||
|
out[at].Paths = append(append([]string(nil), out[at].Paths...), r.Paths...)
|
||||||
|
if out[at].Ref == "" {
|
||||||
|
out[at].Ref = r.Ref
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
// namesRepository is whether a context's repository, as owner/name, is the registered one, which may be
|
||||||
|
// spelled as the URL it was cloned from.
|
||||||
|
func namesRepository(registered, named string) bool {
|
||||||
|
trim := func(s string) string {
|
||||||
|
return strings.TrimSuffix(strings.TrimRight(strings.ToLower(strings.TrimSpace(s)), "/"), ".git")
|
||||||
|
}
|
||||||
|
reg, name := trim(registered), trim(named)
|
||||||
|
return reg == name || strings.HasSuffix(reg, "/"+name)
|
||||||
|
}
|
||||||
|
|
||||||
// manifestOrNil keeps the difference between "declared nothing" and "predates this being kept".
|
// manifestOrNil keeps the difference between "declared nothing" and "predates this being kept".
|
||||||
//
|
//
|
||||||
// A build recorded before the mesh kept manifests has no manifest, and that is not the same as one
|
// A build recorded before the mesh kept manifests has no manifest, and that is not the same as one
|
||||||
|
|||||||
Reference in New Issue
Block a user