Draw a plan's order per module from the graph and the manifests' change, and read no after: line (issue 977, part B, ADR 0419)
This commit is contained in:
@@ -5,7 +5,6 @@ import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"regexp"
|
||||
"slices"
|
||||
"sort"
|
||||
"strconv"
|
||||
@@ -71,9 +70,9 @@ const batchLateAfter = time.Minute
|
||||
// made before the controller began keeping merges (owedLate).
|
||||
const mergeGrace = 10 * time.Minute
|
||||
|
||||
// edgeGroupOrder is a delivery group's order made an edge of a walk's tiers (ADR 0276 decision 5): the
|
||||
// modules of the member after depend on the modules of the member before, and are gated on them.
|
||||
const edgeGroupOrder = "group-order"
|
||||
// edgeChangeOrder is the order the rules of a plan draw among its modules (novox/hq ADR 0419 clauses 3 and 4, delivery_edges.go)
|
||||
// made an edge of its tiers: the module after depends on the module before, and is gated on it.
|
||||
const edgeChangeOrder = "change-order"
|
||||
|
||||
// mergeWindowOf is the window and its maximum, from the controller's settings; a value unreadable is its
|
||||
// default, and said.
|
||||
@@ -1039,9 +1038,13 @@ func planBatch(ctx context.Context, open *stores, batch *inventory.Plan, carry [
|
||||
}
|
||||
}
|
||||
sort.Strings(also)
|
||||
ordered := groupOrderEdges(members, entries, read, edges)
|
||||
ordered, err := changeOrderEdges(ctx, members, moved, edges)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var withheld []string
|
||||
plan := planOfMoves(moved, append(append([]inventory.Edge{}, edges...), ordered...))
|
||||
placedBy(&plan, ordered)
|
||||
// **Withheld, a stopped merge's modules** (novox/hq ADR 0299): a module is built at its branch, which holds the
|
||||
// merge a stop left out of the walk these merges were walked again from — built here only as a dependent, it
|
||||
// would deliver that merge. One a merge of this batch moves is built: that merge carries the stopped change,
|
||||
@@ -1094,7 +1097,14 @@ func planBatch(ctx context.Context, open *stores, batch *inventory.Plan, carry [
|
||||
}
|
||||
var tiers []string
|
||||
for i, t := range plan.Tiers {
|
||||
tiers = append(tiers, fmt.Sprintf("%d: %s", i, strings.Join(t, ", ")))
|
||||
var names []string
|
||||
for _, n := range t {
|
||||
if m := plan.Modules[n]; m != nil && m.Placed != "" {
|
||||
n += " " + m.Placed
|
||||
}
|
||||
names = append(names, n)
|
||||
}
|
||||
tiers = append(tiers, fmt.Sprintf("%d: %s", i, strings.Join(names, ", ")))
|
||||
}
|
||||
var answers []string
|
||||
for _, n := range named {
|
||||
@@ -1122,6 +1132,23 @@ func planBatch(ctx context.Context, open *stores, batch *inventory.Plan, carry [
|
||||
return nil
|
||||
}
|
||||
|
||||
// placedBy writes on each module of a plan the edges of its order that put it after another module of the plan, with the
|
||||
// rule that drew each (novox/hq ADR 0419 clause 5).
|
||||
func placedBy(plan *inventory.Plan, ordered []inventory.Edge) {
|
||||
for _, e := range ordered {
|
||||
m, in := plan.Modules[e.From]
|
||||
if _, before := plan.Modules[e.To]; !in || !before {
|
||||
continue
|
||||
}
|
||||
said := "after " + e.To + " (" + e.Why + ")"
|
||||
if m.Placed == "" {
|
||||
m.Placed = said
|
||||
} else if !strings.Contains(m.Placed, said) {
|
||||
m.Placed += "; " + said
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// unchangedSaid names the modules a walk says matched what runs, for its note.
|
||||
func unchangedSaid(unchanged map[string]string) string {
|
||||
names := make([]string, 0, len(unchanged))
|
||||
@@ -1310,73 +1337,30 @@ type batchMember struct {
|
||||
moved []string
|
||||
}
|
||||
|
||||
// afterLines are the `after: <repository>` lines of a pull request's description, as mesh-delivery reads them.
|
||||
var afterLines = regexp.MustCompile(`(?im)^\s*after:\s*([A-Za-z0-9_.\-/]+)\s*$`)
|
||||
|
||||
// groupOrderEdges is the order of every delivery group among a batch's merges as edges of its walk's tiers
|
||||
// (ADR 0276 decision 5, ADR 0249 unchanged): merges of two repositories or more from one head branch name are
|
||||
// a group; each pair its order rules give puts the modules of the member after in a later tier than the
|
||||
// member before's. A pair in a contradiction orders nothing: its group was refused before it merged.
|
||||
func groupOrderEdges(members []batchMember, entries []inventory.Entry, read map[string][]inventory.ReadRepository,
|
||||
edges []inventory.Edge) []inventory.Edge {
|
||||
byHead := map[string][]batchMember{}
|
||||
// changeOrderEdges is the order of a batch's moved modules as edges of its plan's tiers (novox/hq ADR 0419): drawn
|
||||
// per module from the module graph and from what the merges say of the manifests they touch (delivery_edges.go),
|
||||
// whatever repository the merges are in and whether or not they form a delivery group. No `after:` line is read.
|
||||
// A cycle is said, never lost: the plan puts the modules left in its last tier, and the composed check fails the
|
||||
// group before it merges.
|
||||
func changeOrderEdges(ctx context.Context, members []batchMember, moved []string, edges []inventory.Edge) ([]inventory.Edge, error) {
|
||||
var sources []changeSource
|
||||
for _, m := range members {
|
||||
if m.merge.Head != "" {
|
||||
byHead[m.merge.Head] = append(byHead[m.merge.Head], m)
|
||||
}
|
||||
sources = append(sources, changeSource{Owner: m.merge.Owner, Repo: m.merge.Repo, New: m.merge.Commit,
|
||||
Paths: m.merge.Paths, Truncated: m.merge.PathsTruncated, Removed: m.merge.Removed})
|
||||
}
|
||||
var out []inventory.Edge
|
||||
heads := make([]string, 0, len(byHead))
|
||||
for h := range byHead {
|
||||
heads = append(heads, h)
|
||||
changes, err := changesOf(ctx, sources)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("what the merges say of their manifests cannot be read, so the order of their modules "+
|
||||
"cannot be drawn: %w", err)
|
||||
}
|
||||
sort.Strings(heads)
|
||||
for _, h := range heads {
|
||||
group := byHead[h]
|
||||
repos := map[string]bool{}
|
||||
for _, m := range group {
|
||||
repos[strings.ToLower(m.merge.Owner+"/"+m.merge.Repo)] = true
|
||||
}
|
||||
if len(repos) < 2 {
|
||||
continue
|
||||
}
|
||||
var om []orderMember
|
||||
moved := map[string][]string{}
|
||||
for _, m := range group {
|
||||
repository := m.merge.Owner + "/" + m.merge.Repo
|
||||
id := repository + "@" + m.merge.Commit
|
||||
var after []string
|
||||
for _, l := range afterLines.FindAllStringSubmatch(m.merge.Body, -1) {
|
||||
after = append(after, strings.TrimSuffix(l[1], ".git"))
|
||||
}
|
||||
om = append(om, orderMember{ID: id, Repository: repository, Base: m.merge.Base, Head: m.merge.Commit,
|
||||
Number: m.merge.Number, Paths: m.merge.Paths, PathsTruncated: m.merge.PathsTruncated,
|
||||
Removed: m.merge.Removed, ModuleDirs: m.merge.ModuleDirs, ModuleDirsSaid: m.merge.ModuleDirsSaid,
|
||||
CloneURL: m.merge.CloneURL, After: after})
|
||||
moved[id] = m.moved
|
||||
}
|
||||
order := orderOf(om, reachOfMembers(om, entries, read, edges), edges)
|
||||
contradicted := map[string]bool{}
|
||||
for _, c := range order.Contradictions {
|
||||
for _, id := range c.Members {
|
||||
contradicted[id] = true
|
||||
}
|
||||
}
|
||||
for _, p := range order.Pairs {
|
||||
if contradicted[p.Before] && contradicted[p.After] {
|
||||
continue
|
||||
}
|
||||
for _, before := range moved[p.Before] {
|
||||
for _, after := range moved[p.After] {
|
||||
if before != after {
|
||||
out = append(out, inventory.Edge{From: after, To: before, Kind: edgeGroupOrder})
|
||||
}
|
||||
}
|
||||
}
|
||||
fmt.Printf(" group %s: %s before %s (%s) inside the walk\n", h, p.Before, p.After, p.Why)
|
||||
}
|
||||
order := orderEdges(moved, changes, edges)
|
||||
for _, e := range order.Edges {
|
||||
fmt.Printf(" order: %s\n", edgeSaid(e))
|
||||
}
|
||||
return out
|
||||
if said := order.CycleSaid(); said != "" {
|
||||
fmt.Printf(" %s\n", said)
|
||||
}
|
||||
return order.Edges, nil
|
||||
}
|
||||
|
||||
// searchAfterFailures starts the search a failed walk leaves (ADR 0276 decision 3): every merge it answered
|
||||
|
||||
Reference in New Issue
Block a user