Clients: the kept and preview keys of the checker's states and the candidates key of the catalog's (ADR 0634 §2; issue 1966)
Claude-Session: https://claude.ai/code/session_01NcbgfFSnn24M3GcqttoU7i
This commit is contained in:
@@ -3,10 +3,12 @@ package meshcatalogclient
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
seat "git.novox.be/novox/mesh-delivery/contracts/go/seats/meshcatalog"
|
||||
"git.novox.be/novox/mesh-sdk/go/keys"
|
||||
)
|
||||
|
||||
// FingerprintSet is the `fpset` of a candidate's pull requests: the first 12 hex digits of the sha256 over the lines
|
||||
@@ -36,3 +38,25 @@ func FingerprintSet(pulls []seat.CandidatesByGroupValuePullsItem) string {
|
||||
sum := sha256.Sum256([]byte(strings.Join(all, "\n")))
|
||||
return hex.EncodeToString(sum[:])[:12]
|
||||
}
|
||||
|
||||
// CandidatesKey is the key, in the state candidates, of a group: `<group>` escaped (keys.EscapeName), the branch name the
|
||||
// group's pull requests share (a slash is allowed); a lone pull request is a group of one under its branch name.
|
||||
func CandidatesKey(group string) (string, error) {
|
||||
if group == "" {
|
||||
return "", fmt.Errorf("meshcatalogclient: the group name is empty")
|
||||
}
|
||||
return seat.CandidatesByGroupKey(keys.EscapeName(group)), nil
|
||||
}
|
||||
|
||||
// ParseCandidatesKey is the inverse of CandidatesKey.
|
||||
func ParseCandidatesKey(key string) (string, error) {
|
||||
part, ok := seat.ParseCandidatesByGroupKey(key)
|
||||
if !ok {
|
||||
return "", fmt.Errorf("meshcatalogclient: %q is not a candidates key", key)
|
||||
}
|
||||
group, err := keys.UnescapeName(part)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("meshcatalogclient: %q is not a candidates key: %w", key, err)
|
||||
}
|
||||
return group, nil
|
||||
}
|
||||
|
||||
@@ -156,3 +156,19 @@ func TestVerdictsAreTakenAsTheReadersTookThem(t *testing.T) {
|
||||
t.Error("ModulesKey accepts a dotted name")
|
||||
}
|
||||
}
|
||||
|
||||
func TestCandidatesKeyEscapesTheGroupAndReadsBack(t *testing.T) {
|
||||
key, err := CandidatesKey("fix/1.2")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if key == "fix/1.2" {
|
||||
t.Errorf("the group is not escaped: %q", key)
|
||||
}
|
||||
if group, err := ParseCandidatesKey(key); err != nil || group != "fix/1.2" {
|
||||
t.Errorf("read back = %q, %v", group, err)
|
||||
}
|
||||
if _, err := CandidatesKey(""); err == nil {
|
||||
t.Error("an empty group keys")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -192,3 +192,32 @@ func TestTheCodecsWriteAtTheVersionAndReadBackThroughTheRules(t *testing.T) {
|
||||
t.Error("a preview with no merge commit and no conflict is written")
|
||||
}
|
||||
}
|
||||
|
||||
// The kept and preview keys: a key reads back to its parts, and a part that does not key is refused.
|
||||
func TestKeptAndPreviewKeysReadBack(t *testing.T) {
|
||||
digest := strings.Repeat("ab", 32)
|
||||
key, err := KeptKey(LevelUnit, digest)
|
||||
if err != nil || key != "unit."+digest {
|
||||
t.Fatalf("kept key = %q, %v", key, err)
|
||||
}
|
||||
if level, d, err := ParseKeptKey(key); err != nil || level != LevelUnit || d != digest {
|
||||
t.Errorf("kept key read back = %q %q, %v", level, d, err)
|
||||
}
|
||||
for _, bad := range []string{"fast." + digest, "unit.XY", "unit"} {
|
||||
if _, _, err := ParseKeptKey(bad); err == nil {
|
||||
t.Errorf("kept key %q is read", bad)
|
||||
}
|
||||
}
|
||||
key, err = PreviewKey("novox/mesh-sdk", "h1", "t1")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if repo, h, tr, err := ParsePreviewKey(key); err != nil || repo != "novox/mesh-sdk" || h != "h1" || tr != "t1" {
|
||||
t.Errorf("preview key %q read back = %q %q %q, %v", key, repo, h, tr, err)
|
||||
}
|
||||
for _, bad := range []string{"novox.h1.t1", "a/b.h1", "a/b.h1.t1.x"} {
|
||||
if _, _, _, err := ParsePreviewKey(bad); err == nil {
|
||||
t.Errorf("preview key %q is read", bad)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ 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"
|
||||
@@ -85,3 +86,65 @@ func decode(data []byte, into any) error {
|
||||
}
|
||||
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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user