Files
mesh-delivery/modules/mesh-delivery-forge-bridge/internal/bridge/watched.go
T
jschoubben dce4d01a58 FB1, FB9, FB10: the forge bridge writes one message per move of every watched branch
The bridge watches the registrations' branches by origin (a first view of registrations, then registration-changed),
before the first registration the gate's source's (source-moved); no branch is named in its code, Trunk goes. Every
move is heard on the seat git's branch-moved through the bridge's durable on SEAT_git_branch-moved, its head read by
the seat's verb branch, never the event's: merged with its pull request and `base` (the watched branch) when the
seat's pull names the head a pull request's merge, else `pushed` with branch, head and `before`, both with the
take-in inputs at the head. The last head written per watched branch is kept in the state heads under
branch.<owner>.<name>.<escaped branch>, so a move heard twice writes once, and each watched branch's head is read at
the start and when a branch is registered. A move of an unprotected branch writes nothing. pull.merged into a watched
branch writes nothing (its message is the move's); the forge-made merge's trunk filter goes.

Builds: design 47 G §4, §7, §11, §20, §41, §507, §509, §532, §714, A-227, A-236

Claude-Session: https://claude.ai/code/session_01NcbgfGKaxw984XyAPfLm4h
2026-11-12 09:15:04 +01:00

72 lines
2.1 KiB
Go

package bridge
import (
"slices"
"sync"
)
// Watched is the branches the bridge watches, by repository (design 47 G §4, §11, §507, §532): the registrations' watched
// branches by their origin, from a first view of `registrations` and then `registration-changed`; before the first
// registration, the branches the gate's `source` answers, of every repository. No branch is fixed in code (§7).
type Watched struct {
mu sync.Mutex
byRepo map[string][]string
source []string
registered bool
}
// Registered is one registration as the bridge reads it: its origin `<owner>/<name>` and its watched branches.
type Registered struct {
Origin string
Branches []string
}
// Set takes what the bridge read: the registrations (none before the first) and the gate's source's branches by name.
func (w *Watched) Set(regs []Registered, source []string) {
by := map[string][]string{}
for _, r := range regs {
for _, b := range r.Branches {
if b != "" && !slices.Contains(by[r.Origin], b) {
by[r.Origin] = append(by[r.Origin], b)
}
}
}
w.mu.Lock()
defer w.mu.Unlock()
w.byRepo, w.registered = by, len(regs) > 0
w.source = slices.Clone(source)
}
// Watches says whether a move of branch in repository is one the bridge writes.
func (w *Watched) Watches(repository, branch string) bool {
w.mu.Lock()
defer w.mu.Unlock()
if !w.registered {
return slices.Contains(w.source, branch)
}
return slices.Contains(w.byRepo[repository], branch)
}
// Branches are the watched branches of repository, in the order the registrations name them; before the first
// registration, the gate's source's.
func (w *Watched) Branches(repository string) []string {
w.mu.Lock()
defer w.mu.Unlock()
if !w.registered {
return slices.Clone(w.source)
}
return slices.Clone(w.byRepo[repository])
}
// Repositories are the repositories the registrations name, sorted; none before the first registration.
func (w *Watched) Repositories() []string {
w.mu.Lock()
defer w.mu.Unlock()
out := make([]string, 0, len(w.byRepo))
for r := range w.byRepo {
out = append(out, r)
}
slices.Sort(out)
return out
}