package main // What a pass left (ADR 0428 §6): the outcome file, and the pass's exit. A refused step is not judged by a health // check of its own: the sync is a run-once process, so its non-zero exit is the node-engine's gate (ADR 0136). The // module's step is reported failed, apply-failing is raised, and every apply runs it again until it passes, which is // the "next pass" of §6. Its last stderr lines name each refused repository, its step and the forge's answer. import ( "encoding/json" "fmt" "io" "os" "path/filepath" "strings" ) // WriteOutcome keeps what the pass did per repository, whole or not at all. func WriteOutcome(file string, o Outcome) error { raw, err := json.MarshalIndent(o, "", " ") if err != nil { return err } tmp, err := os.CreateTemp(filepath.Dir(file), ".repositories-*") if err != nil { return err } defer os.Remove(tmp.Name()) if _, err := tmp.Write(append(raw, '\n')); err != nil { tmp.Close() return err } if err := tmp.Chmod(0o644); err != nil { tmp.Close() return err } if err := tmp.Close(); err != nil { return err } return os.Rename(tmp.Name(), file) } // ReadOutcome reads what the last pass left. func ReadOutcome(file string) (*Outcome, error) { raw, err := os.ReadFile(file) if err != nil { return nil, err } var o Outcome if err := json.Unmarshal(raw, &o); err != nil { return nil, fmt.Errorf("the outcome %s is not readable: %w", file, err) } return &o, nil } // Report says on stderr what the pass refused and is the pass's exit: 0 when every listed repository was made, put // right or already right; 1 otherwise. One line per refused repository, "repositories: : refused: // ", then a summary line, so the line the node-engine keeps last names what to look at. func Report(o Outcome, stderr io.Writer) int { if o.Failed != "" { fmt.Fprintf(stderr, "repositories: the pass did not run: %s; nothing was made\n", o.Failed) return 1 } refused := o.Refused() if len(refused) == 0 { return 0 } for _, r := range refused { fmt.Fprintf(stderr, "repositories: %s: %s refused: %s\n", r.Name, r.Step, r.Said) } if len(refused) > 1 { names := make([]string, 0, len(refused)) for _, r := range refused { names = append(names, r.Name) } fmt.Fprintf(stderr, "repositories: %d of %d repositories had a step refused (%s); nothing further of them was done, the rest were\n", len(refused), len(o.Repositories), strings.Join(names, ", ")) } return 1 }