Documentation
¶
Overview ¶
Package mappings owns the declarative repository → Slack-channel configuration: parsing mappings.yaml, the in-memory Provider used at runtime, and the mappings.lock cache that records which entries have been validated. The package replaces the database-backed RepoMappings store.
Index ¶
- Constants
- func LockPath(yamlPath string) string
- func ValidateMappings(m map[string]Org) error
- func WriteLock(path string, l Lock) error
- type Defaults
- type Diff
- type DigestConfig
- type Entry
- type File
- type FileNotFoundError
- type Lock
- type LockEntry
- type Org
- type ParseError
- type PathRule
- type Provider
- func (p *Provider) Digest() DigestConfig
- func (p *Provider) DigestFor(repository string) DigestConfig
- func (p *Provider) Entries() []Entry
- func (p *Provider) Get(_ context.Context, repository string) (store.RepoMapping, error)
- func (p *Provider) HasPathRules() bool
- func (p *Provider) PathChannels(repository string) []string
- func (p *Provider) RepoHasPathRules(repository string) bool
- func (p *Provider) Schedules() []string
- func (p *Provider) TargetsForFiles(repository string, files []string) []store.Target
- type ReactionsOverride
- type RepoConfig
- type Resolved
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 LockFileComment = "DO NOT EDIT — regenerated by notifycat on validation"
LockFileComment is the human-facing warning baked into every written lock.
const LockVersion = 1
LockVersion is the current lock-file schema version.
Variables ¶
This section is empty.
Functions ¶
func LockPath ¶
LockPath derives the lock-file path that lives next to the given mappings.yaml. .yaml / .yml extensions are swapped for .lock; any other suffix gets .lock appended.
func ValidateMappings ¶ added in v0.18.0
ValidateMappings runs the same per-org/per-tier structural checks as Parse over a mappings map. An empty map (no orgs) is valid. Returns an error for invalid org names, empty orgs, bad repo keys, malformed channel IDs, or any repo tier that cannot resolve a channel.
Types ¶
type Defaults ¶ added in v0.18.0
Defaults is the global tier: the config.yaml top-level behavioral settings that per-repo tiers override.
type Diff ¶
Diff is the result of DiffEntries: entries needing validation + lock keys that should be dropped on the next write.
func DiffEntries ¶
DiffEntries compares the current entries against the lock and returns which entries need validation (new or hash-changed) and which lock keys are stale (present in the lock but not in the file).
type DigestConfig ¶ added in v0.16.0
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.
func (*DigestConfig) UnmarshalYAML ¶ added in v0.16.0
func (d *DigestConfig) UnmarshalYAML(node *yaml.Node) error
UnmarshalYAML walks the mapping node by hand (like Org) so we can default Enabled to true — distinguishing a missing `enabled:` key from an explicit `enabled: false` — while keeping KnownFields-style rejection of typos.
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
}
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 FileNotFoundError ¶ added in v0.7.0
FileNotFoundError is returned by Load when the mappings file cannot be opened.
func (*FileNotFoundError) Error ¶ added in v0.7.0
func (e *FileNotFoundError) Error() string
func (*FileNotFoundError) Unwrap ¶ added in v0.7.0
func (e *FileNotFoundError) Unwrap() error
type Lock ¶
type Lock struct {
Comment string `json:"_comment,omitempty"`
Version int `json:"version"`
Entries map[string]LockEntry `json:"entries"`
}
Lock is the on-disk validation cache.
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 ParseError ¶ added in v0.7.0
ParseError is returned by Load when the mappings file cannot be parsed.
func (*ParseError) Error ¶ added in v0.7.0
func (e *ParseError) Error() string
func (*ParseError) Unwrap ¶ added in v0.7.0
func (e *ParseError) Unwrap() error
type PathRule ¶ added in v0.20.0
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 Provider ¶
type Provider struct {
// contains filtered or unexported fields
}
Provider serves repository → mapping lookups from a parsed mappings.yaml. Construct with Load; safe for concurrent reads (no mutation after Load).
func NewProvider ¶ added in v0.17.0
func NewProvider(defaults Defaults, m map[string]Org, digest *DigestConfig) *Provider
NewProvider builds a Provider from already-decoded sections (config.yaml's `mappings:` map and `digest:` block), the in-memory counterpart to Load. A nil digest leaves the feature on by default (see Digest).
func (*Provider) Digest ¶ added in v0.16.0
func (p *Provider) Digest() DigestConfig
Digest returns the effective stuck-PR digest configuration. The feature is enabled by default, so an absent `digest:` section yields {Enabled: true, Schedule: DefaultDigestSchedule}. An explicit section may disable it or override the schedule.
func (*Provider) DigestFor ¶ added in v0.18.0
func (p *Provider) DigestFor(repository string) DigestConfig
DigestFor returns the effective digest config for a repository: the global Digest() merged with the org/* and org/repo tiers (most-specific tier that sets enabled/schedule wins). An unmapped repo yields the global digest.
func (*Provider) Entries ¶
Entries returns validation units in deterministic order: orgs A→Z, explicit repos within each org A→Z, the wildcard entry last. Each entry's Channel is the resolved channel (the tier's own, or inherited from org/*), so the validator and lock operate on what a webhook would actually route to.
func (*Provider) Get ¶
Get returns the resolved mapping for "org/repo": the org/repo tier merged over the org/* tier. Returns store.ErrNotFound when the org is unmapped or neither an explicit tier nor a wildcard tier matches.
func (*Provider) HasPathRules ¶ added in v0.20.0
HasPathRules reports whether any repo tier in the mappings configures a `paths:` block. Used to gate the "path routing needs GITHUB_TOKEN" warnings: without paths there is nothing to warn about.
func (*Provider) PathChannels ¶ added in v0.20.0
PathChannels returns the distinct channels explicitly set on the repository's path rules (those that override the base channel), in sorted order. The base channel is validated separately; these are the extra Slack channels path routing can post to, so validation must confirm the bot is in each.
func (*Provider) RepoHasPathRules ¶ added in v0.20.0
RepoHasPathRules reports whether the specific repository's tier configures a `paths:` block. The runtime uses it to decide, per webhook, whether fetching the PR's changed files is worthwhile — repos without path rules skip the GitHub call entirely.
func (*Provider) Schedules ¶ added in v0.18.0
Schedules returns the sorted distinct set of effective digest schedules across every mapping entry whose effective digest is enabled. The scheduler registers one cron per returned spec.
func (*Provider) TargetsForFiles ¶ added in v0.20.0
TargetsForFiles returns the fan-out destinations for a PR touching files: one Target per distinct matched channel, mentions unioned within each channel. With no path rules, no files, or no match it returns a single base target.
type ReactionsOverride ¶ added in v0.18.0
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).
func (*ReactionsOverride) UnmarshalYAML ¶ added in v0.18.0
func (r *ReactionsOverride) UnmarshalYAML(node *yaml.Node) error
UnmarshalYAML walks the reactions mapping by hand so unknown keys are rejected and every leaf is optional (nil = inherit).
type RepoConfig ¶ added in v0.18.0
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).
func (*RepoConfig) UnmarshalYAML ¶ added in v0.18.0
func (rc *RepoConfig) UnmarshalYAML(node *yaml.Node) error
UnmarshalYAML walks the mapping node by hand so we can keep the mentions tri-state (absent vs [] vs null) and reject unknown keys, mirroring the 0.17 Org decoder but at the per-repo tier level.