Skip to content

Commit 0df75f9

Browse files
authored
Make coder bump idempotent (#2225)
Resolves #2223 In addition to solving what's outlined in the issue, I remove the client-side minute check because it had no clear purpose when the API already returns an error.
1 parent 92bda0d commit 0df75f9

File tree

2 files changed

+23
-104
lines changed

2 files changed

+23
-104
lines changed

cli/bump.go

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -12,55 +12,55 @@ import (
1212
)
1313

1414
const (
15-
bumpDescriptionLong = `To extend the autostop deadline for a workspace.
16-
If no unit is specified in the duration, we assume minutes.`
17-
defaultBumpDuration = 90 * time.Minute
15+
bumpDescriptionLong = `To extend the autostop deadline for a workspace.`
1816
)
1917

2018
func bump() *cobra.Command {
2119
bumpCmd := &cobra.Command{
2220
Args: cobra.RangeArgs(1, 2),
2321
Annotations: workspaceCommand,
24-
Use: "bump <workspace-name> [duration]",
22+
Use: "bump <workspace-name> <duration>",
2523
Short: "Extend the autostop deadline for a workspace.",
2624
Long: bumpDescriptionLong,
2725
Example: "coder bump my-workspace 90m",
2826
RunE: func(cmd *cobra.Command, args []string) error {
29-
bumpDuration := defaultBumpDuration
30-
if len(args) > 1 {
31-
d, err := tryParseDuration(args[1])
32-
if err != nil {
33-
return err
34-
}
35-
bumpDuration = d
36-
}
37-
38-
if bumpDuration < time.Minute {
39-
return xerrors.New("minimum bump duration is 1 minute")
27+
bumpDuration, err := tryParseDuration(args[1])
28+
if err != nil {
29+
return err
4030
}
4131

4232
client, err := createClient(cmd)
4333
if err != nil {
4434
return xerrors.Errorf("create client: %w", err)
4535
}
36+
4637
workspace, err := namedWorkspace(cmd, client, args[0])
4738
if err != nil {
4839
return xerrors.Errorf("get workspace: %w", err)
4940
}
5041

51-
if workspace.LatestBuild.Deadline.IsZero() {
52-
_, _ = fmt.Fprintf(cmd.OutOrStdout(), "no deadline set\n")
42+
newDeadline := time.Now().Add(bumpDuration)
43+
44+
if newDeadline.Before(workspace.LatestBuild.Deadline) {
45+
_, _ = fmt.Fprintf(
46+
cmd.OutOrStdout(),
47+
"The proposed deadline is %s before the current deadline.\n",
48+
workspace.LatestBuild.Deadline.Sub(newDeadline).Round(time.Minute),
49+
)
5350
return nil
5451
}
5552

56-
newDeadline := workspace.LatestBuild.Deadline.Add(bumpDuration)
5753
if err := client.PutExtendWorkspace(cmd.Context(), workspace.ID, codersdk.PutExtendWorkspaceRequest{
5854
Deadline: newDeadline,
5955
}); err != nil {
6056
return err
6157
}
6258

63-
_, _ = fmt.Fprintf(cmd.OutOrStdout(), "Workspace %q will now stop at %s\n", workspace.Name, newDeadline.Format(time.RFC3339))
59+
_, _ = fmt.Fprintf(
60+
cmd.OutOrStdout(),
61+
"Workspace %q will now stop at %s\n", workspace.Name,
62+
newDeadline.Format(time.RFC822),
63+
)
6464

6565
return nil
6666
},

cli/bump_test.go

Lines changed: 4 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -17,47 +17,6 @@ import (
1717
func TestBump(t *testing.T) {
1818
t.Parallel()
1919

20-
t.Run("BumpOKDefault", func(t *testing.T) {
21-
t.Parallel()
22-
23-
// Given: we have a workspace
24-
var (
25-
err error
26-
ctx = context.Background()
27-
client = coderdtest.New(t, &coderdtest.Options{IncludeProvisionerD: true})
28-
user = coderdtest.CreateFirstUser(t, client)
29-
version = coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil)
30-
_ = coderdtest.AwaitTemplateVersionJob(t, client, version.ID)
31-
project = coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID)
32-
workspace = coderdtest.CreateWorkspace(t, client, user.OrganizationID, project.ID)
33-
cmdArgs = []string{"bump", workspace.Name}
34-
stdoutBuf = &bytes.Buffer{}
35-
)
36-
37-
// Given: we wait for the workspace to be built
38-
coderdtest.AwaitWorkspaceBuildJob(t, client, workspace.LatestBuild.ID)
39-
workspace, err = client.Workspace(ctx, workspace.ID)
40-
require.NoError(t, err)
41-
expectedDeadline := workspace.LatestBuild.Deadline.Add(90 * time.Minute)
42-
43-
// Assert test invariant: workspace build has a deadline set equal to now plus ttl
44-
initDeadline := time.Now().Add(time.Duration(*workspace.TTLMillis) * time.Millisecond)
45-
require.WithinDuration(t, initDeadline, workspace.LatestBuild.Deadline, time.Minute)
46-
47-
cmd, root := clitest.New(t, cmdArgs...)
48-
clitest.SetupConfig(t, client, root)
49-
cmd.SetOut(stdoutBuf)
50-
51-
// When: we execute `coder bump <workspace>`
52-
err = cmd.ExecuteContext(ctx)
53-
require.NoError(t, err, "unexpected error")
54-
55-
// Then: the deadline of the latest build is updated
56-
updated, err := client.Workspace(ctx, workspace.ID)
57-
require.NoError(t, err)
58-
require.WithinDuration(t, expectedDeadline, updated.LatestBuild.Deadline, time.Minute)
59-
})
60-
6120
t.Run("BumpSpecificDuration", func(t *testing.T) {
6221
t.Parallel()
6322

@@ -71,15 +30,15 @@ func TestBump(t *testing.T) {
7130
_ = coderdtest.AwaitTemplateVersionJob(t, client, version.ID)
7231
project = coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID)
7332
workspace = coderdtest.CreateWorkspace(t, client, user.OrganizationID, project.ID)
74-
cmdArgs = []string{"bump", workspace.Name, "30"}
33+
cmdArgs = []string{"bump", workspace.Name, "10h"}
7534
stdoutBuf = &bytes.Buffer{}
7635
)
7736

7837
// Given: we wait for the workspace to be built
7938
coderdtest.AwaitWorkspaceBuildJob(t, client, workspace.LatestBuild.ID)
8039
workspace, err = client.Workspace(ctx, workspace.ID)
8140
require.NoError(t, err)
82-
expectedDeadline := workspace.LatestBuild.Deadline.Add(30 * time.Minute)
41+
expectedDeadline := time.Now().Add(10 * time.Hour)
8342

8443
// Assert test invariant: workspace build has a deadline set equal to now plus ttl
8544
initDeadline := time.Now().Add(time.Duration(*workspace.TTLMillis) * time.Millisecond)
@@ -150,7 +109,7 @@ func TestBump(t *testing.T) {
150109
workspace = coderdtest.CreateWorkspace(t, client, user.OrganizationID, project.ID, func(cwr *codersdk.CreateWorkspaceRequest) {
151110
cwr.TTLMillis = nil
152111
})
153-
cmdArgs = []string{"bump", workspace.Name}
112+
cmdArgs = []string{"bump", workspace.Name, "1h"}
154113
stdoutBuf = &bytes.Buffer{}
155114
)
156115
// Unset the workspace TTL
@@ -180,51 +139,11 @@ func TestBump(t *testing.T) {
180139

181140
// When: we execute `coder bump workspace``
182141
err = cmd.ExecuteContext(ctx)
183-
require.NoError(t, err)
142+
require.Error(t, err)
184143

185144
// Then: nothing happens and the deadline remains unset
186145
updated, err := client.Workspace(ctx, workspace.ID)
187146
require.NoError(t, err)
188147
require.Zero(t, updated.LatestBuild.Deadline)
189148
})
190-
191-
t.Run("BumpMinimumDuration", func(t *testing.T) {
192-
t.Parallel()
193-
194-
// Given: we have a workspace with no deadline set
195-
var (
196-
err error
197-
ctx = context.Background()
198-
client = coderdtest.New(t, &coderdtest.Options{IncludeProvisionerD: true})
199-
user = coderdtest.CreateFirstUser(t, client)
200-
version = coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil)
201-
_ = coderdtest.AwaitTemplateVersionJob(t, client, version.ID)
202-
project = coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID)
203-
workspace = coderdtest.CreateWorkspace(t, client, user.OrganizationID, project.ID)
204-
cmdArgs = []string{"bump", workspace.Name, "59s"}
205-
stdoutBuf = &bytes.Buffer{}
206-
)
207-
208-
// Given: we wait for the workspace to build
209-
coderdtest.AwaitWorkspaceBuildJob(t, client, workspace.LatestBuild.ID)
210-
workspace, err = client.Workspace(ctx, workspace.ID)
211-
require.NoError(t, err)
212-
213-
// Assert test invariant: workspace build has a deadline set equal to now plus ttl
214-
initDeadline := time.Now().Add(time.Duration(*workspace.TTLMillis) * time.Millisecond)
215-
require.WithinDuration(t, initDeadline, workspace.LatestBuild.Deadline, time.Minute)
216-
217-
cmd, root := clitest.New(t, cmdArgs...)
218-
clitest.SetupConfig(t, client, root)
219-
cmd.SetOut(stdoutBuf)
220-
221-
// When: we execute `coder bump workspace 59s`
222-
err = cmd.ExecuteContext(ctx)
223-
require.ErrorContains(t, err, "minimum bump duration is 1 minute")
224-
225-
// Then: an error is reported and the deadline remains as before
226-
updated, err := client.Workspace(ctx, workspace.ID)
227-
require.NoError(t, err)
228-
require.WithinDuration(t, workspace.LatestBuild.Deadline, updated.LatestBuild.Deadline, time.Minute)
229-
})
230149
}

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