Skip to content

Commit 482463c

Browse files
authored
feat: extend workspace build reasons to track connection types (#18827)
This PR introduces new build reason values to identify what type of connection triggered a workspace build, helping to troubleshoot workspace-related issues. ## Database Migration Added migration 000349_extend_workspace_build_reason.up.sql that extends the build_reason enum with new values: ``` dashboard, cli, ssh_connection, vscode_connection, jetbrains_connection ``` ## Implementation The build reason is specified through the API when creating new workspace builds: - Dashboard: Automatically sets reason to `dashboard` when users start workspaces via the web interface - CLI `start` command: Sets reason to `cli` when workspaces are started via the command line - CLI `ssh` command: Sets reason to ssh_connection when workspaces are started due to SSH connections - VS Code connections: Will be set to `vscode_connection` by the VS Code extension through CLI hidden flag (coder/vscode-coder#550) - JetBrains connections: Will be set to `jetbrains_connection` by the Jetbrains Toolbox (coder/coder-jetbrains-toolbox#150) and Jetbrains Gateway extension (coder/jetbrains-coder#561) ## UI Changes: * Tooltip with reason in Build history <img width="309" height="457" alt="image" src="https://github.com/user-attachments/assets/bde8440b-bf3b-49a1-a244-ed7e8eb9763c" /> * Reason in Audit Logs Row tooltip <img width="906" height="237" alt="image" src="https://github.com/user-attachments/assets/ebbb62c7-cf07-4398-afbf-323c83fb6426" /> <img width="909" height="188" alt="image" src="https://github.com/user-attachments/assets/1ddbab07-44bf-4dee-8867-b4e2cd56ae96" />
1 parent 0ebd435 commit 482463c

25 files changed

+388
-36
lines changed

cli/parameter.go

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,9 +145,11 @@ func parseParameterMapFile(parameterFile string) (map[string]string, error) {
145145
return parameterMap, nil
146146
}
147147

148-
// buildFlags contains options relating to troubleshooting provisioner jobs.
148+
// buildFlags contains options relating to troubleshooting provisioner jobs
149+
// and setting the reason for the workspace build.
149150
type buildFlags struct {
150151
provisionerLogDebug bool
152+
reason string
151153
}
152154

153155
func (bf *buildFlags) cliOptions() []serpent.Option {
@@ -160,5 +162,17 @@ This is useful for troubleshooting build issues.`,
160162
Value: serpent.BoolOf(&bf.provisionerLogDebug),
161163
Hidden: true,
162164
},
165+
{
166+
Flag: "reason",
167+
Description: `Sets the reason for the workspace build (cli, vscode_connection, jetbrains_connection).`,
168+
Value: serpent.EnumOf(
169+
&bf.reason,
170+
string(codersdk.BuildReasonCLI),
171+
string(codersdk.BuildReasonVSCodeConnection),
172+
string(codersdk.BuildReasonJetbrainsConnection),
173+
),
174+
Default: string(codersdk.BuildReasonCLI),
175+
Hidden: true,
176+
},
163177
}
164178
}

cli/ssh.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -873,7 +873,9 @@ func getWorkspaceAndAgent(ctx context.Context, inv *serpent.Invocation, client *
873873
// It's possible for a workspace build to fail due to the template requiring starting
874874
// workspaces with the active version.
875875
_, _ = fmt.Fprintf(inv.Stderr, "Workspace was stopped, starting workspace to allow connecting to %q...\n", workspace.Name)
876-
_, err = startWorkspace(inv, client, workspace, workspaceParameterFlags{}, buildFlags{}, WorkspaceStart)
876+
_, err = startWorkspace(inv, client, workspace, workspaceParameterFlags{}, buildFlags{
877+
reason: string(codersdk.BuildReasonSSHConnection),
878+
}, WorkspaceStart)
877879
if cerr, ok := codersdk.AsError(err); ok {
878880
switch cerr.StatusCode() {
879881
case http.StatusConflict:

cli/start.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,9 @@ func buildWorkspaceStartRequest(inv *serpent.Invocation, client *codersdk.Client
169169
if buildFlags.provisionerLogDebug {
170170
wbr.LogLevel = codersdk.ProvisionerLogLevelDebug
171171
}
172+
if buildFlags.reason != "" {
173+
wbr.Reason = codersdk.CreateWorkspaceBuildReason(buildFlags.reason)
174+
}
172175

173176
return wbr, nil
174177
}

cli/start_test.go

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -477,3 +477,39 @@ func TestStart_NoWait(t *testing.T) {
477477
pty.ExpectMatch("workspace has been started in no-wait mode")
478478
_ = testutil.TryReceive(ctx, t, doneChan)
479479
}
480+
481+
func TestStart_WithReason(t *testing.T) {
482+
t.Parallel()
483+
ctx := testutil.Context(t, testutil.WaitShort)
484+
485+
// Prepare user, template, workspace
486+
client := coderdtest.New(t, &coderdtest.Options{IncludeProvisionerDaemon: true})
487+
owner := coderdtest.CreateFirstUser(t, client)
488+
member, _ := coderdtest.CreateAnotherUser(t, client, owner.OrganizationID)
489+
version1 := coderdtest.CreateTemplateVersion(t, client, owner.OrganizationID, nil)
490+
coderdtest.AwaitTemplateVersionJobCompleted(t, client, version1.ID)
491+
template := coderdtest.CreateTemplate(t, client, owner.OrganizationID, version1.ID)
492+
workspace := coderdtest.CreateWorkspace(t, member, template.ID)
493+
coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, workspace.LatestBuild.ID)
494+
495+
// Stop the workspace
496+
build := coderdtest.CreateWorkspaceBuild(t, member, workspace, database.WorkspaceTransitionStop)
497+
coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, build.ID)
498+
499+
// Start the workspace with reason
500+
inv, root := clitest.New(t, "start", workspace.Name, "--reason", "cli")
501+
clitest.SetupConfig(t, member, root)
502+
doneChan := make(chan struct{})
503+
pty := ptytest.New(t).Attach(inv)
504+
go func() {
505+
defer close(doneChan)
506+
err := inv.Run()
507+
assert.NoError(t, err)
508+
}()
509+
510+
pty.ExpectMatch("workspace has been started")
511+
_ = testutil.TryReceive(ctx, t, doneChan)
512+
513+
workspace = coderdtest.MustWorkspace(t, member, workspace.ID)
514+
require.Equal(t, codersdk.BuildReasonCLI, workspace.LatestBuild.Reason)
515+
}

coderd/apidoc/docs.go

Lines changed: 44 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

coderd/apidoc/swagger.json

Lines changed: 49 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

coderd/database/dump.sql

Lines changed: 6 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
-- It's not possible to delete enum values.
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
ALTER TYPE build_reason ADD VALUE IF NOT EXISTS 'dashboard';
2+
ALTER TYPE build_reason ADD VALUE IF NOT EXISTS 'cli';
3+
ALTER TYPE build_reason ADD VALUE IF NOT EXISTS 'ssh_connection';
4+
ALTER TYPE build_reason ADD VALUE IF NOT EXISTS 'vscode_connection';
5+
ALTER TYPE build_reason ADD VALUE IF NOT EXISTS 'jetbrains_connection';

coderd/database/models.go

Lines changed: 22 additions & 7 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)