ci

package
v0.30.0 Latest Latest
Warning

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

Go to latest
Published: Apr 4, 2026 License: MIT Imports: 17 Imported by: 0

Documentation

Overview

Package ci implements a local GitHub Actions workflow parser and executor. It provides 80% parity with GitHub Actions by executing `run:` shell blocks inside isolated Podman/Docker containers, while intentionally skipping composite/JS `uses:` actions.

LIMITATION: This engine does NOT support `uses:` actions. Third-party actions like actions/setup-go, actions/upload-artifact, or golangci/golangci-lint-action are skipped with a visible warning. Only `run:` shell blocks are executed. This is a deliberate design decision documented in docs/guide/ci.md.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func CondensedMatrixName

func CondensedMatrixName(jobKey string, matrix map[string]string) string

CondensedMatrixName generates a short display name for matrix jobs suitable for the prefix column. E.g., "build (darwin, arm64)" → "build·dar·a64"

func DiscoverWorkflows

func DiscoverWorkflows(projectDir string) ([]string, error)

DiscoverWorkflows lists all .yml/.yaml files in .github/workflows/.

func MergeEnv

func MergeEnv(maps ...map[string]string) map[string]string

MergeEnv merges multiple env maps in order (later maps override earlier maps).

func ResetWriterRegistry

func ResetWriterRegistry()

ResetWriterRegistry clears the color assignment state. Useful for testing.

func ResolveJobDAG

func ResolveJobDAG(jobs map[string]*Job) ([][]string, error)

ResolveJobDAG performs a topological sort on jobs based on `needs:` dependencies. Returns execution tiers: each tier contains jobs that can run in parallel, and all jobs in a tier depend only on jobs in previous tiers.

Types

type ExecuteConfig

type ExecuteConfig struct {
	Workflow   *Workflow
	Runtime    string            // "podman" or "docker"
	Image      string            // container image override (empty = auto-detect)
	JobFilter  []string          // run only these jobs (empty = all)
	Secrets    map[string]string // secrets from devx Vault
	DryRun     bool
	JSONOutput bool
	ProjectDir string
}

ExecuteConfig holds configuration for a CI execution run.

type ExpandedJob

type ExpandedJob struct {
	JobKey       string            // original job key in the workflow
	DisplayName  string            // human-readable name (e.g. "build (darwin, arm64)")
	Job          *Job              // reference to the original job definition
	MatrixValues map[string]string // resolved matrix values for this expansion
}

ExpandedJob is a concrete job instance with a specific matrix combination resolved.

func ExpandMatrix

func ExpandMatrix(jobKey string, job *Job) []ExpandedJob

ExpandMatrix takes a job and produces one ExpandedJob per matrix combination. If no matrix is defined, returns a single ExpandedJob with empty matrix values.

type Job

type Job struct {
	Name            string             `yaml:"name"`
	RunsOn          string             `yaml:"runs-on"`
	Needs           StringOrSlice      `yaml:"needs"`
	If              string             `yaml:"if"`
	Env             map[string]string  `yaml:"env"`
	Strategy        Strategy           `yaml:"strategy"`
	Services        map[string]Service `yaml:"services"`
	Steps           []Step             `yaml:"steps"`
	TimeoutMinutes  int                `yaml:"timeout-minutes"`
	ContinueOnError bool               `yaml:"continue-on-error"`
}

Job represents a single job within a workflow.

type MatrixDef

type MatrixDef struct {
	// Values holds the primary matrix axes (e.g., {"goos": ["darwin","linux"]}).
	Values  map[string][]string `yaml:"-"`
	Include []map[string]string `yaml:"include"`
	Exclude []map[string]string `yaml:"exclude"`
}

MatrixDef holds the matrix definition including include/exclude.

func (*MatrixDef) UnmarshalYAML

func (m *MatrixDef) UnmarshalYAML(node *yaml.Node) error

UnmarshalYAML handles the polymorphic matrix definition where top-level keys are dynamic axes alongside the reserved "include" and "exclude" keys.

type PrefixedWriter

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

PrefixedWriter is a thread-safe, line-buffered writer that prepends a color-coded job name prefix to each line. It ensures parallel goroutine output doesn't interleave mid-line — identical to Docker Compose's multiplexed output strategy.

func NewPrefixedWriter

func NewPrefixedWriter(jobName string, dest io.Writer, mu *sync.Mutex) *PrefixedWriter

NewPrefixedWriter creates a writer that prepends a styled prefix to every line. The mutex should be shared across all parallel writers to prevent interleaving.

func (*PrefixedWriter) Flush

func (pw *PrefixedWriter) Flush()

Flush writes any remaining buffered content.

func (*PrefixedWriter) Write

func (pw *PrefixedWriter) Write(p []byte) (n int, err error)

Write implements io.Writer. It buffers input and flushes complete lines with the prefix prepended.

type RunResult

type RunResult struct {
	Job      string        `json:"job"`
	Status   string        `json:"status"` // "passed", "failed", "skipped"
	Duration time.Duration `json:"duration"`
	Steps    []StepResult  `json:"steps"`
}

RunResult holds the outcome of a single job execution.

func Execute

func Execute(cfg ExecuteConfig) ([]RunResult, error)

Execute runs the parsed workflow according to the execution plan.

type Service

type Service struct {
	Image   string            `yaml:"image"`
	Env     map[string]string `yaml:"env"`
	Ports   []string          `yaml:"ports"`
	Options string            `yaml:"options"`
}

Service represents a job-level service container (e.g., postgres for CI).

type Step

type Step struct {
	Name             string            `yaml:"name"`
	ID               string            `yaml:"id"`
	Uses             string            `yaml:"uses"`
	Run              string            `yaml:"run"`
	Shell            string            `yaml:"shell"`
	Env              map[string]string `yaml:"env"`
	With             map[string]string `yaml:"with"`
	If               string            `yaml:"if"`
	WorkingDirectory string            `yaml:"working-directory"`
	ContinueOnError  bool              `yaml:"continue-on-error"`
	TimeoutMinutes   int               `yaml:"timeout-minutes"`
}

Step represents a single step within a job.

type StepResult

type StepResult struct {
	Name     string        `json:"name"`
	Status   string        `json:"status"` // "passed", "failed", "skipped"
	Duration time.Duration `json:"duration"`
	Output   string        `json:"output,omitempty"`
}

StepResult holds the outcome of a single step.

type Strategy

type Strategy struct {
	Matrix      MatrixDef `yaml:"matrix"`
	FailFast    *bool     `yaml:"fail-fast"`
	MaxParallel int       `yaml:"max-parallel"`
}

Strategy holds the matrix strategy for a job.

type StringOrSlice

type StringOrSlice []string

StringOrSlice handles YAML fields that can be either a single string or a list.

func (*StringOrSlice) UnmarshalYAML

func (s *StringOrSlice) UnmarshalYAML(node *yaml.Node) error

type TemplateContext

type TemplateContext struct {
	Env     map[string]string // workflow + job + step env
	Secrets map[string]string // from devx Vault providers
	Matrix  map[string]string // current matrix row values

	// Warnings collects non-fatal substitution issues for reporting.
	Warnings []string
}

TemplateContext holds all the values available for ${{ }} expression substitution.

func NewTemplateContext

func NewTemplateContext(env, secrets, matrix map[string]string) *TemplateContext

NewTemplateContext creates a TemplateContext with sensible defaults for the stubbed github.* and runner.* contexts.

func (*TemplateContext) EvaluateCondition

func (tc *TemplateContext) EvaluateCondition(condition string) bool

EvaluateCondition evaluates an `if:` conditional expression. Returns true if the step/job should run.

Strategy:

  • Simple equality (matrix.goos == 'linux') → exact match
  • Simple inequality (matrix.goos != 'linux') → exact non-match
  • Complex expressions (contains(), hashFiles()) → fail-open (return true) with warning
  • Empty string → true (no condition = always run)

func (*TemplateContext) Substitute

func (tc *TemplateContext) Substitute(input string) string

Substitute replaces all ${{ ... }} expressions in the input string.

type Workflow

type Workflow struct {
	Name string            `yaml:"name"`
	Env  map[string]string `yaml:"env"`
	Jobs map[string]*Job   `yaml:"jobs"`
}

Workflow represents a parsed GitHub Actions workflow file.

func ParseWorkflow

func ParseWorkflow(path string) (*Workflow, error)

ParseWorkflow reads and parses a GitHub Actions workflow YAML file.

Jump to

Keyboard shortcuts

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