Skip to content

Commit b59aadb

Browse files
committed
feat(codersdk/toolsdk): add template_version_id parameter to coder_create_workspace_build tool
1 parent 9e2af3e commit b59aadb

File tree

2 files changed

+69
-3
lines changed

2 files changed

+69
-3
lines changed

codersdk/toolsdk/toolsdk.go

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -340,6 +340,11 @@ is provisioned correctly and the agent can connect to the control plane.
340340
"transition": map[string]any{
341341
"type": "string",
342342
"description": "The transition to perform. Must be one of: start, stop, delete",
343+
"enum": []string{"start", "stop", "delete"},
344+
},
345+
"template_version_id": map[string]any{
346+
"type": "string",
347+
"description": "(Optional) The template version ID to use for the workspace build. If not provided, the previously built version will be used.",
343348
},
344349
},
345350
Required: []string{"workspace_id", "transition"},
@@ -358,9 +363,17 @@ is provisioned correctly and the agent can connect to the control plane.
358363
if !ok {
359364
return codersdk.WorkspaceBuild{}, xerrors.New("transition must be a string")
360365
}
361-
return client.CreateWorkspaceBuild(ctx, workspaceID, codersdk.CreateWorkspaceBuildRequest{
366+
templateVersionID, err := uuidFromArgs(args, "template_version_id")
367+
if err != nil {
368+
return codersdk.WorkspaceBuild{}, err
369+
}
370+
cbr := codersdk.CreateWorkspaceBuildRequest{
362371
Transition: codersdk.WorkspaceTransition(rawTransition),
363-
})
372+
}
373+
if templateVersionID != uuid.Nil {
374+
cbr.TemplateVersionID = templateVersionID
375+
}
376+
return client.CreateWorkspaceBuild(ctx, workspaceID, cbr)
364377
},
365378
}
366379

@@ -1232,7 +1245,11 @@ func workspaceAppStatusSlugFromContext(ctx context.Context) (string, bool) {
12321245
}
12331246

12341247
func uuidFromArgs(args map[string]any, key string) (uuid.UUID, error) {
1235-
raw, ok := args[key].(string)
1248+
argKey, ok := args[key]
1249+
if !ok {
1250+
return uuid.Nil, nil // No error if key is not present
1251+
}
1252+
raw, ok := argKey.(string)
12361253
if !ok {
12371254
return uuid.Nil, xerrors.Errorf("%s must be a string", key)
12381255
}

codersdk/toolsdk/toolsdk_test.go

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"testing"
99
"time"
1010

11+
"github.com/google/uuid"
1112
"github.com/stretchr/testify/require"
1213

1314
"github.com/coder/coder/v2/coderd/coderdtest"
@@ -154,6 +155,8 @@ func TestTools(t *testing.T) {
154155
require.NoError(t, err)
155156
require.Equal(t, codersdk.WorkspaceTransitionStop, result.Transition)
156157
require.Equal(t, r.Workspace.ID, result.WorkspaceID)
158+
require.Equal(t, r.TemplateVersion.ID, result.TemplateVersionID)
159+
require.Equal(t, codersdk.WorkspaceTransitionStop, result.Transition)
157160

158161
// Important: cancel the build. We don't run any provisioners, so this
159162
// will remain in the 'pending' state indefinitely.
@@ -172,11 +175,57 @@ func TestTools(t *testing.T) {
172175
require.NoError(t, err)
173176
require.Equal(t, codersdk.WorkspaceTransitionStart, result.Transition)
174177
require.Equal(t, r.Workspace.ID, result.WorkspaceID)
178+
require.Equal(t, r.TemplateVersion.ID, result.TemplateVersionID)
179+
require.Equal(t, codersdk.WorkspaceTransitionStart, result.Transition)
175180

176181
// Important: cancel the build. We don't run any provisioners, so this
177182
// will remain in the 'pending' state indefinitely.
178183
require.NoError(t, client.CancelWorkspaceBuild(ctx, result.ID))
179184
})
185+
186+
t.Run("TemplateVersionChange", func(t *testing.T) {
187+
ctx := testutil.Context(t, testutil.WaitShort)
188+
ctx = toolsdk.WithClient(ctx, memberClient)
189+
190+
// Get the current template version ID before updating
191+
workspace, err := memberClient.Workspace(ctx, r.Workspace.ID)
192+
require.NoError(t, err)
193+
originalVersionID := workspace.LatestBuild.TemplateVersionID
194+
195+
// Create a new template version to update to
196+
newVersion := dbfake.TemplateVersion(t, store).
197+
Seed(database.TemplateVersion{
198+
OrganizationID: owner.OrganizationID,
199+
CreatedBy: owner.UserID,
200+
TemplateID: uuid.NullUUID{UUID: r.Template.ID, Valid: true},
201+
}).Do()
202+
203+
// Update to new version
204+
updateBuild, err := testTool(ctx, t, toolsdk.CreateWorkspaceBuild, map[string]any{
205+
"workspace_id": r.Workspace.ID.String(),
206+
"transition": "start",
207+
"template_version_id": newVersion.TemplateVersion.ID.String(),
208+
})
209+
require.NoError(t, err)
210+
require.Equal(t, codersdk.WorkspaceTransitionStart, updateBuild.Transition)
211+
require.Equal(t, r.Workspace.ID.String(), updateBuild.WorkspaceID.String())
212+
require.Equal(t, newVersion.TemplateVersion.ID.String(), updateBuild.TemplateVersionID.String())
213+
// Cancel the build so it doesn't remain in the 'pending' state indefinitely.
214+
require.NoError(t, client.CancelWorkspaceBuild(ctx, updateBuild.ID))
215+
216+
// Roll back to the original version
217+
rollbackBuild, err := testTool(ctx, t, toolsdk.CreateWorkspaceBuild, map[string]any{
218+
"workspace_id": r.Workspace.ID.String(),
219+
"transition": "start",
220+
"template_version_id": originalVersionID.String(),
221+
})
222+
require.NoError(t, err)
223+
require.Equal(t, codersdk.WorkspaceTransitionStart, rollbackBuild.Transition)
224+
require.Equal(t, r.Workspace.ID.String(), rollbackBuild.WorkspaceID.String())
225+
require.Equal(t, originalVersionID.String(), rollbackBuild.TemplateVersionID.String())
226+
// Cancel the build so it doesn't remain in the 'pending' state indefinitely.
227+
require.NoError(t, client.CancelWorkspaceBuild(ctx, rollbackBuild.ID))
228+
})
180229
})
181230

182231
t.Run("ListTemplateVersionParameters", func(t *testing.T) {

0 commit comments

Comments
 (0)