// Package static implements the "static" source: a git-folder-backed // deployable that can serve plain files or run a Deno backend. Builds // an image from the cloned folder and runs one container. // // The full deploy pipeline is implemented inline in this package // (deploy.go / teardown.go / reconcile.go). It operates directly on // plugin.Workload + the containers / workload_env tables — there is no // longer a synthetic static_sites row backing each workload. // // The legacy internal/staticsite package remains alive to serve the // /api/sites/* HTTP routes and the existing static_sites table; this // plugin does not depend on it for state, only for git-provider // helpers and Deno scaffolding generation. package static import ( "context" "encoding/json" "fmt" "strings" "github.com/alexei/tinyforge/internal/workload/plugin" ) // Config is the per-workload source config blob. Mirrors the fields // that used to live on the static_sites table, less anything moved to // Workload (notification config, webhook secrets, public_face). type Config struct { Provider string `json:"provider"` // "gitea" | "github" | "gitlab"; "" = autodetect BaseURL string `json:"base_url"` // e.g. https://git.example.com RepoOwner string `json:"repo_owner"` RepoName string `json:"repo_name"` Branch string `json:"branch"` FolderPath string `json:"folder_path"` // path within repo AccessToken string `json:"access_token"` // encrypted; optional for public repos Mode string `json:"mode"` // "static" | "deno" RenderMarkdown bool `json:"render_markdown"` StorageEnabled bool `json:"storage_enabled"` StorageLimitMB int `json:"storage_limit_mb"` // ReportCommitStatus, when true, pushes the deploy outcome back to the // git provider as a commit status (pending/success/failure) on the // deployed SHA. Best-effort — a reporting failure never fails a deploy. ReportCommitStatus bool `json:"report_commit_status"` } type source struct{} // Eager registration — the deploy pipeline lives entirely inside this // package now, so the kind is usable as soon as init() fires. No more // "backend not wired" failure mode at deploy time. func init() { plugin.RegisterSource(&source{}) } func (*source) Kind() string { return "static" } func (*source) SchemaSample() any { return Config{ Provider: "gitea", BaseURL: "https://git.example.com", RepoOwner: "owner", RepoName: "pages", Branch: "main", FolderPath: "", Mode: "static", } } func (*source) Validate(cfg json.RawMessage) error { var c Config if len(cfg) == 0 { return fmt.Errorf("static source: config is required") } if err := json.Unmarshal(cfg, &c); err != nil { return fmt.Errorf("static source: invalid json: %w", err) } if strings.TrimSpace(c.RepoOwner) == "" || strings.TrimSpace(c.RepoName) == "" { return fmt.Errorf("static source: repo_owner and repo_name are required") } if c.Mode != "" && c.Mode != "static" && c.Mode != "deno" { return fmt.Errorf("static source: mode must be \"static\" or \"deno\"") } return nil } func (*source) Deploy(ctx context.Context, deps plugin.Deps, w plugin.Workload, intent plugin.DeploymentIntent) error { return deploy(ctx, deps, w, intent) } func (*source) Teardown(ctx context.Context, deps plugin.Deps, w plugin.Workload) error { return teardown(ctx, deps, w) } func (*source) Reconcile(ctx context.Context, deps plugin.Deps, w plugin.Workload) error { return reconcile(ctx, deps, w) }