194 lines
5.6 KiB
Go
194 lines
5.6 KiB
Go
package check
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"sort"
|
|
"strings"
|
|
|
|
"git.novox.be/novox/mesh-sdk/go/delivery"
|
|
)
|
|
|
|
// The read tools (novox/hq ADR 0484 clauses 8 and 13, issue 1686): what the checker stored, as stored, with the line of the
|
|
// status it owes in full, so a check is read live without a shell. They write nothing.
|
|
|
|
// The read tools, named as the module is: checker_ and the noun.
|
|
const (
|
|
VerdictsReadTool = "checker_verdicts"
|
|
PullReadTool = "checker_pull"
|
|
KeptReadTool = "checker_kept"
|
|
)
|
|
|
|
// StateRead reads one state: its keys and a key's stored value (nil for a key with none).
|
|
type StateRead struct {
|
|
Keys func() ([]string, error)
|
|
Get func(key string) (json.RawMessage, error)
|
|
}
|
|
|
|
// Reader answers the read tools from the checker's verdicts and kept states and the indexer's candidates.
|
|
type Reader struct{ VerdictState, KeptState, CandidateState StateRead }
|
|
|
|
// VerdictRead is a verdict as stored with the full report of the status of each pull request it judged (Report), when the
|
|
// candidate still holds those heads; without it the report is that of the verdict alone.
|
|
type VerdictRead struct {
|
|
Key string `json:"key"`
|
|
Verdict json.RawMessage `json:"verdict"`
|
|
Reports map[string]string `json:"reports,omitempty"`
|
|
Note string `json:"note,omitempty"`
|
|
}
|
|
|
|
func (r Reader) candidate(group string) (delivery.Candidate, bool) {
|
|
key, err := delivery.CandidatesKey(group)
|
|
if err != nil || r.CandidateState.Get == nil {
|
|
return delivery.Candidate{}, false
|
|
}
|
|
raw, err := r.CandidateState.Get(key)
|
|
if err != nil || len(raw) == 0 {
|
|
return delivery.Candidate{}, false
|
|
}
|
|
c, err := delivery.DecodeCandidate(raw)
|
|
return c, err == nil
|
|
}
|
|
|
|
func (r Reader) read(key string, raw json.RawMessage) (VerdictRead, error) {
|
|
out := VerdictRead{Key: key, Verdict: raw}
|
|
v, err := delivery.DecodeVerdict(raw)
|
|
if err != nil {
|
|
return out, fmt.Errorf("%s holds what is not a verdict: %w", key, err)
|
|
}
|
|
c, ok := r.candidate(v.Group)
|
|
if !ok || c.HeadsHash != v.Heads {
|
|
out.Note = "the candidate no longer holds these heads"
|
|
return out, nil
|
|
}
|
|
cs := CaseOf(c, v.Trunk)
|
|
out.Reports = map[string]string{}
|
|
if cs == nil {
|
|
return out, nil
|
|
}
|
|
for _, p := range cs.Pulls {
|
|
out.Reports[fmt.Sprintf("%s#%d", p.Repository, p.Number)] = Report(v, cs, p, nil, nil)
|
|
}
|
|
for _, l := range cs.Left {
|
|
out.Reports[strings.SplitN(l, ": ", 2)[0]] = strings.SplitN(l, ": ", 2)[1]
|
|
}
|
|
return out, nil
|
|
}
|
|
|
|
// Verdicts are the verdicts the checker holds, by key; with a group only that group's.
|
|
func (r Reader) Verdicts(group string) ([]VerdictRead, error) {
|
|
if r.VerdictState.Keys == nil || r.VerdictState.Get == nil {
|
|
return nil, fmt.Errorf("the verdicts state cannot be read here")
|
|
}
|
|
keys, err := r.VerdictState.Keys()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
sort.Strings(keys)
|
|
var out []VerdictRead
|
|
for _, k := range keys {
|
|
if group != "" {
|
|
if g, _, err := delivery.ParseCheckerVerdictKey(k); err != nil || g != group {
|
|
continue
|
|
}
|
|
}
|
|
raw, err := r.VerdictState.Get(k)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if len(raw) == 0 {
|
|
continue
|
|
}
|
|
vr, err := r.read(k, raw)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
out = append(out, vr)
|
|
}
|
|
return out, nil
|
|
}
|
|
|
|
// Pull answers for one pull request: the verdict of the candidate that holds it, with its report; for an hq pull request,
|
|
// that hq is judged by merge-check.sh until issue 1296 (HQNote); for one the indexer holds in no candidate, that none does.
|
|
func (r Reader) Pull(repository string, number int) (VerdictRead, error) {
|
|
if r.CandidateState.Keys == nil || r.CandidateState.Get == nil {
|
|
return VerdictRead{}, fmt.Errorf("the candidates state cannot be read here")
|
|
}
|
|
keys, err := r.CandidateState.Keys()
|
|
if err != nil {
|
|
return VerdictRead{}, err
|
|
}
|
|
sort.Strings(keys)
|
|
for _, k := range keys {
|
|
raw, err := r.CandidateState.Get(k)
|
|
if err != nil || len(raw) == 0 {
|
|
continue
|
|
}
|
|
c, err := delivery.DecodeCandidate(raw)
|
|
if err != nil {
|
|
continue
|
|
}
|
|
for _, p := range c.Pulls {
|
|
if p.Repository != repository || p.Number != number {
|
|
continue
|
|
}
|
|
if repository == HQRepository {
|
|
return VerdictRead{Key: k, Note: HQNote}, nil
|
|
}
|
|
vkey, err := delivery.CheckerVerdictKey(c.Group, c.HeadsHash)
|
|
if err != nil {
|
|
return VerdictRead{}, err
|
|
}
|
|
vraw, err := r.VerdictState.Get(vkey)
|
|
if err != nil {
|
|
return VerdictRead{}, err
|
|
}
|
|
if len(vraw) == 0 {
|
|
return VerdictRead{Key: vkey, Note: "no verdict yet for the heads of its candidate"}, nil
|
|
}
|
|
return r.read(vkey, vraw)
|
|
}
|
|
}
|
|
return VerdictRead{}, fmt.Errorf("no candidate holds %s#%d", repository, number)
|
|
}
|
|
|
|
// Kept is the kept verdicts: one key's value as stored, or with an empty key the keys of a level (or every level) and their values.
|
|
func (r Reader) Kept(level, digest string) (map[string]json.RawMessage, error) {
|
|
if r.KeptState.Keys == nil || r.KeptState.Get == nil {
|
|
return nil, fmt.Errorf("the kept state cannot be read here")
|
|
}
|
|
if digest != "" {
|
|
key, err := delivery.KeptKey(level, digest)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
raw, err := r.KeptState.Get(key)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if len(raw) == 0 {
|
|
return nil, fmt.Errorf("no kept verdict %s", key)
|
|
}
|
|
return map[string]json.RawMessage{key: raw}, nil
|
|
}
|
|
keys, err := r.KeptState.Keys()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
sort.Strings(keys)
|
|
out := map[string]json.RawMessage{}
|
|
for _, k := range keys {
|
|
if l, _, err := delivery.ParseKeptKey(k); err != nil || (level != "" && l != level) {
|
|
continue
|
|
}
|
|
raw, err := r.KeptState.Get(k)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if len(raw) > 0 {
|
|
out[k] = raw
|
|
}
|
|
}
|
|
return out, nil
|
|
}
|