workflowkit

package
v0.2026282.1947 Latest Latest
Warning

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

Go to latest
Published: Oct 9, 2026 License: MIT Imports: 20 Imported by: 3

Documentation

Overview

Package workflowkit holds the engine-agnostic workflow IR helpers: the lobster expression grammar (expr-lang plus a grammar-enforcing AST patcher), the `${arg}` template + LOBSTER_ARG_* naming, task-arg resolution, the dependency closure, pipeline validation, the charly.yml / .lobster LOWERING, the cron→OnCalendar conversion, and the workflow graph renderers.

It is a MECHANISM library (kind-blind, capability-free): nothing here dials a provider or knows a plugin word. The lobster engine (plugin-lobster) and any future engine (github-actions, …) share ONE lowering + ONE validator.

Index

Constants

This section is empty.

Variables

View Source
var GraphFormat = []string{"mermaid", "dot", "ascii"}

GraphFormat is the closed renderer vocabulary.

Functions

func Closure

func Closure(tasks map[string]spec.Task, names []string) ([]string, error)

Closure returns the tasks to run for `names`, dependency-first, deduplicated, with every task's depends_on recursively included. A cycle is a hard error naming the chain. The returned order is stable: a depth-first post-order over the declared depends_on lists.

func CronToOnCalendar

func CronToOnCalendar(expr string) (string, error)

CronToOnCalendar converts a 5-field cron expression (or an @-macro) into a systemd `OnCalendar=` value. It validates through robfig/cron's standard parser — the SAME grammar the rest of charly accepts — and renders the parsed bit-set, so lists, ranges, steps and names all lower correctly:

"0 3 * * *"             -> "*-*-* 03:00:00"
"*/15 9-17 * * Mon-Fri" -> "Mon,Tue,Wed,Thu,Fri *-*-* 09..17:00/15:00"
"0 0 1 * *"             -> "*-*-01 00:00:00"

ONE cron form is REJECTED rather than lowered: a restricted day-of-month AND a restricted day-of-week in the same expression (`0 3 1 * 1`). cron fires when EITHER of those two fields matches; systemd's calendar spec requires BOTH. A single `OnCalendar=` line cannot express that OR, and GenerateSystemdTimer writes exactly one — so the conversion returns an error naming the cause instead of a schedule that fires on the wrong days. Either field restricted ALONE (`0 3 1 * *`, `0 3 * * 1`) is unaffected: an unrestricted field is not a restriction.

The result is a valid OnCalendar expression; a caller may assert it with `systemd-analyze calendar`.

func Eval

func Eval(expression string, scope Scope) (bool, error)

Eval compiles and runs a lobster boolean expression against scope. `true`/`false` literals must be lowercase (lobster's spelling). The result must be a bool.

func ExpandVars

func ExpandVars(s string, env map[string]string) string

ExpandVars substitutes ${VAR} and $VAR using env first, then the process environment — so a task's dir/command can reference HOME, the project vars, and resolved params uniformly. Moved VERBATIM from plugin-task's expandVars (R3: one implementation, its callers repointed).

func GraphASCII

func GraphASCII(p *spec.Pipeline) string

GraphASCII renders the graph as an indented dependency listing — the terminal- friendly form, each node followed by what it consumes.

func GraphDot

func GraphDot(p *spec.Pipeline) string

GraphDot renders the graph as graphviz dot.

func GraphMermaid

func GraphMermaid(p *spec.Pipeline) string

GraphMermaid renders the graph as a mermaid `flowchart LR` document.

func GraphNodes

func GraphNodes(p *spec.Pipeline) []string

GraphNodes returns every node id in the pipeline (steps, parallel branches and for_each sub-steps), in declaration order, deduplicated.

func HasRef

func HasRef(s string) bool

HasRef reports whether s contains any `$<id>.<path>` step reference.

func LobsterArgEnvVar

func LobsterArgEnvVar(name string) string

LobsterArgEnvVar returns the env var upstream lobster exposes for one resolved arg: `LOBSTER_ARG_<NAME>`.

func LobsterArgName

func LobsterArgName(name string) string

LobsterArgName normalizes a workflow arg name to upstream lobster's env-var spelling: uppercased, every non-alphanumeric character replaced by `_`. `my-arg` → `MY_ARG`; the env var is `LOBSTER_ARG_MY_ARG`.

func LobsterArgsEnv

func LobsterArgsEnv(args map[string]string) map[string]string

LobsterArgsEnv renders a resolved arg set into the environment upstream lobster builds for a workflow step: one `LOBSTER_ARG_<NAME>` per arg plus the whole set as `LOBSTER_ARGS_JSON`. The JSON is deterministic (Go map marshalling sorts keys).

func Lower

func Lower(p *spec.Pipeline, projectDir, genDir, charlyBin string) ([]byte, []byte, error)

Lower lowers an authored pipeline into its (lobsterYAML, charlyYAML) pair. It validates first, so a lowering never emits a half-valid pair.

The workflow name is the generation directory's basename; every generated charly task is named `_pipeline-<name>-<id>`.

func MergedEnv

func MergedEnv(t spec.Task, args map[string]string) map[string]string

MergedEnv is the variable map every step + the dir resolution sees: the task's vars, then its env, then the RESOLVED args. Later sources win on a key collision. Moved from plugin-task's mergedEnv (R3).

func RefIDs

func RefIDs(refs []string) []string

RefIDs reduces a list of `$<id>.<path>` references to their distinct step ids, in order. It is the seam the validator uses on a plan's collected references.

func RefNames

func RefNames(expression string) []string

RefNames returns the distinct step ids referenced by expression, in first-seen order. It is the seam the validator/lowering uses to know which earlier steps a `when:`/`stdin:`/plan consumes (refs to earlier steps only).

func RenderGraph

func RenderGraph(p *spec.Pipeline, format string) (string, error)

RenderGraph renders the pipeline graph in one of GraphFormat.

func ResolveArgs

func ResolveArgs(t spec.Task, cli map[string]string) (map[string]string, error)

ResolveArgs overlays a task's declared `params:` defaults with the CLI-supplied overrides, and enforces `required: true`. A required param with neither an override nor a default is a hard error. An undeclared CLI arg passes through (forward-compat, and vars-like usage).

func ResolveTaskDir

func ResolveTaskDir(projDir, dir string, env map[string]string) string

ResolveTaskDir resolves a task's dir against the project root, expanding ${VAR} / $VAR references against the merged task env (so `dir: "$HOME/src"` and `dir: "${WORKDIR}/src"` both work). An empty dir is the project root.

func RewriteRefs

func RewriteRefs(s string) string

RewriteRefs rewrites every `$<id>.<path>` step reference in s into a `ref("<id>", "<path>")` call. Exported so the migration hook (plugin-migrate) can reuse the ONE ref grammar (R3).

func SortedNames

func SortedNames(tasks map[string]spec.Task) []string

SortedNames returns a copy of the task names in lexical order.

func Validate

func Validate(expression string) error

Validate compiles expression under the lobster grammar with a stub reference resolver and reports the first grammar/type error. It never evaluates.

func ValidatePipeline

func ValidatePipeline(p *spec.Pipeline) error

ValidatePipeline validates ONE authored pipeline: the exec-arm XOR, the co-field rules, unique step ids (parallel branches and for_each `steps:` included), step references to EARLIER steps only, the lobster expression grammar on every `when:`, and `item_var` ≠ `index_var`. It returns a joined error naming every problem found (never just the first), so an author fixes one round.

func ValidateWorkflowCycles

func ValidateWorkflowCycles(refs map[string][]string) error

ValidateWorkflowCycles detects a cycle in a workflow→workflow reference graph (`name -> the workflow names its steps reach`). It is the graph primitive behind the "workflow: cycles" rule: a pipeline that reaches itself transitively can never terminate. Returns the cycle chain (`a -> b -> a`).

Types

type GraphEdge

type GraphEdge struct {
	From     string
	To       string
	Relation string
}

GraphEdge is one dataflow edge: `To` consumes the result of `From` via `Relation` (when / stdin / for_each / branch).

func GraphEdges

func GraphEdges(p *spec.Pipeline) []GraphEdge

GraphEdges derives the pipeline's dataflow edges. A reference in `when:`, `stdin:` or `for_each:` is a dependency (lobster resolves a `$ref` from a FINISHED step, so the edge is the real scheduling constraint). Parallel branches and for_each sub-steps are attached to their parent with a `branch` edge.

type Scope

type Scope map[string]string

Scope is the set of per-step result envelopes an expression evaluates against: step id -> the step's raw output, a JSON envelope such as `{"json":{...},"stdout":"..."}`. `$fetch.json.name` looks up `json.name` in the `fetch` entry with gjson (a `.json` accessor is the author's, not the engine's: the whole envelope is the lookup root, matching upstream lobster).

Jump to

Keyboard shortcuts

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