Documentation
¶
Index ¶
- func ExecuteCoreHook(ctx context.Context, hookScript string, declaredOutputs []string, env []string, ...) (map[string]string, error)
- func ParseComposeFile(path string) (map[string]InfraService, error)
- func RenderEnvMap(envMap map[string]string, ctx *TemplateContext) (map[string]string, error)
- func RenderTemplate(tmpl string, ctx *TemplateContext) (string, error)
- func ResolveEnvironmentFromCwd(cwd string, environments map[string]*EnvironmentEntry) (string, error)
- func TopologicalSort(services map[string]ServiceConfig) ([]string, error)
- func ValidateConfig(cfg *ProjectConfig) error
- func ValidateConfigWithFS(cfg *ProjectConfig, projectRoot string, fileExists func(string) bool) error
- func WorktreeBasePath() string
- type ComputePort
- type ComputeResources
- type CoreConfig
- type CoreServiceConfig
- type CoreServiceHooks
- type EnvPort
- type EnvironmentDetail
- type EnvironmentEntry
- type EnvironmentMode
- type EnvironmentStatus
- type HookContext
- type HookDef
- type HookRunner
- type HooksConfig
- type InfraService
- type InfrastructureConfig
- type LocalConfig
- type LocalMeta
- type Manager
- func (m *Manager) CoreInit(ctx context.Context, svcName string) error
- func (m *Manager) CoreReset(ctx context.Context, svcName, envName string) error
- func (m *Manager) Destroy(ctx context.Context, envName string) error
- func (m *Manager) Init(ctx context.Context, envName string, branch string) (*EnvironmentEntry, error)
- func (m *Manager) List(ctx context.Context) ([]*EnvironmentEntry, error)
- func (m *Manager) RunCoreHook(ctx context.Context, svcName, action, envName string) (map[string]string, error)
- func (m *Manager) Status(ctx context.Context, envName string) (*EnvironmentDetail, error)
- type ManagerDeps
- type NetworkingPort
- type NoopReporter
- type PortMap
- type ProgressReporter
- type ProjectConfig
- type ProvisionerPort
- type RemoteMeta
- type ServiceConfig
- type State
- type StatePort
- type StepEvent
- type StepHooks
- type StepStatus
- type TemplateContext
- type VMInfo
- type VMSpec
- type ValidationError
- type WorktreeConfig
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func ExecuteCoreHook ¶ added in v0.0.2
func ExecuteCoreHook(ctx context.Context, hookScript string, declaredOutputs []string, env []string, workdir string) (map[string]string, error)
ExecuteCoreHook runs a core service hook script and captures KEY=VALUE outputs. stderr streams to the terminal in real-time for visibility. stdout is captured and parsed for KEY=VALUE pairs. Returns the captured outputs, validated against declaredOutputs.
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 RenderEnvMap ¶
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
- {{core.<service>.<OUTPUT>}} — output value from a core service
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 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, template variable references, and local config. 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 WorktreeBasePath ¶ added in v0.0.2
func WorktreeBasePath() string
WorktreeBasePath returns the fixed base path for all previewctl worktrees. Worktrees are always stored in ~/.previewctl/worktrees to avoid conflicts with user-managed worktrees.
Types ¶
type ComputePort ¶
type ComputePort interface {
// Create sets up compute resources for an environment.
Create(ctx context.Context, envName string, branch 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)
}
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 CoreConfig ¶
type CoreConfig struct {
Services map[string]CoreServiceConfig `yaml:"services,omitempty"`
}
CoreConfig holds managed core services with hook-driven lifecycle.
type CoreServiceConfig ¶ added in v0.0.2
type CoreServiceConfig struct {
Outputs []string `yaml:"outputs,omitempty"`
Hooks *CoreServiceHooks `yaml:"hooks,omitempty"`
}
CoreServiceConfig defines a core service managed by hooks.
type CoreServiceHooks ¶ added in v0.0.2
type CoreServiceHooks struct {
Init string `yaml:"init,omitempty"`
Seed string `yaml:"seed,omitempty"`
Reset string `yaml:"reset,omitempty"`
Destroy string `yaml:"destroy,omitempty"`
}
CoreServiceHooks defines lifecycle hooks for a core service.
type EnvPort ¶
type EnvPort interface {
// Generate writes .env.local files for all services in the environment.
Generate(ctx context.Context, envName string, workdir string, ports PortMap, coreOutputs map[string]map[string]string) error
SymlinkSharedEnvFiles(ctx context.Context, workdir string) error
// Cleanup removes generated env files.
Cleanup(ctx context.Context, workdir string) error
}
EnvPort generates environment configuration files (.env.local, etc).
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"`
CoreOutputs map[string]map[string]string `json:"coreOutputs"`
Local *LocalMeta `json:"local,omitempty"`
Remote *RemoteMeta `json:"remote,omitempty"`
}
EnvironmentEntry is a tracked environment persisted in state.
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" StatusRunning EnvironmentStatus = "running" StatusStopped EnvironmentStatus = "stopped" StatusError EnvironmentStatus = "error" )
type HookContext ¶
type HookContext struct {
EnvName string
Branch string
ProjectName string
ProjectRoot string
WorktreePath string
Ports PortMap
CoreOutputs map[string]map[string]string
Step string
Phase string // "before" or "after"
}
HookContext provides environment variables and working directory for hook execution.
type HookDef ¶
type HookDef struct {
Run string `yaml:"run"`
ContinueOnError bool `yaml:"continue_on_error,omitempty"`
}
HookDef defines a single hook to execute.
type HookRunner ¶
type HookRunner struct {
// contains filtered or unexported fields
}
HookRunner executes hooks defined in the config.
func NewHookRunner ¶
func NewHookRunner(hooks HooksConfig, progress ProgressReporter) *HookRunner
NewHookRunner creates a new hook runner.
func (*HookRunner) RunAfter ¶
func (r *HookRunner) RunAfter(ctx context.Context, step string, hctx *HookContext) error
RunAfter executes all "after" hooks for the given step.
func (*HookRunner) RunBefore ¶
func (r *HookRunner) RunBefore(ctx context.Context, step string, hctx *HookContext) error
RunBefore executes all "before" hooks for the given step.
type HooksConfig ¶
HooksConfig maps step names to their before/after hooks. Step names match the lifecycle steps: allocate_ports, create_compute, symlink_env, generate_env, start_infra, save_state, load_state, destroy_compute, cleanup_env, remove_state.
Additionally, lifecycle-level hooks can be defined: create, delete — these run before/after the entire operation.
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 LocalConfig ¶
type LocalConfig struct {
Worktree WorktreeConfig `yaml:"worktree"`
}
LocalConfig holds local-mode specific configuration.
type LocalMeta ¶
type LocalMeta struct {
WorktreePath string `json:"worktreePath"`
ComposeProjectName string `json:"composeProjectName"`
}
LocalMeta holds local-mode specific metadata.
type Manager ¶
type Manager struct {
// contains filtered or unexported fields
}
Manager orchestrates environment lifecycle by coordinating all ports. It is the single source of truth — all inbound adapters delegate to it.
func NewManager ¶
func NewManager(deps ManagerDeps) *Manager
NewManager creates a new Manager with the given dependencies.
func (*Manager) CoreInit ¶ added in v0.0.2
CoreInit runs the "init" hook for a core service (one-time setup).
func (*Manager) CoreReset ¶ added in v0.0.2
CoreReset runs the "reset" hook for a core service on a specific environment.
func (*Manager) Init ¶
func (m *Manager) Init(ctx context.Context, envName string, branch string) (*EnvironmentEntry, error)
Init creates a new environment end-to-end.
func (*Manager) List ¶
func (m *Manager) List(ctx context.Context) ([]*EnvironmentEntry, error)
List returns all tracked environments.
type ManagerDeps ¶
type ManagerDeps struct {
Compute ComputePort
Networking NetworkingPort
EnvGen EnvPort
State StatePort
Progress ProgressReporter
Config *ProjectConfig
ProjectRoot string
}
ManagerDeps holds the dependencies for creating a Manager.
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)
type PortMap ¶
PortMap maps service names to allocated ports.
func AllocatePortBlock ¶ added in v0.0.2
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)
}
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"`
Core CoreConfig `yaml:"core"`
Infrastructure *InfrastructureConfig `yaml:"infrastructure,omitempty"`
Services map[string]ServiceConfig `yaml:"services"`
Local *LocalConfig `yaml:"local,omitempty"`
Hooks HooksConfig `yaml:"hooks,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 ProvisionerPort ¶
type ProvisionerPort interface {
Provision(ctx context.Context, envName string, spec VMSpec) (*VMInfo, error)
Deprovision(ctx context.Context, vmID string) error
Status(ctx context.Context, vmID string) (*VMInfo, error)
}
ProvisionerPort manages VM lifecycle for preview/sandbox modes. Not implemented in POC; exists to validate interface design.
type RemoteMeta ¶
RemoteMeta holds remote-mode specific metadata (future).
type ServiceConfig ¶
type ServiceConfig struct {
Path string `yaml:"path"`
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"
}
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 State ¶
type State struct {
Version int `json:"version"`
Environments map[string]*EnvironmentEntry `json:"environments"`
}
State is the top-level persisted 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 StepHooks ¶
type StepHooks struct {
Before []HookDef `yaml:"before,omitempty"`
After []HookDef `yaml:"after,omitempty"`
}
StepHooks defines before and after hooks for a step.
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" )
type TemplateContext ¶
type TemplateContext struct {
ServicePorts PortMap
InfraPorts PortMap
CoreOutputs map[string]map[string]string
CurrentService string // set per-service during rendering, enables {{self.port}}
}
TemplateContext holds the values available for template substitution.
type ValidationError ¶
type ValidationError struct {
Errors []string
}
ValidationError collects multiple validation issues.
func (*ValidationError) Error ¶
func (e *ValidationError) Error() string
type WorktreeConfig ¶
type WorktreeConfig struct {
// SymlinkPatterns are glob patterns for gitignored files to symlink from the
// main worktree into each new worktree (e.g. ".env" matches .env files recursively).
// These are typically secret/config files that exist in the main repo but aren't
// tracked by git. Each pattern is matched recursively across the entire repo.
SymlinkPatterns []string `yaml:"symlink_patterns,omitempty"`
}
WorktreeConfig defines worktree settings.