From 6ea86c831b5eb1abd549e5450a932acf0ebf9aba Mon Sep 17 00:00:00 2001 From: ammario Date: Fri, 10 Jun 2022 03:31:13 +0000 Subject: [PATCH] Revert "Make `coder bump` idempotent (#2225)" This reverts commit 0df75f9176ceaed37c037707cc347e2e73c1e01d. I merged on accident. --- cli/bump.go | 38 ++++++++++----------- cli/bump_test.go | 89 +++++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 104 insertions(+), 23 deletions(-) diff --git a/cli/bump.go b/cli/bump.go index 220f6c406b..54d1b4bf58 100644 --- a/cli/bump.go +++ b/cli/bump.go @@ -12,55 +12,55 @@ import ( ) const ( - bumpDescriptionLong = `To extend the autostop deadline for a workspace.` + bumpDescriptionLong = `To extend the autostop deadline for a workspace. +If no unit is specified in the duration, we assume minutes.` + defaultBumpDuration = 90 * time.Minute ) func bump() *cobra.Command { bumpCmd := &cobra.Command{ Args: cobra.RangeArgs(1, 2), Annotations: workspaceCommand, - Use: "bump ", + Use: "bump [duration]", Short: "Extend the autostop deadline for a workspace.", Long: bumpDescriptionLong, Example: "coder bump my-workspace 90m", RunE: func(cmd *cobra.Command, args []string) error { - bumpDuration, err := tryParseDuration(args[1]) - if err != nil { - return err + bumpDuration := defaultBumpDuration + if len(args) > 1 { + d, err := tryParseDuration(args[1]) + if err != nil { + return err + } + bumpDuration = d + } + + if bumpDuration < time.Minute { + return xerrors.New("minimum bump duration is 1 minute") } client, err := createClient(cmd) if err != nil { return xerrors.Errorf("create client: %w", err) } - workspace, err := namedWorkspace(cmd, client, args[0]) if err != nil { return xerrors.Errorf("get workspace: %w", err) } - newDeadline := time.Now().Add(bumpDuration) - - if newDeadline.Before(workspace.LatestBuild.Deadline) { - _, _ = fmt.Fprintf( - cmd.OutOrStdout(), - "The proposed deadline is %s before the current deadline.\n", - workspace.LatestBuild.Deadline.Sub(newDeadline).Round(time.Minute), - ) + if workspace.LatestBuild.Deadline.IsZero() { + _, _ = fmt.Fprintf(cmd.OutOrStdout(), "no deadline set\n") return nil } + newDeadline := workspace.LatestBuild.Deadline.Add(bumpDuration) if err := client.PutExtendWorkspace(cmd.Context(), workspace.ID, codersdk.PutExtendWorkspaceRequest{ Deadline: newDeadline, }); err != nil { return err } - _, _ = fmt.Fprintf( - cmd.OutOrStdout(), - "Workspace %q will now stop at %s\n", workspace.Name, - newDeadline.Format(time.RFC822), - ) + _, _ = fmt.Fprintf(cmd.OutOrStdout(), "Workspace %q will now stop at %s\n", workspace.Name, newDeadline.Format(time.RFC3339)) return nil }, diff --git a/cli/bump_test.go b/cli/bump_test.go index 635bb0b909..041f899691 100644 --- a/cli/bump_test.go +++ b/cli/bump_test.go @@ -17,6 +17,47 @@ import ( func TestBump(t *testing.T) { t.Parallel() + t.Run("BumpOKDefault", func(t *testing.T) { + t.Parallel() + + // Given: we have a workspace + var ( + err error + ctx = context.Background() + client = coderdtest.New(t, &coderdtest.Options{IncludeProvisionerD: true}) + user = coderdtest.CreateFirstUser(t, client) + version = coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil) + _ = coderdtest.AwaitTemplateVersionJob(t, client, version.ID) + project = coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) + workspace = coderdtest.CreateWorkspace(t, client, user.OrganizationID, project.ID) + cmdArgs = []string{"bump", workspace.Name} + stdoutBuf = &bytes.Buffer{} + ) + + // Given: we wait for the workspace to be built + coderdtest.AwaitWorkspaceBuildJob(t, client, workspace.LatestBuild.ID) + workspace, err = client.Workspace(ctx, workspace.ID) + require.NoError(t, err) + expectedDeadline := workspace.LatestBuild.Deadline.Add(90 * time.Minute) + + // Assert test invariant: workspace build has a deadline set equal to now plus ttl + initDeadline := time.Now().Add(time.Duration(*workspace.TTLMillis) * time.Millisecond) + require.WithinDuration(t, initDeadline, workspace.LatestBuild.Deadline, time.Minute) + + cmd, root := clitest.New(t, cmdArgs...) + clitest.SetupConfig(t, client, root) + cmd.SetOut(stdoutBuf) + + // When: we execute `coder bump ` + err = cmd.ExecuteContext(ctx) + require.NoError(t, err, "unexpected error") + + // Then: the deadline of the latest build is updated + updated, err := client.Workspace(ctx, workspace.ID) + require.NoError(t, err) + require.WithinDuration(t, expectedDeadline, updated.LatestBuild.Deadline, time.Minute) + }) + t.Run("BumpSpecificDuration", func(t *testing.T) { t.Parallel() @@ -30,7 +71,7 @@ func TestBump(t *testing.T) { _ = coderdtest.AwaitTemplateVersionJob(t, client, version.ID) project = coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) workspace = coderdtest.CreateWorkspace(t, client, user.OrganizationID, project.ID) - cmdArgs = []string{"bump", workspace.Name, "10h"} + cmdArgs = []string{"bump", workspace.Name, "30"} stdoutBuf = &bytes.Buffer{} ) @@ -38,7 +79,7 @@ func TestBump(t *testing.T) { coderdtest.AwaitWorkspaceBuildJob(t, client, workspace.LatestBuild.ID) workspace, err = client.Workspace(ctx, workspace.ID) require.NoError(t, err) - expectedDeadline := time.Now().Add(10 * time.Hour) + expectedDeadline := workspace.LatestBuild.Deadline.Add(30 * time.Minute) // Assert test invariant: workspace build has a deadline set equal to now plus ttl initDeadline := time.Now().Add(time.Duration(*workspace.TTLMillis) * time.Millisecond) @@ -109,7 +150,7 @@ func TestBump(t *testing.T) { workspace = coderdtest.CreateWorkspace(t, client, user.OrganizationID, project.ID, func(cwr *codersdk.CreateWorkspaceRequest) { cwr.TTLMillis = nil }) - cmdArgs = []string{"bump", workspace.Name, "1h"} + cmdArgs = []string{"bump", workspace.Name} stdoutBuf = &bytes.Buffer{} ) // Unset the workspace TTL @@ -139,11 +180,51 @@ func TestBump(t *testing.T) { // When: we execute `coder bump workspace`` err = cmd.ExecuteContext(ctx) - require.Error(t, err) + require.NoError(t, err) // Then: nothing happens and the deadline remains unset updated, err := client.Workspace(ctx, workspace.ID) require.NoError(t, err) require.Zero(t, updated.LatestBuild.Deadline) }) + + t.Run("BumpMinimumDuration", func(t *testing.T) { + t.Parallel() + + // Given: we have a workspace with no deadline set + var ( + err error + ctx = context.Background() + client = coderdtest.New(t, &coderdtest.Options{IncludeProvisionerD: true}) + user = coderdtest.CreateFirstUser(t, client) + version = coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil) + _ = coderdtest.AwaitTemplateVersionJob(t, client, version.ID) + project = coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) + workspace = coderdtest.CreateWorkspace(t, client, user.OrganizationID, project.ID) + cmdArgs = []string{"bump", workspace.Name, "59s"} + stdoutBuf = &bytes.Buffer{} + ) + + // Given: we wait for the workspace to build + coderdtest.AwaitWorkspaceBuildJob(t, client, workspace.LatestBuild.ID) + workspace, err = client.Workspace(ctx, workspace.ID) + require.NoError(t, err) + + // Assert test invariant: workspace build has a deadline set equal to now plus ttl + initDeadline := time.Now().Add(time.Duration(*workspace.TTLMillis) * time.Millisecond) + require.WithinDuration(t, initDeadline, workspace.LatestBuild.Deadline, time.Minute) + + cmd, root := clitest.New(t, cmdArgs...) + clitest.SetupConfig(t, client, root) + cmd.SetOut(stdoutBuf) + + // When: we execute `coder bump workspace 59s` + err = cmd.ExecuteContext(ctx) + require.ErrorContains(t, err, "minimum bump duration is 1 minute") + + // Then: an error is reported and the deadline remains as before + updated, err := client.Workspace(ctx, workspace.ID) + require.NoError(t, err) + require.WithinDuration(t, workspace.LatestBuild.Deadline, updated.LatestBuild.Deadline, time.Minute) + }) }