Documentation
¶
Overview ¶
Package plugin provides the compile-time plugin system for TerraCi.
The plugin system is organized into three packages:
- pkg/plugin: core interfaces, BasePlugin[C], AppContext, EnablePolicy, RuntimeProvider
- pkg/plugin/registry: global plugin registration and resolution (Register, ByCapability, ResolveProvider)
- pkg/plugin/initwiz: init wizard types (StateMap, InitContributor, InitGroupSpec)
Preferred plugin architecture for runtime-heavy built-in and external plugins:
- plugin.go: registration shell and typed BasePlugin config
- lifecycle.go: cheap Preflight checks only
- runtime.go: lazy RuntimeProvider implementation
- usecases.go: command orchestration over typed runtime
- output.go / report.go: rendering and report assembly
Framework-owned lifecycle stops at configuration and preflight. Heavy clients, caches, and command-specific state should be created lazily from Runtime() and consumed by plugin commands or use-cases rather than cached during startup hooks.
Package plugin provides the compile-time plugin system for TerraCi. Plugins register themselves via init() and blank imports, following the same pattern as database/sql drivers and Caddy modules.
Core types (interfaces, BasePlugin, AppContext) live in this package. Global registry functions live in pkg/plugin/registry. Init wizard types live in pkg/plugin/initwiz.
Index ¶
- func BuildRuntime[T any](ctx context.Context, p RuntimeProvider, appCtx *AppContext) (T, error)
- func RuntimeAs[T any](runtime any) (T, error)
- type AppContext
- func (ctx *AppContext) Config() *config.Config
- func (ctx *AppContext) Freeze()
- func (ctx *AppContext) IsFrozen() bool
- func (ctx *AppContext) Reports() *ReportRegistry
- func (ctx *AppContext) ServiceDir() string
- func (ctx *AppContext) Update(cfg *config.Config, workDir, serviceDir, version string)
- func (ctx *AppContext) Version() string
- func (ctx *AppContext) WorkDir() string
- type BasePlugin
- func (b *BasePlugin[C]) Config() C
- func (b *BasePlugin[C]) ConfigKey() string
- func (b *BasePlugin[C]) DecodeAndSet(decode func(target any) error) error
- func (b *BasePlugin[C]) Description() string
- func (b *BasePlugin[C]) IsConfigured() bool
- func (b *BasePlugin[C]) IsEnabled() bool
- func (b *BasePlugin[C]) Name() string
- func (b *BasePlugin[C]) NewConfig() any
- func (b *BasePlugin[C]) Reset()
- func (b *BasePlugin[C]) SetTypedConfig(cfg C)
- type CIMetadata
- type CIProvider
- func (c *CIProvider) CommitSHA() string
- func (c *CIProvider) Description() string
- func (c *CIProvider) Name() string
- func (c *CIProvider) NewCommentService(ctx *AppContext) (ci.CommentService, bool)
- func (c *CIProvider) NewGenerator(ctx *AppContext, depGraph *graph.DependencyGraph, modules []*discovery.Module) pipeline.Generator
- func (c *CIProvider) PipelineID() string
- func (c *CIProvider) Plugin() Plugin
- func (c *CIProvider) ProviderName() string
- type ChangeDetectionProvider
- type CommandProvider
- type CommentFactory
- type ConfigLoader
- type EnablePolicy
- type EnvDetector
- type FlagOverridable
- type GeneratorFactory
- type PipelineContributor
- type Plugin
- type Preflightable
- type ReportRegistry
- type Resettable
- type RuntimeProvider
- type VersionProvider
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func BuildRuntime ¶ added in v0.9.0
func BuildRuntime[T any](ctx context.Context, p RuntimeProvider, appCtx *AppContext) (T, error)
BuildRuntime calls p.Runtime and type-asserts the result to T in one step. It combines the Runtime() call and RuntimeAs[T]() assertion — the recommended shorthand for plugin use-cases:
func (p *Plugin) runtime(ctx context.Context, appCtx *AppContext) (*myRuntime, error) {
return plugin.BuildRuntime[*myRuntime](ctx, p, appCtx)
}
Types ¶
type AppContext ¶
type AppContext struct {
// contains filtered or unexported fields
}
AppContext is the public API available to plugins.
ServiceDir is the resolved absolute path — use it for runtime file I/O. For pipeline artifact paths (CI templates), use Config.ServiceDir which preserves the original relative value from .terraci.yaml.
After initialization, call Freeze() to prevent the framework from refreshing this shared context from App state again during the current command run.
func NewAppContext ¶ added in v0.9.0
func NewAppContext(cfg *config.Config, workDir, serviceDir, version string, reports *ReportRegistry) *AppContext
NewAppContext creates a framework-managed plugin context.
func (*AppContext) Config ¶
func (ctx *AppContext) Config() *config.Config
Config returns a defensive copy of the loaded TerraCi configuration. For repeated access within a single use-case, cache the result locally:
cfg := appCtx.Config() // use cfg throughout the function
This avoids repeated deep copies while preserving immutability guarantees.
func (*AppContext) Freeze ¶ added in v0.7.5
func (ctx *AppContext) Freeze()
Freeze marks the context as final for framework-managed updates.
func (*AppContext) IsFrozen ¶ added in v0.7.5
func (ctx *AppContext) IsFrozen() bool
IsFrozen returns whether the context has been frozen.
func (*AppContext) Reports ¶ added in v0.7.5
func (ctx *AppContext) Reports() *ReportRegistry
Reports returns the shared in-process report registry.
func (*AppContext) ServiceDir ¶ added in v0.7.3
func (ctx *AppContext) ServiceDir() string
ServiceDir returns the resolved absolute service directory path.
func (*AppContext) Update ¶ added in v0.9.0
func (ctx *AppContext) Update(cfg *config.Config, workDir, serviceDir, version string)
Update refreshes the framework-managed view of app state until the context is frozen.
func (*AppContext) Version ¶
func (ctx *AppContext) Version() string
Version returns the current TerraCi version string.
func (*AppContext) WorkDir ¶
func (ctx *AppContext) WorkDir() string
WorkDir returns the working directory for the current command.
type BasePlugin ¶ added in v0.7.5
type BasePlugin[C any] struct { PluginName string PluginDesc string PluginKey string // config key; defaults to PluginName if empty EnableMode EnablePolicy // how the framework checks if this plugin is active DefaultCfg func() C // factory for default config // IsEnabledFn is an optional custom check for EnabledExplicitly and EnabledByDefault. // For EnabledExplicitly: called when configured, must return true to activate. // For EnabledByDefault: called when configured, return false to deactivate. IsEnabledFn func(C) bool // contains filtered or unexported fields }
BasePlugin provides shared implementation for all plugins that have configuration. C is the plugin's concrete config type. Embedding this gives you:
- Name(), Description()
- ConfigKey(), NewConfig(), DecodeAndSet(), IsConfigured(), IsEnabled()
- Config() (typed access to config)
- Reset() (resets config state; override to reset custom fields)
func (*BasePlugin[C]) Config ¶ added in v0.7.5
func (b *BasePlugin[C]) Config() C
Config returns the typed plugin configuration.
func (*BasePlugin[C]) ConfigKey ¶ added in v0.7.5
func (b *BasePlugin[C]) ConfigKey() string
ConfigKey returns the config section key under "plugins:" in .terraci.yaml.
func (*BasePlugin[C]) DecodeAndSet ¶ added in v0.7.5
func (b *BasePlugin[C]) DecodeAndSet(decode func(target any) error) error
DecodeAndSet decodes plugin config via the provided decoder and stores it.
func (*BasePlugin[C]) Description ¶ added in v0.7.5
func (b *BasePlugin[C]) Description() string
Description returns a human-readable description.
func (*BasePlugin[C]) IsConfigured ¶ added in v0.7.5
func (b *BasePlugin[C]) IsConfigured() bool
IsConfigured returns true if config was loaded for this plugin.
func (*BasePlugin[C]) IsEnabled ¶ added in v0.7.5
func (b *BasePlugin[C]) IsEnabled() bool
IsEnabled returns whether the plugin should be active, based on EnablePolicy.
func (*BasePlugin[C]) Name ¶ added in v0.7.5
func (b *BasePlugin[C]) Name() string
Name returns the plugin's unique identifier.
func (*BasePlugin[C]) NewConfig ¶ added in v0.7.5
func (b *BasePlugin[C]) NewConfig() any
NewConfig returns a new instance of the default config for schema generation.
func (*BasePlugin[C]) Reset ¶ added in v0.7.5
func (b *BasePlugin[C]) Reset()
Reset resets the config state. Override in your plugin to also reset custom fields.
func (*BasePlugin[C]) SetTypedConfig ¶ added in v0.7.5
func (b *BasePlugin[C]) SetTypedConfig(cfg C)
SetTypedConfig sets the typed config directly (used by tests and flag overrides).
type CIMetadata ¶ added in v0.7.5
CIMetadata provides CI-specific metadata.
type CIProvider ¶ added in v0.7.5
type CIProvider struct {
// contains filtered or unexported fields
}
CIProvider is the resolved CI provider, assembled from the focused interfaces above. Returned by ResolveProvider(). CommentFactory is optional — not all CI providers support PR/MR comments.
func NewCIProvider ¶ added in v0.7.5
func NewCIProvider(p Plugin, meta CIMetadata, gen GeneratorFactory, comment CommentFactory) *CIProvider
NewCIProvider constructs a CIProvider. The comment parameter may be nil for CI providers that do not support PR/MR comments.
func (*CIProvider) CommitSHA ¶ added in v0.7.5
func (c *CIProvider) CommitSHA() string
func (*CIProvider) Description ¶ added in v0.7.5
func (c *CIProvider) Description() string
func (*CIProvider) Name ¶ added in v0.7.5
func (c *CIProvider) Name() string
func (*CIProvider) NewCommentService ¶ added in v0.7.5
func (c *CIProvider) NewCommentService(ctx *AppContext) (ci.CommentService, bool)
NewCommentService returns the comment service and true, or nil and false if the CI provider does not support PR/MR comments.
func (*CIProvider) NewGenerator ¶ added in v0.7.5
func (c *CIProvider) NewGenerator(ctx *AppContext, depGraph *graph.DependencyGraph, modules []*discovery.Module) pipeline.Generator
func (*CIProvider) PipelineID ¶ added in v0.7.5
func (c *CIProvider) PipelineID() string
func (*CIProvider) Plugin ¶ added in v0.7.5
func (c *CIProvider) Plugin() Plugin
Plugin returns the underlying plugin instance.
func (*CIProvider) ProviderName ¶ added in v0.7.5
func (c *CIProvider) ProviderName() string
type ChangeDetectionProvider ¶
type ChangeDetectionProvider interface {
Plugin
DetectChangedModules(ctx context.Context, appCtx *AppContext, baseRef string, moduleIndex *discovery.ModuleIndex) (changed []*discovery.Module, changedFiles []string, err error)
DetectChangedLibraries(ctx context.Context, appCtx *AppContext, baseRef string, libraryPaths []string) ([]string, error)
}
ChangeDetectionProvider detects changed modules from git (or other VCS).
type CommandProvider ¶
type CommandProvider interface {
Plugin
Commands(ctx *AppContext) []*cobra.Command
}
CommandProvider adds CLI subcommands to TerraCi.
type CommentFactory ¶ added in v0.7.5
type CommentFactory interface {
Plugin
NewCommentService(ctx *AppContext) ci.CommentService
}
CommentFactory creates PR/MR comment services.
type ConfigLoader ¶ added in v0.7.5
type ConfigLoader interface {
Plugin
ConfigKey() string
NewConfig() any
DecodeAndSet(decode func(target any) error) error
IsConfigured() bool
IsEnabled() bool
}
ConfigLoader declares a config section under "plugins:" in .terraci.yaml. Implemented automatically by embedding BasePlugin[C].
type EnablePolicy ¶ added in v0.7.5
type EnablePolicy int
EnablePolicy controls how the framework determines if a plugin is active.
const ( // EnabledWhenConfigured means the plugin is active if its config section // exists in .terraci.yaml (e.g., gitlab, github). EnabledWhenConfigured EnablePolicy = iota // EnabledExplicitly requires an explicit opt-in beyond having config (e.g., cost, policy). // When IsEnabledFn is set: called after config is loaded, must return true to activate. // When IsEnabledFn is nil: always returns false, even if configured. EnabledExplicitly // EnabledByDefault means the plugin is active unless enabled: false is set (e.g., summary). EnabledByDefault // EnabledAlways means the plugin is always active regardless of config (e.g., git). EnabledAlways )
type EnvDetector ¶ added in v0.7.5
EnvDetector detects whether this plugin's CI environment is active.
type FlagOverridable ¶ added in v0.7.5
FlagOverridable plugins support direct CLI flag overrides on their config.
type GeneratorFactory ¶ added in v0.7.5
type GeneratorFactory interface {
Plugin
NewGenerator(ctx *AppContext, depGraph *graph.DependencyGraph, modules []*discovery.Module) pipeline.Generator
}
GeneratorFactory creates pipeline generators.
type PipelineContributor ¶
type PipelineContributor interface {
Plugin
PipelineContribution(ctx *AppContext) *pipeline.Contribution
}
PipelineContributor plugins add steps or jobs to the generated CI pipeline.
type Plugin ¶
type Plugin interface {
// Name returns a unique identifier (e.g., "gitlab", "cost", "slack").
Name() string
// Description returns a human-readable description.
Description() string
}
Plugin is the core interface every plugin must implement.
type Preflightable ¶ added in v0.9.0
type Preflightable interface {
Plugin
Preflight(ctx context.Context, appCtx *AppContext) error
}
Preflightable plugins run cheap validation after config is loaded, before any command runs. Preflight should stay side-effect-light: do not cache mutable command state or perform heavy runtime setup that can be created lazily inside plugin use-cases.
type ReportRegistry ¶ added in v0.7.5
type ReportRegistry struct {
// contains filtered or unexported fields
}
ReportRegistry allows plugins to publish and consume reports in-memory. In CI (multi-process), reports are still written to JSON files for artifacts. The registry provides an in-process fast path for single-process runs.
func NewReportRegistry ¶ added in v0.7.5
func NewReportRegistry() *ReportRegistry
NewReportRegistry creates a new empty ReportRegistry.
func (*ReportRegistry) All ¶ added in v0.7.5
func (r *ReportRegistry) All() []*ci.Report
All returns all published reports.
func (*ReportRegistry) Get ¶ added in v0.7.5
func (r *ReportRegistry) Get(pluginName string) (*ci.Report, bool)
Get retrieves a report by plugin name.
func (*ReportRegistry) Publish ¶ added in v0.7.5
func (r *ReportRegistry) Publish(report *ci.Report)
Publish stores a report in the registry, keyed by plugin name.
type Resettable ¶ added in v0.7.5
type Resettable interface {
Plugin
Reset()
}
Resettable plugins can reset their mutable state to zero values. Used by test infrastructure to isolate tests from shared plugin singletons.
type RuntimeProvider ¶ added in v0.9.0
type RuntimeProvider interface {
Plugin
Runtime(ctx context.Context, appCtx *AppContext) (any, error)
}
RuntimeProvider is the preferred pattern for plugins with heavy command-time setup. Runtime creation is lazy and command-driven; the framework does not invoke it automatically during startup or preflight.
Use Preflightable for cheap validation and environment checks. Use RuntimeProvider for typed runtime construction inside plugin commands and use-cases.
Typical shape:
func (p *Plugin) Runtime(_ context.Context, appCtx *AppContext) (any, error) {
return newRuntime(appCtx, p.Config(), runtimeOptions{})
}
func (p *Plugin) runtime(ctx context.Context, appCtx *AppContext, opts runtimeOptions) (*myRuntime, error) {
if opts == (runtimeOptions{}) {
rawRuntime, err := p.Runtime(ctx, appCtx)
if err != nil {
return nil, err
}
return RuntimeAs[*myRuntime](rawRuntime)
}
return newRuntime(appCtx, p.Config(), opts)
}
Example ¶
package main
import (
"context"
"fmt"
"github.com/edelwud/terraci/pkg/plugin"
)
type exampleRuntime struct {
workDir string
}
type exampleRuntimePlugin struct {
plugin.BasePlugin[*exampleRuntimeConfig]
}
type exampleRuntimeConfig struct {
Enabled bool
}
func (p *exampleRuntimePlugin) Runtime(_ context.Context, appCtx *plugin.AppContext) (any, error) {
if p.Config() == nil || !p.Config().Enabled {
return nil, fmt.Errorf("example runtime is not enabled")
}
return &exampleRuntime{workDir: appCtx.WorkDir()}, nil
}
func main() {
p := &exampleRuntimePlugin{
BasePlugin: plugin.BasePlugin[*exampleRuntimeConfig]{
PluginName: "example",
PluginDesc: "example runtime plugin",
EnableMode: plugin.EnabledExplicitly,
DefaultCfg: func() *exampleRuntimeConfig { return &exampleRuntimeConfig{} },
IsEnabledFn: func(cfg *exampleRuntimeConfig) bool { return cfg != nil && cfg.Enabled },
},
}
p.SetTypedConfig(&exampleRuntimeConfig{Enabled: true})
appCtx := plugin.NewAppContext(nil, "/repo", "/repo/.terraci", "test", nil)
rawRuntime, _ := p.Runtime(context.Background(), appCtx)
runtime, _ := plugin.RuntimeAs[*exampleRuntime](rawRuntime)
fmt.Println(runtime.workDir)
}
Output: /repo
type VersionProvider ¶
VersionProvider plugins contribute version info to `terraci version`.
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
Package initwiz provides init wizard state management and types for TerraCi.
|
Package initwiz provides init wizard state management and types for TerraCi. |
|
Package registry provides the global plugin registry for TerraCi.
|
Package registry provides the global plugin registry for TerraCi. |