Documentation
¶
Overview ¶
Package converge answers one question mechanically: are we converging?
Convergence is the health metric — the contraction ratio per stream, every tick. It is computed here, mechanically, so one run's answer can be diffed against the next. A stream here is one number a converging family drives in one direction, read now and read at --since, with the ratio between them.
Everything in this file is PURE: it takes already-fetched data and returns findings. The forge, git, the filesystem and the clock are seams (forge.go, git.go, sources.go), so every test is fake-driven and nothing here reaches a network. See docs/SPEC-CHECK.md.
Index ¶
- Constants
- Variables
- func ClassTests(spec string) []string
- func CountScripts(dir string) (int, error)
- func LedgerRows(md string) (rows, open int)
- func Num(v float64, have bool) string
- func ParseCerts(path, text string) (certified, total int, err error)
- func ParseSince(s string, now time.Time) (time.Time, error)
- func PlanSave(path string) error
- func RetiredInWindow(rows []RetiredRow, since, until time.Time) (inWindow, undated int)
- func RoundsFromBody(body string) (int, bool)
- func RoundsFromLogs(dir string) (map[int]int, error)
- type Batch
- type Field
- type Forge
- type GH
- type Git
- type JSON
- type Options
- type PR
- type RealGit
- type Report
- type RetiredRow
- type State
- type Stream
- func AbsentStream(name, measure, want string, lower bool) Stream
- func Classes(nowSpec string, beforeSpec string, haveBefore bool) Stream
- func Edges(receipts []dogfood.Receipt, since, now time.Time, by []string) Stream
- func Fleet(rows []VersionRow, certified, total int, haveCerts bool) Stream
- func Landing(batches []Batch, since, now time.Time) Stream
- func Ledger(md string) Stream
- func PRs(open, closed []PR, since, now time.Time) Stream
- func Scripts(remaining int, rows []RetiredRow, since, now time.Time) Stream
- type StreamJSON
- type StreamState
- type Trend
- type VersionRow
Constants ¶
const BatchPrefix = "integration-"
BatchPrefix is what makes a merged pull request a batch: integration batches only — nothing else enters the queue.
const ForgeLimit = 1000
ForgeLimit is the most pull requests one read will take. A read that hits it is REFUSED rather than truncated: a convergence number computed from the first thousand of an unknown number is a measurement with a lie in it.
const SpecCIPath = "docs/SPEC-CI.md"
SpecCIPath is the document CLASSES counts, relative to the checkout root.
Variables ¶
var Order = []string{"LANDING", "CLASSES", "SCRIPTS", "PRS", "EDGES", "FLEET", "LEDGER"}
Order is the fixed order of the reading.
Functions ¶
func ClassTests ¶
ClassTests returns the `###` entries under `## The class tests`, in the order the document prints them. Entries outside that section are not counted — the document is full of `###` headings that are not class tests.
func CountScripts ¶
CountScripts counts the scripts left in a directory: a regular file whose name carries a script extension, or whose first two bytes are `#!`. Subdirectories are NOT walked — `bin/retired/` is the other side of this measure, and counting it would make the finish line unreachable.
func LedgerRows ¶
LedgerRows counts the ledger's table rows and the ones not yet closed. A cell is closed when it holds PASS and none of the open words, so `FAIL then PASS` is closed and `FAIL` alone is not.
func Num ¶
Num renders one measured number: an integer when it is one, two decimals when it is not, and `-` when the stream does not have it.
func ParseCerts ¶
ParseCerts reads the certificate roll-up and returns the certified units and the total. `certified` is the one status that counts; every other word is a unit that is not.
func ParseSince ¶
ParseSince reads the far edge of the window in either spelling the flag takes: an RFC3339 instant, or a Go duration meaning that long before now. A window that ends before it starts is refused here rather than printed as a negative rate.
func PlanSave ¶
Save writes the state file, whole, through a temporary file in the same directory: a tick killed halfway through leaves the previous tick's memory rather than half of this one's. PlanSave is Save with nothing written: every check the write makes, and the same error.
func RetiredInWindow ¶
func RetiredInWindow(rows []RetiredRow, since, until time.Time) (inWindow, undated int)
RetiredInWindow counts the rows dated inside [since, until], and the rows nobody dated. Both numbers are printed: an undated row is not this window's, and a reader who is not told how many there are will read the count as whole.
func RoundsFromBody ¶
RoundsFromBody reads the rounds a batch's body names.
Types ¶
type Batch ¶
Batch is one integration batch that landed: the pull request, when it merged, and how many gate rounds it took.
type Field ¶
Field is one key=value extra on a stream's line, after the four the spec fixes. The key is written by this package; the value goes through oneline.
type Forge ¶
type Forge interface {
// OpenPRs is every pull request open right now.
OpenPRs(ctx context.Context) ([]PR, error)
// ClosedSince is every pull request closed or merged at or after `since`.
ClosedSince(ctx context.Context, since time.Time) ([]PR, error)
}
Forge is what this verb needs from a forge, and all of it. Neither method writes: convergence reads the queue, it never touches it.
type GH ¶
type GH struct {
Repo string
Timeout time.Duration
// Bin is the gh executable, "gh" unless a caller names another. A test
// names a fake; nothing here searches a path of its own.
Bin string
}
GH is the real forge: `gh pr list`, bounded, reading only. GH_CONFIG_DIR and the rest of the environment come from the caller's, because which identity gh speaks as is the caller's business and never this verb's.
func (GH) ClosedSince ¶
ClosedSince lists what closed or merged inside the window. The search is by DAY, because that is the resolution the forge's search takes; the window's own edges are applied afterwards by the streams, on the timestamps.
type Git ¶
type Git interface {
// RevBefore is the last commit on the current branch at or before t.
RevBefore(ctx context.Context, t time.Time) (string, error)
// Show is one path's content at one revision.
Show(ctx context.Context, rev, path string) (string, error)
}
Git is what CLASSES needs from a checkout, and all of it.
type JSON ¶
type JSON struct {
At string `json:"at"`
Since string `json:"since"`
Streams []StreamJSON `json:"streams"`
Verdict string `json:"verdict"`
Measured int `json:"streams_measured"`
Contracting int `json:"contracting"`
Widening []string `json:"widening"`
Absent []string `json:"absent"`
}
JSON is the whole reading as one object: the same numbers the lines print, for a reader that is a program.
type Options ¶
type Options struct {
Repo string
LedgerPath string
ReceiptsDir string
RetiredPath string
BinDir string // SCRIPTS
RepoDir string // CLASSES
BatchLogs string // LANDING's second source for rounds
VersionsPath string // FLEET
CertsPath string // FLEET's certified fraction
By []string
Since time.Time
Now time.Time
Forge Forge
Git Git // nil when --repo-dir was not given
}
Options is every source of one reading. A path that is empty is a source the caller did not name, and its stream is ABSENT -- never zero, and never guessed from the working directory.
type PR ¶
type PR struct {
Number int
Title string
Body string
Merged bool
CreatedAt time.Time
ClosedAt time.Time
}
PR is one pull request, in the four facts convergence reads.
type RealGit ¶
type RealGit struct {
Dir string
Timeout time.Duration
// Bin is the git executable, "git" unless a caller names another.
Bin string
}
RealGit runs git in one directory, bounded.
type Report ¶
type Report struct {
Streams []Stream
}
Report is one tick: every stream in the fixed order the spec prints them.
func Read ¶
Read takes the reading. Every refusal it returns is exit 2 at the command line and prints no stream line: a partial reading of convergence is the thing this verb exists to replace.
func (Report) Apply ¶
Apply folds the remembered tick into this one and returns the report with its `before` filled in where only history could supply it, the new state, and whether any stream has now widened on two consecutive ticks -- the one condition that is exit 1.
It is one function because the two halves are one decision: a stream's `before` and its widening streak are read from the same remembered entry, and a version of this that filled one without updating the other is how a streak gets counted twice.
func (Report) Verdict ¶
Verdict is the closing line's arithmetic: how many streams were measured, how many are contracting, which are widening and which were never read.
func (Report) VerdictLine ¶
VerdictLine is the last line of the reading.
type RetiredRow ¶
RetiredRow is one script that was retired, and the day the document says so.
func ParseRetired ¶
func ParseRetired(md string) []RetiredRow
ParseRetired reads the retired README: every table row is one retired script, dated by the nearest dated heading or paragraph ABOVE it. A row under no date at all is returned with HaveDate false rather than dropped — a row nobody dated is evidence, and counting it as this window's would be the guess.
type State ¶
type State struct {
Streams map[string]StreamState `json:"streams"`
}
State is the whole memory of the verb: one entry per stream. There is no other state anywhere, and without --state there is none at all.
type Stream ¶
type Stream struct {
Name string // LANDING, CLASSES, SCRIPTS, PRS, EDGES, FLEET, LEDGER
Measure string // what the number counts, printed as measure=
Now float64
Before float64
HaveNow bool
HaveBefore bool
// Lower is true when fewer is converging. CLASSES is the one stream where
// it is false: a class made mechanical cannot come back, so more entries is
// the family contracting, not widening.
Lower bool
// Want is the flag that would have fed this stream, on an absent one.
Want string
// BeforeFrom names where `before` came from when it was not read from a
// source of its own: `state` for the two streams a single photograph cannot
// give a history.
BeforeFrom string
Extra []Field
}
Stream is one measure of convergence: what it counts, what it counts now, what it counted at --since, and which way it is meant to move.
func AbsentStream ¶
AbsentStream is a stream nobody gave a source for: named, counted on the verdict line, and never guessed at.
func Classes ¶
Classes counts the class-test index at both revisions. It is the one stream that converges upwards.
func Edges ¶
Edges is the dogfood gate: the edges nobody has filed an issue for, now and at --since, with the not-ok rate of the rounds inside the window beside it. `by` narrows the rounds to the named friends; empty reads them all.
func Fleet ¶
func Fleet(rows []VersionRow, certified, total int, haveCerts bool) Stream
Fleet is one build across the machines: the units NOT on the majority stamp, so a fleet on one build reads zero. Its `before` can only come from the state file — a snapshot is a photograph of one instant, and there is no honest way to ask it what yesterday looked like.
func Landing ¶
Landing is the cost of landing: gate rounds per integration batch in the window, against the window of equal length immediately before --since.
func Ledger ¶
Ledger is what the pit stop still owes: the rows not yet closed. Like FLEET, its `before` comes from the state file, because the ledger's rows carry a status and not a date.
func PRs ¶
PRs is the queue at both ends: open now, and open at --since. The second is arithmetic rather than a query, because a forge answers what is open now and nothing answers what was open then: it is the still-open ones created before --since, plus the ones created before it and closed inside the window.
func Scripts ¶
func Scripts(remaining int, rows []RetiredRow, since, now time.Time) Stream
Scripts is the sprint's finish line: what is left in bin, against what was left at --since — which is what is left now plus what the window retired.
func (Stream) Line ¶
Line is the stream's whole output: the four fields the spec fixes, then this stream's own extras.
func (Stream) Ratio ¶
Ratio is always now/before, whichever way the stream converges, so one column means one thing down the whole reading. A before of zero has no ratio: the line prints `-` rather than an infinity dressed up as a measurement.
type StreamJSON ¶
type StreamJSON struct {
Name string `json:"stream"`
Measure string `json:"measure"`
Now *float64 `json:"now"`
Before *float64 `json:"before"`
Ratio *float64 `json:"ratio"`
Trend string `json:"trend"`
Want string `json:"source,omitempty"`
Extra map[string]string `json:"extra,omitempty"`
}
StreamJSON is one stream in that object. A number the verb does not have is null rather than zero, for the same reason the line prints `-`.
type StreamState ¶
type StreamState struct {
Now float64 `json:"now"`
At string `json:"at"`
Widening int `json:"widening_ticks"`
}
StreamState is what one tick remembers about one stream: the value it read, when it read it, and how many consecutive ticks that stream has been widening. The streak is the only thing in this verb that cannot be recomputed from the sources, which is why it is the only thing kept.
type Trend ¶
type Trend string
Trend is which way a stream moved, in the stream's own direction of travel.
const ( // Contracting is the number moving the way this stream converges. Contracting Trend = "contracting" // Flat is a number that did not move, and a first tick, which has nothing // to have moved from. Flat Trend = "flat" // Widening is the number moving the other way: the one word this verb // exists to print. Widening Trend = "widening" // AbsentTrend is a stream whose source was not named. It is not zero and it // is not flat — it is unread, and the line says so rather than contributing // a number nobody measured. AbsentTrend Trend = "absent" )
type VersionRow ¶
VersionRow is one unit of the fleet and the build it is on. A unit is a machine in a roll-up and a binary in one machine's snapshot; the measure is the same either way — how many are not on the one build.
func ParseVersions ¶
func ParseVersions(path, text string) ([]VersionRow, error)
ParseVersions reads either header and refuses anything else by name. A file this verb half-understands is worse than one it refuses: the number it would print is a fleet on one build.