Files
mesh-delivery/contracts/go/clients/meshdeliverycheckerclient/codec.go
T

151 lines
5.5 KiB
Go

package meshdeliverycheckerclient
import (
"encoding/json"
"fmt"
"strings"
checker "git.novox.be/novox/mesh-delivery/contracts/go/seats/meshdeliverychecker"
"git.novox.be/novox/mesh-sdk/go/keys"
)
// The codecs of the three states the checker writes and others read (the view and the gate read verdicts, the indexer reads
// previews, the checker and the tools read kept verdicts): a value is written at the version of the kept values after its rules
// (CheckVerdict, CheckKept, CheckPreview) and read back through the same rules. The checker's owed state is read by no other
// part and keeps its own codec.
// EncodeVerdict is v as JSON at the kept values' version, refused by CheckVerdict's rules.
func EncodeVerdict(v checker.VerdictsByGroupHeadsValue) ([]byte, error) {
if err := CheckVerdict(v); err != nil {
return nil, err
}
v.V = keys.Version
return json.Marshal(v)
}
// DecodeVerdict reads a `verdicts` value; it refuses an unknown version (keys.ErrUnknownVersion) and what EncodeVerdict refuses.
func DecodeVerdict(data []byte) (checker.VerdictsByGroupHeadsValue, error) {
var v checker.VerdictsByGroupHeadsValue
if err := decode(data, &v); err != nil {
return v, err
}
if err := CheckVerdict(v); err != nil {
return checker.VerdictsByGroupHeadsValue{}, err
}
return v, nil
}
// EncodeKept is k as JSON at the kept values' version, refused by CheckKept's rules.
func EncodeKept(k checker.KeptByLevelDigestValue) ([]byte, error) {
if err := CheckKept(k); err != nil {
return nil, err
}
k.V = keys.Version
return json.Marshal(k)
}
// DecodeKept reads a `kept` value; it refuses an unknown version and what EncodeKept refuses.
func DecodeKept(data []byte) (checker.KeptByLevelDigestValue, error) {
var k checker.KeptByLevelDigestValue
if err := decode(data, &k); err != nil {
return k, err
}
if err := CheckKept(k); err != nil {
return checker.KeptByLevelDigestValue{}, err
}
return k, nil
}
// EncodePreview is p as JSON at the kept values' version, refused by CheckPreview's rules.
func EncodePreview(p checker.PreviewsByRepositoryHeadTrunkValue) ([]byte, error) {
if err := CheckPreview(p); err != nil {
return nil, err
}
p.V = keys.Version
return json.Marshal(p)
}
// DecodePreview reads a `previews` value; it refuses an unknown version and what EncodePreview refuses.
func DecodePreview(data []byte) (checker.PreviewsByRepositoryHeadTrunkValue, error) {
var p checker.PreviewsByRepositoryHeadTrunkValue
if err := decode(data, &p); err != nil {
return p, err
}
if err := CheckPreview(p); err != nil {
return checker.PreviewsByRepositoryHeadTrunkValue{}, err
}
return p, nil
}
func decode(data []byte, into any) error {
if err := keys.CheckVersion(data); err != nil {
return err
}
if err := json.Unmarshal(data, into); err != nil {
return fmt.Errorf("meshdeliverycheckerclient: value does not fit its shape: %w", err)
}
return nil
}
// KeptKey is the key, in the state kept, of a kept verdict: `<level>.<digest>`, the level unit or integration and the digest,
// lowercase hex, of everything that package's tests read at that level as the language's build module names it.
func KeptKey(level, digest string) (string, error) {
if err := checkLevel(level); err != nil {
return "", err
}
if digest == "" || strings.Trim(digest, "0123456789abcdef") != "" {
return "", fmt.Errorf("meshdeliverycheckerclient: %q is not a digest, lowercase hex", digest)
}
return checker.KeptByLevelDigestKey(level, digest), nil
}
// ParseKeptKey is the inverse of KeptKey.
func ParseKeptKey(key string) (level, digest string, err error) {
level, digest, ok := checker.ParseKeptByLevelDigestKey(key)
if !ok {
return "", "", fmt.Errorf("meshdeliverycheckerclient: %q is not a kept key, <level>.<digest>", key)
}
if _, err = KeptKey(level, digest); err != nil {
return "", "", fmt.Errorf("meshdeliverycheckerclient: %q is not a kept key: %w", key, err)
}
return level, digest, nil
}
// PreviewKey is the key, in the state previews, of a head merged onto a trunk commit: `<repository>.<head>.<trunk>`, the
// repository's owner and name each escaped (keys.EscapeName).
func PreviewKey(repository, head, trunk string) (string, error) {
if err := CheckRepository(repository); err != nil {
return "", err
}
if err := keys.CheckName("head", head); err != nil {
return "", err
}
if err := keys.CheckName("trunk commit", trunk); err != nil {
return "", err
}
owner, name, _ := strings.Cut(repository, "/")
return checker.PreviewsByRepositoryHeadTrunkKey(keys.EscapeName(owner)+"/"+keys.EscapeName(name), head, trunk), nil
}
// ParsePreviewKey is the inverse of PreviewKey.
func ParsePreviewKey(key string) (repository, head, trunk string, err error) {
repo, head, trunk, ok := checker.ParsePreviewsByRepositoryHeadTrunkKey(key)
if !ok || strings.Contains(trunk, ".") {
return "", "", "", fmt.Errorf("meshdeliverycheckerclient: %q is not a preview key, <repository>.<head>.<trunk>", key)
}
owner, name, found := strings.Cut(repo, "/")
if !found {
return "", "", "", fmt.Errorf("meshdeliverycheckerclient: %q is not a preview key: the repository has no slash", key)
}
owner, err1 := keys.UnescapeName(owner)
name, err2 := keys.UnescapeName(name)
if err1 != nil || err2 != nil {
return "", "", "", fmt.Errorf("meshdeliverycheckerclient: %q is not a preview key: the repository does not unescape", key)
}
repository = owner + "/" + name
if _, err := PreviewKey(repository, head, trunk); err != nil {
return "", "", "", fmt.Errorf("meshdeliverycheckerclient: %q is not a preview key: %w", key, err)
}
return repository, head, trunk, nil
}