Create external plugins to extend uptool with custom integrations.
Built-in vs Plugin:
- Built-in: Compiled into uptool (npm, Helm, Terraform) - for widely-used ecosystems
- Plugin: External
.solibrary - for custom/experimental/proprietary integrations
Plugins allow custom integrations without forking uptool.
Implement the engine.Integration interface:
type Integration interface {
Name() string
Detect(ctx context.Context, repoRoot string) ([]*Manifest, error)
Plan(ctx context.Context, manifest *Manifest, planCtx *PlanContext) (*UpdatePlan, error)
Apply(ctx context.Context, plan *UpdatePlan) (*ApplyResult, error)
Validate(ctx context.Context, manifest *Manifest) error
}Export a RegisterWith function:
func RegisterWith(register func(name string, constructor func() engine.Integration)) {
register("yourintegration", New)
}my-plugin/
├── go.mod
├── plugin.go # Integration implementation
└── main.go # Plugin entry point
// plugin.go
package main
import (
"context"
"github.com/santosr2/uptool/internal/engine"
)
type MyIntegration struct{}
func New() engine.Integration {
return &MyIntegration{}
}
func (i *MyIntegration) Name() string {
return "myintegration"
}
func (i *MyIntegration) Detect(ctx context.Context, repoRoot string) ([]*engine.Manifest, error) {
// Find manifest files
return manifests, nil
}
func (i *MyIntegration) Plan(ctx context.Context, manifest *engine.Manifest, planCtx *engine.PlanContext) (*engine.UpdatePlan, error) {
// Query registry for updates, use planCtx for policy settings
return plan, nil
}
func (i *MyIntegration) Apply(ctx context.Context, plan *engine.UpdatePlan) (*engine.ApplyResult, error) {
// Update manifest file
return result, nil
}
func (i *MyIntegration) Validate(ctx context.Context, manifest *engine.Manifest) error {
// Validate manifest syntax
return nil
}// main.go
package main
import "github.com/santosr2/uptool/internal/engine"
func RegisterWith(register func(name string, constructor func() engine.Integration)) {
register("myintegration", New)
}
func main() {}# Build as shared library
go build -buildmode=plugin -o myintegration.so .uptool searches for plugins in these locations (in order):
./plugins/- Current directory~/.config/uptool/plugins/- User config/etc/uptool/plugins/- System-wide$UPTOOL_PLUGIN_DIR- Custom location
Install:
mkdir -p ~/.config/uptool/plugins
cp myintegration.so ~/.config/uptool/plugins/Verify:
uptool list --experimental
# Should show "myintegration"// plugin_test.go
package main
import (
"context"
"testing"
)
func TestDetect(t *testing.T) {
integration := New()
manifests, err := integration.Detect(context.Background(), "./testdata")
if err != nil {
t.Fatal(err)
}
if len(manifests) != 1 {
t.Errorf("expected 1 manifest, got %d", len(manifests))
}
}# Build and test
go build -buildmode=plugin -o myintegration.so .
cp myintegration.so ~/.config/uptool/plugins/
uptool scan --only=myintegration- Version compatibility: Match uptool's Go version and dependencies
- Error handling: Return descriptive errors with context
- Logging: Use structured logging, avoid print statements
- Context: Respect context cancellation
- Resource cleanup: Close files, network connections
- Testing: >80% coverage target
- Documentation: Add README with usage examples
See [examples/plugins/python/](https://github.com/santosr2/uptool/blob/{{ extra.uptool_version }}/examples/plugins/) for a complete example:
- Detects
pyproject.toml,requirements.txt,Pipfile - Queries PyPI registry
- Updates dependency versions
# .goreleaser.yml
builds:
- id: plugin
main: .
flags:
- -buildmode=plugin
goos: [linux, darwin]
goarch: [amd64, arm64]#!/bin/bash
PLUGIN_DIR="${HOME}/.config/uptool/plugins"
mkdir -p "$PLUGIN_DIR"
curl -LO "https://github.com/you/plugin/releases/latest/download/plugin-$(uname -s)-$(uname -m).so"
mv plugin-*.so "$PLUGIN_DIR/myplugin.so"- Plugin must be compiled with same Go version as uptool
- Shared libraries are OS/arch specific
- Cannot modify core engine behavior
- Plugin crashes may crash uptool
- [Integration Examples](https://github.com/santosr2/uptool/blob/{{ extra.uptool_version }}/internal/integrations/) - Built-in integration code
- API Reference - Engine API documentation
- CONTRIBUTING.md - Development guidelines