Documentation
¶
Overview ¶
Package ops parses intent-level operations. The user expresses WHAT resolved ownership should look like; the planner decides which lines change. Scope is a directory, file path, or glob (§4.1).
Index ¶
Constants ¶
const ( ZeroMatchRequire = "require" ZeroMatchSkip = "skip" ZeroMatchDeclare = "declare" )
Zero-match policies (R-21).
const ( ExceptZeroMatchRequire = "require" ExceptZeroMatchAllow = "allow" )
Except zero-match policies (R-28). Require shares R-21's spelling — the default posture has one name across both knobs.
Variables ¶
This section is empty.
Functions ¶
func FoldOwner ¶ added in v0.0.13
FoldOwner is THE identity under which two owner tokens are the same owner (R-38a). @handles fold to lowercase (GitHub does); an email is left alone, because the local part of an address is not ours to case-fold.
Every comparison of two owners in this repository asks this function — add, remove, rename's old name, set_owners, commutation and resolution — with no site free to use its own. Byte equality is what let `remove_owner(/x/, @ORG/TEAM)` report "unchanged" against a file holding @org/team: a fleet run of "revoke the departed team" reported converged on every repository that capitalised the handle.
Folding governs MATCHING only, never output: the spelling on the line is preserved (R-38b) and only `rename_owner` writes a new one (R-38d).
internal/lint had a byte-identical unexported copy, which is where this identity was first written down; it now calls this one. Two copies of an identity is how they drift.
func StaticConflict ¶ added in v0.0.10
StaticConflict reports a pair of ops whose order changes the outcome, decided from the op strings alone with no tree.
plan.Build already refuses order-dependent batches (R-8), but it learns the overlap from a concrete path in the repository, so the verdict is repo-shaped and `sync` reports it at exit 2. A fleet then files all 100 repos under `needs-human` one at a time while `check`, which opens no repo, calls the policy valid — for a defect that was in the policy the whole time. The canonical case is the one the README already warns about:
set_owners(*, [@org/everyone]) # displaces add_owner(/services/api/, @org/api) # co-owns
Sound rather than complete, deliberately: only pairs where pattern.Contains PROVES one scope covers the other, because exit 3 halts a rollout and a false positive there is the expensive direction. Everything else stays with plan.Build's tree-based R-8, at exit 2 per repo.
func WithExcept ¶ added in v0.0.13
WithExcept returns the op string s re-spelled with an except clause carrying pats, and reports whether that clause survives the grammar's own splitting.
R-37's `except` array is validated, applied and REPORTED as the `<scope> except <pat> …` string it is equivalent to (R-37a), so this is the one place that writes that string. A caller that spelled it one way to validate and another to report is how an array-spelled op came to echo itself WITHOUT its carve in the R-8 remedy: advice to run an op that displaces the owners the carve existed to protect (adversarial-review finding).
ok is false when the patterns cannot be carried by an op string at all, which the caller must report in the operator's terms rather than by parsing the mangled result: a pattern holding a comma re-splits as another ARGUMENT, and the arity error that follows names an owner list nobody wrote. The check is the round trip itself rather than a list of forbidden characters, because a balanced character class is live pattern syntax (R-37c) and survives.
s must be an op string Parse accepted, and must not already carry an except clause; both spellings on one op are refused before this is reached (R-37b).
Types ¶
type Op ¶
type Op struct {
Kind Kind `json:"kind"`
Scope string `json:"scope,omitempty"` // pattern text; empty for rename_owner
// Owner is rename_owner's OLD name and nothing else. add/remove/set all
// carry their targets in Owners, so no site can read a stale single value
// off an op that names several owners (R-33) — the field is simply not
// set for them.
Owner string `json:"owner,omitempty"`
NewOwner string `json:"new_owner,omitempty"` // rename new name
// Owners is the target set for add_owner, remove_owner and set_owners:
// non-nil for all three, length >= 1 for add/remove (R-33d), possibly
// empty for set_owners, which is how "nobody owns this" is spelled.
Owners []string `json:"owners,omitempty"`
Raw string `json:"raw"`
// OnZeroMatch selects behavior when Scope matches zero tracked files:
// "" (== "require") | "require" | "skip" | "declare". The zero value
// preserves R-5 exactly, which is why adding this changes nothing for
// ops built by Parse.
OnZeroMatch string `json:"on_zero_match,omitempty"`
// Except is the op's scope-subtraction patterns (R-26a): tracked paths
// matching any of them are out of the op's scope. Parsed from the one
// spelling `<scope> except <pat> [<pat> ...]`; there is no JSON field
// carrying excepts, so an op built any other way has none.
Except []string `json:"except,omitempty"`
// OnExceptZeroMatch selects behavior when an except pattern matches zero
// tracked files AND the op will write (R-28): "" (== "require") |
// "require" | "allow". Policy object form only, like OnZeroMatch.
OnExceptZeroMatch string `json:"on_except_zero_match,omitempty"`
// ID is a policy-file label used in results and errors; "" from --op.
ID string `json:"id,omitempty"`
}
Op is one parsed operation.