ci

package
v0.4.3 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 6, 2026 License: GPL-3.0 Imports: 12 Imported by: 0

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

View Source
const ProseOriginDefault = "built-in default"

ProseOriginDefault names the built-in glob set in per-path attributions.

Variables

View Source
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.

View Source
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

func GateFingerprint(steps []GateStep) string

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

func InheritOff(projects []*types.Project) bool

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

func MergeFreeRange(history []types.Commit, green string) bool

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

func PRMergeFreeRange(history []types.Commit, green string) bool

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

func (c ChangeClassifier) Classify(ctx context.Context, paths []string, green string) GateDelta

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

type DedupEntry struct {
	Project     string
	Target      string
	Hash        string
	ExtraBuilds int
	ExtraMs     int64
}

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

type Forecaster interface {
	Plan(projects []*types.Project, maxShards int) [][]*types.Project
}

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

func (d GateDelta) Lines() []string

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

func (d GateDelta) LowRiskOnly() bool

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

type GateStep struct {
	Project string
	Target  string
	Key     string
}

GateStep is one (project, target) step's live cache key, as Magus.ComputeTargetKey mints it.

type InheritFinding added in v0.4.3

type InheritFinding struct {
	Run    string
	Commit string
	Delta  GateDelta
}

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

type MissBuild struct {
	Project    string
	Target     string
	Hash       string
	DurationMs int64
	File       string
}

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

func WithMaxShards(n int) Option

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.

func Build

func Build(projects []*types.Project, source string, opts ...Option) (Plan, error)

Build partitions projects into at most maxShards shards via ceil-division (or a forecaster).

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.

type Shard

type Shard struct {
	ID       string
	Projects []*types.Project
}

Shard is one runner's worth of work; ID is zero-padded so log entries sort correctly.

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.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL