bundlegen

package
v0.5.0 Latest Latest
Warning

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

Go to latest
Published: May 29, 2026 License: Apache-2.0, MIT Imports: 19 Imported by: 0

Documentation

Overview

Package bundlegen is the OpenAPI → bundle generator. It is deliberately a constrained, fail-loud subset: request/response must be $ref'd component object schemas, scalars + arrays + $ref + nullable→proto3-optional are supported, and any unsupported construct (allOf/oneOf/anyOf/additionalProperties/untyped/inline) is a hard error rather than a lossy bundle. Output is byte-reproducible (sorted, deterministic marshal) for the consumer's buf-breaking story.

Add emits one immutable layer per call. It walks every paths.<path>.<method> operation in the input OpenAPI document, sorted by (path, method) ascending for byte-reproducibility, and emits one contract per operation sharing the same contract_version. The descriptor set is the union of every referenced request/response schema, deduped. A document with a single operation is the degenerate case — one operation, one contract.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Add added in v0.3.0

func Add(openapiSrc, bundleDir string, force bool) error

Add reads the OpenAPI doc from openapiSrc — a local file path or an http(s):// URL (fetched at build time; the bytes are passed through into the committed bundle, so a URL fetch stays point-in-time) — and emits a new immutable layer into bundleDir/<version>/, where <version> is the doc's info.version. Every paths.<path>.<method> operation becomes one contract; all contracts share the same contract_version. The descriptor set is the union of every referenced request/response schema across all operations (deduped). The fail-loud doctrine applies: any unsupported construct in any walked operation rejects the whole bundle, not just that operation.

By default, Add refuses to overwrite an existing layer: a frozen version is never rewritten. When force is true, an existing same-version layer dir is replaced wholesale — the pre-commit-iteration escape hatch for a caller still refining the OpenAPI. Once a layer is committed and consumers depend on it, the default (force=false) guards against accidental clobbering.

func Remove added in v0.3.0

func Remove(bundleDir, version string) error

Remove hard-deletes a version's layer from bundleDir. It is oldest-only: version must be the lexically-oldest layer present, and at least one other layer must remain — the bundle is never emptied and the current version is never removed. Any other request is a hard error.

func Retire added in v0.3.0

func Retire(bundleDir, version string) error

Retire scaffolds a transform-shim override for version in bundleDir. It converts version from the default (direct-route) behaviour to a transform that chains to its immediate newer neighbour, leaving the request and response stanza arrays empty for a human to fill.

Hard errors:

  • version is not a layer in bundleDir
  • version is the newest layer (the current version is never retired)
  • version already has an override in resolution.yaml

Any existing overrides for other versions are preserved verbatim. Operator comments in resolution.yaml are not preserved across the rewrite.

func Verify added in v0.3.0

func Verify(bundleDir string) error

Verify loads the bundle at bundleDir via bundle.Load and returns the typed error on any inconsistency, or nil on success. It is the thin command-facing wrapper that gives a CI consumer a single pass/fail over layers, resolution.yaml, and the transform chains. It also refuses a resolution.yaml that still carries an unresolved drift-shim candidates block — a draft pasted in unedited is a no-op override at runtime, but shipping one signals the operator never picked an OPTION A / B and is almost always a mistake.

Types

type CandidatePair added in v0.4.0

type CandidatePair struct {
	From, To string
	Type     string
	Signals  []Signal
}

CandidatePair is one ambiguous rename: a removed field and an added field that share a primitive type but cannot be auto-renamed without guessing operator intent. The renderer emits both interpretations side by side in a YAML candidates block so a reviewer commits to one.

type CoerceArgs added in v0.4.0

type CoerceArgs struct {
	Field string
	To    string
}

CoerceArgs are the arguments of a `coerce` stanza.

type Confidence added in v0.4.0

type Confidence string

Confidence labels how trustworthy a drafted stanza is. Confident stanzas follow from unambiguous shape changes; Ambiguous stanzas need operator judgment between alternative interpretations.

const (
	Confident Confidence = "confident"
	Ambiguous Confidence = "ambiguous"
)

type DefaultArgs added in v0.4.0

type DefaultArgs struct {
	Field string
	Value any
}

DefaultArgs are the arguments of a `default` stanza.

type OptionalizeArgs added in v0.4.0

type OptionalizeArgs struct {
	Field string
}

OptionalizeArgs are the arguments of an `optionalize` stanza.

type RenameArgs added in v0.4.0

type RenameArgs struct {
	From, To string
}

RenameArgs are the arguments of a `rename` stanza.

type RenderOptions added in v0.4.0

type RenderOptions struct {
	Date string
}

RenderOptions tunes ShimProposal.RenderYAML output. Date sets the header comment's drafted-on stamp; an empty value resolves to today (UTC, YYYY-MM-DD).

type ShimProposal added in v0.4.0

type ShimProposal struct {
	FromVersion        string
	ToVersion          string
	Request            []StanzaProposal
	RequestCandidates  []CandidatePair
	Response           []StanzaProposal
	ResponseCandidates []CandidatePair
	Notes              []string
}

ShimProposal is the draft of a single resolution.yaml override entry: request and response stanza lists, candidate (ambiguous) pairs, plus any notes the drafter could not express mechanically.

func DraftShim added in v0.4.0

func DraftShim(fromOpenAPI, toOpenAPI []byte) (*ShimProposal, error)

DraftShim compares two OpenAPI documents — the frozen "from" contract and the drifted "to" contract — and proposes a transform-shim override that bridges them. It detects four change classes at the request and response message's top-level fields:

  • a field in the "to" shape that the "from" shape lacks (a pure addition) becomes a `default` stanza filling the new field with a type-appropriate placeholder
  • a field present in both but with a changed primitive type becomes a `coerce` stanza
  • a removed/added pair whose case-normalized names match becomes a confident `rename` stanza
  • a removed/added pair sharing a primitive type but with differently-normalized names becomes an ambiguous candidate the renderer surfaces as both `rename` and `delete + add` alternatives

A field in the "from" shape that has no peer left after pair matching becomes a Note — the transform verb set has no way to drop a known field; the operator must reconcile by hand. Top-level object properties only; nested objects, arrays, and oneOf/allOf are not yet supported.

func DraftShimStrict added in v0.4.0

func DraftShimStrict(fromOpenAPI, toOpenAPI []byte) (*ShimProposal, error)

DraftShimStrict is the operator escape hatch: it suppresses every confident case-rename match and reports each removed/added pair as a candidate instead. Use when the drafter's confidence is itself the thing in question — for example when reviewing a high-stakes contract drift and an auto-rename would short-circuit a decision the operator wants to make.

func (*ShimProposal) RenderYAML added in v0.4.0

func (p *ShimProposal) RenderYAML(opts RenderOptions) string

RenderYAML emits the shim proposal as a YAML list element ready to paste into a `resolution.yaml`'s `overrides:` block. Confident stanzas land as fully-formed YAML entries; ambiguous pairs appear as commented-out OPTION A / OPTION B blocks so the operator picks intent. Notes are rendered as a top comment block; the renderer never modifies a layer, never edits an existing resolution.yaml, and is idempotent — a no-op proposal still emits a header and an empty override skeleton so a reviewer sees the drafter ran.

type Signal added in v0.4.0

type Signal struct {
	Kind  SignalKind
	Value string // empty for bare signals
}

Signal is one structural observation the drafter recorded about a proposed stanza or candidate pair. Bare signals carry no Value; parametric signals carry a primitive-type token. Build a Signal through one of the constructor functions below — they enforce the bare-vs-parametric invariant — so a renderer downstream can rely on String() emitting the canonical "kind" or "kind:value" form without re-validating.

func CaseRenameSignal added in v0.4.0

func CaseRenameSignal() Signal

CaseRenameSignal is the bare observation that two field names share their case-and-separator-normalized form.

func FromTypeSignal added in v0.4.0

func FromTypeSignal(t string) Signal

FromTypeSignal carries the "from" side primitive type of a change.

func NoNameSignal added in v0.4.0

func NoNameSignal() Signal

NoNameSignal is the bare observation that a pair shares no name signal at all (same type but otherwise unrelated identifiers).

func PureAddSignal added in v0.4.0

func PureAddSignal() Signal

PureAddSignal is the bare observation that a field is present in the "to" shape only.

func SameTypeSignal added in v0.4.0

func SameTypeSignal(t string) Signal

SameTypeSignal carries the shared primitive type of a rename or candidate pair.

func ToTypeSignal added in v0.4.0

func ToTypeSignal(t string) Signal

ToTypeSignal carries the "to" side primitive type of a change.

func TypeChangeSignal added in v0.4.0

func TypeChangeSignal() Signal

TypeChangeSignal is the bare observation that a field's primitive type changed; pair it with FromTypeSignal and ToTypeSignal to carry the before/after tokens.

func (Signal) String added in v0.4.0

func (s Signal) String() string

String returns the canonical surfaced form: "kind" for bare signals, "kind:value" for parametric ones. The renderer joins these with ", " when emitting the explanatory YAML comment alongside a stanza.

type SignalKind added in v0.4.0

type SignalKind string

SignalKind enumerates the structural observations the drafter can record about a proposed stanza or candidate pair. A bare kind describes a structural fact on its own; a parametric kind carries a primitive-type token in the accompanying Signal.Value.

const (
	SignalKindPureAdd    SignalKind = "pure-add"
	SignalKindTypeChange SignalKind = "type-change"
	SignalKindFromType   SignalKind = "from"
	SignalKindToType     SignalKind = "to"
	SignalKindCaseRename SignalKind = "case-rename"
	SignalKindSameType   SignalKind = "same-type"
	SignalKindNoName     SignalKind = "no-name-signal"
)

type StanzaArgs added in v0.4.0

type StanzaArgs interface {
	// contains filtered or unexported methods
}

StanzaArgs is the sealed set of typed arguments for the transform verbs the drafter can emit. Each implementer corresponds to exactly one transform.Kind; a StanzaProposal's Verb selects which implementer is expected to populate Args.

type StanzaProposal added in v0.4.0

type StanzaProposal struct {
	Verb       transform.Kind
	Args       StanzaArgs
	Confidence Confidence
	Signals    []Signal
}

StanzaProposal is one drafted transform stanza, before any YAML rendering. Verb is the canonical transform.Kind that selects which StanzaArgs implementer is held in Args; Signals records the structural observations that produced the proposal so the renderer can surface *why* the drafter emitted it.

Jump to

Keyboard shortcuts

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