Skip to content

status (TTY): final Targets redraw on Close overwrites the last line of the deployment status table #145

Description

@koh-sh

Summary

Running apcdeploy status interactively (stderr is a TTY) always corrupts its own output: the last line of the deployment status table is erased and replaced by a duplicate of the Targets summary row.

Details

internal/status/executor.go finalises the Targets row and then renders the status table, while tg.Close() is deferred:

tg.Done(id, summarizeDeployment(deploymentInfo))   // executor.go:98
display.DeploymentStatus(e.reporter, ...)          // executor.go:106 — Header + Table on stderr
return nil                                         // deferred tg.Close() fires here (executor.go:61)

ttyTargets.Close() (internal/cli/targets_tty.go:205-228) unconditionally performs one final redraw(). redraw() (targets_tty.go:91-97) emits \033[<N>A\r\033[J — cursor up N rows (N = number of Targets rows), then clear to end of screen — assuming the cursor still sits directly below the Targets block. After display.DeploymentStatus has printed the Header and Table, the cursor is below the table instead, so the final redraw moves up into the table, deletes its last line (e.g. the Duration row), and prints the row summary there a second time.

The animation goroutine (targets_tty.go:122-141) also keeps redrawing every ~120 ms until Close, so any tick that fires between Done and Close corrupts the table the same way.

The comment at executor.go:99-105 ("In TTY mode the Targets renderer has already finalised by the time the table prints, so the two views stack cleanly") does not hold — Done() finalises the row state, but the renderer stays active until Close().

rollback already avoids this exact hazard by rendering display.DeploymentStatus before opening the Targets block (internal/rollback/executor.go:99-102).

Reproduction

Run apcdeploy status -c apcdeploy.yml in a terminal against any profile with a completed deployment. The table's last line is replaced by a duplicated ✓ COMPLETE — v<N> ... row. Reproduces every time.

Fix direction

Close the Targets block before rendering the table: either call display.DeploymentStatus after tg.Close() (drop the defer and close explicitly), or render the table before opening Targets like rollback does.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions