mesh-issues: import hq's issue folders at their own numbers, and an issue with a folder is whole in the tracker (hq ADR 0275, to-be 53 slice 3)
mesh/merge-gate pass: builds mesh-issues → novox; no bus step; every machine composes with the change as it did without (4 of 4 compose)
mesh/repo-check pass: its merge-check.sh passed, each part in its toolchain: merge-check.sh (go), merge-check-typescript.sh (typescript)
mesh/delivery delivered
mesh/merge-gate pass: builds mesh-issues → novox; no bus step; every machine composes with the change as it did without (4 of 4 compose)
mesh/repo-check pass: its merge-check.sh passed, each part in its toolchain: merge-check.sh (go), merge-check-typescript.sh (typescript)
mesh/delivery delivered
This commit is contained in:
@@ -22,14 +22,15 @@ import (
|
||||
const Seat = "issue-tracker"
|
||||
|
||||
// Verbs are the seat's verbs, as the manifest declares and claims them.
|
||||
var Verbs = []string{"open", "get", "list", "move", "note", "link"}
|
||||
var Verbs = []string{"open", "get", "list", "move", "note", "link", "import"}
|
||||
|
||||
func logf(format string, a ...any) { fmt.Fprintf(os.Stderr, format+"\n", a...) }
|
||||
|
||||
// Settings are the operator's values for this module, merged by the mesh into one JSON file.
|
||||
type Settings struct {
|
||||
// FirstNumber is the number the first issue gets: read once, when the counter is started, and never
|
||||
// again. The counter never starts below an issue already kept.
|
||||
// FirstNumber is the number the first issue gets: read once for the counter, when it is started, and
|
||||
// never again for it. The counter never starts below an issue already kept. The import reads it as the
|
||||
// boundary between the folders hq numbered before the tracker and the issues the tracker numbered.
|
||||
FirstNumber uint64 `json:"first-number"`
|
||||
// Owners is the registered list `located-in` may name (to-be 53 §3).
|
||||
Owners []string `json:"owners"`
|
||||
@@ -67,6 +68,9 @@ func main() {
|
||||
Logf: logf,
|
||||
Sleep: time.Sleep,
|
||||
}
|
||||
if len(os.Args) > 1 && os.Args[1] == "dry-run" {
|
||||
os.Exit(dryRunAtTheTerminal(t, os.Args[2:]))
|
||||
}
|
||||
if _, err := t.Settings(); err != nil {
|
||||
logf("[mesh-issues] the settings cannot be read (%v): every open and move will say so", err)
|
||||
}
|
||||
@@ -76,6 +80,43 @@ func main() {
|
||||
}
|
||||
}
|
||||
|
||||
// dryRunAtTheTerminal is `mesh-issues dry-run <hq checkout> <settings.json>`: the import's dry run over a
|
||||
// checkout on disk, against no tracker, before the module is rolled out. It reads, writes nothing, and
|
||||
// prints what the import would create from that checkout, as the verb's dry run would answer against an
|
||||
// empty tracker. Not a way to import: only the verb writes, and it reads the record over the bus.
|
||||
func dryRunAtTheTerminal(t *Tracker, args []string) int {
|
||||
if len(args) != 2 {
|
||||
logf("usage: mesh-issues dry-run <hq checkout> <settings.json>")
|
||||
return 2
|
||||
}
|
||||
t.Store = emptyStore{}
|
||||
t.Settings = func() (Settings, error) { return readSettings(args[1]) }
|
||||
out, err := t.Import(ImportAsk{DryRun: true}, dirRecords{dir: args[0]})
|
||||
if err != nil {
|
||||
logf("%v", err)
|
||||
return 1
|
||||
}
|
||||
enc := json.NewEncoder(os.Stdout)
|
||||
enc.SetIndent("", " ")
|
||||
_ = enc.Encode(out)
|
||||
return 0
|
||||
}
|
||||
|
||||
// emptyStore is a Store that holds nothing and takes nothing: the terminal's dry run.
|
||||
type emptyStore struct{}
|
||||
|
||||
func (emptyStore) Get(string, string) (*Entry, error) { return nil, nil }
|
||||
func (emptyStore) Create(string, string, any) (uint64, error) {
|
||||
return 0, errors.New("a dry run at the terminal writes nothing")
|
||||
}
|
||||
func (emptyStore) Update(string, string, any, uint64) (uint64, error) {
|
||||
return 0, errors.New("a dry run at the terminal writes nothing")
|
||||
}
|
||||
func (emptyStore) Keys(string) ([]string, error) { return nil, nil }
|
||||
func (emptyStore) Increment(string, string, int) (uint64, error) {
|
||||
return 0, errors.New("a dry run at the terminal writes nothing")
|
||||
}
|
||||
|
||||
// args reads one call's arguments strictly: an argument the verb does not take is refused, never ignored,
|
||||
// so nothing a caller sends is silently dropped — and no argument can say who the caller is.
|
||||
type args struct {
|
||||
@@ -285,8 +326,7 @@ func Tools(t *Tracker) []stdio.Tool {
|
||||
"development cycle's rules: located needs located-in, owners on the registered list; resolved needs " +
|
||||
"located-in and fixed-by (the pull requests or commits), and an issue in the mesh's core also replay " +
|
||||
"(the replay's id, such as R361) or replay-none (why no replay is possible); wontfix needs a reason. " +
|
||||
"A refused move changes nothing and says which rule refused it. An issue with a folder in hq keeps its " +
|
||||
"status there and is refused here.",
|
||||
"A refused move changes nothing and says which rule refused it.",
|
||||
Input: schema([]string{"number", "status"}, map[string]any{
|
||||
"number": number("the issue's number"),
|
||||
"status": map[string]any{"type": "string", "enum": Statuses, "description": "the status it moves to"},
|
||||
@@ -379,5 +419,35 @@ func Tools(t *Tracker) []stdio.Tool {
|
||||
}
|
||||
return t.Link(ask)
|
||||
}},
|
||||
{Name: Seat + ".import",
|
||||
Description: "Import hq's issue folders (04-ISSUES/NNN-slug/00-report.md), read through the records module at " +
|
||||
"the commit its checkout stands at, each as an issue under its own number with the status, owners, fix " +
|
||||
"and replay its report gives. It only ever creates an issue that is not there, or fills the status of one " +
|
||||
"the tracker holds without a status; it never overwrites an issue, never advances the counter, refuses a " +
|
||||
"folder numbered past the counter or past the tracker's first number without an issue, and run again " +
|
||||
"changes nothing and says so. With dry-run it writes nothing and says what it would do; with commit it " +
|
||||
"refuses a checkout standing elsewhere. The answer is a row per folder and the counts.",
|
||||
Input: schema(nil, map[string]any{
|
||||
"dry-run": map[string]any{"type": "boolean", "description": "read everything, write nothing, say what would be done"},
|
||||
"commit": text("the commit of hq the record must stand at (a prefix is enough); refused when it stands elsewhere"),
|
||||
}),
|
||||
Run: func(m map[string]any) (any, error) {
|
||||
a, err := readArgs("import", m, "dry-run", "commit")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var ask ImportAsk
|
||||
if ask.DryRun, err = a.flag("dry-run"); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if ask.Commit, err = a.str("commit"); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
records := t.Records
|
||||
if records == nil {
|
||||
records = busRecords{}
|
||||
}
|
||||
return t.Import(ask, records)
|
||||
}},
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user