118 lines
4.2 KiB
Go
118 lines
4.2 KiB
Go
package main
|
|
|
|
import (
|
|
"encoding/json"
|
|
"errors"
|
|
"fmt"
|
|
"strconv"
|
|
"strings"
|
|
|
|
stdio "git.novox.be/novox/mesh-sdk/go"
|
|
sdk "git.novox.be/novox/mesh-sdk/go/delivery"
|
|
)
|
|
|
|
// The gate writes nothing to the forge: what a transition owes it — a status, the view on the pull request, a line of the
|
|
// commit's note, a comment — is one key of the gate's bucket owed, `<repository>.<number>.<head>.<act>` (mesh-sdk go/delivery
|
|
// OwedKey), which the forge bridge performs once for each revision (novox/hq ADR 0437 §8, ADR 0450 §4). The number is 0 for
|
|
// a commit no pull request names; a comment's act carries a sequence number, so two comments on one head are two acts.
|
|
// What the gate keeps is the effect owed until its key is written (effects.go); the forge's own refusal is the bridge's
|
|
// to say on FORGE, and the gate has no retry for it.
|
|
|
|
// noPage is the target of a status whose delivery has no page to point at.
|
|
const noPage = "none"
|
|
|
|
// notesRef is the notes ref the commit's note is kept under.
|
|
const notesRef = "mesh-plan"
|
|
|
|
// OwedStore is the gate's bucket owed.
|
|
type OwedStore interface {
|
|
// Put writes the act under its key, unless that key holds the same act already (a revision is an act to perform).
|
|
Put(key string, o sdk.Owed) error
|
|
}
|
|
|
|
// kvOwed is owed over the runtime.
|
|
type kvOwed struct{}
|
|
|
|
func (kvOwed) Put(key string, o sdk.Owed) error {
|
|
raw, err := sdk.EncodeOwed(o)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if e, err := stdio.State("owed").Get(key); err == nil && e != nil {
|
|
if kept, err := sdk.DecodeOwed(e.Value); err == nil && sdk.SameOwed(kept, o) {
|
|
return nil
|
|
}
|
|
}
|
|
_, err = stdio.State("owed").Put(key, json.RawMessage(raw))
|
|
return err
|
|
}
|
|
|
|
// owe writes one owed act as its key. An act that has no key (a name the key refuses, a status with no page to point at) is
|
|
// said and dropped, since writing it again would fail the same.
|
|
func (h *Holder) owe(repository string, number int, head, act string, o sdk.Owed) error {
|
|
if h.Owed == nil {
|
|
return errors.New("no owed bucket")
|
|
}
|
|
key, err := sdk.OwedKey(repository, number, head, act)
|
|
if err == nil {
|
|
o.Act = actKind(act)
|
|
_, err = sdk.EncodeOwed(o)
|
|
}
|
|
if err != nil {
|
|
h.Refuse(fmt.Errorf("the act %q on %s#%d at %s cannot be owed and is dropped: %v", act, repository, number, shortOf(head, 12), err))
|
|
return nil
|
|
}
|
|
return h.Owed.Put(key, o)
|
|
}
|
|
|
|
// actKind is the kind of an owed act: `status=<context>` is a status, `comment.<seq>` a comment.
|
|
func actKind(act string) string {
|
|
kind, _, _ := sdk.ParseOwedAct(act)
|
|
return kind
|
|
}
|
|
|
|
// statusAct is the act of a status of a context.
|
|
func statusAct(context string) string { return sdk.OwedStatus + "=" + context }
|
|
|
|
// commentAct is the act of the seq-th comment on a head.
|
|
func commentAct(seq int) string {
|
|
act, _ := sdk.OwedCommentAct(seq)
|
|
return act
|
|
}
|
|
|
|
// owedOf is an effect as the act its key names and its value: the repository and number are the delivery's (or, for a
|
|
// group's status, the member's the effect names in Last), the body the view's.
|
|
func owedOf(e Effect, repository string, number int, head, body, page string) (act string, value sdk.Owed, num int, hd string) {
|
|
num, hd = number, head
|
|
switch e.Kind {
|
|
case EffectNote:
|
|
hd = e.Commit
|
|
if e.Commit != head {
|
|
num = 0 // the merge commit is named by no pull request
|
|
}
|
|
return sdk.OwedNote, sdk.Owed{Text: e.Line, Ref: notesRef}, num, hd
|
|
case EffectView:
|
|
return sdk.OwedView, sdk.Owed{Text: body}, num, hd
|
|
case EffectStatus:
|
|
// The owed status must name where it points; a delivery with no pull request page points at none, which the forge's
|
|
// tool leaves out (it links only an http or https address).
|
|
if page == "" {
|
|
page = noPage
|
|
}
|
|
return statusAct(e.Context), sdk.Owed{Context: e.Context, State: e.State, Text: e.Line, Target: page}, num, e.Commit
|
|
case EffectComment:
|
|
seq, _ := strconv.Atoi(e.Context)
|
|
return commentAct(seq), sdk.Owed{Text: e.Line}, num, hd
|
|
}
|
|
return "", sdk.Owed{}, 0, ""
|
|
}
|
|
|
|
// memberOfLast reads the repository, pull request number and page a group's status effect names in Last
|
|
// (`owner/repo#N page`).
|
|
func memberOfLast(last string) (repository string, number int, page string) {
|
|
where, page, _ := strings.Cut(last, " ")
|
|
repository, n, _ := strings.Cut(where, "#")
|
|
number, _ = strconv.Atoi(n)
|
|
return repository, number, page
|
|
}
|