probe

package module
v1.26.0 Latest Latest
Warning

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

Go to latest
Published: Oct 12, 2026 License: MIT Imports: 40 Imported by: 0

README

English | 日本語





PROBE





Probe is a powerful YAML-based workflow automation tool designed for testing, monitoring, and automation tasks.

GitHub Workflow Status GitHub Release Go Documentation

Write a workflow across HTTP, gRPC, databases, mail, SSH and shell in readable YAML, and Probe runs its jobs in parallel; a new protocol can be added as an action. Probe is a single binary that runs the same on your machine, in CI and from cron, with the result in its exit status. A workflow an AI coding agent wrote can be checked before it runs, and run without the writes and connections you did not allow. Documentation: probe.linyo.ws

Architecture

Features

Probe was made for reproducible experiments in computer science: a workflow that drives many protocols is written down in YAML, short enough to read, and run again the same way. The same workflows serve as end-to-end tests that keep software reliable, which matters more now that AI agents, not people, write much of the code.

  • Flexible. HTTP, gRPC, MySQL, PostgreSQL, SQLite, SMTP, IMAP, DNS, SSH and shell are built in, external actions add a browser, GraphQL and JMAP, and a new protocol can be added as an action of its own. Jobs run in parallel unless needs orders them, so one run can call an endpoint, query the row it wrote and read the mail it sent, and repeat runs the same workflow on an interval as a monitor.
  • Easy to run and keep. A workflow is YAML you can read, and steps several scenarios share, such as a login, live in one job file that uses: embedded runs. Probe is a single binary with nothing to install alongside it, so it runs the same on your machine, in CI and from cron, and probe dag prints the jobs as a flowchart in ASCII or Mermaid. Results show in the terminal job by job, with the reason a step failed, and --report also writes them as JSON, JUnit XML, Markdown or a GitHub Actions job summary.
  • Ready for AI coding agents. probe skill teaches an agent to write workflows for the version installed, and probe check finds its mistakes before anything runs. --read-only and --allow-host refuse writes, and connections to hosts you did not list, before they are sent, so a workflow the agent wrote can be run safely. A step can also check responses against your OpenAPI document or .proto files, not only against the agent's own test.

Beyond that, a workflow has outputs to pass data between steps and jobs, test to assert on any response and say which condition did not hold, retry, skipif, wait and timeout, iteration over a list written in the workflow or read from a file, defaults for settings shared across steps and jobs, fail_fast to stop a job at its first failure and always for a cleanup that runs after one, and merging of several YAML files on one command line, where --var and --env-file give the values that differ from run to run.

Understanding Probe covers how these fit together, and Comparison says where k6, Hurl, Venom, runn, Blackbox exporter or GitHub Actions is the better answer.

Quick Start

Install the binary:

go install github.com/mozership/probe/cmd/probe@latest

Write a workflow:

# health-check.yml
name: API Health Check
jobs:
- name: Check API Status
  steps:
  - name: Ping API
    uses: http
    with:
      url: https://api.example.com
      get: /health
    test: res.code == 200

Run it:

probe health-check.yml
API Health Check

⏺ Check API Status (Completed in 0.02s)
  ⎿ 0. ✓  Ping API

Total workflow time: 0.02s ✓ All jobs succeeded

Quickstart goes through this step by step, and Your First Workflow grows it into something you can leave running.

Built-in Actions

Action Use it for
http HTTP requests and their responses
db Queries against MySQL, PostgreSQL and SQLite
smtp Delivering mail
imap Reading a mailbox
ssh Commands on a remote host
shell Commands on the machine running Probe
grpc gRPC and Connect calls, streaming included
dns The records a DNS server answers for a name
embedded Running another job file from a step
hello Printing a report line

These are external actions, each in a repository of its own, which a step pins by commit:

Action Use it for
browser Driving a real browser
graphql GraphQL queries over HTTP
jmap JMAP methods
mail-latency Measuring delivery latency from received messages
redis Commands on a Redis or Valkey server
s3 Objects in S3 and S3-compatible storage
websocket Sending and receiving messages over WebSocket

Documentation

  • Guide — installation, the CLI, and the concepts behind workflows, jobs, steps and data flow
  • How-tos — API testing, monitoring, performance, environments and error handling
  • Tutorials — building a monitoring system, an API test pipeline, and multi-environment tests
  • Reference — YAML configuration, CLI options, built-in functions and environment variables

Runnable workflows live in examples/.

Contributing

Issues, feature requests and pull requests are all welcome.

License

MIT. See LICENSE.

Author

linyows

Documentation

Index

Constants

View Source
const (
	// SeverityError is a finding that stops the workflow from running as it
	// is written, or that makes a step read what is never there.
	SeverityError = "error"
	// SeverityWarning is a finding that the workflow may run with, but that
	// leaves it checking less than it seems to.
	SeverityWarning = "warning"
)

Severities of a Finding.

View Source
const (
	// ExitOK means every job succeeded.
	ExitOK = 0
	// ExitTestFailed means a test did not hold: it evaluated to false, could
	// not be evaluated, or did not evaluate to a boolean; or a request or a
	// response broke the contract an action checked it against.
	ExitTestFailed = 1
	// ExitConfigError means the workflow or the command line was wrong, a
	// step asked for what the guard of the run does not allow, or a report
	// file could not be written, so the run could not do what it was asked
	// to.
	ExitConfigError = 2
	// ExitActionError means an action returned an error, such as a refused
	// connection or a timeout, so a test could not be checked at all.
	ExitActionError = 3
)

Exit codes of a probe run. They tell apart what a caller such as CI or cron has to do about a failure: a failed test points at the system under test, a configuration error at the workflow or the command line, and an action error at the environment, such as a target that cannot be reached.

View Source
const (
	IconSuccess  = "✓ "
	IconError    = "✗ "
	IconTriangle = "△ "
	IconCircle   = "⏺"
	IconWait     = "🕐︎"
	IconSkip     = "⏭ "
	IconRetry    = "⟳"
)

Icon constants

View Source
const (
	// DefaultMaxRepeatCount is the default upper limit for repeat count
	DefaultMaxRepeatCount = 10000
	// DefaultMaxAttempts is the default upper limit for max attempts
	DefaultMaxAttempts = 10000
	// EnvMaxRepeatCount is the environment variable name for overriding max repeat count
	EnvMaxRepeatCount = "PROBE_MAX_REPEAT_COUNT"
	// EnvMaxAttempts is the environment variable name for overriding max attempts
	EnvMaxAttempts = "PROBE_MAX_ATTEMPTS"
)
View Source
const (
	FailureAssertion = report.FailureAssertion
	FailureTestError = report.FailureTestError
	FailureTestType  = report.FailureTestType
	FailureAction    = report.FailureAction
	FailureTemplate  = report.FailureTemplate

	FailureContractResponse = report.FailureContractResponse
	FailureContractRequest  = report.FailureContractRequest
	FailureRefused          = report.FailureRefused
)

Failure kinds recorded on a StepFailure. They are the kinds a report carries, so they are defined there.

View Source
const DefaultSkillDir = ".claude/skills/probe"

DefaultSkillDir is where probe skill install puts the skill when no directory is given: the project-level skills directory of Claude Code.

View Source
const (
	// DefaultStepTimeout is the default timeout for action execution
	DefaultStepTimeout = 5 * time.Minute
)

Variables

This section is empty.

Functions

func BuildReport

func BuildReport(name, description string, rs *Result, order []string, startedAt, finishedAt time.Time) *report.Report

BuildReport assembles a Report from the results of a run. Jobs are listed in the given order, which is the order they are declared in the workflow.

func Guide

func Guide(topic string) (string, error)

Guide returns the Markdown page for a topic. An action's page can also be asked for as actions/<name>.

func GuideIndex

func GuideIndex() string

GuideIndex renders the list of topics probe guide prints without one.

func InstallSkill

func InstallSkill(dir string) (string, error)

InstallSkill writes SKILL.md into dir, creating it, and returns the path it wrote. An existing SKILL.md is replaced, so running it again after an upgrade brings the skill up to date.

The default directory is inside the project, which the user may have checked out from anywhere, so the file is written through safefile.Replace: a symlink at SKILL.md, or at .claude or another directory on the way, cannot redirect it to a file elsewhere.

func Skill

func Skill() string

Skill returns the agent skill as Markdown.

Types

type ActionRunner

type ActionRunner interface {
	RunActions(name string, with map[string]any, opts RunOptions) (map[string]any, error)
}

ActionRunner defines the interface for running actions

type BufferedReporter

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

BufferedReporter keeps the original behaviour: a spinner during the run and the complete report at the end.

func NewBufferedReporter

func NewBufferedReporter(p *Printer) *BufferedReporter

NewBufferedReporter creates a reporter that prints the report at the end.

func (*BufferedReporter) Finish

func (r *BufferedReporter) Finish(rs *Result)

func (*BufferedReporter) JobDone

func (r *BufferedReporter) JobDone(jobID string, jr *JobResult)

func (*BufferedReporter) Start

func (r *BufferedReporter) Start(name, description string)

func (*BufferedReporter) StepDone

func (r *BufferedReporter) StepDone(jobID string, sr StepResult)

func (*BufferedReporter) StepStart

func (r *BufferedReporter) StepStart(jobID, stepName string)

type CheckOptions

type CheckOptions struct {
	// Actions are the names of the actions a step may use, besides the
	// external ones it names by a path or a repository. When it is empty,
	// the names are not checked.
	Actions []string
	// Params are the keys each action takes in with, by its name. The with
	// of an action it does not name, which may take any key, is not
	// checked.
	Params map[string][]string
	// Manifest reads the action.yml of an external action, a local one
	// relative to baseDir, so that its with is checked against the params
	// it declares. When it is nil, the with of an external action is not
	// checked, and nothing is read from the network.
	Manifest func(uses, baseDir string) (*actionref.Manifest, error)
}

CheckOptions tunes Check.

type Config

type Config struct {
	Log     io.Writer
	Verbose bool
	Timing  bool
	// Output selects how the report is delivered while jobs run.
	Output OutputMode
	// Reports lists the report files written once the run has finished.
	Reports []report.Target
	// Guard is what the run allows its actions to do, such as only reading,
	// and only from some hosts. Each step's action is told it, and a step
	// whose action does not keep to it is refused unless it is allowed.
	Guard actionrpc.Guard
	// Env are environment variables read from files, by name, for the vars
	// of the workflow to read where the environment has none of the name.
	// They are given to the vars alone: Probe reads none of its own
	// settings from them, and the actions do not have them in their
	// environment.
	Env map[string]string
	// Vars are values for the vars of the workflow, by name, given by the
	// person running it. Each is taken as it is, in place of what the
	// workflow writes for the var, and the other vars read it.
	Vars map[string]string
	// Actions are the names of the actions of Probe, which a workflow
	// cannot give to an external action under actions. When it is empty,
	// the names a workflow gives are not checked against them.
	Actions []string
}

type ErrorType

type ErrorType string

ErrorType represents different categories of errors

const (
	ErrorTypeValidation    ErrorType = "validation"
	ErrorTypeExecution     ErrorType = "execution"
	ErrorTypeConfiguration ErrorType = "configuration"
	ErrorTypeNetwork       ErrorType = "network"
	ErrorTypeFile          ErrorType = "file"
	ErrorTypeAction        ErrorType = "action"
	ErrorTypeDependency    ErrorType = "dependency"
)

type Executor

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

Executor handles job execution with buffered output

func NewExecutor

func NewExecutor(w *Workflow, job *Job) *Executor

NewExecutor creates a new job executor

func (*Executor) Execute

func (e *Executor) Execute(ctx JobContext) bool

Execute runs a job with buffered output

type ExitStatus

type ExitStatus int

ExitStatus represents the unified status across all actions

const (
	ExitStatusSuccess ExitStatus = 0 // Action succeeded
	ExitStatusFailure ExitStatus = 1 // Action failed
)

func (ExitStatus) Int

func (e ExitStatus) Int() int

Int returns the ExitStatus as an int for comparison

func (ExitStatus) String

func (e ExitStatus) String() string

String returns the ExitStatus as a string

type Finding

type Finding struct {
	Severity string
	File     string // the file it is in; empty when it cannot be told
	Line     int    // the line it is on; 0 when it cannot be told
	Where    string // the job and step it is in, such as job "Users", step 1 "Create"
	Message  string
}

Finding is one thing Check found in a workflow.

func Check

func Check(path string, opts CheckOptions) ([]Finding, error)

Check reads the workflow at path, as a run reads it, and returns what is wrong with it or weak in it, without running anything: keys a workflow does not take, what a run would refuse to load, actions that do not exist, needs that cannot be met, expressions and templates that do not parse, and outputs read before or without being published, as errors; and steps that nothing checks, or whose test reads nothing, as warnings.

The error it returns is for a workflow that cannot be read at all, such as a file that does not exist.

func (Finding) String

func (f Finding) String() string

String is the finding on one line, as probe check prints it.

type GuideTopic

type GuideTopic struct {
	Name  string // what to pass to probe guide
	Group string // the heading it is listed under
	Title string // the page's first heading
	// contains filtered or unexported fields
}

GuideTopic is one page probe guide can print.

func GuideTopics

func GuideTopics() []GuideTopic

GuideTopics lists every topic, references first, then one per action, then the concepts.

type Interval

type Interval struct {
	time.Duration
}

Interval represents a time interval that can be specified as a number (seconds) or duration string

func (Interval) MarshalYAML

func (i Interval) MarshalYAML() (any, error)

MarshalYAML implements custom YAML marshaling for Interval

func (*Interval) UnmarshalYAML

func (i *Interval) UnmarshalYAML(unmarshal func(any) error) error

UnmarshalYAML implements custom YAML unmarshaling for Interval

type Iteration

type Iteration struct {
	// Entries is the list written in the workflow.
	Entries []map[string]any
	// Expr is the template that gives the list, as "{{ outputs.users.rows }}".
	// It is empty when the list is written in the workflow.
	Expr string
}

Iteration is what a step runs once for each entry of, with the entry's keys as vars: a list written in the workflow, or a template that gives one when the step is reached, such as the cases read from a file or the rows an earlier step published.

func (Iteration) MarshalYAML

func (it Iteration) MarshalYAML() (any, error)

MarshalYAML writes the iteration as it is written in a workflow.

func (*Iteration) UnmarshalYAML

func (it *Iteration) UnmarshalYAML(unmarshal func(any) error) error

UnmarshalYAML reads a list of maps as Entries and a string as Expr.

type Job

type Job struct {
	Name  string   `yaml:"name" validate:"required"`
	ID    string   `yaml:"id,omitempty"`
	Needs []string `yaml:"needs,omitempty"`
	// Always runs the job once the jobs it needs are over, whether or not
	// they succeeded, as a job that removes what they made has to.
	Always bool    `yaml:"always,omitempty"`
	Steps  []*Step `yaml:"steps" validate:"required"`
	// FailFast skips the steps after one that failed, as steps that only
	// work on what an earlier one made would fail for its reason.
	FailFast bool    `yaml:"fail_fast,omitempty"`
	Repeat   *Repeat `yaml:"repeat"`
	Defaults any     `yaml:"defaults"`
	SkipIf   string  `yaml:"skipif,omitempty"`
}

func LoadEmbeddedJob

func LoadEmbeddedJob(path string) (*Job, error)

LoadEmbeddedJob loads a job definition from an embedded YAML file

func (*Job) ApplyDefaults

func (j *Job) ApplyDefaults()

ApplyDefaults merges the job's defaults into the with of every step that uses the action they are keyed by. A value the step sets itself wins, and nested objects are merged key by key.

func (*Job) RunIndependently

func (j *Job) RunIndependently(vars map[string]any, printer *Printer, jobID string) (bool, map[string]any, string, string, time.Duration)

RunIndependently executes a job independently with its own context and result tracking Returns success/failure status, outputs, report, error message, and duration

Unlike RunStandalone, it resolves an external action only when a step runs it, as it did before RunStandalone existed: a skipped job or step does not need its action, and one that cannot be resolved fails its step.

func (*Job) RunStandalone

func (j *Job) RunStandalone(vars map[string]any, printer *Printer, jobID, baseDir string, opts ...StandaloneOption) JobRun

RunStandalone runs the job outside a workflow, as an embedded job is run. A local action is resolved relative to baseDir, the directory of the file the job comes from, or to the working directory when baseDir is empty.

func (*Job) Start

func (j *Job) Start(ctx JobContext) error

func (*Job) UseActions

func (j *Job) UseActions(names map[string]string) error

UseActions reads the job by names, the names a workflow gives its external actions: a uses or a key of the defaults that is one of them becomes the action it stands for. The embedded action does so for the job it runs, with the names of the workflow that embeds it, before ApplyDefaults.

type JobContext

type JobContext struct {
	Vars map[string]any `expr:"vars"`
	Config
	Failed bool
	// Current job ID for this context
	CurrentJobID string
	// Repeat tracking
	IsRepeating   bool
	RepeatCurrent int
	RepeatTotal   int
	StepCounters  map[int]StepRepeatCounter // step index -> counter

	// Print writer
	Printer *Printer
	// Result for managing job-level output
	Result *Result
	// Job scheduler for managing job dependencies and execution
	JobScheduler *JobScheduler
	// Shared outputs across all jobs (accessible via expressions as "outputs")
	Outputs *Outputs `expr:"outputs"`
	// contains filtered or unexported fields
}

JobContext provides context data for job execution

func (*JobContext) SetFailed

func (j *JobContext) SetFailed()

SetFailed marks the job context as failed

type JobResult

type JobResult struct {
	JobName     string
	JobID       string
	Status      string
	StartTime   time.Time
	EndTime     time.Time
	Success     bool
	StepResults []StepResult // Store all step results for this job
	// contains filtered or unexported fields
}

JobResult stores execution results for a job

type JobRun

type JobRun struct {
	// Success is true when every step passed or the job was skipped.
	Success bool
	// Outputs are the outputs the job's steps published.
	Outputs map[string]any
	// Report is the report of the job's steps.
	Report string
	// Err is set when the job could not run as it was written, such as when
	// a step is invalid or an action cannot be resolved. A step that fails
	// leaves it nil and Success false.
	Err error
	// Refused is set when the guard the job ran under refused a step, the
	// first one, so that the step that embeds the job is refused as well
	// rather than failing as a job whose test was false.
	Refused *actionrpc.Refused
	// Duration is how long the job took.
	Duration time.Duration
}

JobRun is the outcome of a job run on its own with RunStandalone.

type JobScheduler

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

func NewJobScheduler

func NewJobScheduler() *JobScheduler

func (*JobScheduler) AddJob

func (js *JobScheduler) AddJob(job *Job) error

func (*JobScheduler) AllJobsCompleted

func (js *JobScheduler) AllJobsCompleted() bool

func (*JobScheduler) CanRunJob

func (js *JobScheduler) CanRunJob(jobID string) bool

func (*JobScheduler) GetRepeatInfo

func (js *JobScheduler) GetRepeatInfo(jobID string) (current, target int)

GetRepeatInfo returns current repeat counter and target for a job

func (*JobScheduler) GetRunnableJobs

func (js *JobScheduler) GetRunnableJobs() []string

func (*JobScheduler) IncrementRepeatCounter

func (js *JobScheduler) IncrementRepeatCounter(jobID string)

IncrementRepeatCounter increments the repeat counter for a job

func (*JobScheduler) MarkJobsWithFailedDependencies

func (js *JobScheduler) MarkJobsWithFailedDependencies() []string

MarkJobsWithFailedDependencies marks jobs as failed if their dependencies have failed, except those that always run. It iterates until no more jobs are newly marked, propagating failures transitively through multi-level dependency chains.

func (*JobScheduler) SetJobStatus

func (js *JobScheduler) SetJobStatus(jobID string, status JobStatus, success bool)

func (*JobScheduler) ShouldRepeatJob

func (js *JobScheduler) ShouldRepeatJob(jobID string) bool

ShouldRepeatJob checks if a job should be repeated

func (*JobScheduler) ValidateDependencies

func (js *JobScheduler) ValidateDependencies() error

type JobStatus

type JobStatus int
const (
	JobPending JobStatus = iota
	JobRunning
	JobCompleted
	JobFailed
)

type LogLevel

type LogLevel int

LogLevel defines different logging levels

const (
	LogLevelDebug LogLevel = iota
	LogLevelInfo
	LogLevelWarn
	LogLevelError
)

type MockActionRunner

type MockActionRunner struct {
	Results map[string]map[string]any
	Errors  map[string]error
	// States is the state each action leaves in the job, keyed by its name.
	States map[string]map[string]any
	// Calls records each call of an action for a step, in order.
	Calls map[string][]actionrpc.Call
	// contains filtered or unexported fields
}

MockActionRunner implements ActionRunner for testing

func NewMockActionRunner

func NewMockActionRunner() *MockActionRunner

NewMockActionRunner creates a new mock action runner

func (*MockActionRunner) RunActions

func (m *MockActionRunner) RunActions(name string, with map[string]any, opts RunOptions) (map[string]any, error)

RunActions returns the mocked result or error for the given action

func (*MockActionRunner) RunStep

func (m *MockActionRunner) RunStep(name string, call actionrpc.Call, opts RunOptions) (map[string]any, map[string]any, error)

RunStep records the call and returns the result and the state set for the action.

func (*MockActionRunner) SetError

func (m *MockActionRunner) SetError(actionName string, err error)

SetError sets the expected error for an action

func (*MockActionRunner) SetResult

func (m *MockActionRunner) SetResult(actionName string, result map[string]any)

SetResult sets the expected result for an action

type NameTakenError

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

NameTakenError reports an output whose name was taken before it was published, so that outputs.<name> holds something else. It is a warning: the step's value is kept under its id when that can be.

func (*NameTakenError) Error

func (e *NameTakenError) Error() string

type OutputMode

type OutputMode int

OutputMode selects how a workflow run delivers its report.

const (
	// OutputModeAuto picks spinner on an interactive terminal and stream otherwise.
	OutputModeAuto OutputMode = iota
	// OutputModeSpinner shows a spinner while running and prints the whole
	// report once every job has finished.
	OutputModeSpinner
	// OutputModeStream prints each job block as soon as it is final and logs
	// step progress to stderr while jobs are still running.
	OutputModeStream
)

func ParseOutputMode

func ParseOutputMode(s string) (OutputMode, error)

ParseOutputMode converts a user supplied name into an OutputMode.

func (OutputMode) String

func (m OutputMode) String() string

type Outputs

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

Outputs manages step outputs across the entire workflow

func NewOutputs

func NewOutputs() *Outputs

NewOutputs creates a new Outputs instance

func (*Outputs) Get

func (o *Outputs) Get(stepID string) (map[string]any, bool)

Get retrieves outputs for a step (existing functionality)

func (*Outputs) GetAll

func (o *Outputs) GetAll() map[string]any

GetAll returns all outputs (safe copy for expression evaluation). A run's own outputs stand in front of its parent's.

func (*Outputs) GetAllWithFlat

func (o *Outputs) GetAllWithFlat() map[string]any

GetAllWithFlat returns all outputs including flat access for expression evaluation

func (*Outputs) GetConflicts

func (o *Outputs) GetConflicts() map[string][]string

GetConflicts returns information about conflicted output names

func (*Outputs) GetFlat

func (o *Outputs) GetFlat(outputName string) (any, bool)

GetFlat retrieves output by name directly (new functionality)

func (*Outputs) Set

func (o *Outputs) Set(stepID string, outputs map[string]any) error

Set stores outputs for a step with flat access support

type PluginActionRunner

type PluginActionRunner struct{}

PluginActionRunner implements ActionRunner using the plugin system

func (*PluginActionRunner) RunActions

func (p *PluginActionRunner) RunActions(name string, with map[string]any, opts RunOptions) (map[string]any, error)

RunActions executes an action using the plugin system

func (*PluginActionRunner) RunStep

func (p *PluginActionRunner) RunStep(name string, call actionrpc.Call, opts RunOptions) (map[string]any, map[string]any, error)

RunStep executes an action for a step using the plugin system, telling it about the step, giving it the state it left in the job and returning the state it leaves.

type Printer

type Printer struct {
	Buffer    map[string]*strings.Builder
	BufferIDs []string // Order preservation
	// contains filtered or unexported fields
}

Printer implements PrintWriter for console print

func NewPrinter

func NewPrinter(verbose bool, bufferIDs []string) *Printer

NewPrinter creates a new console print writer

func (*Printer) AddSpinnerSuffix

func (p *Printer) AddSpinnerSuffix(txt string)

func (*Printer) Fprint

func (p *Printer) Fprint(w io.Writer, a ...any)

func (*Printer) Fprintf

func (p *Printer) Fprintf(w io.Writer, f string, a ...any)

func (*Printer) Fprintln

func (p *Printer) Fprintln(w io.Writer, a ...any)

func (*Printer) GenerateReport

func (p *Printer) GenerateReport(rs *Result) string

GenerateReport generates a complete workflow report string using Result data

func (*Printer) GenerateReportOnlySteps

func (p *Printer) GenerateReportOnlySteps(rs *Result) string

func (*Printer) LogDebug

func (p *Printer) LogDebug(format string, args ...any)

LogDebug prints debug messages (only in verbose mode)

func (*Printer) LogError

func (p *Printer) LogError(format string, args ...any)

LogError prints error messages to stderr

func (*Printer) LogWarn

func (p *Printer) LogWarn(format string, args ...any)

LogWarn prints a warning to the error writer: something the user should know about that does not make the run fail.

func (*Printer) Masker

func (p *Printer) Masker() *mask.Masker

Masker returns the masker the printer applies. It is nil when none was installed, and on a nil Printer, which some contexts run without.

func (*Printer) PrintEchoContent

func (p *Printer) PrintEchoContent(content string)

PrintEchoContent prints echo content with proper indentation in verbose mode

func (*Printer) PrintError

func (p *Printer) PrintError(format string, args ...any)

PrintError prints an error message

func (*Printer) PrintHeader

func (p *Printer) PrintHeader(name, description string)

PrintHeader prints the workflow name and description

func (*Printer) PrintMapData

func (p *Printer) PrintMapData(data map[string]any)

PrintMapData prints map data with proper formatting for nested structures

func (*Printer) PrintReport

func (p *Printer) PrintReport(rs *Result)

PrintReport prints a complete workflow report using Result data

func (*Printer) PrintRequestResponse

func (p *Printer) PrintRequestResponse(stepIdx int, stepName string, req, res map[string]any, rt string)

PrintRequestResponse prints request and response data with proper formatting

func (*Printer) PrintSeparator

func (p *Printer) PrintSeparator()

PrintSeparator prints a separator line for verbose output

func (*Printer) PrintTestResult

func (p *Printer) PrintTestResult(success bool, testExpr string, context any)

PrintTestResult prints test result in verbose mode

func (*Printer) PrintVerbose

func (p *Printer) PrintVerbose(format string, args ...any)

PrintVerbose prints verbose output (only if verbose mode is enabled)

func (*Printer) Reporter

func (p *Printer) Reporter() Reporter

Reporter returns the installed output strategy, or nil when none was set.

func (*Printer) SetBufferIDs

func (p *Printer) SetBufferIDs(ids []string)

SetBufferIDs records the job order the report is rendered in. Workflow.Start sets it once job IDs are assigned, because a caller cannot know an ID that the scheduler generates for a job that omitted one.

func (*Printer) SetMasker

func (p *Printer) SetMasker(m *mask.Masker)

SetMasker installs the masker applied to everything the printer writes.

func (*Printer) SetReporter

func (p *Printer) SetReporter(r Reporter)

SetReporter installs the output strategy used for this run.

func (*Printer) StartSpinner

func (p *Printer) StartSpinner()

func (*Printer) StepStart

func (p *Printer) StepStart(jobID, stepName string)

StepStart announces that a step began. The buffered reporter turns this into the spinner suffix, the stream reporter into a stderr progress line.

func (*Printer) StopSpinner

func (p *Printer) StopSpinner()

type Probe

type Probe struct {
	FilePath string

	Config Config
	// contains filtered or unexported fields
}

func New

func New(path string, v bool) *Probe

func (*Probe) DagAscii

func (p *Probe) DagAscii() (string, error)

DagAscii returns the ASCII art representation of the workflow job dependencies with steps

func (*Probe) DagMermaid

func (p *Probe) DagMermaid() (string, error)

DagMermaid returns the Mermaid format representation of the workflow job dependencies

func (*Probe) Do

func (p *Probe) Do() error

func (*Probe) ExitStatus

func (p *Probe) ExitStatus() int

func (*Probe) Load

func (p *Probe) Load() error

type ProbeError

type ProbeError struct {
	Type      ErrorType
	Operation string
	Message   string
	Cause     error
	Context   map[string]any
}

ProbeError is the base error type with context information

func NewActionError

func NewActionError(operation, message string, cause error) *ProbeError

func NewConfigurationError

func NewConfigurationError(operation, message string, cause error) *ProbeError

func NewExecutionError

func NewExecutionError(operation, message string, cause error) *ProbeError

func NewFileError

func NewFileError(operation, message string, cause error) *ProbeError

func NewProbeError

func NewProbeError(errorType ErrorType, operation, message string, cause error) *ProbeError

NewProbeError creates a new ProbeError

func (*ProbeError) Error

func (e *ProbeError) Error() string

func (*ProbeError) Is

func (e *ProbeError) Is(target error) bool

func (*ProbeError) Unwrap

func (e *ProbeError) Unwrap() error

func (*ProbeError) WithContext

func (e *ProbeError) WithContext(key string, value any) *ProbeError

WithContext adds context information to the error

type Repeat

type Repeat struct {
	Count    int      `yaml:"count" validate:"required,gte=0"`
	Interval Interval `yaml:"interval"`
	Async    bool     `yaml:"async,omitempty"`
}

Repeat defines the repeat configuration for jobs

func (*Repeat) Validate

func (r *Repeat) Validate() error

Validate performs custom validation for Repeat

type Reporter

type Reporter interface {
	Start(name, description string)
	StepStart(jobID, stepName string)
	StepDone(jobID string, sr StepResult)
	JobDone(jobID string, jr *JobResult)
	Finish(rs *Result)
}

Reporter decides when the parts of a workflow report reach the user. Jobs run concurrently, so implementations are called from several goroutines and must serialize their own writes.

type ResponseTime

type ResponseTime struct {
	Duration string  `expr:"duration"`
	Sec      float64 `expr:"sec"`
}

ResponseTime provides response time information for expressions

type Result

type Result struct {
	Jobs map[string]*JobResult
	// contains filtered or unexported fields
}

Result manages execution results for multiple jobs

func NewResult

func NewResult() *Result

NewResult creates a new Result instance

func (*Result) AddStepResult

func (rs *Result) AddStepResult(jobID string, stepResult StepResult)

AddStepResult adds a StepResult to the specified job result

func (*Result) SetReporter

func (rs *Result) SetReporter(r Reporter)

SetReporter installs the reporter notified when steps and jobs finish.

type RunOptions

type RunOptions struct {
	// Verbose raises the action's log level to debug.
	Verbose bool
	// Quiet silences the action's own log records. It is set for a retry
	// attempt that still has another attempt left: actions have no notion of
	// being retried, so a failure there would otherwise be reported at error
	// level even though the step goes on to succeed.
	Quiet bool
	// Masker hides the workflow's secrets in the action's log records.
	Masker *mask.Masker
	// BaseDir is the directory a local action's path is relative to: the
	// directory of the workflow file. The working directory is used when it
	// is empty.
	BaseDir string
}

RunOptions controls how a single action invocation is run and logged.

type StandaloneOption

type StandaloneOption func(*standaloneConfig)

StandaloneOption changes how RunStandalone runs a job.

func WithActions

func WithActions(names map[string]string) StandaloneOption

WithActions tells the steps of the job the names a workflow gives its external actions, such as those of the workflow that embeds it, for a job the job itself embeds to be read by. The job's own steps are read by them with UseActions.

func WithBuiltinActions

func WithBuiltinActions(names []string) StandaloneOption

WithBuiltinActions tells the job the names of the actions of Probe, so that a uses that names no action stops the job before any step runs. Without it, such a step fails when it is run.

func WithGuard

func WithGuard(guard actionrpc.Guard) StandaloneOption

WithGuard runs the job under guard, such as the guard of the run of the step that embeds it, so that a workflow cannot get round its guard by embedding a job.

func WithRunID

func WithRunID(id string) StandaloneOption

WithRunID runs the job as part of the run id names, such as the run of the step that embeds it, so that its actions are told the same run. Without it the job is a run of its own.

type StatusType

type StatusType int

StatusType represents the status of execution

const (
	StatusSuccess StatusType = iota
	StatusError
	StatusWarning
	StatusSkipped
)

type Step

type Step struct {
	Name      string            `yaml:"name"`
	ID        string            `yaml:"id,omitempty"`
	Uses      string            `yaml:"uses" validate:"required"`
	With      map[string]any    `yaml:"with"`
	Test      string            `yaml:"test"`
	Echo      string            `yaml:"echo"`
	Vars      map[string]any    `yaml:"vars"`
	Iteration Iteration         `yaml:"iteration"`
	Wait      string            `yaml:"wait,omitempty"`
	SkipIf    string            `yaml:"skipif,omitempty"`
	Outputs   map[string]string `yaml:"outputs,omitempty"`
	Retry     *StepRetry        `yaml:"retry,omitempty"`
	Timeout   Interval          `yaml:"timeout,omitempty"`

	Idx  int        `yaml:"-"`
	Expr *expr.Expr `yaml:"-"`
	// contains filtered or unexported fields
}

func (*Step) Do

func (st *Step) Do(jCtx *JobContext)

func (*Step) DoTest

func (st *Step) DoTest(printer *Printer) (string, bool)

func (*Step) SetCtx

func (st *Step) SetCtx(j JobContext, override map[string]any)

type StepActionRunner

type StepActionRunner interface {
	ActionRunner
	RunStep(name string, call actionrpc.Call, opts RunOptions) (result, newState map[string]any, err error)
}

StepActionRunner is an ActionRunner that also tells an action about the step it runs for and carries the state it keeps in a job, as actionrpc.StepAction describes. A runner that is not one runs every action with its parameters alone.

type StepContext

type StepContext struct {
	Vars        map[string]any `expr:"vars"`
	Res         map[string]any `expr:"res"`
	Req         map[string]any `expr:"req"`
	RT          ResponseTime   `expr:"rt"`
	Report      string         `expr:"report"`
	Outputs     map[string]any `expr:"outputs"`
	Status      int            `expr:"status"`
	RepeatIndex int            `expr:"repeat_index"`
}

StepContext provides context data for step expression evaluation

type StepFailure

type StepFailure struct {
	Kind    string
	Message string
	// Request and Response are what the action sent and received. They are left
	// nil when the action asked not to be dumped (res.dump: false).
	Request  map[string]any
	Response map[string]any
	// Violations are what broke the contract, when Kind is a contract's.
	Violations []report.Violation
}

StepFailure describes a failed step without terminal formatting, so that reports can serialize it.

type StepRepeatCounter

type StepRepeatCounter struct {
	SuccessCount int
	FailureCount int
	// SkippedCount is the runs in which the step was not run: an earlier
	// step of the run failed in a job with fail_fast, or its iteration
	// came to no entry. They are neither successes nor failures of the
	// step.
	SkippedCount int
	Name         string
	// Test is the test of the step the counter is of, empty when it has
	// none. The counter is kept by the index of the step as it ran, which
	// an iteration makes another than its index in the job, so what the
	// step's result needs of the step is kept here.
	Test        string
	LastResult  bool
	RepeatTotal int      // Total number of times the step should be repeated
	EchoOutputs []string // Formatted echo output captured per iteration
	// Failure is why the first iteration that failed did, so that the step's
	// result keeps the kind of failure, such as an action error, rather than
	// only the count.
	Failure *StepFailure
	// Checked is whether an action checked a response against a contract,
	// which checks the step as a test does.
	Checked bool
	// Contract is what the first iteration's response was matched to in
	// its contract.
	Contract *report.Contract
}

StepRepeatCounter tracks the execution results of repeated steps

type StepResult

type StepResult struct {
	Index         int
	Name          string
	Status        StatusType
	StartedAt     time.Time
	RT            string
	RTSec         float64
	WaitTime      string
	TestOutput    string
	EchoOutput    string
	Report        string
	HasTest       bool
	RetryAttempt  int                // Number of attempts made (0 = retry not performed, 1 = succeeded first try)
	RetryMax      int                // Maximum retry attempts configured
	RepeatCounter *StepRepeatCounter // For repeat execution information
	// The fields below feed the report files. Unlike StartedAt and RT they are
	// recorded whether or not --timing is set, and they carry no terminal styling.
	Test    string        // The test expression, empty when the step has none
	Elapsed time.Duration // Wall time from the action's start to the result
	Failure *StepFailure  // Why the step failed; nil unless Status is StatusError
	// Contract is what the response was matched to in the contract the
	// action checked it against; nil when it checked none.
	Contract *report.Contract
}

StepResult represents the result of a step execution

type StepRetry

type StepRetry struct {
	MaxAttempts  int      `yaml:"max_attempts" validate:"required,gte=1"`
	Interval     Interval `yaml:"interval"`
	InitialDelay Interval `yaml:"initial_delay,omitempty"`
}

StepRetry defines the retry configuration for steps until success (status 0)

func (*StepRetry) Validate

func (s *StepRetry) Validate() error

Validate performs custom validation for StepRetry

type StreamReporter

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

StreamReporter prints the report incrementally.

A job block is only printed once the job is final, which keeps blocks from interleaving even though jobs run concurrently. Blocks are held back until every earlier job in workflow order has been printed, so the finished report is identical to the buffered one. Step level progress goes to stderr, which is what keeps a CI log alive while the first job is still running.

func NewStreamReporter

func NewStreamReporter(p *Printer) *StreamReporter

NewStreamReporter creates a reporter that flushes job blocks as they finish.

func (*StreamReporter) Finish

func (r *StreamReporter) Finish(rs *Result)

func (*StreamReporter) JobDone

func (r *StreamReporter) JobDone(jobID string, jr *JobResult)

func (*StreamReporter) Start

func (r *StreamReporter) Start(name, description string)

func (*StreamReporter) StepDone

func (r *StreamReporter) StepDone(jobID string, sr StepResult)

func (*StreamReporter) StepStart

func (r *StreamReporter) StepStart(jobID, stepName string)

type Workflow

type Workflow struct {
	Name        string         `yaml:"name" validate:"required"`
	Description string         `yaml:"description,omitempty"`
	Jobs        []Job          `yaml:"jobs" validate:"required"`
	Vars        map[string]any `yaml:"vars"`
	// Defaults are the with of each action, by its uses, for the steps of
	// every job. A job's own defaults come before them, and a step's with
	// before both.
	Defaults any `yaml:"defaults"`
	// Actions gives names to external actions, for the steps and the
	// defaults of the jobs to name them by. Load writes the action in place
	// of each name, so nothing that runs the workflow sees one.
	Actions map[string]string `yaml:"actions,omitempty"`
	// Secrets names environment variables whose values must not appear in
	// anything Probe prints or writes.
	Secrets []string `yaml:"secrets,omitempty"`
	// contains filtered or unexported fields
}

func (*Workflow) Env

func (w *Workflow) Env() map[string]string

func (*Workflow) Graph

func (w *Workflow) Graph() dag.Graph

Graph returns the jobs and steps of the workflow in the form the DAG renderers draw. The steps of an embedded job are read from its file, at the path its `with.path` names after the workflow's vars are expanded, relative to the working directory.

func (*Workflow) RunID

func (w *Workflow) RunID() string

RunID returns the ID of the run Start began, which every action of the run is told about, or an empty string before Start.

func (*Workflow) SetExitStatus

func (w *Workflow) SetExitStatus(isErr bool)

func (*Workflow) Start

func (w *Workflow) Start(c Config) error

Start executes the workflow with the given configuration

Directories

Path Synopsis
Package actionref resolves an action that a step's `uses` names outside Probe to the executable that serves it.
Package actionref resolves an action that a step's `uses` names outside Probe to the executable that serves it.
Package actionrpc is the protocol between the workflow runner and its actions.
Package actionrpc is the protocol between the workflow runner and its actions.
Package actions maps the action names usable in a step's `uses` to the built-in plugins that implement them.
Package actions maps the action names usable in a step's `uses` to the built-in plugins that implement them.
db
dns
Package dns is the dns action: it asks a DNS server for the records of a name, and returns what the server answered.
Package dns is the dns action: it asks a DNS server for the records of a name, and returns what the server answered.
grpc/testserver command
smtp/testserver command
ssh
Package binary turns raw response payloads into either printable text or a file on disk, based on the declared MIME type.
Package binary turns raw response payloads into either printable text or a file on disk, based on the declared MIME type.
cmd
probe command
Package dag provides generic graph algorithms that work with any data structure, and the renderers that draw a workflow's jobs as a graph.
Package dag provides generic graph algorithms that work with any data structure, and the renderers that draw a workflow's jobs as a graph.
e2e
dns-server command
Command dns-server answers DNS queries for a few records of example.test, over UDP and TCP.
Command dns-server answers DNS queries for a few records of example.test, over UDP and TCP.
echo-server command
Command echo-server echoes a POSTed JSON body back as the data of the response, with the request headers.
Command echo-server echoes a POSTed JSON body back as the data of the response, with the request headers.
Package envfile reads files of environment variables, one NAME=value a line, as the .env files many tools keep beside a project.
Package envfile reads files of environment variables, one NAME=value a line, as the .env files many tools keep beside a project.
Package expr evaluates the expressions and {{ }} templates of a workflow.
Package expr evaluates the expressions and {{ }} templates of a workflow.
Package jsonutil decodes and compares the JSON values that actions return.
Package jsonutil decodes and compares the JSON values that actions return.
Package mapping converts between untyped action parameter maps and tagged Go structs.
Package mapping converts between untyped action parameter maps and tagged Go structs.
Package mask hides secret values in everything Probe prints or writes.
Package mask hides secret values in everything Probe prints or writes.
Package procgroup stops the process groups that steps leave running in the background once the workflow that started them is over.
Package procgroup stops the process groups that steps leave running in the background once the workflow that started them is over.
Package report renders the result of a workflow run as files for machines and for people: JSON, JUnit XML, Markdown and the GitHub Actions job summary.
Package report renders the result of a workflow run as files for machines and for people: JSON, JUnit XML, Markdown and the GitHub Actions job summary.
Package safefile writes files that a symlink planted in the current directory must not redirect.
Package safefile writes files that a symlink planted in the current directory must not redirect.
Package truncate shortens long values before they are logged or printed, marking where they were cut.
Package truncate shortens long values before they are logged or printed, marking where they were cut.

Jump to

Keyboard shortcuts

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