errparse

package
v0.19.1049 Latest Latest
Warning

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

Go to latest
Published: Jul 10, 2026 License: AGPL-3.0 Imports: 3 Imported by: 0

Documentation

Overview

Package errparse turns the raw error output of a failed runner job into a typed compositeerrors.CompositeError.

Parsing is hierarchical: a single failure blob is a stack of nested errors (cloud-provider inside tool inside orchestration), and we want to surface the most specific layer — "Missing IAM permission s3:CreateBucket", not "terraform apply failed". Parsers therefore declare a Layer, and the registry tries the deepest (provider) layer first, then tool, then a generic emit-the-body fallback.

The deepest layer holds the most parsers and grows without bound, so gating must be cheap: a parser advertises the Tools it applies to (a free facet index) and the Signals that must be physically present in the text (a single compiled multi-pattern scan). A parser's expensive Parse only runs when its facet gate passes and one of its signals is present, so per-error cost is a function of the text length and the handful of matched candidates — not the total number of registered parsers.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Parse

Parse dispatches ctx against the default registry.

func Register

func Register(p Parser)

Register adds a parser to the default registry.

Types

type Layer

type Layer int

Layer orders parsers from most-specific to generic. Lower layers are tried first, so a provider-level cause wins over the tool-level fallback.

const (
	// LayerProvider is the cloud-provider layer (AWS/Azure/GCP error codes).
	LayerProvider Layer = 0
	// LayerTool is the execution-tool layer (terraform/helm/pulumi/docker).
	LayerTool Layer = 10
	// LayerGeneric is the always-matches fallback that emits the cleaned error
	// body when no specific parser recognises the failure.
	LayerGeneric Layer = 100
)

type Owner

type Owner struct {
	Type string
	ID   string
}

Owner identifies the row a runner job belongs to (polymorphic: table name + id), e.g. ("install_deploys", "<id>").

type ParseContext

type ParseContext struct {
	// Raw is the untruncated error output captured from the job.
	Raw string

	// Tool is the execution tool, or ToolUnknown when it can't be determined.
	Tool Tool

	// Operation is the job operation (e.g. "apply-plan"), free-form.
	Operation string

	// Group is the runner job group (e.g. "deploy", "build", "sandbox").
	Group string

	// Owner is the row the job belongs to.
	Owner Owner

	// Meta carries the runner-sent error metadata (step, handler, job_type, ...).
	Meta map[string]string

	// ResolveProvider lazily resolves the cloud provider. It is optional: when
	// nil, Provider() reports ProviderUnknown.
	ResolveProvider func() Provider
	// contains filtered or unexported fields
}

ParseContext carries the facets a parser gates and parses on. The free facets (Raw, Tool, Operation, Group, Owner, Meta) are populated eagerly by the caller from the already-loaded runner job; Provider is resolved lazily and memoized so an unmatched job never pays for the DB lookup.

func (*ParseContext) Provider

func (c *ParseContext) Provider() Provider

Provider returns the cloud provider, resolving it at most once. It fails open to ProviderUnknown so an unresolvable owner never suppresses provider parsing (provider gating is a false-positive guard, never the sole gate).

type Parser

type Parser interface {
	// Layer places the parser in the specificity hierarchy.
	Layer() Layer

	// Tools are the execution tools this parser applies to. An empty slice
	// means tool-agnostic (considered for every job). Used to bucket parsers
	// for cheap facet-based narrowing.
	Tools() []Tool

	// Signals are substrings that must be present in the raw text for this
	// parser to be a candidate. They are compiled into a single multi-pattern
	// matcher per bucket. An empty slice means "always a candidate" (used by
	// the generic fallback), which never runs the matcher.
	Signals() []string

	// Applicable confirms the parser should run after a signal match, using the
	// finer facets (notably Provider). It must fail open on unknown facets.
	Applicable(ctx *ParseContext) bool

	// Parse attempts to produce a typed error, or returns nil to defer to the
	// next candidate. It must be selective: a miss returns nil rather than a
	// low-confidence match.
	Parse(ctx *ParseContext) compositeerrors.CompositeError
}

Parser recognises one class of failure. Implementations must be pure and local: no DB or network access (the one lazy DB facet, Provider, is resolved by the context, not the parser).

type Provider

type Provider string

Provider is the cloud provider a job targeted. It is resolved lazily because it costs a DB lookup, and only matters once a provider-specific signal has already been found in the text.

const (
	ProviderUnknown Provider = ""
	ProviderAWS     Provider = "aws"
	ProviderAzure   Provider = "azure"
	ProviderGCP     Provider = "gcp"
)

type Registry

type Registry struct {
	// contains filtered or unexported fields
}

Registry holds the registered parsers and dispatches a ParseContext to them. Parsers are grouped into facet buckets by Tool; within a bucket the signaled parsers share one compiled matcher. The bucket layout is built once, lazily, on the first Parse so that init-time registration order does not matter.

Registration is expected to happen entirely at init time (parser packages blank-imported at the chokepoint). Register panics if called after the first Parse, because a late parser would be silently dropped from the already-built buckets — a bug that is far easier to catch as a panic than as a parser that mysteriously never fires.

Parsers are referenced by their index into r.parsers everywhere (buckets, dedup, candidates) rather than by interface value: a Parser may be any implementation, including a non-comparable struct, so it must never be used as a map key.

func (*Registry) Parse

Parse runs the applicable parsers against ctx and returns the first confident match in layer order (provider, then tool, then generic), or nil when nothing matches. Within a layer, ties are broken by registration order so dispatch is deterministic regardless of bucket collection order.

func (*Registry) Register

func (r *Registry) Register(p Parser)

Register adds a parser. It is intended to be called from init functions and panics on misuse (nil parser, empty signal string, or registration after the registry has been built).

type Tool

type Tool string

Tool is the underlying execution tool a runner job used. It is derived from the runner job type and used as a free facet to bucket parsers, so terraform parsers are never even considered for a helm job.

const (
	ToolUnknown    Tool = ""
	ToolTerraform  Tool = "terraform"
	ToolHelm       Tool = "helm"
	ToolPulumi     Tool = "pulumi"
	ToolDocker     Tool = "docker"
	ToolKubernetes Tool = "kubernetes"
	ToolOCI        Tool = "oci"
)

Directories

Path Synopsis
Package aws holds the AWS provider-layer CompositeError parsers: cloud error codes surfaced from a runner job's raw output.
Package aws holds the AWS provider-layer CompositeError parsers: cloud error codes surfaced from a runner job's raw output.
Package generic holds the tool-agnostic, always-matching fallback parser.
Package generic holds the tool-agnostic, always-matching fallback parser.
Package helm holds tool-layer CompositeError parsers for helm jobs.
Package helm holds tool-layer CompositeError parsers for helm jobs.
Package terraform holds tool-layer CompositeError parsers for terraform jobs.
Package terraform holds tool-layer CompositeError parsers for terraform jobs.

Jump to

Keyboard shortcuts

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