Help us shape the future of Go! Take the 2026 Go Developer Survey

analysis

package
v0.4.0 Latest Latest
Warning

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

Go to latest
Published: Oct 31, 2026 License: Apache-2.0 Imports: 20 Imported by: 0

Documentation

Overview

Package analysis answers "which flows and hooks break if this API changes?" (design §9). For each request version it finds the consumers (flow request nodes, post-hooks, and the version's own extract and assert), what each one reads from the response and which inputs it fills, and checks those reads against the best contract available: pinned examples, else the last saved response.

The package does no logging and reads files only through Contracts.

Index

Constants

View Source
const (
	SourceSchema   = "schema"   // OpenAPI response schemas kept at import
	SourceExample  = "example"  // pinned examples
	SourceResponse = "response" // the last saved response
)

Contract sources, best first (design §9).

View Source
const (
	ReadBody     = "body"     // a body path from a template, e.g. nodes.login.body.data.token
	ReadJSONPath = "jsonpath" // an extraction's JSONPath
	ReadHeader   = "header"
	ReadCookie   = "cookie"
	ReadRegex    = "regex"   // an extraction's regex over the body text
	ReadExtract  = "extract" // an extract name the version does not define
	ReadInput    = "input"   // an input the request needs and the node does not fill
)

Read kinds: what part of the response (or which input) a read relies on.

View Source
const (
	KindNode    = "node"    // a request node in a flow or an inline hook step
	KindHook    = "hook"    // a post-hook step of the request
	KindRequest = "request" // the version's own extract and assert
)

Consumer kinds.

Variables

View Source
var (
	ErrUnknownRequest = errors.New("unknown request")
	ErrUnknownVersion = errors.New("unknown version")
)

Errors for Impact's target.

Functions

func ContractKey

func ContractKey(requestPath, version string) string

ContractKey is the key of a request version in Replaced.By: the request's path and the version label.

func Warnings

func Warnings(reports []Report) diag.List

Warnings turns broken reads into validate warnings (FLW-CONTRACT-001, FLW-CONTRACT-002), each at the reading template. Unknown extract names are left to validate's FLW-NODE-010.

Types

type Consumer

type Consumer struct {
	Kind         string   `json:"kind"`
	Collection   string   `json:"collection"`    // where the consumer is declared
	CollectionID model.ID `json:"collection_id"` //
	File         string   `json:"file"`          // the flow, hook flow or request file
	Flow         string   `json:"flow,omitempty"`
	Node         string   `json:"node,omitempty"`
	Hook         string   `json:"hook,omitempty"` // e.g. "post · request auth/login · inline #0"
	Version      string   `json:"version"`
	Fills        []string `json:"fills,omitempty"` // the node's with keys
	Reads        []Read   `json:"reads,omitempty"`
	Status       Status   `json:"status"`
	Reason       string   `json:"reason,omitempty"` // why the whole consumer is broken, when no single read is
}

Consumer is one user of a request version and everything it relies on.

type Contract

type Contract struct {
	Source  string
	Files   []string
	Samples []Sample
	// Removed says the request version is gone: a changed API description no longer has it. Every consumer
	// of it is broken, whatever it reads.
	Removed bool
}

Contract is what a request version is known to return. Source is empty when nothing is known.

type ContractInfo

type ContractInfo struct {
	Source string   `json:"source"` // SourceExample, SourceResponse, or empty when nothing is known
	Files  []string `json:"files,omitempty"`
}

ContractInfo says what a version's consumers were checked against.

type Contracts

type Contracts interface {
	Contract(c model.Collection, r model.Request, version string) (Contract, diag.List)
}

Contracts finds the contract of one request version.

type Coverage

type Coverage struct {
	Operations []OperationCoverage
}

Coverage says how much of an API description the flows use: which operations some flow calls, which of their documented statuses a run has ever got, and which response fields some flow reads.

func Cover

func Cover(cs []model.Collection, src Contracts, runs []report.Run) Coverage

Cover measures the flows of cs against the operations of their API descriptions. An operation is a request version that came from a description (it has an operation id) and has response schemas. Statuses are seen in runs, the saved run reports passed in; fields are read by the flows' templates, extracts and checks.

func (Coverage) Totals

func (c Coverage) Totals() Totals

Totals adds the operations up.

type DataLink struct {
	From string `json:"from"`
	To   string `json:"to"`
	Via  string `json:"via"`
}

DataLink says that node To reads a value node From made: either its output (`{{nodes.login.token}}`, Via "login.token") or a variable From wrote (`{{vars.token}}`, Via "token"). Links are for drawing and explaining a flow; they do not change how it runs.

func DataLinks(f model.Flow) []DataLink

DataLinks lists the values the nodes of f pass to each other, in the order the readers appear. A variable counts as made by the last node before the reader that writes it, except a value made by a generator: it is fresh, not taken from another step. A node reading its own output is not a link.

type FileContracts

type FileContracts struct {
	DataDir func(model.ID) string
}

FileContracts reads response schemas (<request>.schemas/<version>- <status>.json, written by OpenAPI import), pinned examples (<request>.examples/*.json, next to the request file) and saved responses (<data>/responses/<request-id>/ <version>/last.json). DataDir maps a collection id to its data dir.

func (FileContracts) Contract

func (f FileContracts) Contract(c model.Collection, r model.Request, version string) (Contract, diag.List)

Contract returns the examples for version (and unversioned ones), or else the last saved response. Unreadable examples are warnings and are skipped.

type OperationCoverage

type OperationCoverage struct {
	Collection string
	Request    string // the request's path
	Version    string
	Used       []string     // the flows and hooks that call it
	Statuses   []StatusSeen // the statuses the description documents
	Read       []string     // response fields a flow reads, as JSONPaths ($.user.id)
	Unread     []string     // response fields no flow reads
}

OperationCoverage is one operation of the description: a request version that came from it.

type Read

type Read struct {
	Kind   string `json:"kind"`
	Expr   string `json:"expr"`             // as written: nodes.login.token, response.body.id, extract token, with.tenant
	Target string `json:"target"`           // what is checked: $.data.token, a header, cookie or input name
	Via    string `json:"via,omitempty"`    // the extract name a node read goes through
	Reader string `json:"reader,omitempty"` // the node whose template reads it; empty for flow-level templates
	File   string `json:"file"`
	Path   string `json:"path"` // YAML path of the reading template
	Status Status `json:"status"`
	Reason string `json:"reason,omitempty"`
	// contains filtered or unexported fields
}

Read is one thing a consumer relies on.

type Replaced

type Replaced struct {
	Base Contracts
	By   map[string]Contract
}

Replaced answers with the contracts in By where it has one and with Base for everything else. It is how a changed API description is tried on the flows that use it before the change is imported: By holds what the new description says, and a contract with Removed set stands for a request version the description dropped.

func (Replaced) Contract

func (r Replaced) Contract(c model.Collection, req model.Request, version string) (Contract, diag.List)

Contract returns the replacement for the request version, or the base contract.

type Report

type Report struct {
	Collection   string         `json:"collection"`
	CollectionID model.ID       `json:"collection_id"`
	Request      string         `json:"request"` // path, e.g. auth/login
	RequestID    model.ID       `json:"request_id"`
	Versions     []VersionUsage `json:"versions"`
	Status       Status         `json:"status"` // the worst version's
}

Report is the impact of one request: its versions and their consumers.

func Analyze

func Analyze(cs []model.Collection, src Contracts) ([]Report, diag.List)

Analyze reports every request version that has consumers, for validate's contract warnings.

func Impact

func Impact(cs []model.Collection, t Target, version string, src Contracts) (Report, diag.List, error)

Impact reports who uses request t, across every collection in cs, and whether they still fit its contract. version limits the report to one version; empty means all of them. diags are contract-source problems.

type Sample

type Sample struct {
	Source       string      // SourceExample or SourceResponse
	File         string      // the example or saved-response file
	Status       int         // HTTP status
	Headers      http.Header // response headers
	HeadersKnown bool        // false when an example lists no headers: header reads cannot be judged
	Body         any         // the JSON body, or nil when the body is not JSON
	Text         string      // the body text, when it is not JSON
	Schema       any         // for SourceSchema: the response's JSON Schema
}

Sample is one response a contract is made of.

type SkipReader

type SkipReader struct {
	Skipped  string
	Reader   string
	Reads    string
	Required bool
}

SkipReader is a step that reads something a skipped step would have made. Required is false when the read has a default (?? or ?.), so a missing value is nil rather than an error.

func SkipReaders

func SkipReaders(f model.Flow, skip []string) []SkipReader

SkipReaders lists, in flow order, every step that reads the output of a skipped step (nodes.<id>…) or a variable the last earlier writer of which is skipped. A step inside a skipped container is skipped too; a skipped step is never reported as a reader.

type Status

type Status string

Status is how a consumer fares against a contract. Ranked Compatible < Unknown < Broken.

const (
	Compatible Status = "compatible"
	Unknown    Status = "unknown"
	Broken     Status = "broken"
)

Statuses.

type StatusSeen

type StatusSeen struct {
	Status int
	Seen   bool
}

StatusSeen is a documented status and whether a recorded run ever got it.

type Target

type Target struct {
	Collection model.ID
	Request    model.ID
}

Target names one request: the collection that holds it and its id.

type Totals

type Totals struct {
	Operations, Used       int
	Statuses, SeenStatuses int
	Fields, ReadFields     int
}

Totals counts what is covered.

type VersionUsage

type VersionUsage struct {
	Version   string       `json:"version"`
	Contract  ContractInfo `json:"contract"`
	Consumers []Consumer   `json:"consumers"`
	Status    Status       `json:"status"` // the worst consumer's
}

VersionUsage is every consumer of one request version.

Jump to

Keyboard shortcuts

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