diff --git a/internal/docker/client.go b/internal/docker/client.go index 10af151..38cc198 100644 --- a/internal/docker/client.go +++ b/internal/docker/client.go @@ -480,6 +480,20 @@ func (c *Client) CloneRepo( return c.performClone(ctx, cfg) } +// RemoveImage removes a Docker image by ID or tag. +// It returns nil if the image was successfully removed or does not exist. +func (c *Client) RemoveImage(ctx context.Context, imageID string) error { + _, err := c.docker.ImageRemove(ctx, imageID, image.RemoveOptions{ + Force: true, + PruneChildren: true, + }) + if err != nil && !client.IsErrNotFound(err) { + return fmt.Errorf("failed to remove image %s: %w", imageID, err) + } + + return nil +} + func (c *Client) performBuild( ctx context.Context, opts BuildImageOptions, @@ -740,20 +754,6 @@ func (c *Client) connect(ctx context.Context) error { return nil } -// RemoveImage removes a Docker image by ID or tag. -// It returns nil if the image was successfully removed or does not exist. -func (c *Client) RemoveImage(ctx context.Context, imageID string) error { - _, err := c.docker.ImageRemove(ctx, imageID, image.RemoveOptions{ - Force: true, - PruneChildren: true, - }) - if err != nil && !client.IsErrNotFound(err) { - return fmt.Errorf("failed to remove image %s: %w", imageID, err) - } - - return nil -} - func (c *Client) close() error { if c.docker != nil { err := c.docker.Close() diff --git a/internal/handlers/app.go b/internal/handlers/app.go index 0685a72..e4ee8bb 100644 --- a/internal/handlers/app.go +++ b/internal/handlers/app.go @@ -499,7 +499,7 @@ func (h *Handlers) HandleAppLogs() http.HandlerFunc { return } - _, _ = writer.Write([]byte(logs)) //nolint:gosec // logs are from trusted container output, not user input + _, _ = writer.Write([]byte(logs)) //nolint:gosec // response Content-Type is text/plain, not rendered as HTML } } diff --git a/internal/service/deploy/deploy.go b/internal/service/deploy/deploy.go index 19a65a4..0959729 100644 --- a/internal/service/deploy/deploy.go +++ b/internal/service/deploy/deploy.go @@ -726,6 +726,7 @@ func (svc *Service) cleanupCancelledDeploy( } else { svc.log.Info("cleaned up build dir from cancelled deploy", "app", app.Name, "path", dirPath) + _ = deployment.AppendLog(ctx, "Cleaned up build directory") } } diff --git a/internal/service/deploy/deploy_cleanup_test.go b/internal/service/deploy/deploy_cleanup_test.go index 1474342..5a49ee5 100644 --- a/internal/service/deploy/deploy_cleanup_test.go +++ b/internal/service/deploy/deploy_cleanup_test.go @@ -32,7 +32,7 @@ func TestCleanupCancelledDeploy_RemovesBuildDir(t *testing.T) { require.NoError(t, os.MkdirAll(deployDir, 0o750)) // Create a file inside to verify full removal - require.NoError(t, os.WriteFile(filepath.Join(deployDir, "work"), []byte("test"), 0o640)) + require.NoError(t, os.WriteFile(filepath.Join(deployDir, "work"), []byte("test"), 0o600)) // Also create a dir for a different deployment (should NOT be removed) otherDir := filepath.Join(buildDir, "99-xyz789") diff --git a/internal/service/deploy/export_test.go b/internal/service/deploy/export_test.go index a5aa241..bd90daa 100644 --- a/internal/service/deploy/export_test.go +++ b/internal/service/deploy/export_test.go @@ -52,10 +52,10 @@ func NewTestServiceWithConfig(log *slog.Logger, cfg *config.Config, dockerClient // cleanupCancelledDeploy for testing. It removes build directories matching // the deployment ID prefix. func (svc *Service) CleanupCancelledDeploy( - ctx context.Context, + _ context.Context, appName string, deploymentID int64, - imageID string, + _ string, ) { // We can't create real models.App/Deployment in tests easily, // so we test the build dir cleanup portion directly. diff --git a/static/js/app.js b/static/js/app.js index 4829867..c5f1758 100644 --- a/static/js/app.js +++ b/static/js/app.js @@ -369,7 +369,7 @@ document.addEventListener("alpine:init", () => { init() { // Read initial logs from script tag (avoids escaping issues) const initialLogsEl = this.$el.querySelector(".initial-logs"); - this.logs = initialLogsEl?.textContent || "Loading..."; + this.logs = initialLogsEl?.dataset.logs || "Loading..."; // Set up scroll tracking this.$nextTick(() => { diff --git a/templates/deployments.html b/templates/deployments.html index 731e78c..1016fc8 100644 --- a/templates/deployments.html +++ b/templates/deployments.html @@ -98,7 +98,7 @@ title="Scroll to bottom" >↓ Follow - {{if .Logs.Valid}}{{end}} + {{if .Logs.Valid}}{{end}} {{end}}