84 lines
3.4 KiB
Go
84 lines
3.4 KiB
Go
// Package meshconfigclient is the logic every reader of the seat mesh-config's state kept shares (novox/hq ADR 0565
|
|
// clause 5, ADR 0634 §4): the checker and the assigner's composition check lay a pull request's own held values over its
|
|
// modules' values. The layout of a value is the seat's contract's; this holds what the readers share over it: a pull
|
|
// request's key, a held value's key and the rule that a value is the one its key names.
|
|
package meshconfigclient
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"strings"
|
|
|
|
seat "git.novox.be/novox/mesh-contracts/go/seats/meshconfig"
|
|
)
|
|
|
|
// PullKey is a pull request's key, `owner/repository#number` with `/` and `#` as dots, the form the seat keeps a pull
|
|
// request's values under. The three parts hold no dot, star, angle bracket or space.
|
|
func PullKey(pull string) (string, error) {
|
|
owner, repository, number, err := splitPull(pull)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
return owner + "." + repository + "." + number, nil
|
|
}
|
|
|
|
func splitPull(pull string) (owner, repository, number string, err error) {
|
|
owner, rest, ok := strings.Cut(strings.TrimSpace(pull), "/")
|
|
repository, number, ok2 := strings.Cut(rest, "#")
|
|
if !ok || !ok2 || owner == "" || repository == "" || number == "" || strings.ContainsAny(owner+repository+number, ".*> ") {
|
|
return "", "", "", fmt.Errorf("meshconfig: %q is not a pull request, owner/repository#number", pull)
|
|
}
|
|
return owner, repository, number, nil
|
|
}
|
|
|
|
// HeldValueKey is a held value's key in the state kept: the pull request's key, the node, the module and the config key,
|
|
// joined by dots.
|
|
func HeldValueKey(pull, node, module, key string) (string, error) {
|
|
owner, repository, number, err := splitPull(pull)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
if node == "" || module == "" || key == "" {
|
|
return "", fmt.Errorf("meshconfig: a held value names a node, a module and a key")
|
|
}
|
|
return seat.KeptByOwnerRepositoryNumberNodeModuleKeyKey(owner, repository, number, node, module, key), nil
|
|
}
|
|
|
|
// Kept is one held value, as the seat types it.
|
|
type Kept = seat.KeptByOwnerRepositoryNumberNodeModuleKeyValue
|
|
|
|
// CheckKept refuses a held value that names no pull request, head, declaration, node, module or key.
|
|
func CheckKept(v Kept) error {
|
|
if _, err := PullKey(v.Pull); err != nil {
|
|
return err
|
|
}
|
|
if v.Head == "" || v.Declaration == "" || v.Node == "" || v.Module == "" || v.Key == "" {
|
|
return fmt.Errorf("meshconfig: a held value of %s names a head, a declaration, a node, a module and a key", v.Pull)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// DecodeKept reads a value of the state kept under its key: the value the seat types, checked, and the one its key
|
|
// names. A value kept under another key than its own fields make is refused, so a reader never lays a value over the
|
|
// wrong pull request or module.
|
|
func DecodeKept(key string, raw []byte) (Kept, error) {
|
|
v, err := seat.DecodeKeptByOwnerRepositoryNumberNodeModuleKeyValue(raw)
|
|
if err != nil {
|
|
return Kept{}, fmt.Errorf("meshconfig: the held value %s is not one: %w", key, err)
|
|
}
|
|
if err := CheckKept(v); err != nil {
|
|
return Kept{}, err
|
|
}
|
|
want, err := HeldValueKey(v.Pull, v.Node, v.Module, v.Key)
|
|
if err != nil {
|
|
return Kept{}, err
|
|
}
|
|
if want != key {
|
|
return Kept{}, fmt.Errorf("meshconfig: the held value kept under %s names %s", key, want)
|
|
}
|
|
return v, nil
|
|
}
|
|
|
|
// ValueOf is the value held, as the operator approved it, in its JSON form.
|
|
func ValueOf(v Kept) (json.RawMessage, error) { return json.Marshal(v.Value) }
|