From af8bbf536f4263a80855cf4fcd1da11374f1c01b Mon Sep 17 00:00:00 2001 From: pavel Date: Thu, 14 May 2026 22:00:04 +0200 Subject: [PATCH] fix deploy and logs --- internal/app/deploy_service.go | 24 +++++++++++++++++++++++- internal/app/project_service.go | 8 ++++++++ internal/app/routes_handlers.go | 10 +++++++--- internal/app/systemd_service.go | 2 +- web/app.js | 2 +- 5 files changed, 40 insertions(+), 6 deletions(-) diff --git a/internal/app/deploy_service.go b/internal/app/deploy_service.go index 16a5c2a..60672f4 100644 --- a/internal/app/deploy_service.go +++ b/internal/app/deploy_service.go @@ -78,6 +78,9 @@ func (a *App) deployProjectFromMain(_ context.Context, p Project) error { return err } repoDir := filepath.Join(projectDir, "repo") + if _, err := os.Stat(repoDir); err != nil { + return fmt.Errorf("repo checkout missing at %s (trigger deploy webhook/push first)", repoDir) + } binDir := filepath.Join(projectDir, "bin") if err := os.MkdirAll(binDir, 0o755); err != nil { return err @@ -97,6 +100,25 @@ func (a *App) deployProjectFromMain(_ context.Context, p Project) error { return err } } + if err := a.buildProjectBinary(p); err != nil { + return err + } + return runSystemctlUser(p.UnixUser, "restart", p.ServiceName) +} + +func (a *App) buildProjectBinary(p Project) error { + projectDir, err := a.projectDirFor(p) + if err != nil { + return err + } + repoDir := filepath.Join(projectDir, "repo") + binDir := filepath.Join(projectDir, "bin") + if err := os.MkdirAll(binDir, 0o755); err != nil { + return err + } + if err := ensureOwnedByUnixUser(binDir, p.UnixUser, 0o755); err != nil { + return err + } binaryPath := filepath.Join(binDir, "app") if err := runCmd("go", "-C", repoDir, "build", "-o", binaryPath, "."); err != nil { return fmt.Errorf("build failed: %w", err) @@ -104,5 +126,5 @@ func (a *App) deployProjectFromMain(_ context.Context, p Project) error { if err := ensureOwnedByUnixUser(binaryPath, p.UnixUser, 0o755); err != nil { return err } - return runSystemctlUser(p.UnixUser, "restart", p.ServiceName) + return nil } diff --git a/internal/app/project_service.go b/internal/app/project_service.go index 5373faf..2f2297a 100644 --- a/internal/app/project_service.go +++ b/internal/app/project_service.go @@ -103,6 +103,14 @@ func (a *App) provisionProject(ctx context.Context, p *Project) error { p.ProvisionError = err.Error() return err } + if p.RepoURL != "" { + if err := a.buildProjectBinary(*p); err != nil { + _ = a.updateProvisioningState(ctx, p.ID, "failed", err.Error()) + p.ProvisionState = "failed" + p.ProvisionError = err.Error() + return err + } + } if err := a.renderSystemdForProject(ctx, *p); err != nil { _ = a.updateProvisioningState(ctx, p.ID, "failed", err.Error()) diff --git a/internal/app/routes_handlers.go b/internal/app/routes_handlers.go index 27af924..93c9ed2 100644 --- a/internal/app/routes_handlers.go +++ b/internal/app/routes_handlers.go @@ -248,11 +248,12 @@ func (a *App) handleProjectLogs(w http.ResponseWriter, r *http.Request, user Use http.Error(w, err.Error(), http.StatusBadRequest) return } - lines := 200 + lines := 100 + const maxLogBytes = 64 * 1024 if raw := r.URL.Query().Get("lines"); raw != "" { n, err := strconv.Atoi(raw) - if err != nil || n < 1 || n > 1000 { - http.Error(w, "lines must be 1-1000", http.StatusBadRequest) + if err != nil || n < 1 || n > 300 { + http.Error(w, "lines must be 1-300", http.StatusBadRequest) return } lines = n @@ -262,5 +263,8 @@ func (a *App) handleProjectLogs(w http.ResponseWriter, r *http.Request, user Use http.Error(w, err.Error(), http.StatusBadGateway) return } + if len(logs) > maxLogBytes { + logs = logs[:maxLogBytes] + "\n... (truncated)" + } writeJSON(w, http.StatusOK, map[string]any{"lines": lines, "logs": logs}) } diff --git a/internal/app/systemd_service.go b/internal/app/systemd_service.go index e6d67e2..a009e88 100644 --- a/internal/app/systemd_service.go +++ b/internal/app/systemd_service.go @@ -246,5 +246,5 @@ func (a *App) getServiceStatus(p Project) (ServiceStatus, error) { } func (a *App) getServiceLogs(p Project, lines int) (string, error) { - return runJournalctlUser(p.UnixUser, "-u", p.ServiceName, "--no-pager", "-n", strconv.Itoa(lines), "-o", "short-iso") + return runJournalctlUser(p.UnixUser, "-u", p.ServiceName, "--no-pager", "-n", strconv.Itoa(lines), "-r", "-o", "short-iso") } diff --git a/web/app.js b/web/app.js index ba3d207..48ade3b 100644 --- a/web/app.js +++ b/web/app.js @@ -138,7 +138,7 @@ async function loadLogs(projectNode, projectID) { const out = projectNode.querySelector('[data-logs-out]'); out.textContent = 'loading logs...'; try { - const res = await api(`/api/projects/${projectID}/logs?lines=200`); + const res = await api(`/api/projects/${projectID}/logs?lines=100`); out.textContent = res.logs || '(no logs)'; } catch (err) { out.textContent = `logs error: ${err.message}`;