orc

package module
v0.0.0-...-a25d478 Latest Latest
Warning

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

Go to latest
Published: Apr 20, 2026 License: MIT Imports: 21 Imported by: 0

README

orc

A Go library for defining and executing task runbooks — with dependency ordering, conditional execution, undo support, and a bubbletea TUI.

Install

Install the CLI:

go install github.com/zoenetic/orc/cmd/orc@latest

Getting started

Use orc init to scaffold a new project:

orc init my-project
cd my-project

Or in an existing directory:

orc init .

This creates main.go, go.mod, and a .gitignore with the right entries. Flags:

orc init [directory] [--git] [--yes]

  --git|-g  initialize as a git repository
  --yes|-y  skip confirmation prompt

Or add orc to an existing go project and do it yourself:

go get github.com/zoenetic/orc

Defining plans

Each exported method on your Plans struct that returns *orc.Runbook is a named plan. The method name is used as the plan name (case-insensitive). A method named Default is used when no plan is specified.

package main

import "github.com/zoenetic/orc"

type Plans struct{}

func main() { orc.Main[Plans]() }

func (p *Plans) Default() *orc.Runbook {
	rb := orc.New("hello world", orc.Options{
		Concurrency: 2,
	})

	sayHello := rb.Task("say hello",
		orc.Do{
			Cmds: orc.Sh("echo hello"),
		},
	)

	sayBonjour := rb.Task("say bonjour",
		orc.Do{
			Cmds: orc.Sh("echo bonjour"),
		},
	)

	_ = rb.Task("say goodbye",
		orc.Do{
			Cmds: orc.Sh("echo goodbye"),
		},
		orc.DependsOn{sayHello, sayBonjour},
	)

	return rb
}

CLI commands

orc run      [plan] [-v]          execute a plan
orc preview  [plan]               show what would run and last-run status per task
orc validate [plan]               check for dependency cycles and errors
orc rollback [plan] [run-id]      run undo commands in reverse stage order
orc history  [-n N]               show recent run history (default: last 20)

All commands except history accept an optional plan name (defaults to default). rollback also accepts a run ID to target a specific past run.

Task options

Option Description
orc.Do{Cmds, If, Unless, Confirm} Do clause: commands to run, with optional conditions and post-conditions
orc.Undo{Cmds, If, Unless, Confirm} Undo clause: run on rollback in reverse stage order
orc.DependsOn{tasks...} Declare dependencies (determines stage ordering)

Commands

orc.Cmd(cmd, args...) runs a command with explicit arguments without a shell:

orc.Cmd("kubectl", "apply", "-f", "deploy.yaml")

orc.Sh(cmd) runs a shell string via sh -c. Env vars can be passed as additional arguments:

orc.Sh("echo $GREETING", orc.Env("GREETING", "hello"))

Clauses

If, Unless, and Confirm are fields on Do and Undo structs. They control whether the clause runs and assert post-conditions.

If — run the clause only if the command exits 0:

orc.Do{
    Cmds: orc.Sh("make build"),
    If:   orc.Sh("git diff --quiet HEAD"),
}

Unless — skip the clause if the command exits 0:

orc.Do{
    Cmds:   orc.Sh("docker build ."),
    Unless: orc.Sh("docker image inspect myapp:latest"),
}

Confirm — assert a condition after the clause executes; fails the task if it exits non-zero:

orc.Do{
    Cmds:    orc.Sh("kubectl apply -f deploy.yaml"),
    Confirm: orc.Sh("kubectl rollout status deployment/myapp"),
}

All three can be combined on a single clause. If and Unless are evaluated before execution; Confirm is evaluated after. The same fields are available on Undo clauses.

Environment variables

Env vars cascade from runbook → task → command, with each level able to override the parent.

rb := orc.New("deploy", orc.Options{})
rb.Env(orc.Env("ENV", "staging"))   // applies to all tasks

task := rb.Task("deploy",
    orc.Do{Cmds: orc.Sh("./deploy.sh", orc.Env("ENV", "prod"))},  // overrides at command level
)
task.Env("REGION", "eu-west-1")     // overrides at task level

Package dependencies

rb.Use declares a required CLI tool. orc checks it exists in PATH before running.

rb.Use("kubectl")
rb.Use("helm")

License

MIT

Documentation

Index

Constants

View Source
const (
	StateFile   = "orc.state.json"
	HistoryFile = ".orc/runs.ndjson"
)

Variables

This section is empty.

Functions

func Main

func Main[T any](exec ...Executor)

Types

type Command

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

func Cmd

func Cmd(cmd string, args ...string) *Command

func Sh

func Sh(cmd string, env ...*EnvVar) []*Command

func (*Command) String

func (c *Command) String() string

type DependsOn

type DependsOn []*Task

type Display

type Display struct{}

Display is the bubbletea-based TUI executor. Pass it to Main to enable the rich interactive run/preview/validate/rollback experience.

func (Display) Execute

func (Display) Execute(ctx context.Context, rb *Runbook, opts RunOptions) bool

func (Display) Preview

func (Display) Preview(ctx context.Context, rb *Runbook, opts RunOptions) bool

func (Display) Rollback

func (Display) Rollback(ctx context.Context, rb *Runbook, opts RunOptions, runID string) bool

func (Display) Validate

func (Display) Validate(ctx context.Context, rb *Runbook, opts RunOptions) bool

type Do

type Do struct {
	Cmds    []*Command
	If      []*Command
	Unless  []*Command
	Confirm []*Command
}

type EnvVar

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

func Env

func Env(name, value string) *EnvVar

func (*EnvVar) String

func (v *EnvVar) String() string

type Executor

type Executor interface {
	Execute(ctx context.Context, rb *Runbook, opts RunOptions) bool
	Preview(ctx context.Context, rb *Runbook, opts RunOptions) bool
	Validate(ctx context.Context, rb *Runbook, opts RunOptions) bool
	Rollback(ctx context.Context, rb *Runbook, opts RunOptions, runID string) bool
}

type Options

type Options struct {
	Concurrency int
	PkgSource
}

type Pkg

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

type PkgSource

type PkgSource interface {
	Name() string
	Available() bool
	Install(ctx context.Context, p *Pkg) error
}

func Apt

func Apt() PkgSource

func Dnf

func Dnf() PkgSource

func Nix

func Nix() PkgSource

func Winget

func Winget() PkgSource

type PreviewResult

type PreviewResult struct {
	Stages [][]*Task
	Tasks  map[string]PreviewTaskResult
	Errors []error
}

type PreviewTaskResult

type PreviewTaskResult struct {
	Status TaskStatus
	Err    error
}

type RollbackResult

type RollbackResult struct {
	Completed bool
	Tasks     map[string]TaskResult
	Errors    []error
}

type RunOptions

type RunOptions struct {
	Plan       string
	Verbose    bool
	Env        []*EnvVar
	TaskOutput func(taskName string) io.Writer
	OnEvent    func(event TaskEvent)
}

type RunRecord

type RunRecord struct {
	ID       string                `json:"id"`
	Version  int                   `json:"version"`
	Runbook  string                `json:"runbook"`
	Plan     string                `json:"plan"`
	Commit   string                `json:"commit"`
	Started  time.Time             `json:"started"`
	Finished time.Time             `json:"finished"`
	Duration time.Duration         `json:"duration"`
	Status   RunStatus             `json:"status"`
	Tasks    map[string]TaskRecord `json:"tasks"`
}

func LoadHistory

func LoadHistory(n int) ([]RunRecord, error)

func LoadRecord

func LoadRecord() (*RunRecord, error)

func LoadRecordByID

func LoadRecordByID(id string) (*RunRecord, error)

func LoadState

func LoadState() (*RunRecord, error)

type RunResult

type RunResult struct {
	Completed bool
	Tasks     map[string]TaskResult
	Outputs   map[string]any
	Errors    []error
}

type RunStatus

type RunStatus string
const (
	RunSucceeded     RunStatus = "succeeded"
	RunFailed        RunStatus = "failed"
	RunConfirmFailed RunStatus = "confirm_failed"
	RunCancelled     RunStatus = "cancelled"
)

type Runbook

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

func New

func New(name string, opts Options) *Runbook

func (*Runbook) Env

func (rb *Runbook) Env(vars ...*EnvVar) *Runbook

func (*Runbook) Name

func (rb *Runbook) Name() string

func (*Runbook) Preview

func (rb *Runbook) Preview(ctx context.Context, opts RunOptions) *PreviewResult

func (*Runbook) Rollback

func (rb *Runbook) Rollback(ctx context.Context, opts RunOptions, runID string) RollbackResult

func (*Runbook) Run

func (rb *Runbook) Run(ctx context.Context, opts RunOptions) RunResult

func (*Runbook) Stages

func (rb *Runbook) Stages() ([][]*Task, map[*Task][]*Task, error)

func (*Runbook) Task

func (r *Runbook) Task(name string, opts ...TaskOption) *Task

func (*Runbook) Use

func (rb *Runbook) Use(name string, sources ...PkgSource) *Runbook

func (*Runbook) Validate

func (rb *Runbook) Validate(ctx context.Context) *ValidateResult

type Task

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

func (*Task) DoClauses

func (t *Task) DoClauses() []Do

func (*Task) Env

func (t *Task) Env(name, value string) *Task

func (*Task) Name

func (t *Task) Name() string

func (*Task) UndoClauses

func (t *Task) UndoClauses() []Undo

type TaskEvent

type TaskEvent struct {
	Task     *Task
	Status   TaskStatus
	Err      error
	Duration time.Duration
}

type TaskOption

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

type TaskRecord

type TaskRecord struct {
	Status   string        `json:"status"`
	Started  time.Time     `json:"started,omitempty"`
	Finished time.Time     `json:"finished,omitempty"`
	Duration time.Duration `json:"duration,omitempty"`
	Err      string        `json:"err,omitempty"`
}

type TaskResult

type TaskResult struct {
	Name     string
	Status   TaskStatus
	Err      error
	Duration time.Duration
	Started  time.Time
	Finished time.Time
}

type TaskStatus

type TaskStatus string
const (
	StatusPending       TaskStatus = "pending"
	StatusBlocked       TaskStatus = "blocked"
	StatusReady         TaskStatus = "ready"
	StatusRunning       TaskStatus = "running"
	StatusSatisfied     TaskStatus = "satisfied"
	StatusSucceeded     TaskStatus = "succeeded"
	StatusConfirmFailed TaskStatus = "confirm_failed"
	StatusSkipped       TaskStatus = "skipped"
	StatusCancelled     TaskStatus = "cancelled"
	StatusFailed        TaskStatus = "failed"
)

func (TaskStatus) IsComplete

func (s TaskStatus) IsComplete() bool

func (TaskStatus) IsTerminal

func (s TaskStatus) IsTerminal() bool

type Undo

type Undo struct {
	Cmds    []*Command
	If      []*Command
	Unless  []*Command
	Confirm []*Command
}

type ValidateResult

type ValidateResult struct {
	Errors []error
}

Directories

Path Synopsis
cmd
orc command

Jump to

Keyboard shortcuts

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