domain

package
v0.0.20 Latest Latest
Warning

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

Go to latest
Published: Apr 22, 2026 License: AGPL-3.0 Imports: 18 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func BuildComposeEnv added in v0.0.6

func BuildComposeEnv(projectName, envName string, ports PortMap) []string

BuildComposeEnv builds the environment variables for running docker compose commands. Includes COMPOSE_PROJECT_NAME and port mappings (e.g., REDIS_PORT=6421). The returned slice is suitable for passing to ComputeAccess.Exec.

func ComposeProjectName added in v0.0.4

func ComposeProjectName(projectName, envName string) string

ComposeProjectName returns the compose project name for this environment. Sanitizes to match Docker Compose requirements: lowercase alphanumeric, hyphens, underscores.

func ExecuteCoreHook added in v0.0.2

func ExecuteCoreHook(ctx context.Context, hookScript string, declaredOutputs []string, env []string, workdir string, stderr io.Writer) (map[string]string, error)

ExecuteCoreHook runs a core service hook script and captures KEY=VALUE outputs. Both stdout and stderr stream to the terminal in real-time for visibility. KEY=VALUE lines on stdout are redacted (value replaced with ********) before display. stdout is also captured and parsed for KEY=VALUE pairs. Returns the captured outputs, validated against declaredOutputs.

func GenerateComposeFile added in v0.0.7

func GenerateComposeFile(cfg *ProjectConfig, manifest *Manifest) ([]byte, error)

GenerateComposeFile generates a Docker Compose YAML file from service definitions. Only services with a `start` command are included. nginx is always added implicitly. The compose file contains ALL startable services — autostart controls which are started on create, not which are generated.

func GenerateErrorPages added in v0.0.7

func GenerateErrorPages(envName string) map[string][]byte

GenerateErrorPages returns a map of filename → HTML content for nginx error pages.

func GenerateNginxConfig added in v0.0.7

func GenerateNginxConfig(cfg *ProjectConfig, manifest *Manifest, domain string) ([]byte, error)

GenerateNginxConfig generates an nginx configuration file from the manifest and service definitions. Each service gets its own server block with explicit hostname matching.

Enabled services get full proxy blocks with a custom 502 error page. Disabled services (known but not started) get a friendly status page telling the user how to start the service. Unknown subdomains hit the default server with a 404 page.

func Hostname added in v0.0.4

func Hostname() string

Hostname returns the machine hostname for audit logging.

func ParseComposeFile added in v0.0.2

func ParseComposeFile(path string) (map[string]InfraService, error)

ParseComposeFile reads a docker compose YAML file and extracts infrastructure service definitions including service names, images, and port mappings.

func RenderEnvFileContent added in v0.0.4

func RenderEnvFileContent(env map[string]string) []byte

RenderEnvFileContent renders a map of env vars to KEY=VALUE format content. Keys are sorted for deterministic output.

func RenderEnvMap

func RenderEnvMap(envMap map[string]string, ctx *TemplateContext) (map[string]string, error)

RenderEnvMap renders all template variables in a map of env vars.

func RenderTemplate

func RenderTemplate(tmpl string, ctx *TemplateContext) (string, error)

RenderTemplate replaces {{var}} placeholders in a string with values from the context. Supported variable patterns:

  • {{services.<name>.port}} — allocated port for an application service
  • {{infrastructure.<name>.port}} — allocated port for an infrastructure service
  • {{provisioner.<service>.<OUTPUT>}} — output value from a provisioner service
  • {{env.name}} — the current environment name
  • {{store.<key>}} — value from the persistent key-value store
  • {{proxy.url.<service>}} — full URL for a service (https://{env}--{service}.{domain})
  • {{proxy.domain}} — the proxy domain (e.g., "preview.airgoods.com")

func ResolveEnvironmentFromCwd

func ResolveEnvironmentFromCwd(cwd string, environments map[string]*EnvironmentEntry) (string, error)

ResolveEnvironmentFromCwd determines the environment name by checking if the current working directory is inside any known worktree path from state.

func SanitizeName added in v0.0.5

func SanitizeName(name string) string

SanitizeName replaces characters not safe for use in database names, file paths, and Docker Compose project names. Lowercase alphanumeric, hyphens, and underscores only.

func TopologicalSort

func TopologicalSort(services map[string]ServiceConfig) ([]string, error)

TopologicalSort performs Kahn's algorithm to produce a topological ordering of services based on their dependsOn relationships. Returns an error if a cycle is detected or a dependency references an unknown service.

func ValidateConfig

func ValidateConfig(cfg *ProjectConfig) error

ValidateConfig performs deep validation of a ProjectConfig. It checks structural correctness, port collisions, dependency references, and template variable references. It does NOT check file system paths — use ValidateConfigWithFS for that.

func ValidateConfigWithFS

func ValidateConfigWithFS(cfg *ProjectConfig, projectRoot string, fileExists func(string) bool) error

ValidateConfigWithFS performs all config validation plus file system checks. projectRoot is the directory containing previewctl.yaml. fileExists is a function that checks if a path exists (allows testing).

func WriteManifest added in v0.0.4

func WriteManifest(m *Manifest, w io.Writer) error

WriteManifest encodes a manifest as JSON to the given writer.

Types

type AuditEntry added in v0.0.4

type AuditEntry struct {
	Timestamp  time.Time `json:"timestamp"`
	Step       string    `json:"step"`
	Action     string    `json:"action"` // "executed", "skipped", "verified", "verify_failed", "invalidated", "failed"
	Machine    string    `json:"machine"`
	DurationMs int64     `json:"durationMs,omitempty"`
	Message    string    `json:"message,omitempty"`
	Error      string    `json:"error,omitempty"`
}

AuditEntry is an append-only log entry recording what happened during lifecycle operations.

type ComposeConfig added in v0.0.7

type ComposeConfig struct {
	Autostart []string     `yaml:"autostart"`       // services started on create (proxy is always implicit if enabled)
	Image     string       `yaml:"image"`           // base Docker image for app containers (e.g., "node:20")
	Proxy     *ProxyConfig `yaml:"proxy,omitempty"` // reverse proxy configuration
}

ComposeConfig defines how previewctl generates and manages Docker Compose for application services in remote mode.

type ComputeAccess added in v0.0.4

type ComputeAccess interface {
	// WriteFile writes content to a path relative to the compute root.
	WriteFile(ctx context.Context, relPath string, data []byte, mode os.FileMode) error

	// ReadFile reads content from a path relative to the compute root.
	ReadFile(ctx context.Context, relPath string) ([]byte, error)

	// Exec runs a command in the compute root directory.
	// Stderr streams to the configured writer. Stdout is captured and returned silently.
	Exec(ctx context.Context, command string, env []string) (stdout string, err error)

	// VerboseExec runs a command and tees stdout to stderr for real-time visibility.
	// Use for user-defined hooks and build commands where output should always be visible.
	VerboseExec(ctx context.Context, command string, env []string) (stdout string, err error)

	// Root returns the compute root path (local path or remote working dir).
	Root() string
}

ComputeAccess provides uniform access to a compute location. Local mode wraps filesystem operations; remote mode wraps SSH/SCP.

func NewDomainLocalComputeAccess added in v0.0.4

func NewDomainLocalComputeAccess(root string) ComputeAccess

func NewDomainSSHComputeAccess added in v0.0.4

func NewDomainSSHComputeAccess(host, user, root string) ComputeAccess

NewDomainSSHComputeAccess creates a ComputeAccess backed by SSH to a remote host. This is the direct-mode constructor (backward compatible).

func NewDomainSSHComputeAccessWithOpts added in v0.0.7

func NewDomainSSHComputeAccessWithOpts(opts SSHComputeAccessOpts) ComputeAccess

NewDomainSSHComputeAccessWithOpts creates a ComputeAccess with full SSH options.

type ComputeAccessInfo added in v0.0.4

type ComputeAccessInfo struct {
	Type            string            `json:"type"`                      // "local" or "ssh"
	Path            string            `json:"path,omitempty"`            // local worktree path or remote root
	Host            string            `json:"host,omitempty"`            // VM hostname (ssh)
	User            string            `json:"user,omitempty"`            // SSH user
	ManagedWorktree bool              `json:"managedWorktree,omitempty"` // true = created by previewctl
	Metadata        map[string]string `json:"metadata,omitempty"`        // hook-provided metadata (e.g., "vm_zone", "gcp_project")
}

ComputeAccessInfo stores how to reach the compute location so environments can be reconnected across CLI invocations.

type ComputeHooks added in v0.0.4

type ComputeHooks struct {
	Create  string     `yaml:"create"`
	Destroy string     `yaml:"destroy"`
	Outputs []string   `yaml:"outputs,omitempty"`
	SSH     *SSHConfig `yaml:"ssh,omitempty"`
}

ComputeHooks defines lifecycle hooks for compute resources.

type ComputePort

type ComputePort interface {
	// Create sets up compute resources for an environment.
	// branch is the target branch to use/create.
	// baseBranch is the branch to create from (empty = use branch as-is).
	Create(ctx context.Context, envName string, branch string, baseBranch string) (*ComputeResources, error)

	// Start starts per-environment services (infra containers, etc).
	Start(ctx context.Context, envName string, ports PortMap) error

	// Stop stops services without destroying data or resources.
	Stop(ctx context.Context, envName string) error

	// Destroy tears down all compute resources.
	Destroy(ctx context.Context, envName string) error

	// IsRunning checks if environment compute resources are active.
	IsRunning(ctx context.Context, envName string) (bool, error)

	// DetectBranch returns the current git branch for a worktree path.
	DetectBranch(ctx context.Context, worktreePath string) (string, error)
}

ComputePort manages the compute substrate for an environment. Local: git worktree + docker compose for per-env infrastructure. Preview: VM provisioning + full compose stack. Sandbox: isolated VM with network policies.

type ComputeResources

type ComputeResources struct {
	WorktreePath string `json:"worktreePath,omitempty"` // local mode
	VMId         string `json:"vmId,omitempty"`         // preview/sandbox mode
	ExternalIP   string `json:"externalIp,omitempty"`   // preview/sandbox mode
}

ComputeResources holds the result of creating compute resources for an environment.

type CoreResetOpts added in v0.0.20

type CoreResetOpts struct {
	// NoPropagate skips regenerating remote manifest/env/compose files and
	// restarting dependent services after a successful reset. State is still
	// updated with fresh provisioner outputs. Use this when you want to batch
	// several resets and run a single SyncRemote at the end.
	NoPropagate bool
}

CoreResetOpts configures the behavior of CoreReset.

type DomainLocalComputeAccess added in v0.0.4

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

func (*DomainLocalComputeAccess) Exec added in v0.0.4

func (l *DomainLocalComputeAccess) Exec(ctx context.Context, command string, env []string) (string, error)

func (*DomainLocalComputeAccess) ReadFile added in v0.0.4

func (l *DomainLocalComputeAccess) ReadFile(_ context.Context, relPath string) ([]byte, error)

func (*DomainLocalComputeAccess) Root added in v0.0.4

func (l *DomainLocalComputeAccess) Root() string

func (*DomainLocalComputeAccess) SetStderr added in v0.0.7

func (l *DomainLocalComputeAccess) SetStderr(w io.Writer)

func (*DomainLocalComputeAccess) VerboseExec added in v0.0.16

func (l *DomainLocalComputeAccess) VerboseExec(ctx context.Context, command string, env []string) (string, error)

func (*DomainLocalComputeAccess) WriteFile added in v0.0.4

func (l *DomainLocalComputeAccess) WriteFile(_ context.Context, relPath string, data []byte, mode os.FileMode) error

type DomainSSHComputeAccess added in v0.0.4

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

DomainSSHComputeAccess implements ComputeAccess over SSH. It uses the system ssh binary. Lives in domain to avoid circular imports.

Two connection modes:

  • ProxyCommand mode: uses -o ProxyCommand=... (cloud-agnostic, no local SSH config needed)
  • Direct mode: uses user@host (requires SSH config or direct access)

func (*DomainSSHComputeAccess) Exec added in v0.0.4

func (s *DomainSSHComputeAccess) Exec(ctx context.Context, command string, env []string) (string, error)

func (*DomainSSHComputeAccess) Host added in v0.0.4

func (s *DomainSSHComputeAccess) Host() string

Host returns the SSH host.

func (*DomainSSHComputeAccess) ProxyCommand added in v0.0.7

func (s *DomainSSHComputeAccess) ProxyCommand() string

ProxyCommand returns the configured proxy command, if any.

func (*DomainSSHComputeAccess) ReadFile added in v0.0.4

func (s *DomainSSHComputeAccess) ReadFile(ctx context.Context, relPath string) ([]byte, error)

func (*DomainSSHComputeAccess) Root added in v0.0.4

func (s *DomainSSHComputeAccess) Root() string

func (*DomainSSHComputeAccess) SSHArgs added in v0.0.7

func (s *DomainSSHComputeAccess) SSHArgs() []string

sshArgs returns the SSH arguments for building external SSH commands (e.g., for syscall.Exec).

func (*DomainSSHComputeAccess) SetStderr added in v0.0.7

func (s *DomainSSHComputeAccess) SetStderr(w io.Writer)

func (*DomainSSHComputeAccess) User added in v0.0.4

func (s *DomainSSHComputeAccess) User() string

User returns the SSH user.

func (*DomainSSHComputeAccess) VerboseExec added in v0.0.16

func (s *DomainSSHComputeAccess) VerboseExec(ctx context.Context, command string, env []string) (string, error)

func (*DomainSSHComputeAccess) WriteFile added in v0.0.4

func (s *DomainSSHComputeAccess) WriteFile(ctx context.Context, relPath string, data []byte, _ os.FileMode) error

type EnvironmentDetail

type EnvironmentDetail struct {
	Entry        *EnvironmentEntry `json:"entry"`
	InfraRunning bool              `json:"infraRunning"`
}

EnvironmentDetail is an enriched view with live infrastructure checks.

type EnvironmentEntry

type EnvironmentEntry struct {
	Name               string                       `json:"name"`
	Mode               EnvironmentMode              `json:"mode"`
	Branch             string                       `json:"branch"`
	Status             EnvironmentStatus            `json:"status"`
	CreatedAt          time.Time                    `json:"createdAt"`
	UpdatedAt          time.Time                    `json:"updatedAt"`
	Ports              PortMap                      `json:"ports"`
	ProvisionerOutputs map[string]map[string]string `json:"provisionerOutputs"`
	Compute            *ComputeAccessInfo           `json:"compute,omitempty"`
	Env                map[string]string            `json:"env,omitempty"`             // persistent key-value store for hooks
	EnabledServices    []string                     `json:"enabledServices,omitempty"` // services currently enabled (seeded from autostart, updated by service start/stop)
	Steps              map[string]*StepRecord       `json:"steps,omitempty"`
	AuditLog           []AuditEntry                 `json:"auditLog,omitempty"`
}

EnvironmentEntry is a tracked environment persisted in state.

func (*EnvironmentEntry) AppendAudit added in v0.0.4

func (e *EnvironmentEntry) AppendAudit(entry AuditEntry)

AppendAudit adds an audit log entry.

func (*EnvironmentEntry) DisableService added in v0.0.7

func (e *EnvironmentEntry) DisableService(name string)

DisableService removes a service from the enabled set.

func (*EnvironmentEntry) EnableService added in v0.0.7

func (e *EnvironmentEntry) EnableService(name string)

EnableService adds a service to the enabled set (idempotent).

func (*EnvironmentEntry) GetEnv added in v0.0.7

func (e *EnvironmentEntry) GetEnv(key string) (string, bool)

GetEnv reads a value from the environment's persistent store.

func (*EnvironmentEntry) InvalidateStep added in v0.0.13

func (e *EnvironmentEntry) InvalidateStep(name, reason string) bool

InvalidateStep marks a completed step as invalidated so it will re-run. Returns true if the step was actually invalidated (was previously completed).

func (*EnvironmentEntry) InvalidateStepsFrom added in v0.0.4

func (e *EnvironmentEntry) InvalidateStepsFrom(stepName string, orderedSteps []string)

InvalidateStepsFrom removes checkpoint records for the named step and all steps that come after it in the given ordered step list.

func (*EnvironmentEntry) IsManagedWorktree added in v0.0.4

func (e *EnvironmentEntry) IsManagedWorktree() bool

IsManagedWorktree returns whether the worktree was created by previewctl.

func (*EnvironmentEntry) IsServiceEnabled added in v0.0.7

func (e *EnvironmentEntry) IsServiceEnabled(name string) bool

IsServiceEnabled returns true if the service is in the enabled set.

func (*EnvironmentEntry) SetEnv added in v0.0.7

func (e *EnvironmentEntry) SetEnv(key, value string)

SetEnv sets a key-value pair in the environment's persistent store.

func (*EnvironmentEntry) SetStepRecord added in v0.0.4

func (e *EnvironmentEntry) SetStepRecord(rec *StepRecord)

SetStepRecord records a step completion/failure.

func (*EnvironmentEntry) StepCompleted added in v0.0.4

func (e *EnvironmentEntry) StepCompleted(name string) bool

StepCompleted returns true if the named step has a "completed" record.

func (*EnvironmentEntry) StepOutputs added in v0.0.4

func (e *EnvironmentEntry) StepOutputs(name string) map[string]any

StepOutputs returns the outputs map for a completed step, or nil.

func (*EnvironmentEntry) WorktreePath added in v0.0.4

func (e *EnvironmentEntry) WorktreePath() string

WorktreePath returns the worktree path from ComputeAccessInfo, or empty string.

type EnvironmentMode

type EnvironmentMode string

EnvironmentMode represents the deployment mode of an environment.

const (
	ModeLocal   EnvironmentMode = "local"
	ModePreview EnvironmentMode = "preview"
	ModeSandbox EnvironmentMode = "sandbox"
)

type EnvironmentStatus

type EnvironmentStatus string

EnvironmentStatus represents the lifecycle status of an environment.

const (
	StatusCreating    EnvironmentStatus = "creating"
	StatusProvisioned EnvironmentStatus = "provisioned"
	StatusRunning     EnvironmentStatus = "running"
	StatusStopped     EnvironmentStatus = "stopped"
	StatusError       EnvironmentStatus = "error"
)

type InfraService added in v0.0.2

type InfraService struct {
	Name   string
	Image  string
	Port   int
	EnvVar string // e.g., "REDIS_PORT" (extracted from ${REDIS_PORT:-6379} patterns)
}

InfraService holds parsed infrastructure service information from a compose file.

type InfrastructureConfig added in v0.0.2

type InfrastructureConfig struct {
	ComposeFile string `yaml:"compose_file"`
}

InfrastructureConfig holds infrastructure configuration.

type Manager

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

Manager orchestrates environment lifecycle by coordinating all ports.

func NewManager

func NewManager(deps ManagerDeps) *Manager

NewManager creates a new Manager with the given dependencies.

func (*Manager) Attach added in v0.0.4

func (m *Manager) Attach(ctx context.Context, envName string, worktreePath string) (*EnvironmentEntry, error)

Attach creates a preview environment using an existing worktree.

func (*Manager) BuildProvisionerStepOrder added in v0.0.4

func (m *Manager) BuildProvisionerStepOrder() []string

BuildProvisionerStepOrder returns the canonical step order for the provisioner phase.

func (*Manager) BuildRunnerStepOrder added in v0.0.4

func (m *Manager) BuildRunnerStepOrder() []string

BuildRunnerStepOrder returns the canonical step order for the runner phase.

func (*Manager) BuildSSHComputeAccess added in v0.0.7

func (m *Manager) BuildSSHComputeAccess(entry *EnvironmentEntry) ComputeAccess

buildSSHComputeAccess constructs SSH compute access from an environment entry. It resolves the SSH config template from the project config using store values, or falls back to stored proxy_command in metadata, or direct host connection.

func (*Manager) CoreInit added in v0.0.2

func (m *Manager) CoreInit(ctx context.Context, svcName string) error

func (*Manager) CoreReset added in v0.0.2

func (m *Manager) CoreReset(ctx context.Context, svcName, envName string, opts CoreResetOpts) error

func (*Manager) Destroy

func (m *Manager) Destroy(ctx context.Context, envName string) error

func (*Manager) DryRunStep added in v0.0.7

func (m *Manager) DryRunStep(ctx context.Context, envName, stepName string) (string, error)

DryRunStep shows a diff of what a step would change. For generation steps, compares the current file on the VM with what would be generated. For other steps, describes what would happen.

func (*Manager) GetEnvironment added in v0.0.7

func (m *Manager) GetEnvironment(ctx context.Context, envName string) (*EnvironmentEntry, error)

GetEnvironment returns a single environment entry from state, or nil if not found.

func (*Manager) Init

func (m *Manager) Init(ctx context.Context, envName, branch, baseBranch string) (*EnvironmentEntry, error)

Init creates a new environment end-to-end: provisions then runs. branch is the target branch. baseBranch is the branch to create from (empty = use branch as-is).

func (*Manager) List

func (m *Manager) List(ctx context.Context) ([]*EnvironmentEntry, error)

func (*Manager) PrintStep added in v0.0.7

func (m *Manager) PrintStep(ctx context.Context, envName, stepName string) (string, error)

PrintStep generates and returns the full content for a step without executing it.

func (*Manager) Provision added in v0.0.4

func (m *Manager) Provision(ctx context.Context, envName, branch, baseBranch, fromStep string) (*EnvironmentEntry, error)

Provision runs the provisioner phase only. Does NOT run the runner. fromStep invalidates that step and all subsequent steps, forcing re-execution.

func (*Manager) ProvisionAttach added in v0.0.4

func (m *Manager) ProvisionAttach(ctx context.Context, envName, worktreePath, fromStep string) (*EnvironmentEntry, error)

ProvisionAttach runs the provisioner phase on an existing worktree.

func (*Manager) Reconcile added in v0.0.7

func (m *Manager) Reconcile(ctx context.Context, envName string, dryRun ...bool) (*ReconcileReport, error)

Reconcile verifies all runner steps and re-executes any whose side effects are missing. Hook-owned steps are skipped since previewctl can't verify user-defined hooks.

Progress is reported via the ProgressReporter for each step:

  • StepStarted: "Verifying <step>..."
  • StepCompleted: verification passed or heal succeeded
  • StepFailed: heal failed
  • StepSkipped: hook-owned or never completed

func (*Manager) Run added in v0.0.4

func (m *Manager) Run(ctx context.Context, manifestPath, fromStep string) error

Run reads a manifest and executes the runner phase only. Stateless — does not persist state.

func (*Manager) RunCoreHook added in v0.0.2

func (m *Manager) RunCoreHook(ctx context.Context, svcName, action, envName string) (map[string]string, error)

func (*Manager) RunStep added in v0.0.7

func (m *Manager) RunStep(ctx context.Context, envName, stepName string) error

RunStep executes a single runner-phase step in isolation. Loads the environment from state, reconstructs compute access, reads the manifest, and runs only the specified step (always executes, ignoring cache).

func (*Manager) RunSteps added in v0.0.7

func (m *Manager) RunSteps(ctx context.Context, envName string, stepNames []string) error

RunSteps executes a sequence of runner steps in order, reusing a single SSH connection and step registry. All steps are forced (cache bypassed).

func (*Manager) SaveEnvironment added in v0.0.7

func (m *Manager) SaveEnvironment(ctx context.Context, envName string, entry *EnvironmentEntry) error

SaveEnvironment persists an environment entry to state.

func (*Manager) SetNoCache added in v0.0.4

func (m *Manager) SetNoCache(v bool)

SetNoCache sets whether checkpoint caching is disabled.

func (*Manager) SetStatus added in v0.0.4

func (m *Manager) SetStatus(ctx context.Context, envName string, status EnvironmentStatus) error

SetStatus updates an environment's status.

func (*Manager) Status

func (m *Manager) Status(ctx context.Context, envName string) (*EnvironmentDetail, error)

func (*Manager) SyncRemote added in v0.0.20

func (m *Manager) SyncRemote(ctx context.Context, envName string) error

SyncRemote regenerates every VM-side artifact we know how to regenerate (manifest, env files, compose, nginx) from current state and restarts every currently-enabled service. Useful as a recovery tool when the VM has drifted from state (e.g., a propagation failed mid-flight after a reset).

No-op for local environments. Unlike `refresh`, SyncRemote does not rerun runner_before / build_services / runner_deploy — it only reconciles what could have changed as a result of state mutations (creds, store values, port allocations, enabled-service set).

type ManagerDeps

type ManagerDeps struct {
	Compute     ComputePort
	Networking  NetworkingPort
	State       StatePort
	Progress    ProgressReporter
	Config      *ProjectConfig
	ProjectRoot string
	NoCache     bool
}

ManagerDeps holds the dependencies for creating a Manager.

type Manifest added in v0.0.4

type Manifest struct {
	Version            int                          `json:"version"`
	EnvName            string                       `json:"env_name"`
	ProjectName        string                       `json:"project_name"`
	Branch             string                       `json:"branch"`
	Mode               string                       `json:"mode"`
	Ports              PortMap                      `json:"ports"`
	ProvisionerOutputs map[string]map[string]string `json:"provisioner_outputs,omitempty"`
	Services           map[string]ManifestService   `json:"services,omitempty"`
	Infrastructure     *ManifestInfrastructure      `json:"infrastructure,omitempty"`
	EnabledServices    []string                     `json:"enabled_services,omitempty"`
}

Manifest is the single source of truth written to the compute location. It contains fully resolved values — no template variables.

func BuildManifest added in v0.0.4

func BuildManifest(
	cfg *ProjectConfig,
	envName, branch, mode string,
	ports PortMap,
	provisionerOutputs map[string]map[string]string,
	store map[string]string,
) (*Manifest, error)

BuildManifest resolves all template variables and builds a complete manifest.

func ReadManifest added in v0.0.4

func ReadManifest(r io.Reader) (*Manifest, error)

ReadManifest decodes a manifest from the given reader.

func (*Manifest) EnvFilePaths added in v0.0.4

func (m *Manifest) EnvFilePaths() map[string]map[string]string

EnvFilePaths returns a map of relative file paths to env var maps, grouping services that share the same env file path.

type ManifestInfrastructure added in v0.0.4

type ManifestInfrastructure struct {
	ComposeFile string `json:"compose_file"`
}

ManifestInfrastructure describes infrastructure configuration.

type ManifestService added in v0.0.4

type ManifestService struct {
	Path    string            `json:"path"`
	EnvFile string            `json:"env_file"`
	Env     map[string]string `json:"env,omitempty"`
}

ManifestService describes a service with fully resolved env vars.

type NetworkingPort

type NetworkingPort interface {
	// AllocatePorts returns deterministic port assignments for all services and infrastructure.
	AllocatePorts(envName string) (PortMap, error)

	// GetServiceURL returns the URL to reach a named service in the environment.
	GetServiceURL(envName string, service string) (string, error)
}

NetworkingPort handles port allocation and service URL resolution. Local: deterministic offset from base ports. Preview: reverse proxy with subdomain routing (future).

type NoopReporter

type NoopReporter struct{}

NoopReporter is a ProgressReporter that discards all events.

func (NoopReporter) OnStep

func (NoopReporter) OnStep(StepEvent)

func (NoopReporter) StderrWriter added in v0.0.7

func (NoopReporter) StderrWriter() io.Writer

type PortMap

type PortMap map[string]int

PortMap maps service names to allocated ports.

func AllocatePortBlock added in v0.0.2

func AllocatePortBlock(envName string, serviceNames []string) (PortMap, error)

AllocatePortBlock selects a block of ports for an environment and assigns one port per service name. Ports are checked for availability. Returns a PortMap with service names mapped to allocated ports.

type ProgressReporter

type ProgressReporter interface {
	OnStep(event StepEvent)
	// StderrWriter returns a writer for hook stderr output.
	// The reporter may indent or buffer this output for display.
	StderrWriter() io.Writer
}

ProgressReporter receives lifecycle step events from the manager. Inbound adapters implement this to render progress (CLI spinners, SSE, etc).

type ProjectConfig

type ProjectConfig struct {
	Version        int                      `yaml:"version"`
	Name           string                   `yaml:"name"`
	Provisioner    ProvisionerConfig        `yaml:"provisioner"`
	Infrastructure *InfrastructureConfig    `yaml:"infrastructure,omitempty"`
	Services       map[string]ServiceConfig `yaml:"services"`
	Runner         *RunnerConfig            `yaml:"runner,omitempty"`

	// Mode is the deployment mode (e.g., "local"). Set at load time, not from YAML.
	Mode string `yaml:"-"`

	// InfraServices is populated by parsing the compose file referenced in
	// Infrastructure.ComposeFile. It is not read from YAML directly.
	InfraServices map[string]InfraService `yaml:"-"`
}

ProjectConfig is the top-level previewctl.yaml configuration.

func LoadConfig

func LoadConfig(path string) (*ProjectConfig, error)

LoadConfig reads and parses a previewctl.yaml file.

func LoadConfigWithOverlay added in v0.0.2

func LoadConfigWithOverlay(basePath, mode string) (*ProjectConfig, error)

LoadConfigWithOverlay loads a base config and merges a mode-specific overlay if present.

func ParseConfig

func ParseConfig(data []byte) (*ProjectConfig, error)

ParseConfig parses YAML bytes into a ProjectConfig.

func (*ProjectConfig) ServiceNames added in v0.0.2

func (c *ProjectConfig) ServiceNames() []string

ServiceNames returns a sorted list of all service and infrastructure names that need port assignments.

type ProvisionerConfig added in v0.0.4

type ProvisionerConfig struct {
	Before   string                              `yaml:"before,omitempty"`
	After    string                              `yaml:"after,omitempty"`
	Compute  *ComputeHooks                       `yaml:"compute,omitempty"`
	Services map[string]ProvisionerServiceConfig `yaml:"services,omitempty"`
}

ProvisionerConfig holds managed provisioner services with hook-driven lifecycle.

type ProvisionerServiceConfig added in v0.0.4

type ProvisionerServiceConfig struct {
	Outputs []string `yaml:"outputs,omitempty"`
	Init    string   `yaml:"init,omitempty"`
	Seed    string   `yaml:"seed,omitempty"`
	Reset   string   `yaml:"reset,omitempty"`
	Destroy string   `yaml:"destroy,omitempty"`
}

ProvisionerServiceConfig defines a provisioner service managed by hooks.

type ProxyConfig added in v0.0.7

type ProxyConfig struct {
	Enabled *bool  `yaml:"enabled,omitempty"` // defaults to true if omitted
	Domain  string `yaml:"domain"`            // e.g., "preview.airgoods.com"
	Type    string `yaml:"type,omitempty"`    // "nginx" (default). Future: "traefik", "caddy"
}

ProxyConfig defines the reverse proxy that sits in front of preview services.

func (*ProxyConfig) IsEnabled added in v0.0.7

func (p *ProxyConfig) IsEnabled() bool

IsEnabled returns whether the proxy is enabled (defaults to true).

func (*ProxyConfig) ResolvedType added in v0.0.7

func (p *ProxyConfig) ResolvedType() string

ResolvedType returns the proxy type, defaulting to "nginx".

type ReconcileReport added in v0.0.7

type ReconcileReport struct {
	Results []ReconcileResult
	Healed  int
	Failed  int
	OK      int
	Skipped int
	NotRun  int
}

ReconcileReport is the full outcome of a reconcile run.

type ReconcileResult added in v0.0.7

type ReconcileResult struct {
	Step       string
	Action     string // "ok", "healed", "failed", "skipped", "not_run"
	Message    string
	DurationMs int64
}

ReconcileResult describes the outcome of reconciling a single step.

type RunnerConfig added in v0.0.4

type RunnerConfig struct {
	Before  string         `yaml:"before,omitempty"`
	Deploy  string         `yaml:"deploy,omitempty"`
	Destroy string         `yaml:"destroy,omitempty"`
	After   string         `yaml:"after,omitempty"`
	Compose *ComposeConfig `yaml:"compose,omitempty"`
}

RunnerConfig holds runner lifecycle hooks.

type SSHComputeAccessOpts added in v0.0.7

type SSHComputeAccessOpts struct {
	Host         string // SSH host (direct mode) or logical hostname (proxy mode)
	User         string
	Root         string
	ProxyCommand string // when set, uses -o ProxyCommand=... instead of relying on SSH config
	IdentityFile string // path to SSH private key (optional)
}

SSHComputeAccessOpts configures SSH compute access creation.

type SSHConfig added in v0.0.7

type SSHConfig struct {
	// ProxyCommand is the SSH ProxyCommand used to tunnel into the VM.
	// Example: "gcloud compute start-iap-tunnel {{store.VM_NAME}} %p --listen-on-stdin --zone={{store.GCP_ZONE}} --project={{store.GCP_PROJECT}}"
	ProxyCommand string `yaml:"proxy_command"`
	// User is the SSH username. Example: "{{store.SSH_USER}}"
	User string `yaml:"user"`
	// UserCommand is a shell command that resolves the SSH username dynamically.
	// Useful when different users (CI vs human) SSH into the same VM.
	// Example: "gcloud compute os-login describe-profile --format='value(posixAccounts[0].username)'"
	// Takes precedence over User when set.
	UserCommand string `yaml:"user_command"`
	// IdentityFile is the path to the SSH private key. Supports ~ expansion.
	// Example: "~/.ssh/google_compute_engine"
	IdentityFile string `yaml:"identity_file"`
	// Root is the remote working directory. Defaults to "/app".
	Root string `yaml:"root,omitempty"`
}

SSHConfig defines how previewctl connects to remote compute via SSH. All fields support {{store.KEY}} template resolution.

type ServiceConfig

type ServiceConfig struct {
	Path      string            `yaml:"path"`
	Port      int               `yaml:"port,omitempty"` // fixed port — skips the port allocator when set
	Command   string            `yaml:"command,omitempty"`
	DependsOn []string          `yaml:"depends_on,omitempty"`
	Env       map[string]string `yaml:"env,omitempty"`
	EnvFile   string            `yaml:"env_file,omitempty"` // relative to path, defaults to ".env.local"
	Build     string            `yaml:"build,omitempty"`    // build command (run on host before container starts)
	Start     string            `yaml:"start,omitempty"`    // start command (run inside container). Required for compose generation.
	Proxy     []ServiceProxy    `yaml:"proxy,omitempty"`    // optional reverse proxy rules for nginx
}

ServiceConfig defines an application service.

func (ServiceConfig) ResolvedEnvFile added in v0.0.2

func (s ServiceConfig) ResolvedEnvFile() string

ResolvedEnvFile returns the env file path relative to the service path. Defaults to ".env.local" if not configured.

type ServiceProxy added in v0.0.7

type ServiceProxy struct {
	Path       string             `yaml:"path"`                  // source path the browser sends, e.g., "/api" or "/iapi"
	TargetPath string             `yaml:"target_path,omitempty"` // path rewritten to on the target service. Defaults to Path if omitted.
	To         ServiceProxyTarget `yaml:"to"`
}

ServiceProxy defines a reverse proxy rule on a service's subdomain. When configured, nginx generates a location block that proxies the given path to the target service's port (same-origin for IAP cookie compatibility).

func (*ServiceProxy) ResolvedTargetPath added in v0.0.7

func (p *ServiceProxy) ResolvedTargetPath() string

ResolvedTargetPath returns the target path, defaulting to Path if not set.

type ServiceProxyTarget added in v0.0.7

type ServiceProxyTarget struct {
	Service string `yaml:"service"` // target service name, resolved to its port at generation time
}

ServiceProxyTarget identifies the target service for a proxy rule.

type State

type State struct {
	Version      int                          `json:"version"`
	Environments map[string]*EnvironmentEntry `json:"environments"`
}

State is the top-level persisted state.

func NewState

func NewState() *State

NewState returns an initialized empty state.

type StatePort

type StatePort interface {
	// Load returns the full state.
	Load(ctx context.Context) (*State, error)

	// Save persists the full state.
	Save(ctx context.Context, state *State) error

	// GetEnvironment returns a single environment entry, or nil if not found.
	GetEnvironment(ctx context.Context, name string) (*EnvironmentEntry, error)

	// SetEnvironment creates or updates an environment entry.
	SetEnvironment(ctx context.Context, name string, entry *EnvironmentEntry) error

	// RemoveEnvironment deletes an environment entry.
	RemoveEnvironment(ctx context.Context, name string) error
}

StatePort persists previewctl state. File-based for POC; interface accommodates Postgres/etcd later.

type StepEvent

type StepEvent struct {
	Step    string // e.g. "allocate_ports", "create_worktree", "create_database"
	Status  StepStatus
	Message string // human-readable detail
	Error   error  // non-nil when Status == StepFailed
}

StepEvent is emitted by the manager at each lifecycle transition.

type StepOpts added in v0.0.4

type StepOpts struct {
	Name        string
	StartMsg    string
	CompleteMsg *string
	Fn          func() error
	Verify      VerifyFunc            // nil = pure, skip on checkpoint alone
	Outputs     func() map[string]any // capture outputs after success
}

StepOpts configures step execution behavior.

type StepRecord added in v0.0.4

type StepRecord struct {
	Name       string           `json:"name"`
	Status     StepRecordStatus `json:"status"`
	StartedAt  time.Time        `json:"startedAt"`
	FinishedAt time.Time        `json:"finishedAt"`
	DurationMs int64            `json:"durationMs"`
	Machine    string           `json:"machine"`
	Error      string           `json:"error,omitempty"`
	Outputs    map[string]any   `json:"outputs,omitempty"`
}

StepRecord is the checkpoint persisted for a single step execution.

type StepRecordStatus added in v0.0.4

type StepRecordStatus string

StepRecordStatus represents the persisted outcome of a step.

const (
	StepRecordCompleted   StepRecordStatus = "completed"
	StepRecordFailed      StepRecordStatus = "failed"
	StepRecordInvalidated StepRecordStatus = "invalidated"
)

type StepStatus

type StepStatus string

StepStatus represents the status of a lifecycle step.

const (
	StepStarted   StepStatus = "started"
	StepCompleted StepStatus = "completed"
	StepFailed    StepStatus = "failed"
	StepSkipped   StepStatus = "skipped"
	StepStreaming StepStatus = "streaming" // stop spinner, hook will stream its own output
)

type TemplateContext

type TemplateContext struct {
	ServicePorts       PortMap
	InfraPorts         PortMap
	ProvisionerOutputs map[string]map[string]string
	CurrentService     string            // set per-service during rendering, enables {{self.port}}
	EnvName            string            // environment name, enables {{env.name}}
	Store              map[string]string // persistent key-value store, enables {{store.KEY}}
	ProxyDomain        string            // proxy domain (e.g., "preview.airgoods.com"), enables {{proxy.*}}
}

TemplateContext holds the values available for template substitution.

type VMInfo

type VMInfo struct {
	ID         string
	ExternalIP string
	Status     string
}

VMInfo describes a provisioned VM (future).

type VMSpec

type VMSpec struct {
	MachineType string
	DiskSizeGB  int
	Image       string
	Region      string
}

VMSpec defines requirements for provisioning a VM (future).

type ValidationError

type ValidationError struct {
	Errors []string
}

ValidationError collects multiple validation issues.

func (*ValidationError) Error

func (e *ValidationError) Error() string

type VerifyFunc added in v0.0.4

type VerifyFunc func(ctx context.Context) error

VerifyFunc checks that a previously-completed step's side effects still hold.

Jump to

Keyboard shortcuts

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