diff --git a/admin/admin.go b/admin/admin.go index 738e530..f5426a3 100644 --- a/admin/admin.go +++ b/admin/admin.go @@ -30,7 +30,7 @@ func AdminHandler(w http.ResponseWriter, r *http.Request) { API Log System Log Env Vars - Deploy + Server ` html := app.RenderHTMLForRequest("Admin", "Admin Dashboard", content, r) diff --git a/admin/deploy.go b/admin/deploy.go index f1497f8..b8a8122 100644 --- a/admin/deploy.go +++ b/admin/deploy.go @@ -39,8 +39,8 @@ func sourceDir() string { return filepath.Join(home, "src", "mu") } -// DeployHandler shows the deploy page and handles deploy requests -func DeployHandler(w http.ResponseWriter, r *http.Request) { +// UpdateHandler shows the update/restart page and handles requests +func UpdateHandler(w http.ResponseWriter, r *http.Request) { _, _, err := auth.RequireAdmin(r) if err != nil { app.Forbidden(w, r, "Admin access required") @@ -52,27 +52,32 @@ func DeployHandler(w http.ResponseWriter, r *http.Request) { return } - // GET — render deploy page + // GET — render server page content := `

← Admin

-

Deploy

-

Pull latest code, build, and restart the service.

+

Server

Source: ` + sourceDir() + `

- + +
` - html := app.RenderHTMLForRequest("Admin", "Deploy", content, r) + html := app.RenderHTMLForRequest("Admin", "Server", content, r) w.Write([]byte(html)) } @@ -111,7 +121,7 @@ func handleDeploy(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(map[string]interface{}{ "success": false, - "logs": []deployLogEntry{{Step: "lock", Output: "Deploy already in progress", Success: false}}, + "logs": []deployLogEntry{{Step: "lock", Output: "Already in progress", Success: false}}, }) return } @@ -124,22 +134,37 @@ func handleDeploy(w http.ResponseWriter, r *http.Request) { deployMu.Unlock() }() + var req struct { + Action string `json:"action"` + } + json.NewDecoder(r.Body).Decode(&req) + dir := sourceDir() var logs []deployLogEntry success := true - steps := []struct { + type step struct { name string cmd string args []string - }{ - {"git pull", "git", []string{"pull", "origin", "main"}}, - {"go install", "go", []string{"install"}}, - {"restart service", "sudo", []string{"-n", "systemctl", "restart", "mu"}}, } - for _, step := range steps { - entry := runStep(dir, step.name, step.cmd, step.args) + var steps []step + switch req.Action { + case "restart": + steps = []step{ + {"restart service", "sudo", []string{"-n", "systemctl", "restart", "mu"}}, + } + default: // "update" + steps = []step{ + {"git pull", "git", []string{"pull", "origin", "main"}}, + {"go install", "go", []string{"install"}}, + {"restart service", "sudo", []string{"-n", "systemctl", "restart", "mu"}}, + } + } + + for _, s := range steps { + entry := runStep(dir, s.name, s.cmd, s.args) logs = append(logs, entry) if !entry.Success { success = false @@ -163,8 +188,18 @@ func runStep(dir, name, cmdName string, args []string) deployLogEntry { cmd := exec.Command(cmdName, args...) cmd.Dir = dir - // Inherit env so go build picks up GOPATH etc - cmd.Env = append(os.Environ(), "HOME="+os.Getenv("HOME")) + // Inherit env and ensure Go/snap paths are available + home := os.Getenv("HOME") + path := os.Getenv("PATH") + goPath := filepath.Join(home, "go", "bin") + goRoot := "/usr/local/go/bin" + if !strings.Contains(path, goPath) { + path = goPath + ":" + path + } + if !strings.Contains(path, goRoot) { + path = goRoot + ":" + path + } + cmd.Env = append(os.Environ(), "HOME="+home, "PATH="+path) var stdout, stderr bytes.Buffer cmd.Stdout = &stdout diff --git a/main.go b/main.go index e4818d9..4e8f2d2 100644 --- a/main.go +++ b/main.go @@ -209,7 +209,7 @@ func main() { "/admin/api": true, "/admin/log": true, "/admin/env": true, - "/admin/deploy": true, + "/admin/server": true, "/plans": false, // Public - shows pricing options "/donate": false, "/wallet": false, // Public - shows wallet info; auth checked in handler @@ -281,8 +281,8 @@ func main() { // environment variables status http.HandleFunc("/admin/env", admin.EnvHandler) - // deploy - http.HandleFunc("/admin/deploy", admin.DeployHandler) + // server update and restart + http.HandleFunc("/admin/server", admin.UpdateHandler) // plans page (public - overview of options) http.HandleFunc("/plans", app.Plans)