Skip to content

Commit 9f974c8

Browse files
Kira-Pilotmafredrijohnstcn
authored andcommitted
feat: added include_deleted to getWorkspaceByOwnerAndName (#2164)
* feat: added include_deleted relates to #1955 * Update coderd/workspaces.go defining vars in the scope of conditional Co-authored-by: Mathias Fredriksson <mafredri@gmail.com> * Update coderd/workspaces.go avoid newline Co-authored-by: Mathias Fredriksson <mafredri@gmail.com> * Update coderd/workspaces.go Co-authored-by: Mathias Fredriksson <mafredri@gmail.com> * PR feedback * wrote test, added type * Update coderd/workspaces_test.go shortening test name Co-authored-by: Cian Johnston <cian@coder.com> * taking out api.ts change for now * casing Co-authored-by: Mathias Fredriksson <mafredri@gmail.com> Co-authored-by: Cian Johnston <cian@coder.com>
1 parent 6caffb1 commit 9f974c8

File tree

7 files changed

+72
-7
lines changed

7 files changed

+72
-7
lines changed

.vscode/settings.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@
8383
"workspaceapp",
8484
"workspaceapps",
8585
"workspacebuilds",
86+
"workspacename",
8687
"wsconncache",
8788
"xerrors",
8889
"xstate",

cli/create.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ func create() *cobra.Command {
4949
workspaceName, err = cliui.Prompt(cmd, cliui.PromptOptions{
5050
Text: "Specify a name for your workspace:",
5151
Validate: func(workspaceName string) error {
52-
_, err = client.WorkspaceByOwnerAndName(cmd.Context(), codersdk.Me, workspaceName)
52+
_, err = client.WorkspaceByOwnerAndName(cmd.Context(), codersdk.Me, workspaceName, codersdk.WorkspaceByOwnerAndNameParams{})
5353
if err == nil {
5454
return xerrors.Errorf("A workspace already exists named %q!", workspaceName)
5555
}
@@ -61,7 +61,7 @@ func create() *cobra.Command {
6161
}
6262
}
6363

64-
_, err = client.WorkspaceByOwnerAndName(cmd.Context(), codersdk.Me, workspaceName)
64+
_, err = client.WorkspaceByOwnerAndName(cmd.Context(), codersdk.Me, workspaceName, codersdk.WorkspaceByOwnerAndNameParams{})
6565
if err == nil {
6666
return xerrors.Errorf("A workspace already exists named %q!", workspaceName)
6767
}

cli/root.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -214,7 +214,7 @@ func namedWorkspace(cmd *cobra.Command, client *codersdk.Client, identifier stri
214214
return codersdk.Workspace{}, xerrors.Errorf("invalid workspace name: %q", identifier)
215215
}
216216

217-
return client.WorkspaceByOwnerAndName(cmd.Context(), owner, name)
217+
return client.WorkspaceByOwnerAndName(cmd.Context(), owner, name, codersdk.WorkspaceByOwnerAndNameParams{})
218218
}
219219

220220
// createConfig consumes the global configuration flag to produce a config root.

coderd/workspaces.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,10 +165,32 @@ func (api *API) workspaceByOwnerAndName(rw http.ResponseWriter, r *http.Request)
165165
owner := httpmw.UserParam(r)
166166
workspaceName := chi.URLParam(r, "workspacename")
167167

168+
includeDeleted := false
169+
if s := r.URL.Query().Get("include_deleted"); s != "" {
170+
var err error
171+
includeDeleted, err = strconv.ParseBool(s)
172+
if err != nil {
173+
httpapi.Write(rw, http.StatusBadRequest, httpapi.Response{
174+
Message: fmt.Sprintf("Invalid boolean value %q for \"include_deleted\" query param.", s),
175+
Validations: []httpapi.Error{
176+
{Field: "include_deleted", Detail: "Must be a valid boolean"},
177+
},
178+
})
179+
return
180+
}
181+
}
182+
168183
workspace, err := api.Database.GetWorkspaceByOwnerIDAndName(r.Context(), database.GetWorkspaceByOwnerIDAndNameParams{
169184
OwnerID: owner.ID,
170185
Name: workspaceName,
171186
})
187+
if includeDeleted && errors.Is(err, sql.ErrNoRows) {
188+
workspace, err = api.Database.GetWorkspaceByOwnerIDAndName(r.Context(), database.GetWorkspaceByOwnerIDAndNameParams{
189+
OwnerID: owner.ID,
190+
Name: workspaceName,
191+
Deleted: includeDeleted,
192+
})
193+
}
172194
if errors.Is(err, sql.ErrNoRows) {
173195
// Do not leak information if the workspace exists or not
174196
httpapi.Forbidden(rw)

coderd/workspaces_test.go

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -258,7 +258,7 @@ func TestWorkspaceByOwnerAndName(t *testing.T) {
258258
t.Run("NotFound", func(t *testing.T) {
259259
t.Parallel()
260260
client := coderdtest.New(t, nil)
261-
_, err := client.WorkspaceByOwnerAndName(context.Background(), codersdk.Me, "something")
261+
_, err := client.WorkspaceByOwnerAndName(context.Background(), codersdk.Me, "something", codersdk.WorkspaceByOwnerAndNameParams{})
262262
var apiErr *codersdk.Error
263263
require.ErrorAs(t, err, &apiErr)
264264
require.Equal(t, http.StatusUnauthorized, apiErr.StatusCode())
@@ -271,9 +271,38 @@ func TestWorkspaceByOwnerAndName(t *testing.T) {
271271
coderdtest.AwaitTemplateVersionJob(t, client, version.ID)
272272
template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID)
273273
workspace := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID)
274-
_, err := client.WorkspaceByOwnerAndName(context.Background(), codersdk.Me, workspace.Name)
274+
_, err := client.WorkspaceByOwnerAndName(context.Background(), codersdk.Me, workspace.Name, codersdk.WorkspaceByOwnerAndNameParams{})
275275
require.NoError(t, err)
276276
})
277+
t.Run("Deleted", func(t *testing.T) {
278+
t.Parallel()
279+
client := coderdtest.New(t, &coderdtest.Options{IncludeProvisionerD: true})
280+
user := coderdtest.CreateFirstUser(t, client)
281+
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil)
282+
coderdtest.AwaitTemplateVersionJob(t, client, version.ID)
283+
template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID)
284+
workspace := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID)
285+
coderdtest.AwaitWorkspaceBuildJob(t, client, workspace.LatestBuild.ID)
286+
287+
// Given:
288+
// We delete the workspace
289+
build, err := client.CreateWorkspaceBuild(context.Background(), workspace.ID, codersdk.CreateWorkspaceBuildRequest{
290+
Transition: codersdk.WorkspaceTransitionDelete,
291+
})
292+
require.NoError(t, err, "delete the workspace")
293+
coderdtest.AwaitWorkspaceBuildJob(t, client, build.ID)
294+
295+
// Then:
296+
// When we call without includes_deleted, we don't expect to get the workspace back
297+
_, err = client.WorkspaceByOwnerAndName(context.Background(), workspace.OwnerName, workspace.Name, codersdk.WorkspaceByOwnerAndNameParams{})
298+
require.ErrorContains(t, err, "403")
299+
300+
// Then:
301+
// When we call with includes_deleted, we should get the workspace back
302+
workspaceNew, err := client.WorkspaceByOwnerAndName(context.Background(), workspace.OwnerName, workspace.Name, codersdk.WorkspaceByOwnerAndNameParams{IncludeDeleted: true})
303+
require.NoError(t, err)
304+
require.Equal(t, workspace.ID, workspaceNew.ID)
305+
})
277306
}
278307

279308
func TestWorkspaceFilter(t *testing.T) {

codersdk/workspaces.go

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -258,9 +258,17 @@ func (c *Client) Workspaces(ctx context.Context, filter WorkspaceFilter) ([]Work
258258
return workspaces, json.NewDecoder(res.Body).Decode(&workspaces)
259259
}
260260

261+
type WorkspaceByOwnerAndNameParams struct {
262+
IncludeDeleted bool `json:"include_deleted,omitempty"`
263+
}
264+
261265
// WorkspaceByOwnerAndName returns a workspace by the owner's UUID and the workspace's name.
262-
func (c *Client) WorkspaceByOwnerAndName(ctx context.Context, owner string, name string) (Workspace, error) {
263-
res, err := c.Request(ctx, http.MethodGet, fmt.Sprintf("/api/v2/users/%s/workspace/%s", owner, name), nil)
266+
func (c *Client) WorkspaceByOwnerAndName(ctx context.Context, owner string, name string, params WorkspaceByOwnerAndNameParams) (Workspace, error) {
267+
res, err := c.Request(ctx, http.MethodGet, fmt.Sprintf("/api/v2/users/%s/workspace/%s", owner, name), nil, func(r *http.Request) {
268+
q := r.URL.Query()
269+
q.Set("include_deleted", fmt.Sprintf("%t", params.IncludeDeleted))
270+
r.URL.RawQuery = q.Encode()
271+
})
264272
if err != nil {
265273
return Workspace{}, err
266274
}

site/src/api/typesGenerated.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -463,6 +463,11 @@ export interface WorkspaceBuildsRequest extends Pagination {
463463
readonly WorkspaceID: string
464464
}
465465

466+
// From codersdk/workspaces.go:261:6
467+
export interface WorkspaceByOwnerAndNameParams {
468+
readonly include_deleted?: boolean
469+
}
470+
466471
// From codersdk/workspaces.go:219:6
467472
export interface WorkspaceFilter {
468473
readonly organization_id?: string

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy