Documentation
¶
Overview ¶
Package render turns a snapshot.Snapshot into text. Every renderer is a pure function of (Snapshot, Options): no clock, no environment, no Kubernetes, no globals — which is exactly what makes the golden tests in this package a complete specification of wfctl's output.
Two conventions run through every renderer, because a fleet view that cannot tell "nothing" from "unknown" is worse than no view at all:
- "-" is an absent value: a gate has no source, a settled node has no pending age.
- "?" is an unproven one: this snapshot cannot say. A table that prints any "?" also prints a footnote naming the fix.
Colour is decided by the caller, never here: NO_COLOR, --no-color and TTY detection all belong to the CLI, and a renderer that sniffed the environment could not be golden-tested.
Index ¶
- func DOT(w io.Writer, s *snapshot.Snapshot) error
- func Explain(w io.Writer, s *snapshot.Snapshot, ref adapter.NodeRef, o Options) error
- func Graph(w io.Writer, s *snapshot.Snapshot, o Options) error
- func History(w io.Writer, events []eventsv1.Event, o Options) error
- func JSON(w io.Writer, v any) error
- func Mermaid(w io.Writer, s *snapshot.Snapshot) error
- func Nodes(w io.Writer, s *snapshot.Snapshot, o Options) error
- func Source(w io.Writer, s *snapshot.Snapshot, name string, o Options) error
- func Sources(w io.Writer, s *snapshot.Snapshot, o Options) error
- func Status(w io.Writer, s *snapshot.Snapshot, o Options) error
- func Tree(w io.Writer, s *snapshot.Snapshot, o Options) error
- func YAML(w io.Writer, v any) error
- type Options
- type Palette
- type Table
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func DOT ¶
DOT writes the graph as Graphviz source, for `-o dot`.
State is carried by colour, role by shape, and the two exceptional structures — a hold and a cycle — by border treatments, so a rendered diagram answers "what is stuck, and why" without a legend lookup. The dashed red edges are the engine's own attribution: each points from a blocked node's blocker to the node it is blocking.
func Explain ¶
Explain walks a node's attribution chain to its root cause and names the fix.
The walk is the engine's own attribution read backwards: each blocked node names its nearest unsettled ancestor — or, for SharedSourceBlocked, the sibling that shares its source — so following those links terminates at the one node whose state actually has to change. SelfHeld and GraphCycle name no ancestor and end the walk where they are; a visited set makes the walk total even against an attribution chain that loops.
func Graph ¶
Graph renders the default graph view: dependsOn depth layers, or "waves".
Every node in a wave can advance concurrently with every other node in it, which is the property the layering exists to show: the frontier is wide, not a queue. Anything that never layered is listed apart, because a cycle has no depth and inventing one would suggest an order the engine explicitly refuses to assume.
func History ¶
History renders one row per event, for `wfctl history`.
TIME is how long ago the event last occurred — kubectl's own "LAST SEEN" convention, collapsed to a single column — anchored on snapshot.EventTime, which already resolves eventTime, the series' last-observed heartbeat, or the deprecated firstTimestamp in that order. COUNT is the series' occurrence count, the recorder's own way of collapsing a repeated event onto a single object instead of a new one each time. NOTE is printed verbatim except for characters a table cell cannot carry.
func JSON ¶
JSON writes v as indented JSON with a trailing newline.
A Snapshot round-trips through this and back through snapshot.FileSource unchanged — `wfctl snapshot > f.json` then `--from f.json` is the contract the golden fixtures themselves rely on.
func Mermaid ¶
Mermaid writes the graph as Mermaid flowchart source, for `-o mermaid`.
The encoding is the DOT one restated for a renderer that lives in a pull request or a runbook: colour is state, a hexagon is a gate, a dashed border is a hold, a thick border is a cycle, and the dashed red links are the engine's blocked-by attribution. Node ids are positional (n0, n1, …) because Mermaid ids may not contain the slashes a node reference is made of; the label carries the real name.
func Nodes ¶
Nodes renders one row per evaluated node.
The row is the fleet's per-node truth in the order an operator asks for it: what it is, what state it reached, and — when it did not reach Settled — who is holding it up. PIN and OBSERVED are short SHAs because the question they answer is "are these the same?", which seven characters settle.
func Source ¶
Source renders one managed GitRepository in detail.
Unlike the table, this view prints full SHAs and the provenance annotations verbatim: it is what an operator reads before writing to the object, and before a write the exact value matters.
func Sources ¶
Sources renders one row per managed GitRepository.
This is the pin ledger: the pin, what the ref actually advertises, and who owns the field. `-o wide` adds the provenance of the last advance, which is the durable record, unlike events, which the apiserver eventually expires.
func Status ¶
Status renders the fleet summary: the Wavefront itself, the phase and counts, the structural verdict, the exceptional-state lists, and the diagnostics.
Under the derive origin every count is printed twice — what the controller published, and what re-deriving now says — with the disagreements marked. Under any other origin there is only one number to print, and pretending otherwise would imply a comparison that was never made.
func Tree ¶
Tree renders the graph as rooted trees, for `wfctl graph --tree`.
Roots are wave 0 — the nodes nothing gates — and each is expanded depth first. The DAG is not a tree, so a node with several parents is expanded under the first one that reaches it and referred back to everywhere else: printing its subtree once per parent would multiply a shared platform component across the whole fleet and bury the shape it is meant to show.
Types ¶
type Options ¶
type Options struct {
// Wide selects the extra columns of `-o wide`.
Wide bool
// Palette colours state cells; the zero value is colourless.
Palette Palette
// Now anchors every rendered age. Zero means time.Now — the golden tests
// set it so ages are stable.
Now time.Time
}
Options is every knob the renderers share.
type Palette ¶
type Palette struct {
Enabled bool
}
Palette colours terminal output.
Whether colour is wanted is the CLI's decision (NO_COLOR, --no-color, term.IsTerminal): render never inspects the environment, so its output is a pure function of its inputs and can be golden-tested. The zero Palette is colourless, which is what a test, a pipe, and a file all want.
func NewPalette ¶
NewPalette returns a Palette that colours only when enabled.
type Table ¶
type Table struct {
// contains filtered or unexported fields
}
Table is a tabwriter-backed column layout with a header.
Colour is applied *after* layout, never before. text/tabwriter measures a cell by counting its runes (Writer.updateWidth), and bracketing an escape sequence in tabwriter.Escape does not exempt it: endEscape calls updateWidth for exactly that case, so Escape protects a tab or newline from being read as a separator, not a colour from being counted as width. Feeding it coloured cells therefore pads every coloured row by the byte length of its ANSI sequences and skews the whole table.
So rows are held until Flush, laid out from their ANSI-stripped text, and the styled text is substituted back into the finished lines. An uncoloured table takes a fast path through that substitution and its bytes are exactly what the tabwriter produced.