Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit7c07599

Browse files
Emyrkkylecarbs
authored andcommitted
fix: Sort workspace by name by created_at (#2214)
* fix: Sort workspace by name by created_atFix bug where deleting workspaces with the same name returns theoldest deleted workspace
1 parent0249532 commit7c07599

File tree

10 files changed

+60
-29
lines changed

10 files changed

+60
-29
lines changed

‎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(workspaceNamestring)error {
52-
_,err=client.WorkspaceByOwnerAndName(cmd.Context(),codersdk.Me,workspaceName, codersdk.WorkspaceByOwnerAndNameParams{})
52+
_,err=client.WorkspaceByOwnerAndName(cmd.Context(),codersdk.Me,workspaceName, codersdk.WorkspaceOptions{})
5353
iferr==nil {
5454
returnxerrors.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, codersdk.WorkspaceByOwnerAndNameParams{})
64+
_,err=client.WorkspaceByOwnerAndName(cmd.Context(),codersdk.Me,workspaceName, codersdk.WorkspaceOptions{})
6565
iferr==nil {
6666
returnxerrors.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-
returnclient.WorkspaceByOwnerAndName(cmd.Context(),owner,name, codersdk.WorkspaceByOwnerAndNameParams{})
217+
returnclient.WorkspaceByOwnerAndName(cmd.Context(),owner,name, codersdk.WorkspaceOptions{})
218218
}
219219

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

‎coderd/database/databasefake/databasefake.go

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -375,7 +375,9 @@ func (q *fakeQuerier) GetWorkspaceByOwnerIDAndName(_ context.Context, arg databa
375375
q.mutex.RLock()
376376
deferq.mutex.RUnlock()
377377

378+
varfound*database.Workspace
378379
for_,workspace:=rangeq.workspaces {
380+
workspace:=workspace
379381
ifworkspace.OwnerID!=arg.OwnerID {
380382
continue
381383
}
@@ -385,7 +387,14 @@ func (q *fakeQuerier) GetWorkspaceByOwnerIDAndName(_ context.Context, arg databa
385387
ifworkspace.Deleted!=arg.Deleted {
386388
continue
387389
}
388-
returnworkspace,nil
390+
391+
// Return the most recent workspace with the given name
392+
iffound==nil||workspace.CreatedAt.After(found.CreatedAt) {
393+
found=&workspace
394+
}
395+
}
396+
iffound!=nil {
397+
return*found,nil
389398
}
390399
return database.Workspace{},sql.ErrNoRows
391400
}

‎coderd/database/queries.sql.go

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more aboutcustomizing how changed files appear on GitHub.

‎coderd/database/queries/workspaces.sql

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,8 @@ FROM
7070
WHERE
7171
owner_id= @owner_id
7272
AND deleted= @deleted
73-
ANDLOWER("name")=LOWER(@name);
73+
ANDLOWER("name")=LOWER(@name)
74+
ORDER BY created_atDESC;
7475

7576
-- name: GetWorkspaceOwnerCountsByTemplateIDs :many
7677
SELECT

‎coderd/workspaces.go

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,18 +35,16 @@ func (api *API) workspace(rw http.ResponseWriter, r *http.Request) {
3535
return
3636
}
3737

38-
// The `deleted` query parameter (which defaults to `false`) MUST match the
39-
// `Deleted` field on the workspace otherwise you will get a 410 Gone.
4038
var (
41-
deletedStr=r.URL.Query().Get("deleted")
39+
deletedStr=r.URL.Query().Get("include_deleted")
4240
showDeleted=false
4341
)
4442
ifdeletedStr!="" {
4543
varerrerror
4644
showDeleted,err=strconv.ParseBool(deletedStr)
4745
iferr!=nil {
4846
httpapi.Write(rw,http.StatusBadRequest, httpapi.Response{
49-
Message:fmt.Sprintf("Invalid boolean value %q for\"deleted\" query param.",deletedStr),
47+
Message:fmt.Sprintf("Invalid boolean value %q for\"include_deleted\" query param.",deletedStr),
5048
Validations: []httpapi.Error{
5149
{Field:"deleted",Detail:"Must be a valid boolean"},
5250
},

‎coderd/workspaces_test.go

Lines changed: 35 additions & 4 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", codersdk.WorkspaceByOwnerAndNameParams{})
261+
_,err:=client.WorkspaceByOwnerAndName(context.Background(),codersdk.Me,"something", codersdk.WorkspaceOptions{})
262262
varapiErr*codersdk.Error
263263
require.ErrorAs(t,err,&apiErr)
264264
require.Equal(t,http.StatusUnauthorized,apiErr.StatusCode())
@@ -271,7 +271,7 @@ 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, codersdk.WorkspaceByOwnerAndNameParams{})
274+
_,err:=client.WorkspaceByOwnerAndName(context.Background(),codersdk.Me,workspace.Name, codersdk.WorkspaceOptions{})
275275
require.NoError(t,err)
276276
})
277277
t.Run("Deleted",func(t*testing.T) {
@@ -294,12 +294,43 @@ func TestWorkspaceByOwnerAndName(t *testing.T) {
294294

295295
// Then:
296296
// 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{})
297+
_,err=client.WorkspaceByOwnerAndName(context.Background(),workspace.OwnerName,workspace.Name, codersdk.WorkspaceOptions{})
298298
require.ErrorContains(t,err,"403")
299299

300300
// Then:
301301
// 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})
302+
workspaceNew,err:=client.WorkspaceByOwnerAndName(context.Background(),workspace.OwnerName,workspace.Name, codersdk.WorkspaceOptions{IncludeDeleted:true})
303+
require.NoError(t,err)
304+
require.Equal(t,workspace.ID,workspaceNew.ID)
305+
306+
// Given:
307+
// We recreate the workspace with the same name
308+
workspace,err=client.CreateWorkspace(context.Background(),user.OrganizationID, codersdk.CreateWorkspaceRequest{
309+
TemplateID:workspace.TemplateID,
310+
Name:workspace.Name,
311+
AutostartSchedule:workspace.AutostartSchedule,
312+
TTLMillis:workspace.TTLMillis,
313+
})
314+
require.NoError(t,err)
315+
coderdtest.AwaitWorkspaceBuildJob(t,client,workspace.LatestBuild.ID)
316+
317+
// Then:
318+
// We can fetch the most recent workspace
319+
workspaceNew,err=client.WorkspaceByOwnerAndName(context.Background(),workspace.OwnerName,workspace.Name, codersdk.WorkspaceOptions{})
320+
require.NoError(t,err)
321+
require.Equal(t,workspace.ID,workspaceNew.ID)
322+
323+
// Given:
324+
// We delete the workspace again
325+
build,err=client.CreateWorkspaceBuild(context.Background(),workspace.ID, codersdk.CreateWorkspaceBuildRequest{
326+
Transition:codersdk.WorkspaceTransitionDelete,
327+
})
328+
require.NoError(t,err,"delete the workspace")
329+
coderdtest.AwaitWorkspaceBuildJob(t,client,build.ID)
330+
331+
// Then:
332+
// When we fetch the deleted workspace, we get the most recently deleted one
333+
workspaceNew,err=client.WorkspaceByOwnerAndName(context.Background(),workspace.OwnerName,workspace.Name, codersdk.WorkspaceOptions{IncludeDeleted:true})
303334
require.NoError(t,err)
304335
require.Equal(t,workspace.ID,workspaceNew.ID)
305336
})

‎codersdk/workspaces.go

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -39,16 +39,16 @@ type CreateWorkspaceBuildRequest struct {
3939
}
4040

4141
typeWorkspaceOptionsstruct {
42-
Deletedbool`json:"deleted,omitempty"`
42+
IncludeDeletedbool`json:"include_deleted,omitempty"`
4343
}
4444

4545
// asRequestOption returns a function that can be used in (*Client).Request.
4646
// It modifies the request query parameters.
4747
func (oWorkspaceOptions)asRequestOption()requestOption {
4848
returnfunc(r*http.Request) {
4949
q:=r.URL.Query()
50-
ifo.Deleted {
51-
q.Set("deleted","true")
50+
ifo.IncludeDeleted {
51+
q.Set("include_deleted","true")
5252
}
5353
r.URL.RawQuery=q.Encode()
5454
}
@@ -62,7 +62,7 @@ func (c *Client) Workspace(ctx context.Context, id uuid.UUID) (Workspace, error)
6262
// DeletedWorkspace returns a single workspace that was deleted.
6363
func (c*Client)DeletedWorkspace(ctx context.Context,id uuid.UUID) (Workspace,error) {
6464
o:=WorkspaceOptions{
65-
Deleted:true,
65+
IncludeDeleted:true,
6666
}
6767
returnc.getWorkspace(ctx,id,o.asRequestOption())
6868
}
@@ -258,12 +258,8 @@ func (c *Client) Workspaces(ctx context.Context, filter WorkspaceFilter) ([]Work
258258
returnworkspaces,json.NewDecoder(res.Body).Decode(&workspaces)
259259
}
260260

261-
typeWorkspaceByOwnerAndNameParamsstruct {
262-
IncludeDeletedbool`json:"include_deleted,omitempty"`
263-
}
264-
265261
// WorkspaceByOwnerAndName returns a workspace by the owner's UUID and the workspace's name.
266-
func (c*Client)WorkspaceByOwnerAndName(ctx context.Context,ownerstring,namestring,paramsWorkspaceByOwnerAndNameParams) (Workspace,error) {
262+
func (c*Client)WorkspaceByOwnerAndName(ctx context.Context,ownerstring,namestring,paramsWorkspaceOptions) (Workspace,error) {
267263
res,err:=c.Request(ctx,http.MethodGet,fmt.Sprintf("/api/v2/users/%s/workspace/%s",owner,name),nil,func(r*http.Request) {
268264
q:=r.URL.Query()
269265
q.Set("include_deleted",fmt.Sprintf("%t",params.IncludeDeleted))

‎site/src/api/api.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@ export const getWorkspaces = async (filter?: TypesGen.WorkspaceFilter): Promise<
144144
exportconstgetWorkspaceByOwnerAndName=async(
145145
username="me",
146146
workspaceName:string,
147-
params?:TypesGen.WorkspaceByOwnerAndNameParams,
147+
params?:TypesGen.WorkspaceOptions,
148148
):Promise<TypesGen.Workspace>=>{
149149
constresponse=awaitaxios.get<TypesGen.Workspace>(`/api/v2/users/${username}/workspace/${workspaceName}`,{
150150
params,

‎site/src/api/typesGenerated.ts

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -464,11 +464,6 @@ export interface WorkspaceBuildsRequest extends Pagination {
464464
readonlyWorkspaceID:string
465465
}
466466

467-
// From codersdk/workspaces.go:261:6
468-
exportinterfaceWorkspaceByOwnerAndNameParams{
469-
readonlyinclude_deleted?:boolean
470-
}
471-
472467
// From codersdk/workspaces.go:219:6
473468
exportinterfaceWorkspaceFilter{
474469
readonlyorganization_id?:string
@@ -478,7 +473,7 @@ export interface WorkspaceFilter {
478473

479474
// From codersdk/workspaces.go:41:6
480475
exportinterfaceWorkspaceOptions{
481-
readonlydeleted?:boolean
476+
readonlyinclude_deleted?:boolean
482477
}
483478

484479
// From codersdk/workspaceresources.go:21:6

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp