Files
mesh-catalog/checks/removedpackages/main.go
T
jschoubben 4797790959 Catalogue checks follow the narrowed mesh-sdk: a sibling replace is no forge fetch, no source imports what left mesh-sdk, nothing requires the controller's repository (ADR 0593 §1, §11)
deps skips a forge requirement the go.mod already replaces to a directory (a package of the module's own repository), which
it used to look for in a clone beside the check and fail. The new check removedpackages refuses an import of a package
mesh-sdk gave up and a use of the build runner through mesh-sdk's buildstep; it is red on mesh-provisioner until the
provisioner stops composing (the release's provisioner subtask). controllerdeps also refuses a go.mod requiring the
controller's repository.

Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
2026-11-02 18:34:55 +01:00

167 lines
6.0 KiB
Go

// Command removedpackages refuses a Go source of the catalogue that imports what mesh-sdk gave up in the release that
// narrowed it (novox/hq ADR 0593 §1): a package that left for its owner, and the build runner's names that left
// mesh-sdk's buildstep for mesh-build-go's package.
//
// A module compiles against the mesh-sdk version it pins, so a source that still names a removed package builds until the
// pin moves, and then breaks in a delivery of its own; and a later change could bring the import back with the old pin.
// This check refuses it at once, from the source alone:
//
// - an import of a package in Removed (or one under it);
// - in a file importing mesh-sdk's buildstep (under any name), a selector naming anything that is not in
// BuildstepContract: what is left of that package is what the delivery parts read, and the runner is
// mesh-build-go's package (git.novox.be/novox/mesh-catalog/modules/mesh-build-go/buildstep).
//
// It reads the non-test and test Go files under modules/ and checks/ (testdata, vendor and node_modules left out).
//
// go run . <catalogue root>
//
// Exits 1 on a finding. The lists are the release's: a package that goes later is added here with the change.
package main
import (
"fmt"
"go/ast"
"go/parser"
"go/token"
"io/fs"
"os"
"path/filepath"
"sort"
"strconv"
"strings"
)
const sdk = "git.novox.be/novox/mesh-sdk/go"
// Removed are the packages of mesh-sdk that left it, each with where its logic is now.
var Removed = map[string]string{
"buildcpu": "the build runner's package, git.novox.be/novox/mesh-catalog/modules/mesh-build-go/buildstep/buildcpu",
"buildstep/conformance": "the build runner's package, git.novox.be/novox/mesh-catalog/modules/mesh-build-go/buildstep/conformance",
"delivery/buildrun": "the builder's package (mesh-delivery-builder), imported by its repository's modules",
"compose": "the node-engine, which alone composes (ADR 0593 §6)",
"compose/frombus": "the node-engine, which alone composes (ADR 0593 §6)",
"compose/fromruntime": "the node-engine, which alone composes (ADR 0593 §6)",
"compose/judge": "the assigner's own package",
"takein": "the node-engine, which alone composes (ADR 0593 §6)",
"validate": "the node-engine, which alone composes (ADR 0593 §6)",
"facts": "nothing: the controller they served is ended (ADR 0590)",
"example": "nothing: no module imports it (ADR 0593 §12)",
"packageguard": "nothing: a test helper of mesh-sdk's own",
}
// BuildstepContract are the names mesh-sdk's buildstep keeps: the failure contract, the fetch request, the stale-step sweep,
// the step id and the module tree shape the delivery parts read.
var BuildstepContract = map[string]bool{
"AskWhat": true, "Boot": true, "By": true, "CapacitySetting": true, "Clip": true, "ConsoleFailure": true, "CutLine": true,
"EndOne": true, "EndStale": true, "EndStaleAtStart": true, "EndStaleRound": true, "Failure": true, "FetchRequest": true,
"FetchRequestProperties": true, "Hidden": true, "Launchers": true, "LauncherSuffix": true, "LineBytes": true,
"ModuleTree": true, "NewID": true, "OutputBytes": true, "Owner": true, "PackagesArg": true, "ParseFetchRequest": true,
"PassingLine": true, "RestartReason": true, "Scan": true, "ScanOf": true, "StaleAttempts": true, "StaleRetry": true,
"StaleServed": true,
}
// Findings is every refusal in the Go sources under root, sorted.
func Findings(root string) ([]string, error) {
var out []string
for _, top := range []string{"modules", "checks"} {
err := filepath.WalkDir(filepath.Join(root, top), func(path string, d fs.DirEntry, err error) error {
if err != nil {
if os.IsNotExist(err) {
return nil
}
return err
}
if d.IsDir() {
switch d.Name() {
case "testdata", "vendor", "node_modules", ".mesh-build":
return filepath.SkipDir
}
return nil
}
if !strings.HasSuffix(path, ".go") {
return nil
}
rel, _ := filepath.Rel(root, path)
found, err := fileFindings(path, filepath.ToSlash(rel))
if err != nil {
return err
}
out = append(out, found...)
return nil
})
if err != nil {
return nil, err
}
}
sort.Strings(out)
return out, nil
}
func fileFindings(path, rel string) ([]string, error) {
file, err := parser.ParseFile(token.NewFileSet(), path, nil, parser.SkipObjectResolution)
if err != nil {
return nil, fmt.Errorf("%s: %w", rel, err)
}
var out []string
buildstep := ""
for _, imp := range file.Imports {
p, err := strconv.Unquote(imp.Path.Value)
if err != nil {
continue
}
sub, ok := strings.CutPrefix(p, sdk+"/")
if !ok {
continue
}
for pkg, to := range Removed {
if sub == pkg || strings.HasPrefix(sub, pkg+"/") {
out = append(out, fmt.Sprintf("%s: imports %s, which left mesh-sdk; it is %s (novox/hq ADR 0593 §1)", rel, p, to))
break
}
}
if sub == "buildstep" {
buildstep = "buildstep"
if imp.Name != nil {
buildstep = imp.Name.Name
}
}
}
if buildstep == "" || buildstep == "_" || buildstep == "." {
return out, nil
}
seen := map[string]bool{}
ast.Inspect(file, func(n ast.Node) bool {
sel, ok := n.(*ast.SelectorExpr)
if !ok {
return true
}
id, ok := sel.X.(*ast.Ident)
if !ok || id.Name != buildstep || !sel.Sel.IsExported() || BuildstepContract[sel.Sel.Name] || seen[sel.Sel.Name] {
return true
}
seen[sel.Sel.Name] = true
out = append(out, fmt.Sprintf("%s: uses %s.%s, which is the build runner's, no longer mesh-sdk's buildstep; import git.novox.be/novox/mesh-catalog/modules/mesh-build-go/buildstep (novox/hq ADR 0593 §1)", rel, buildstep, sel.Sel.Name))
return true
})
return out, nil
}
func main() {
if len(os.Args) != 2 {
fmt.Fprintln(os.Stderr, "usage: removedpackages <catalogue root>")
os.Exit(2)
}
found, err := Findings(os.Args[1])
if err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(2)
}
for _, f := range found {
fmt.Println(f)
}
if len(found) > 0 {
os.Exit(1)
}
fmt.Println("no source imports a package mesh-sdk gave up")
}