Documentation
¶
Overview ¶
Package ci computes provider-agnostic fan-out plans for CI systems from a magus workspace. CI system wrappers translate the output into their own matrix/pipeline format.
Index ¶
- Constants
- Variables
- func CommentOnlyDeclared(old, cur string, syn spells.CommentSyntax) bool
- func GateFingerprint(steps []GateStep) string
- func InheritOff(projects []*types.Project) bool
- func MergeFreeRange(history []types.Commit, green string) bool
- func PRMergeFreeRange(history []types.Commit, green string) bool
- func PoolSaturated(m *types.MachineSnapshot) bool
- func StripComments(src string, syn spells.CommentSyntax) string
- type ChangeClass
- type ChangeClassifier
- type ClassifiedPath
- type DedupEntry
- type DedupResult
- type Forecaster
- type GateDecision
- type GateDelta
- type GateFacts
- type GateStep
- type InheritFinding
- type InheritProbe
- type MissBuild
- type Option
- type Plan
- type ProseScope
- type Shard
Constants ¶
const ProseOriginDefault = "built-in default"
ProseOriginDefault names the built-in glob set in per-path attributions.
Variables ¶
var DefaultProseGlobs = []string{"**/*.md", "**/*.markdown"}
DefaultProseGlobs are the prose globs magus ships: markdown sources, which covers docs and changelog prose. They apply only while NO project declares gate_low_risk; the first declaration replaces them workspace-wide.
var ErrInvalidMaxShards = errors.New("ci: max shards must be -1 (unlimited) or a positive integer")
ErrInvalidMaxShards is returned when WithMaxShards receives a value of 0 or any negative integer other than -1 (the sentinel for "unlimited").
Functions ¶
func CommentOnlyDeclared ¶ added in v0.4.3
func CommentOnlyDeclared(old, cur string, syn spells.CommentSyntax) bool
CommentOnlyDeclared reports whether two sources of a declared language differ only in comments: both strip to byte-identical text. No token-stream normalization happens - whitespace may be semantics (Python indentation), so the only thing removed is the comment spans themselves. Reformatting a code line therefore re-gates even in languages where it is inert, which is the safe direction.
func GateFingerprint ¶ added in v0.4.3
GateFingerprint condenses a gate's per-step cache keys into one identity. Derived from the step-key machinery rather than a fresh tree hash, so it inherits everything a real run keys on: sources, spell claims, tool versions, the env allowlist, and the charm set. Order-insensitive; an empty selection fingerprints to "".
func InheritOff ¶ added in v0.4.3
InheritOff reports whether any project declared gate_inherit false, the workspace's off-switch for CI verdict inheritance. One declaration turns it off workspace-wide, the same reach a gate_low_risk declaration has.
A project that DROPPED an option counts as off too. Load tolerates a key it does not recognize so a magusfile from the future cannot deadlock the binary that would build its successor, but several options are opt-outs whose absence is the permissive answer: an ignored `gate_inherit = false` reads as inheritance on, and an ignored `gate_low_risk = []` restores the prose globs the author deleted. The binary cannot tell which kind it dropped, because not knowing the key is the whole premise. So the one decision that can SKIP CI declines whenever the magusfile was not fully understood.
func MergeFreeRange ¶ added in v0.4.3
MergeFreeRange reports whether walking history (newest first) from its head down to green crosses no merge commit. green at the head is a trivially merge-free range. A green commit the walk never reaches reports false: a range that cannot be bounded cannot be vouched for.
func PRMergeFreeRange ¶ added in v0.4.3
PRMergeFreeRange is MergeFreeRange with the head commit exempt from the merge rule. A CI provider tests a pull request as a synthetic merge of the branch into its base (GitHub's refs/pull/N/merge), so under a PR checkout the head is ALWAYS a merge, and it is the harness's rather than the delta's: the classification diffs the tree it produced against green, so everything it folded in is accounted for. A merge anyone pushed sits below the synthetic head and still refuses.
func PoolSaturated ¶ added in v0.4.3
func PoolSaturated(m *types.MachineSnapshot) bool
PoolSaturated reports whether a new run would queue against the machine budget: something is already waiting, or an axis with a limit is fully held. A nil snapshot is an absent arbiter and reads as idle (fail open).
func StripComments ¶ added in v0.4.3
func StripComments(src string, syn spells.CommentSyntax) string
StripComments returns src with its comment spans removed, using the language's declared syntax. It is a string-aware state machine: a comment token inside a declared string form is content, a string quote inside a comment is comment, and block comments nest only where declared. A DIRECTIVE comment (declared prefix on the comment body) is code and stays.
A comment span includes the horizontal whitespace immediately before it, and, when the comment is the only thing on its line, the line itself - newline included. Indentation of code lines is never touched: that is the no-whitespace-normalization rule, and Python is why it exists.
Types ¶
type ChangeClass ¶ added in v0.4.3
type ChangeClass int
ChangeClass is the risk class of one changed path.
const ( // ClassCode is everything the three low-risk classes do not cover. ClassCode ChangeClass = iota // ClassGenerated is a path a declared output glob or magus itself owns. ClassGenerated // ClassProse is a path an effective gate_low_risk glob claims; magus ships // markdown defaults (see DefaultProseGlobs). ClassProse // ClassCommentOnly is a file whose delta touches only comments. ClassCommentOnly )
func (ChangeClass) String ¶ added in v0.4.3
func (c ChangeClass) String() string
String is the word the per-path verdict lines print.
type ChangeClassifier ¶ added in v0.4.3
type ChangeClassifier struct {
// Role returns each path's describe-file role ("output", "maintained",
// "source", ...), keyed by the path as passed. Missing entries classify by
// the remaining classes alone.
Role func(ctx context.Context, paths []string) (map[string]string, error)
// Prose is the effective glob set, from ProseScopes. Empty means the prose
// class is off.
Prose []ProseScope
// Syntax routes a file extension (lowercase, with dot) to the comment
// syntax a spell DECLARED for it (spells.CommentSyntaxIndex over the
// projects' resolved spells). An unclaimed extension classifies as code.
Syntax map[string]spells.CommentSyntax
// At returns a file's content at the green gate's revision. An error means
// the path did not exist there or cannot be read; the path reads as code.
At func(ctx context.Context, rev, path string) (string, error)
// Working returns a file's current working-tree content.
Working func(path string) (string, error)
}
ChangeClassifier classifies the paths changed since a green gate. Its dependencies are functions rather than the workspace types that provide them, so the class table is testable against literal content.
func (ChangeClassifier) Classify ¶ added in v0.4.3
Classify assigns each changed path its risk class against green, the commit the recorded gate passed at, and the reason a reader disputes it by. Every failure to classify (an unreadable revision, a file that does not lex) lands the path in ClassCode: the gate runs.
type ClassifiedPath ¶ added in v0.4.3
type ClassifiedPath struct {
Path string
Class ChangeClass
// Why names what classified it: the claiming role, the matching glob and
// its origin, or the comment-comparison outcome.
Why string
}
ClassifiedPath is one changed path's class and the fact it rests on, so a reader can dispute the decision from the message alone.
type DedupEntry ¶
DedupEntry is one (project, target, hash) that was built redundantly across shards, with how many extra builds it caused and the wasted time.
type DedupResult ¶
type DedupResult struct {
TotalMisses int
UniqueKeys int
RedundantBuilds int
RedundantMs int64
// Approx is set when some events lack a Hash (older reports), so grouping is
// by (project, target) only and the count is an approximation.
Approx bool
// Top lists redundant keys sorted by wasted time descending.
Top []DedupEntry
}
DedupResult is the cross-shard redundant-build analysis.
func Dedup ¶
func Dedup(misses []MissBuild) DedupResult
Dedup measures cross-shard redundant builds: when the same (project, target, hash) is a cache miss on more than one shard, those extra builds are waste a shared remote cache would eliminate. Within a single shard's File a key counts once; the longest of the duplicated builds is treated as the necessary one, so the wasted time is total minus max.
type Forecaster ¶
Forecaster is the optional adaptive partitioner that replaces ceil-division when supplied to Build. Defined by interface to avoid an import cycle with magus/ci/forecast.
type GateDecision ¶ added in v0.4.3
type GateDecision int
GateDecision is what the gate does about a redundancy finding.
const ( // GateRun executes the gate with nothing printed. GateRun GateDecision = iota // GateAdvise prints the finding and executes the gate anyway. GateAdvise // GateRefuse does not execute; the refusal names the green gate and exits 75. GateRefuse )
func DecideGate ¶ added in v0.4.3
func DecideGate(f GateFacts) GateDecision
DecideGate is the decision matrix. It is a pure function so the matrix is testable without a store, a daemon, or a repository.
type GateDelta ¶ added in v0.4.3
type GateDelta struct {
Paths []ClassifiedPath
}
GateDelta is the per-path verdict over one delta.
func (GateDelta) Lines ¶ added in v0.4.3
Lines renders one verdict line per path - every file, never a summary, because the refusal's reader must be able to reconstruct the decision.
func (GateDelta) LowRiskOnly ¶ added in v0.4.3
LowRiskOnly reports whether every classified path avoided ClassCode. An empty delta is low-risk: nothing changed since the green gate.
type GateFacts ¶ added in v0.4.3
type GateFacts struct {
// Redundant: a green gate is on record for this branch with an identical
// input fingerprint, or with a delta that classifies entirely low-risk.
Redundant bool
// Saturated: the machine admission pool would queue this run.
Saturated bool
// Forced: the caller passed the override flag; the check is off.
Forced bool
// Nested: this magus runs under another one. It never refuses, because the
// pool it reads counts its own ancestors' claims as load.
Nested bool
}
GateFacts are what DecideGate combines. Zero value decides GateRun.
type GateStep ¶ added in v0.4.3
GateStep is one (project, target) step's live cache key, as Magus.ComputeTargetKey mints it.
type InheritFinding ¶ added in v0.4.3
InheritFinding is a fired verdict-inheritance decision: the green run being inherited, its head commit, and the classified delta a reader disputes it by.
func (InheritFinding) AnnotationText ¶ added in v0.4.3
func (f InheritFinding) AnnotationText() string
AnnotationText renders the finding for a CI annotation: the inherited run, its commit, and every changed path with its class, so the annotation alone lets a reader reconstruct and dispute the decision.
func (InheritFinding) SummaryMarkdown ¶ added in v0.4.3
func (f InheritFinding) SummaryMarkdown() string
SummaryMarkdown renders the finding for the workflow's job summary, under the same explicitness contract: every file, its class, and what classified it - never a count.
type InheritProbe ¶ added in v0.4.3
type InheritProbe struct {
// Disabled: the workspace declared gate_inherit false; nothing is probed.
Disabled bool
// LastGreenRun asks the CI provider for the branch/PR's newest green run
// of this same pipeline. ok=false is the ordinary no-answer case.
LastGreenRun func(ctx context.Context) (run, commit string, ok bool)
// History lists commits from HEAD, newest first, deep enough to reach a
// green run worth inheriting.
History func(ctx context.Context) ([]types.Commit, error)
// Changed lists the paths whose content differs between the working tree
// and the green commit.
Changed func(ctx context.Context, green string) ([]string, error)
Classifier ChangeClassifier
}
InheritProbe gathers the CI verdict-inheritance inputs. Dependencies are functions for ChangeClassifier's reason: the decision is testable with a stubbed provider and no repository.
func (InheritProbe) Evaluate ¶ added in v0.4.3
func (p InheritProbe) Evaluate(ctx context.Context) (InheritFinding, bool)
Evaluate decides. ok=false means the plan proceeds exactly as it would have before this feature existed, with no output at all; ok=true carries the full finding, because an inherited verdict is never a silent skip.
type MissBuild ¶
MissBuild is one cache-miss event, tagged with the shard report File it came from so the same key seen on two shards counts as two builds (and the same key twice within one shard counts once).
type Option ¶
type Option func(*config)
Option mutates the Build configuration.
func WithForecaster ¶
func WithForecaster(f Forecaster) Option
WithForecaster enables adaptive sharding; nil clears it (falls back to ceil-division).
func WithMaxShards ¶
WithMaxShards sets the shard limit; -1 = unlimited (capped at 256); 0 or other negatives return ErrInvalidMaxShards.
type Plan ¶
type Plan struct {
Shards []Shard
Source string
MaxParallel int // 0 = no cap (renderers emit max-parallel = len(Shards))
}
Plan is the output of Build: shards for a CI matrix plus source label and concurrency cap.
type ProseScope ¶ added in v0.4.3
type ProseScope struct {
// Dir is the declaring project's workspace-relative path; "" or "." matches
// against the whole workspace-relative path.
Dir string
// Globs are doublestar patterns relative to Dir.
Globs []string
// Origin is what the per-path attribution names: ProseOriginDefault, or
// `gate_low_risk of project <path>`.
Origin string
}
ProseScope is one source of prose globs: the built-in default set, or one project's gate_low_risk declaration. Globs match the way review_required's do - relative to the declaring project's directory - so an author names files the same way their sources and outputs already do.
func ProseScopes ¶ added in v0.4.3
func ProseScopes(projects []*types.Project) []ProseScope
ProseScopes resolves the workspace's effective prose globs. No declaration anywhere means the shipped defaults; ANY declaration replaces them with the union of declared scopes, so a workspace that declares `[]` and nothing else has turned the prose class off entirely.
Directories
¶
| Path | Synopsis |
|---|---|
|
Package annotate emits CI job-log structure: the fold markers and the warning/error notices a CI provider recognizes.
|
Package annotate emits CI job-log structure: the fold markers and the warning/error notices a CI provider recognizes. |
|
Package forecast picks an adaptive CI shard count using a USL model (N* = sqrt(W/α)) and packs projects via LPT bin-packing.
|
Package forecast picks an adaptive CI shard count using a USL model (N* = sqrt(W/α)) and packs projects via LPT bin-packing. |
|
Package volatility provides Wilson-score volatility prediction and auto-retry for magus test runs.
|
Package volatility provides Wilson-score volatility prediction and auto-retry for magus test runs. |