feat: static sites feature with Gitea/GitHub/GitLab support and Deno backend
Deploy static content from Git repository folders with optional server-side
API endpoints. Supports Gitea/Forgejo/Gogs, GitHub, and GitLab with provider
autodetection.
- New Sites entity with CRUD, encrypted secrets, and manual/push/tag sync triggers
- Pluggable GitProvider interface with three implementations
- Deno container mode: auto-generates router from API_{method}_{name} exports
- Static container mode: nginx serving files with optional markdown rendering
- Wizard UI with provider selector, repo picker, branch/folder tree pickers
- Deploy pipeline builds fresh image, starts container, configures NPM proxy
- Stop/Start buttons, force redeploy on manual trigger
- Periodic health checker detects crashed containers
- Proxy route existence check during auto-sync
This commit is contained in:
@@ -16,6 +16,7 @@ import (
|
||||
"github.com/alexei/docker-watcher/internal/npm"
|
||||
"github.com/alexei/docker-watcher/internal/proxy"
|
||||
"github.com/alexei/docker-watcher/internal/stale"
|
||||
"github.com/alexei/docker-watcher/internal/staticsite"
|
||||
"github.com/alexei/docker-watcher/internal/store"
|
||||
"github.com/alexei/docker-watcher/internal/webhook"
|
||||
)
|
||||
@@ -42,6 +43,7 @@ type Server struct {
|
||||
dnsProvider dns.Provider
|
||||
onDNSProviderChanged DNSProviderChangedFunc
|
||||
|
||||
staticSiteManager *staticsite.Manager
|
||||
backupEngine *backup.Engine
|
||||
dbPath string
|
||||
shutdownFunc func() // called after restore to trigger graceful shutdown
|
||||
@@ -83,6 +85,11 @@ func NewServer(
|
||||
return s
|
||||
}
|
||||
|
||||
// SetStaticSiteManager sets the static site manager on the server.
|
||||
func (s *Server) SetStaticSiteManager(mgr *staticsite.Manager) {
|
||||
s.staticSiteManager = mgr
|
||||
}
|
||||
|
||||
// SetStaleScanner sets the stale scanner on the server.
|
||||
// Called after both the API server and scanner are initialized.
|
||||
func (s *Server) SetStaleScanner(scanner *stale.Scanner) {
|
||||
@@ -243,6 +250,26 @@ func (s *Server) Router() chi.Router {
|
||||
r.Post("/volumes/{volId}/upload", s.uploadToVolume)
|
||||
})
|
||||
})
|
||||
// Static sites.
|
||||
r.Get("/sites", s.listStaticSites)
|
||||
r.Route("/sites/{id}", func(r chi.Router) {
|
||||
r.Get("/", s.getStaticSite)
|
||||
r.Get("/secrets", s.listStaticSiteSecrets)
|
||||
|
||||
// Admin-only mutations.
|
||||
r.Group(func(r chi.Router) {
|
||||
r.Use(auth.AdminOnly)
|
||||
r.Put("/", s.updateStaticSite)
|
||||
r.Delete("/", s.deleteStaticSite)
|
||||
r.Post("/deploy", s.deployStaticSite)
|
||||
r.Post("/stop", s.stopStaticSite)
|
||||
r.Post("/start", s.startStaticSite)
|
||||
r.Post("/secrets", s.createStaticSiteSecret)
|
||||
r.Put("/secrets/{sid}", s.updateStaticSiteSecret)
|
||||
r.Delete("/secrets/{sid}", s.deleteStaticSiteSecret)
|
||||
})
|
||||
})
|
||||
|
||||
r.Get("/deploys", s.listDeploys)
|
||||
r.Get("/deploys/{id}/logs", s.streamDeployLogs)
|
||||
r.Get("/events", s.streamEvents)
|
||||
@@ -294,6 +321,14 @@ func (s *Server) Router() chi.Router {
|
||||
// Project creation.
|
||||
r.Post("/projects", s.createProject)
|
||||
|
||||
// Static site creation and tools.
|
||||
r.Post("/sites", s.createStaticSite)
|
||||
r.Post("/sites/test-connection", s.testStaticSiteConnection)
|
||||
r.Post("/sites/branches", s.listStaticSiteBranches)
|
||||
r.Post("/sites/tree", s.listStaticSiteTree)
|
||||
r.Post("/sites/detect-provider", s.detectStaticSiteProvider)
|
||||
r.Post("/sites/repos", s.listStaticSiteRepos)
|
||||
|
||||
// Quick deploy endpoints.
|
||||
r.Post("/deploy/inspect", s.inspectImage)
|
||||
r.Post("/deploy/quick", s.quickDeploy)
|
||||
|
||||
Reference in New Issue
Block a user