Skip to content

Commit d351821

Browse files
authored
fix(cli/cliui): skip startup script logs when Wait=false (#21105)
When users pass --wait=no or set CODER_SSH_WAIT=no, startup logs are no longer dumped to stderr. The stage indicator is still shown, just not the log content. Fixes #13580
1 parent 0c453d7 commit d351821

File tree

2 files changed

+97
-10
lines changed

2 files changed

+97
-10
lines changed

cli/cliui/agent.go

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -208,19 +208,25 @@ func (aw *agentWaiter) handleConnected(ctx context.Context, agent codersdk.Works
208208
aw.sw.Log(time.Time{}, codersdk.LogLevelInfo, "==> ℹ︎ To connect immediately, reconnect with --wait=no or CODER_SSH_WAIT=no, see --help for more information.")
209209
}
210210

211-
agent, err := aw.streamLogs(ctx, agent, follow, fetchedAgent)
212-
if err != nil {
213-
return err
214-
}
215-
216-
// If we were following, wait until startup completes.
217-
if follow {
218-
agent, err = aw.pollWhile(ctx, agent, func(agent codersdk.WorkspaceAgent) bool {
219-
return agent.LifecycleState.Starting()
220-
})
211+
// In non-blocking mode (Wait=false), we don't stream logs. This prevents
212+
// dumping a wall of logs on users who explicitly pass --wait=no. The stage
213+
// indicator is still shown, just not the log content. See issue #13580.
214+
if aw.opts.Wait {
215+
var err error
216+
agent, err = aw.streamLogs(ctx, agent, follow, fetchedAgent)
221217
if err != nil {
222218
return err
223219
}
220+
221+
// If we were following, wait until startup completes.
222+
if follow {
223+
agent, err = aw.pollWhile(ctx, agent, func(agent codersdk.WorkspaceAgent) bool {
224+
return agent.LifecycleState.Starting()
225+
})
226+
if err != nil {
227+
return err
228+
}
229+
}
224230
}
225231

226232
// Handle final lifecycle state.

cli/cliui/agent_test.go

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,87 @@ func TestAgent(t *testing.T) {
268268
"For more information and troubleshooting, see",
269269
},
270270
},
271+
{
272+
// Verify that in non-blocking mode (Wait=false), startup script
273+
// logs are suppressed. This prevents dumping a wall of logs on
274+
// users who explicitly pass --wait=no. See issue #13580.
275+
name: "No logs in non-blocking mode",
276+
opts: cliui.AgentOptions{
277+
FetchInterval: time.Millisecond,
278+
Wait: false,
279+
},
280+
iter: []func(context.Context, *testing.T, *codersdk.WorkspaceAgent, <-chan string, chan []codersdk.WorkspaceAgentLog) error{
281+
func(_ context.Context, _ *testing.T, agent *codersdk.WorkspaceAgent, _ <-chan string, logs chan []codersdk.WorkspaceAgentLog) error {
282+
agent.Status = codersdk.WorkspaceAgentConnected
283+
agent.FirstConnectedAt = ptr.Ref(time.Now())
284+
agent.StartedAt = ptr.Ref(time.Now())
285+
agent.LifecycleState = codersdk.WorkspaceAgentLifecycleStartError
286+
agent.ReadyAt = ptr.Ref(time.Now())
287+
// These logs should NOT be shown in non-blocking mode.
288+
logs <- []codersdk.WorkspaceAgentLog{
289+
{
290+
CreatedAt: time.Now(),
291+
Output: "Startup script log 1",
292+
},
293+
{
294+
CreatedAt: time.Now(),
295+
Output: "Startup script log 2",
296+
},
297+
}
298+
return nil
299+
},
300+
},
301+
// Note: Log content like "Startup script log 1" should NOT appear here.
302+
want: []string{
303+
"⧗ Running workspace agent startup scripts (non-blocking)",
304+
"✘ Running workspace agent startup scripts (non-blocking)",
305+
"Warning: A startup script exited with an error and your workspace may be incomplete.",
306+
"For more information and troubleshooting, see",
307+
},
308+
},
309+
{
310+
// Verify that even after waiting for the agent to connect, logs
311+
// are still suppressed in non-blocking mode. See issue #13580.
312+
name: "No logs after connection wait in non-blocking mode",
313+
opts: cliui.AgentOptions{
314+
FetchInterval: time.Millisecond,
315+
Wait: false,
316+
},
317+
iter: []func(context.Context, *testing.T, *codersdk.WorkspaceAgent, <-chan string, chan []codersdk.WorkspaceAgentLog) error{
318+
func(_ context.Context, _ *testing.T, agent *codersdk.WorkspaceAgent, _ <-chan string, _ chan []codersdk.WorkspaceAgentLog) error {
319+
agent.Status = codersdk.WorkspaceAgentConnecting
320+
return nil
321+
},
322+
func(_ context.Context, t *testing.T, agent *codersdk.WorkspaceAgent, output <-chan string, _ chan []codersdk.WorkspaceAgentLog) error {
323+
return waitLines(t, output, "⧗ Waiting for the workspace agent to connect")
324+
},
325+
func(_ context.Context, _ *testing.T, agent *codersdk.WorkspaceAgent, _ <-chan string, logs chan []codersdk.WorkspaceAgentLog) error {
326+
agent.Status = codersdk.WorkspaceAgentConnected
327+
agent.FirstConnectedAt = ptr.Ref(time.Now())
328+
agent.StartedAt = ptr.Ref(time.Now())
329+
agent.LifecycleState = codersdk.WorkspaceAgentLifecycleStartError
330+
agent.ReadyAt = ptr.Ref(time.Now())
331+
// These logs should NOT be shown in non-blocking mode,
332+
// even though we waited for connection.
333+
logs <- []codersdk.WorkspaceAgentLog{
334+
{
335+
CreatedAt: time.Now(),
336+
Output: "Startup script log 1",
337+
},
338+
}
339+
return nil
340+
},
341+
},
342+
// Note: Log content should NOT appear here despite waiting for connection.
343+
want: []string{
344+
"⧗ Waiting for the workspace agent to connect",
345+
"✔ Waiting for the workspace agent to connect",
346+
"⧗ Running workspace agent startup scripts (non-blocking)",
347+
"✘ Running workspace agent startup scripts (non-blocking)",
348+
"Warning: A startup script exited with an error and your workspace may be incomplete.",
349+
"For more information and troubleshooting, see",
350+
},
351+
},
271352
{
272353
name: "Error when shutting down",
273354
opts: cliui.AgentOptions{

0 commit comments

Comments
 (0)