exprlang

package
v0.0.0-...-e740c03 Latest Latest
Warning

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

Go to latest
Published: Oct 11, 2026 License: MIT Imports: 17 Imported by: 0

Documentation

Overview

Package exprlang evaluates the expression form of a resource type's check/in/out — the JSON-over-HTTP alternative to writing those three as shell commands.

It is a leaf: it knows nothing of pipelines, resources, or the store. Everything context-specific (which env names are allowed, which directory file() may read, the source/version/params in scope) arrives in an Input, so the only thing this package decides is what the language can do.

The language is expr-lang/expr, chosen for what it CANNOT do. It has no statements, no loops, no assignment, and no I/O except through the functions handed to it here — so a resource type written this way cannot run a shell command, cannot outlive its call, and cannot be made to by any amount of cleverness in a pipeline file. Adding a scripting engine with those capabilities would have meant owning a sandbox; this way there is nothing to sandbox.

What the expression form buys over shell, concretely: no dependency on curl/jq being installed, no quoting hazard (values are values, never text spliced into a command), errors that propagate instead of being swallowed by a pipeline's exit status, and HTTP that can be concurrent and rate-limit-aware because steps owns the fan-out (see http.go).

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func CloseIdleConnections

func CloseIdleConnections()

CloseIdleConnections releases the keep-alive connections a run left behind. Called when an evaluation finishes so a test's goroutine leak check sees a quiet package, and so a long watch loop does not hold sockets to an API it polls every few minutes.

func Compile

func Compile(slot Slot, src string) error

Compile parses and type-checks one slot's expression without running it, so a syntax error is reported by `steps validate` and by preflight rather than halfway through a watch loop.

It cannot be reported at LOAD time: internal/config depends on nothing internal and imports no third-party code but the YAML parser (enforced by depguard), which is what keeps the config types a leaf everything else can agree on. A syntax error is therefore a validate-time fact, not a parse-time one — see resource.CompileExprPrograms for where that is wired.

func RunCheck

func RunCheck(ctx context.Context, src string, in Input) ([]map[string]any, error)

RunCheck evaluates a check expression and returns the versions it produced, oldest first — the same contract, and the same caller responsibility for ordering, as a shell check's stdout.

func RunIn

func RunIn(ctx context.Context, src string, in Input) (map[string]string, error)

RunIn evaluates an in expression and returns the files it produced, as a map of artifact-relative path to contents.

Returning a file map rather than handing the language a write() builtin is what keeps an expression pure: no side effects means the result is a function of its inputs, which is the property the resource cache is already built on. The caller writes the files (see resource.exprRunIn), and is also where the path guard lives.

func RunOut

func RunOut(ctx context.Context, src string, in Input) (map[string]any, error)

RunOut evaluates an out expression and returns the version it published, or nil when it published nothing versionable — the same tolerance a shell out: gets for printing no JSON.

func Webhook

func Webhook(src string, wantBool bool) (func(env WebhookEnv) (any, error), error)

Webhook compiles an expression over one webhook delivery into a plain func; it is pure (no env(), http(), file(), fail() or clock), so compiling once when the pipeline is set is safe, and wantBool makes a non-boolean filter: a compile error.

Types

type Input

type Input struct {
	// Source is the resource's source: block. Always in scope.
	Source map[string]any
	// Version is the version being fetched (in), or the check cursor — the
	// last version this pipeline recorded (check). Never in scope for out,
	// which produces a version rather than consuming one.
	Version map[string]any
	// Params are the get's or put's params:. In scope for in and out.
	Params map[string]any
	// EnvAllow is the resource type's env: list, and the complete set of
	// names env() will resolve. See envFunc for why there is no baseline.
	EnvAllow []string
	// Dir is the put's read view, the only directory file() may read from.
	// Out slot only.
	Dir string
	// Inputs are the put's input names, sorted: the complete set version()
	// will answer for. Out slot only.
	Inputs []string
	// Versions are what this build's gets fetched, by get name, restricted
	// to Inputs. Out slot only.
	Versions map[string]map[string]any
}

Input is everything an expression evaluates against.

type Slot

type Slot string

Slot names one of the three lifecycle stages an expression can implement. The stages differ in what they see and what they may do, so the slot is a parameter to everything here rather than a caller convention.

const (
	SlotCheck Slot = "check"
	SlotIn    Slot = "in"
	SlotOut   Slot = "out"
)

The three lifecycle stages, spelled as they are in YAML so an error message reads as the key the author wrote.

type WebhookEnv

type WebhookEnv struct {
	Provider string            `expr:"provider"`
	Event    string            `expr:"event"`
	Method   string            `expr:"method"`
	Headers  map[string]string `expr:"headers"`
	Query    map[string]string `expr:"query"`
	Body     string            `expr:"body"`
	Payload  any               `expr:"payload"`
}

WebhookEnv is what a webhook expression reads. A struct rather than a map so payload is typed any: a JSON body can be an object, an array, or absent.

Jump to

Keyboard shortcuts

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