Documentation
¶
Overview ¶
Package domain holds the routing domain's contracts: the ports, DTOs, enums, constants, and pure validation for resolving a repository (and a PR's changed files) to the Slack channel(s) and behavioural config that apply, across the global/org/repo tiers and monorepo path rules.
It depends only on the standard library, the shared kernel, and the YAML codec used to decode the mappings section of config.yaml onto these types (transition debt: the wire-decoding lives on the domain types until a later phase splits wire types from domain types). It never imports application, infrastructure, or a platform client (store/slack/github).
Index ¶
Constants ¶
const ChannelMention = "<!channel>"
ChannelMention is the Slack wire token used when an entry omits the `mentions:` key — operators see `@channel` in Slack.
const DefaultDigestSchedule = "0 9 * * *"
DefaultDigestSchedule is the cron spec used when the digest section is absent or omits `schedule`: 9am every morning, in the configured digest timezone (default UTC; see DigestConfig.Timezone).
const WildcardKey = "*"
WildcardKey is the org-level tier key (the literal "*"): it both supplies defaults that explicit repo tiers inherit and matches any repo not named explicitly.
Variables ¶
var ErrNotFound = errors.New("store: not found")
ErrNotFound is returned when a repository resolves to no mapping. It is the routing provider's port-contract sentinel. The message string is retained verbatim ("store: not found") so store.ErrNotFound can alias this value during the migration without changing any error text or errors.Is behaviour.
Functions ¶
This section is empty.
Types ¶
type ChangedFilesReader ¶
type ChangedFilesReader interface {
ListPullRequestFiles(ctx context.Context, owner, repo string, number int) ([]string, error)
}
ChangedFilesReader fetches the repo-relative paths a PR touches. The GitHub client satisfies it.
type Defaults ¶
type Defaults struct {
Reactions Reactions
IgnoreAIReviews bool
DependabotFormat bool
// GitProvider is the deployment's single git_provider; the Provider stamps it
// on every entry so it hashes into the lock (see Entry.Provider).
GitProvider kernel.Provider
}
Defaults is the global tier: the config.yaml top-level behavioral settings that per-repo tiers override.
type DigestConfig ¶
DigestConfig is the `digest:` section: a scheduled reminder that lists open PRs nobody has touched since the previous day. The global section is optional and the feature is on by default, so an absent section behaves like `{enabled: true}` with the default schedule. Per-repo tiers reuse this type to override Enabled/Schedule.
Timezone is global-only — the server runs a single cron clock, so the zone belongs on the global section and is rejected on a per-repo tier. Empty means the default (UTC); config.Load resolves it to a *time.Location and fails fast on an invalid zone.
type Entry ¶
type Entry struct {
Org string
Repo string // empty when Wildcard is true
Wildcard bool
Channel string
Mentions []string
// PathChannels are the distinct channels a repo's `paths:` rules add on top
// of Channel (sorted, deduped). They feed both validation (bot membership)
// and the entry hash, so adding or repointing a path channel re-triggers
// validation. Always empty for a wildcard entry (paths are named-tier only).
PathChannels []string
// Provider is the deployment's git_provider (e.g. "github"). It hashes into
// every entry so flipping the provider — under which the same org/repo names
// point at different remote objects — revalidates the whole lock.
Provider kernel.Provider
}
Entry is one validation unit: an explicit (org, repo) pair or an (org, "*") wildcard. Each entry has its own hash in mappings.lock.
func (Entry) Hash ¶
Hash is the cache key for an entry: sha256 over canonical JSON of the validation-relevant fields. Mentions are deliberately excluded — they only affect message formatting at Slack-send time, not anything the validator checks (channel membership, bot scopes, webhook events). A mention edit shouldn't invalidate the entry's cache.
type File ¶
type File struct {
Digest *DigestConfig `yaml:"digest"`
Mappings map[string]Org `yaml:"mappings"`
}
File is the parsed mappings.yaml document.
type Org ¶
type Org map[string]RepoConfig
Org maps each repo name (or the literal "*") to its tier config. The "*" key is the org-level tier: it both supplies defaults that explicit repo tiers inherit and matches any repo not named explicitly.
type PathRule ¶
PathRule is one entry in a repo tier's `paths:` block: a normalized directory and the routing applied to files under it. Channel/Mentions carry the same tri-state inheritance as a repo tier (empty Channel inherits; MentionsPresent distinguishes absent from an explicit empty list).
type Reactions ¶
type Reactions struct {
Enabled bool
NewPR string
MergedPR string
ClosedPR string
Approved string
Commented string
RequestChange string
BotReview string
}
Reactions is the resolved per-repo reaction-emoji set (Slack emoji names without colons). Enabled gates whether close/review reactions are added at all. Empty BotReview disables the bot-reviewer marker.
type ReactionsOverride ¶
type ReactionsOverride struct {
Enabled *bool
NewPR *string
MergedPR *string
ClosedPR *string
Approved *string
Commented *string
RequestChange *string
BotReview *string
}
ReactionsOverride is a tier's optional reaction overrides; each nil field inherits from a less-specific tier (org/* then the global config.yaml set).
type RepoConfig ¶
type RepoConfig struct {
Channel string
Mentions []string
MentionsPresent bool
Reactions *ReactionsOverride
IgnoreAIReviews *bool
DependabotFormat *bool
Digest *DigestConfig
// Paths is the optional per-directory routing for a monorepo, in
// declaration order (order is significant for tie-breaking). Only valid on
// a named repo tier — ValidateMappings rejects it on the "*" tier.
Paths []PathRule
}
RepoConfig is one tier (org/repo or org/*). Phase A carries routing only. An empty Channel means this tier does not set a channel (it inherits). MentionsPresent distinguishes an absent mentions key (inherit) from an explicit empty list (ping nobody).
type RepoMapping ¶
type RepoMapping struct {
Repository string
SlackChannel string
Mentions []string
// Resolved per-repo behavioral config (global config.yaml defaults merged
// with org/* and org/repo overrides). Formatting-only — not part of
// validation or the lock.
Reactions Reactions
IgnoreAIReviews bool
DependabotFormat bool
}
RepoMapping is the value object handlers and validators consume — a GitHub repository routed to a Slack channel with an optional mentions list, and resolved behavioral config (global defaults merged with org/* and org/repo overrides). The source of truth for routing lives in config.yaml's mappings: section (loaded by internal/config / internal/mappings); the type stays here so consumers don't have to know who produced it.
type Resolved ¶
Resolved is the effective routing config for one repository after merging the org/repo tier over the org/* tier.
type RoutingProvider ¶
type RoutingProvider interface {
// Get returns the resolved mapping for "org/repo", or ErrNotFound when no
// tier matches.
Get(ctx context.Context, repository string) (RepoMapping, error)
// RepoHasPathRules reports whether the repository configures a `paths:` block.
RepoHasPathRules(repository string) bool
// TargetsForFiles returns the fan-out destinations for a PR touching files.
TargetsForFiles(repository string, files []string) []Target
}
RoutingProvider resolves a repository to its behavioural mapping and, for a monorepo with path rules, the per-channel fan-out targets for a set of changed files. The application-layer provider satisfies it; the per-PR router depends on it.
type Target ¶
Target is one fan-out destination resolved for a PR: a channel and the mentions to ping there. Produced by the mappings resolver, consumed by the open handler.
type TargetResolver ¶
type TargetResolver interface {
ResolveTargets(ctx context.Context, repository string, prNumber int) (RepoMapping, []Target, error)
}
TargetResolver resolves the per-PR fan-out: the repository's behaviour plus the per-channel targets, layering path rules over the base tier when a changed-files reader is available.