From a1fec34b64c2d135bb32a9f5fdebab7e4bb57c9d Mon Sep 17 00:00:00 2001 From: johnstcn Date: Tue, 31 May 2022 17:23:44 +0000 Subject: [PATCH 1/8] chore: codersdk: refactor time.Duration to millisecond timestamp --- cli/autostart.go | 10 +-- cli/autostart_test.go | 8 +-- cli/bump_test.go | 18 +++--- cli/create.go | 3 +- cli/list.go | 14 +++-- cli/root_test.go | 4 ++ cli/ssh.go | 2 +- cli/ttl.go | 15 ++--- cli/ttl_test.go | 10 +-- .../executor/lifecycle_executor_test.go | 20 +++--- coderd/coderdtest/coderdtest.go | 2 +- coderd/workspaces.go | 63 ++++++++++++------- coderd/workspaces_test.go | 62 +++++++++--------- codersdk/organizations.go | 8 +-- codersdk/workspaces.go | 8 +-- 15 files changed, 141 insertions(+), 106 deletions(-) diff --git a/cli/autostart.go b/cli/autostart.go index 870eafa94c0dd..ddf29191096e4 100644 --- a/cli/autostart.go +++ b/cli/autostart.go @@ -51,15 +51,15 @@ func autostartShow() *cobra.Command { return err } - if workspace.AutostartSchedule == "" { + if workspace.AutostartSchedule == nil || *workspace.AutostartSchedule == "" { _, _ = fmt.Fprintf(cmd.OutOrStdout(), "not enabled\n") return nil } - validSchedule, err := schedule.Weekly(workspace.AutostartSchedule) + validSchedule, err := schedule.Weekly(*workspace.AutostartSchedule) if err != nil { // This should never happen. - _, _ = fmt.Fprintf(cmd.OutOrStdout(), "invalid autostart schedule %q for workspace %s: %s\n", workspace.AutostartSchedule, workspace.Name, err.Error()) + _, _ = fmt.Fprintf(cmd.OutOrStdout(), "invalid autostart schedule %q for workspace %s: %s\n", *workspace.AutostartSchedule, workspace.Name, err.Error()) return nil } @@ -110,7 +110,7 @@ func autostartEnable() *cobra.Command { } err = client.UpdateWorkspaceAutostart(cmd.Context(), workspace.ID, codersdk.UpdateWorkspaceAutostartRequest{ - Schedule: validSchedule.String(), + Schedule: &spec, }) if err != nil { return err @@ -153,7 +153,7 @@ func autostartDisable() *cobra.Command { } err = client.UpdateWorkspaceAutostart(cmd.Context(), workspace.ID, codersdk.UpdateWorkspaceAutostartRequest{ - Schedule: "", + Schedule: nil, }) if err != nil { return err diff --git a/cli/autostart_test.go b/cli/autostart_test.go index 31f3ab600614f..741d67b8904b9 100644 --- a/cli/autostart_test.go +++ b/cli/autostart_test.go @@ -34,7 +34,7 @@ func TestAutostart(t *testing.T) { ) err := client.UpdateWorkspaceAutostart(ctx, workspace.ID, codersdk.UpdateWorkspaceAutostartRequest{ - Schedule: sched, + Schedule: ptr(sched), }) require.NoError(t, err) @@ -76,7 +76,7 @@ func TestAutostart(t *testing.T) { // Ensure autostart schedule updated updated, err := client.Workspace(ctx, workspace.ID) require.NoError(t, err, "fetch updated workspace") - require.Equal(t, sched, updated.AutostartSchedule, "expected autostart schedule to be set") + require.Equal(t, sched, *updated.AutostartSchedule, "expected autostart schedule to be set") // Disable schedule cmd, root = clitest.New(t, "autostart", "disable", workspace.Name) @@ -90,7 +90,7 @@ func TestAutostart(t *testing.T) { // Ensure autostart schedule updated updated, err = client.Workspace(ctx, workspace.ID) require.NoError(t, err, "fetch updated workspace") - require.Empty(t, updated.AutostartSchedule, "expected autostart schedule to not be set") + require.Nil(t, updated.AutostartSchedule, "expected autostart schedule to not be set") }) t.Run("Enable_NotFound", func(t *testing.T) { @@ -155,6 +155,6 @@ func TestAutostart(t *testing.T) { // Ensure nothing happened updated, err := client.Workspace(ctx, workspace.ID) require.NoError(t, err, "fetch updated workspace") - require.Equal(t, expectedSchedule, updated.AutostartSchedule, "expected default autostart schedule") + require.Equal(t, expectedSchedule, *updated.AutostartSchedule, "expected default autostart schedule") }) } diff --git a/cli/bump_test.go b/cli/bump_test.go index dd54eccbe770c..da00bb33b7fd3 100644 --- a/cli/bump_test.go +++ b/cli/bump_test.go @@ -40,8 +40,8 @@ func TestBump(t *testing.T) { expectedDeadline := workspace.LatestBuild.Deadline.Add(90 * time.Minute) // Assert test invariant: workspace build has a deadline set equal to now plus ttl - require.WithinDuration(t, workspace.LatestBuild.Deadline, time.Now().Add(*workspace.TTL), time.Minute) - require.NoError(t, err) + 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) @@ -81,8 +81,8 @@ func TestBump(t *testing.T) { expectedDeadline := workspace.LatestBuild.Deadline.Add(30 * time.Minute) // Assert test invariant: workspace build has a deadline set equal to now plus ttl - require.WithinDuration(t, workspace.LatestBuild.Deadline, time.Now().Add(*workspace.TTL), time.Minute) - require.NoError(t, err) + 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) @@ -121,8 +121,8 @@ func TestBump(t *testing.T) { require.NoError(t, err) // Assert test invariant: workspace build has a deadline set equal to now plus ttl - require.WithinDuration(t, workspace.LatestBuild.Deadline, time.Now().Add(*workspace.TTL), time.Minute) - require.NoError(t, err) + 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) @@ -147,7 +147,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, func(cwr *codersdk.CreateWorkspaceRequest) { - cwr.TTL = nil + cwr.TTLMillis = nil }) cmdArgs = []string{"bump", workspace.Name} stdoutBuf = &bytes.Buffer{} @@ -199,8 +199,8 @@ func TestBump(t *testing.T) { require.NoError(t, err) // Assert test invariant: workspace build has a deadline set equal to now plus ttl - require.WithinDuration(t, workspace.LatestBuild.Deadline, time.Now().Add(*workspace.TTL), time.Minute) - require.NoError(t, err) + 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) diff --git a/cli/create.go b/cli/create.go index fedfb071b47e6..f576c683a9a2e 100644 --- a/cli/create.go +++ b/cli/create.go @@ -222,11 +222,12 @@ func create() *cobra.Command { return err } + ttlMillis := ttl.Milliseconds() workspace, err := client.CreateWorkspace(cmd.Context(), organization.ID, codersdk.CreateWorkspaceRequest{ TemplateID: template.ID, Name: workspaceName, AutostartSchedule: &schedSpec, - TTL: &ttl, + TTLMillis: &ttlMillis, ParameterValues: parameters, }) if err != nil { diff --git a/cli/list.go b/cli/list.go index ad22692a5ece9..3b39d09c5390f 100644 --- a/cli/list.go +++ b/cli/list.go @@ -87,15 +87,16 @@ func list() *cobra.Command { duration := time.Now().UTC().Sub(workspace.LatestBuild.Job.CreatedAt).Truncate(time.Second) autostartDisplay := "-" - if workspace.AutostartSchedule != "" { - if sched, err := schedule.Weekly(workspace.AutostartSchedule); err == nil { + if workspace.AutostartSchedule != nil && *workspace.AutostartSchedule != "" { + if sched, err := schedule.Weekly(*workspace.AutostartSchedule); err == nil { autostartDisplay = sched.Cron() } } autostopDisplay := "-" - if workspace.TTL != nil { - autostopDisplay = durationDisplay(*workspace.TTL) + if workspace.TTLMillis != nil && *workspace.TTLMillis > 0 { + dur := time.Duration(*workspace.TTLMillis) * time.Millisecond + autostopDisplay = durationDisplay(dur) if has, ext := hasExtension(workspace); has { autostopDisplay += fmt.Sprintf(" (+%s)", durationDisplay(ext.Round(time.Minute))) } @@ -128,10 +129,11 @@ func hasExtension(ws codersdk.Workspace) (bool, time.Duration) { if ws.LatestBuild.Deadline.IsZero() { return false, 0 } - if ws.TTL == nil { + if ws.TTLMillis == nil { return false, 0 } - delta := ws.LatestBuild.Deadline.Add(-*ws.TTL).Sub(ws.LatestBuild.CreatedAt) + ttl := time.Duration(*ws.TTLMillis) * time.Millisecond + delta := ws.LatestBuild.Deadline.Add(-ttl).Sub(ws.LatestBuild.CreatedAt) if delta < time.Minute { return false, 0 } diff --git a/cli/root_test.go b/cli/root_test.go index 28206cc46707f..3cfb7c0621911 100644 --- a/cli/root_test.go +++ b/cli/root_test.go @@ -20,3 +20,7 @@ func TestRoot(t *testing.T) { require.Contains(t, errStr, "Run 'coder delete --help' for usage.") }) } + +func ptr[T any](v T) *T { + return &v +} diff --git a/cli/ssh.go b/cli/ssh.go index d168c0113c4a7..b0ba71698b8f8 100644 --- a/cli/ssh.go +++ b/cli/ssh.go @@ -290,7 +290,7 @@ func notifyCondition(ctx context.Context, client *codersdk.Client, workspaceID u return time.Time{}, nil } - if ws.TTL == nil || *ws.TTL == 0 { + if ws.TTLMillis == nil || *ws.TTLMillis == 0 { return time.Time{}, nil } diff --git a/cli/ttl.go b/cli/ttl.go index 29417ff943501..077b561179dcb 100644 --- a/cli/ttl.go +++ b/cli/ttl.go @@ -49,12 +49,13 @@ func ttlShow() *cobra.Command { return xerrors.Errorf("get workspace: %w", err) } - if workspace.TTL == nil { + if workspace.TTLMillis == nil || *workspace.TTLMillis == 0 { _, _ = fmt.Fprintf(cmd.OutOrStdout(), "not set\n") return nil } - _, _ = fmt.Fprintf(cmd.OutOrStdout(), "%s\n", workspace.TTL) + dur := time.Duration(*workspace.TTLMillis) * time.Millisecond + _, _ = fmt.Fprintf(cmd.OutOrStdout(), "%s\n", dur) return nil }, @@ -96,10 +97,10 @@ func ttlset() *cobra.Command { _, _ = fmt.Fprintf(cmd.OutOrStdout(), "warning: ttl rounded down to %s\n", truncated) } - err = client.UpdateWorkspaceTTL(cmd.Context(), workspace.ID, codersdk.UpdateWorkspaceTTLRequest{ - TTL: &truncated, - }) - if err != nil { + millis := truncated.Milliseconds() + if err = client.UpdateWorkspaceTTL(cmd.Context(), workspace.ID, codersdk.UpdateWorkspaceTTLRequest{ + TTLMillis: &millis, + }); err != nil { return xerrors.Errorf("update workspace ttl: %w", err) } @@ -130,7 +131,7 @@ func ttlunset() *cobra.Command { } err = client.UpdateWorkspaceTTL(cmd.Context(), workspace.ID, codersdk.UpdateWorkspaceTTLRequest{ - TTL: nil, + TTLMillis: nil, }) if err != nil { return xerrors.Errorf("update workspace ttl: %w", err) diff --git a/cli/ttl_test.go b/cli/ttl_test.go index d6ea9929eeb4f..5debf34a80cc7 100644 --- a/cli/ttl_test.go +++ b/cli/ttl_test.go @@ -34,7 +34,7 @@ func TestTTL(t *testing.T) { ) err := client.UpdateWorkspaceTTL(ctx, workspace.ID, codersdk.UpdateWorkspaceTTLRequest{ - TTL: &ttl, + TTLMillis: ptr(ttl.Milliseconds()), }) require.NoError(t, err) @@ -73,7 +73,7 @@ func TestTTL(t *testing.T) { // Ensure ttl updated updated, err := client.Workspace(ctx, workspace.ID) require.NoError(t, err, "fetch updated workspace") - require.Equal(t, ttl.Truncate(time.Minute), *updated.TTL) + require.Equal(t, ttl.Truncate(time.Minute), time.Duration(*updated.TTLMillis)*time.Millisecond) require.Contains(t, stdoutBuf.String(), "warning: ttl rounded down") // unset schedule @@ -87,7 +87,7 @@ func TestTTL(t *testing.T) { // Ensure ttl updated updated, err = client.Workspace(ctx, workspace.ID) require.NoError(t, err, "fetch updated workspace") - require.Nil(t, updated.TTL, "expected ttl to not be set") + require.Nil(t, updated.TTLMillis, "expected ttl to not be set") }) t.Run("ZeroInvalid", func(t *testing.T) { @@ -116,7 +116,7 @@ func TestTTL(t *testing.T) { // Ensure ttl updated updated, err := client.Workspace(ctx, workspace.ID) require.NoError(t, err, "fetch updated workspace") - require.Equal(t, ttl.Truncate(time.Minute), *updated.TTL) + require.Equal(t, ttl.Truncate(time.Minute), time.Duration(*updated.TTLMillis)*time.Millisecond) require.Contains(t, stdoutBuf.String(), "warning: ttl rounded down") // A TTL of zero is not considered valid. @@ -131,7 +131,7 @@ func TestTTL(t *testing.T) { // Ensure ttl remains as before updated, err = client.Workspace(ctx, workspace.ID) require.NoError(t, err, "fetch updated workspace") - require.Equal(t, ttl.Truncate(time.Minute), *updated.TTL) + require.Equal(t, ttl.Truncate(time.Minute), time.Duration(*updated.TTLMillis)*time.Millisecond) }) t.Run("Set_NotFound", func(t *testing.T) { diff --git a/coderd/autobuild/executor/lifecycle_executor_test.go b/coderd/autobuild/executor/lifecycle_executor_test.go index 8ca7e321d9030..1fe8db3a19ed9 100644 --- a/coderd/autobuild/executor/lifecycle_executor_test.go +++ b/coderd/autobuild/executor/lifecycle_executor_test.go @@ -44,7 +44,7 @@ func TestExecutorAutostartOK(t *testing.T) { sched, err := schedule.Weekly("* * * * *") require.NoError(t, err) require.NoError(t, client.UpdateWorkspaceAutostart(ctx, workspace.ID, codersdk.UpdateWorkspaceAutostartRequest{ - Schedule: sched.String(), + Schedule: ptr(sched.String()), })) // When: the autobuild executor ticks @@ -95,7 +95,7 @@ func TestExecutorAutostartTemplateUpdated(t *testing.T) { sched, err := schedule.Weekly("* * * * *") require.NoError(t, err) require.NoError(t, client.UpdateWorkspaceAutostart(ctx, workspace.ID, codersdk.UpdateWorkspaceAutostartRequest{ - Schedule: sched.String(), + Schedule: ptr(sched.String()), })) // When: the autobuild executor ticks @@ -138,7 +138,7 @@ func TestExecutorAutostartAlreadyRunning(t *testing.T) { sched, err := schedule.Weekly("* * * * *") require.NoError(t, err) require.NoError(t, client.UpdateWorkspaceAutostart(ctx, workspace.ID, codersdk.UpdateWorkspaceAutostartRequest{ - Schedule: sched.String(), + Schedule: ptr(sched.String()), })) // When: the autobuild executor ticks @@ -316,12 +316,12 @@ func TestExecutorAutostopNotEnabled(t *testing.T) { }) // Given: we have a user with a workspace that has no TTL set workspace = mustProvisionWorkspace(t, client, func(cwr *codersdk.CreateWorkspaceRequest) { - cwr.TTL = nil + cwr.TTLMillis = nil }) ) // Given: workspace has no TTL set - require.Nil(t, workspace.TTL) + require.Nil(t, workspace.TTLMillis) // Given: workspace is running require.Equal(t, codersdk.WorkspaceTransitionStart, workspace.LatestBuild.Transition) @@ -359,7 +359,7 @@ func TestExecutorWorkspaceDeleted(t *testing.T) { sched, err := schedule.Weekly("* * * * *") require.NoError(t, err) require.NoError(t, client.UpdateWorkspaceAutostart(ctx, workspace.ID, codersdk.UpdateWorkspaceAutostartRequest{ - Schedule: sched.String(), + Schedule: ptr(sched.String()), })) // Given: workspace is deleted @@ -402,7 +402,7 @@ func TestExecutorWorkspaceAutostartTooEarly(t *testing.T) { sched, err := schedule.Weekly(futureTimeCron) require.NoError(t, err) require.NoError(t, client.UpdateWorkspaceAutostart(ctx, workspace.ID, codersdk.UpdateWorkspaceAutostartRequest{ - Schedule: sched.String(), + Schedule: ptr(sched.String()), })) // When: the autobuild executor ticks @@ -461,7 +461,7 @@ func TestExecutorWorkspaceAutostopNoWaitChangedMyMind(t *testing.T) { ) // Given: the user changes their mind and decides their workspace should not auto-stop - err := client.UpdateWorkspaceTTL(ctx, workspace.ID, codersdk.UpdateWorkspaceTTLRequest{TTL: nil}) + err := client.UpdateWorkspaceTTL(ctx, workspace.ID, codersdk.UpdateWorkspaceTTLRequest{TTLMillis: nil}) require.NoError(t, err) // When: the autobuild executor ticks after the deadline @@ -572,6 +572,10 @@ func mustWorkspace(t *testing.T, client *codersdk.Client, workspaceID uuid.UUID) return ws } +func ptr[T any](v T) *T { + return &v +} + func TestMain(m *testing.M) { goleak.VerifyTestMain(m) } diff --git a/coderd/coderdtest/coderdtest.go b/coderd/coderdtest/coderdtest.go index 6fbe4256d692e..5d4442005b8f4 100644 --- a/coderd/coderdtest/coderdtest.go +++ b/coderd/coderdtest/coderdtest.go @@ -400,7 +400,7 @@ func CreateWorkspace(t *testing.T, client *codersdk.Client, organization uuid.UU TemplateID: templateID, Name: randomUsername(), AutostartSchedule: ptr("CRON_TZ=US/Central * * * * *"), - TTL: ptr(8 * time.Hour), + TTLMillis: ptr((8 * time.Hour).Milliseconds()), } for _, mutator := range mutators { mutator(&req) diff --git a/coderd/workspaces.go b/coderd/workspaces.go index 85566f1a1df9e..47adebcc5a69d 100644 --- a/coderd/workspaces.go +++ b/coderd/workspaces.go @@ -345,7 +345,7 @@ func (api *API) postWorkspacesByOrganization(rw http.ResponseWriter, r *http.Req dbAutostartSchedule.String = *createWorkspace.AutostartSchedule } - dbTTL, err := validWorkspaceTTL(createWorkspace.TTL) + dbTTL, err := validWorkspaceTTLMillis(createWorkspace.TTLMillis) if err != nil { httpapi.Write(rw, http.StatusBadRequest, httpapi.Response{ Message: "validate workspace ttl", @@ -527,20 +527,15 @@ func (api *API) putWorkspaceAutostart(rw http.ResponseWriter, r *http.Request) { return } - var dbSched sql.NullString - if req.Schedule != "" { - validSched, err := schedule.Weekly(req.Schedule) - if err != nil { - httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{ - Message: fmt.Sprintf("invalid autostart schedule: %s", err), - }) - return - } - dbSched.String = validSched.String() - dbSched.Valid = true + dbSched, err := validWorkspaceSchedule(req.Schedule) + if err != nil { + httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{ + Message: fmt.Sprintf("invalid autostart schedule: %s", err), + }) + return } - err := api.Database.UpdateWorkspaceAutostart(r.Context(), database.UpdateWorkspaceAutostartParams{ + err = api.Database.UpdateWorkspaceAutostart(r.Context(), database.UpdateWorkspaceAutostartParams{ ID: workspace.ID, AutostartSchedule: dbSched, }) @@ -564,7 +559,7 @@ func (api *API) putWorkspaceTTL(rw http.ResponseWriter, r *http.Request) { return } - dbTTL, err := validWorkspaceTTL(req.TTL) + dbTTL, err := validWorkspaceTTLMillis(req.TTLMillis) if err != nil { httpapi.Write(rw, http.StatusBadRequest, httpapi.Response{ Message: "validate workspace ttl", @@ -837,6 +832,13 @@ func convertWorkspace( job database.ProvisionerJob, template database.Template, owner database.User) codersdk.Workspace { + + var autostartSchedule *string + if workspace.AutostartSchedule.Valid { + autostartSchedule = &workspace.AutostartSchedule.String + } + + ttlMillis := convertWorkspaceTTLMillis(workspace.Ttl) return codersdk.Workspace{ ID: workspace.ID, CreatedAt: workspace.CreatedAt, @@ -848,25 +850,28 @@ func convertWorkspace( TemplateName: template.Name, Outdated: workspaceBuild.TemplateVersionID.String() != template.ActiveVersionID.String(), Name: workspace.Name, - AutostartSchedule: workspace.AutostartSchedule.String, - TTL: convertSQLNullInt64(workspace.Ttl), + AutostartSchedule: autostartSchedule, + TTLMillis: ttlMillis, } } -func convertSQLNullInt64(i sql.NullInt64) *time.Duration { +func convertWorkspaceTTLMillis(i sql.NullInt64) *int64 { if !i.Valid { return nil } - return (*time.Duration)(&i.Int64) + millis := time.Duration(i.Int64).Milliseconds() + return &millis } -func validWorkspaceTTL(ttl *time.Duration) (sql.NullInt64, error) { - if ttl == nil { +func validWorkspaceTTLMillis(millis *int64) (sql.NullInt64, error) { + if millis == nil { return sql.NullInt64{}, nil } - truncated := ttl.Truncate(time.Minute) + dur := time.Duration(*millis) * time.Millisecond + + truncated := dur.Truncate(time.Minute) if truncated < time.Minute { return sql.NullInt64{}, xerrors.New("ttl must be at least one minute") } @@ -902,3 +907,19 @@ func validWorkspaceDeadline(old, new time.Time) error { return nil } + +func validWorkspaceSchedule(s *string) (sql.NullString, error) { + if s == nil || *s == "" { + return sql.NullString{}, nil + } + + _, err := schedule.Weekly(*s) + if err != nil { + return sql.NullString{}, err + } + + return sql.NullString{ + Valid: true, + String: *s, + }, nil +} diff --git a/coderd/workspaces_test.go b/coderd/workspaces_test.go index 2ac65fd3c0a3a..8c6e1f47519f1 100644 --- a/coderd/workspaces_test.go +++ b/coderd/workspaces_test.go @@ -178,7 +178,7 @@ func TestPostWorkspacesByOrganization(t *testing.T) { TemplateID: template.ID, Name: "testing", AutostartSchedule: ptr("CRON_TZ=US/Central * * * * *"), - TTL: ptr(59 * time.Second), + TTLMillis: ptr((59 * time.Second).Milliseconds()), } _, err := client.CreateWorkspace(context.Background(), template.OrganizationID, req) require.Error(t, err) @@ -198,7 +198,7 @@ func TestPostWorkspacesByOrganization(t *testing.T) { TemplateID: template.ID, Name: "testing", AutostartSchedule: ptr("CRON_TZ=US/Central * * * * *"), - TTL: ptr(24*7*time.Hour + time.Minute), + TTLMillis: ptr((24*7*time.Hour + time.Minute).Milliseconds()), } _, err := client.CreateWorkspace(context.Background(), template.OrganizationID, req) require.Error(t, err) @@ -451,7 +451,7 @@ func TestWorkspaceUpdateAutostart(t *testing.T) { testCases := []struct { name string - schedule string + schedule *string expectedError string at time.Time expectedNext time.Time @@ -459,12 +459,12 @@ func TestWorkspaceUpdateAutostart(t *testing.T) { }{ { name: "disable autostart", - schedule: "", + schedule: ptr(""), expectedError: "", }, { name: "friday to monday", - schedule: "CRON_TZ=Europe/Dublin 30 9 * * 1-5", + schedule: ptr("CRON_TZ=Europe/Dublin 30 9 * * 1-5"), expectedError: "", at: time.Date(2022, 5, 6, 9, 31, 0, 0, dublinLoc), expectedNext: time.Date(2022, 5, 9, 9, 30, 0, 0, dublinLoc), @@ -472,7 +472,7 @@ func TestWorkspaceUpdateAutostart(t *testing.T) { }, { name: "monday to tuesday", - schedule: "CRON_TZ=Europe/Dublin 30 9 * * 1-5", + schedule: ptr("CRON_TZ=Europe/Dublin 30 9 * * 1-5"), expectedError: "", at: time.Date(2022, 5, 9, 9, 31, 0, 0, dublinLoc), expectedNext: time.Date(2022, 5, 10, 9, 30, 0, 0, dublinLoc), @@ -481,7 +481,7 @@ func TestWorkspaceUpdateAutostart(t *testing.T) { { // DST in Ireland began on Mar 27 in 2022 at 0100. Forward 1 hour. name: "DST start", - schedule: "CRON_TZ=Europe/Dublin 30 9 * * *", + schedule: ptr("CRON_TZ=Europe/Dublin 30 9 * * *"), expectedError: "", at: time.Date(2022, 3, 26, 9, 31, 0, 0, dublinLoc), expectedNext: time.Date(2022, 3, 27, 9, 30, 0, 0, dublinLoc), @@ -490,7 +490,7 @@ func TestWorkspaceUpdateAutostart(t *testing.T) { { // DST in Ireland ends on Oct 30 in 2022 at 0200. Back 1 hour. name: "DST end", - schedule: "CRON_TZ=Europe/Dublin 30 9 * * *", + schedule: ptr("CRON_TZ=Europe/Dublin 30 9 * * *"), expectedError: "", at: time.Date(2022, 10, 29, 9, 31, 0, 0, dublinLoc), expectedNext: time.Date(2022, 10, 30, 9, 30, 0, 0, dublinLoc), @@ -498,17 +498,17 @@ func TestWorkspaceUpdateAutostart(t *testing.T) { }, { name: "invalid location", - schedule: "CRON_TZ=Imaginary/Place 30 9 * * 1-5", + schedule: ptr("CRON_TZ=Imaginary/Place 30 9 * * 1-5"), expectedError: "status code 500: invalid autostart schedule: parse schedule: provided bad location Imaginary/Place: unknown time zone Imaginary/Place", }, { name: "invalid schedule", - schedule: "asdf asdf asdf ", + schedule: ptr("asdf asdf asdf "), expectedError: `status code 500: invalid autostart schedule: validate weekly schedule: expected schedule to consist of 5 fields with an optional CRON_TZ= prefix`, }, { name: "only 3 values", - schedule: "CRON_TZ=Europe/Dublin 30 9 *", + schedule: ptr("CRON_TZ=Europe/Dublin 30 9 *"), expectedError: `status code 500: invalid autostart schedule: validate weekly schedule: expected schedule to consist of 5 fields with an optional CRON_TZ= prefix`, }, } @@ -526,7 +526,7 @@ func TestWorkspaceUpdateAutostart(t *testing.T) { project = coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) workspace = coderdtest.CreateWorkspace(t, client, user.OrganizationID, project.ID, func(cwr *codersdk.CreateWorkspaceRequest) { cwr.AutostartSchedule = nil - cwr.TTL = nil + cwr.TTLMillis = nil }) ) @@ -547,12 +547,14 @@ func TestWorkspaceUpdateAutostart(t *testing.T) { updated, err := client.Workspace(ctx, workspace.ID) require.NoError(t, err, "fetch updated workspace") - require.Equal(t, testCase.schedule, updated.AutostartSchedule, "expected autostart schedule to equal requested") - - if testCase.schedule == "" { + if testCase.schedule == nil || *testCase.schedule == "" { + require.Nil(t, updated.AutostartSchedule) return } - sched, err := schedule.Weekly(updated.AutostartSchedule) + + require.EqualValues(t, *testCase.schedule, *updated.AutostartSchedule, "expected autostart schedule to equal requested") + + sched, err := schedule.Weekly(*updated.AutostartSchedule) require.NoError(t, err, "parse returned schedule") next := sched.Next(testCase.at) @@ -569,7 +571,7 @@ func TestWorkspaceUpdateAutostart(t *testing.T) { _ = coderdtest.CreateFirstUser(t, client) wsid = uuid.New() req = codersdk.UpdateWorkspaceAutostartRequest{ - Schedule: "9 30 1-5", + Schedule: ptr("9 30 1-5"), } ) @@ -586,32 +588,32 @@ func TestWorkspaceUpdateTTL(t *testing.T) { testCases := []struct { name string - ttl *time.Duration + ttlMillis *int64 expectedError string }{ { name: "disable ttl", - ttl: nil, + ttlMillis: nil, expectedError: "", }, { name: "below minimum ttl", - ttl: ptr(30 * time.Second), + ttlMillis: ptr((30 * time.Second).Milliseconds()), expectedError: "ttl must be at least one minute", }, { name: "minimum ttl", - ttl: ptr(time.Minute), + ttlMillis: ptr(time.Minute.Milliseconds()), expectedError: "", }, { name: "maximum ttl", - ttl: ptr(24 * 7 * time.Hour), + ttlMillis: ptr((24 * 7 * time.Hour).Milliseconds()), expectedError: "", }, { name: "above maximum ttl", - ttl: ptr(24*7*time.Hour + time.Minute), + ttlMillis: ptr((24*7*time.Hour + time.Minute).Milliseconds()), expectedError: "ttl must be less than 7 days", }, } @@ -629,15 +631,15 @@ func TestWorkspaceUpdateTTL(t *testing.T) { project = coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) workspace = coderdtest.CreateWorkspace(t, client, user.OrganizationID, project.ID, func(cwr *codersdk.CreateWorkspaceRequest) { cwr.AutostartSchedule = nil - cwr.TTL = nil + cwr.TTLMillis = nil }) ) // ensure test invariant: new workspaces have no autostop schedule. - require.Nil(t, workspace.TTL, "expected newly-minted workspace to have no TTL") + require.Nil(t, workspace.TTLMillis, "expected newly-minted workspace to have no TTL") err := client.UpdateWorkspaceTTL(ctx, workspace.ID, codersdk.UpdateWorkspaceTTLRequest{ - TTL: testCase.ttl, + TTLMillis: testCase.ttlMillis, }) if testCase.expectedError != "" { @@ -650,7 +652,7 @@ func TestWorkspaceUpdateTTL(t *testing.T) { updated, err := client.Workspace(ctx, workspace.ID) require.NoError(t, err, "fetch updated workspace") - require.Equal(t, testCase.ttl, updated.TTL, "expected autostop ttl to equal requested") + require.Equal(t, testCase.ttlMillis, updated.TTLMillis, "expected autostop ttl to equal requested") }) } @@ -661,7 +663,7 @@ func TestWorkspaceUpdateTTL(t *testing.T) { _ = coderdtest.CreateFirstUser(t, client) wsid = uuid.New() req = codersdk.UpdateWorkspaceTTLRequest{ - TTL: ptr(time.Hour), + TTLMillis: ptr(time.Hour.Milliseconds()), } ) @@ -685,8 +687,8 @@ func TestWorkspaceExtend(t *testing.T) { workspace = coderdtest.CreateWorkspace(t, client, user.OrganizationID, project.ID) extend = 90 * time.Minute _ = coderdtest.AwaitWorkspaceBuildJob(t, client, workspace.LatestBuild.ID) - oldDeadline = time.Now().Add(*workspace.TTL).UTC() - newDeadline = time.Now().Add(*workspace.TTL + extend).UTC() + oldDeadline = time.Now().Add(time.Duration(*workspace.TTLMillis) * time.Millisecond).UTC() + newDeadline = time.Now().Add(time.Duration(*workspace.TTLMillis)*time.Millisecond + extend).UTC() ) workspace, err := client.Workspace(ctx, workspace.ID) diff --git a/codersdk/organizations.go b/codersdk/organizations.go index 1ac435439267d..c252acc524eff 100644 --- a/codersdk/organizations.go +++ b/codersdk/organizations.go @@ -65,10 +65,10 @@ type CreateTemplateRequest struct { // CreateWorkspaceRequest provides options for creating a new workspace. type CreateWorkspaceRequest struct { - TemplateID uuid.UUID `json:"template_id" validate:"required"` - Name string `json:"name" validate:"username,required"` - AutostartSchedule *string `json:"autostart_schedule"` - TTL *time.Duration `json:"ttl"` + TemplateID uuid.UUID `json:"template_id" validate:"required"` + Name string `json:"name" validate:"username,required"` + AutostartSchedule *string `json:"autostart_schedule"` + TTLMillis *int64 `json:"ttl_ms,omitempty"` // ParameterValues allows for additional parameters to be provided // during the initial provision. ParameterValues []CreateParameterRequest `json:"parameter_values,omitempty"` diff --git a/codersdk/workspaces.go b/codersdk/workspaces.go index 3ad1ac42fb830..cbf94f392da60 100644 --- a/codersdk/workspaces.go +++ b/codersdk/workspaces.go @@ -26,8 +26,8 @@ type Workspace struct { LatestBuild WorkspaceBuild `json:"latest_build"` Outdated bool `json:"outdated"` Name string `json:"name"` - AutostartSchedule string `json:"autostart_schedule"` - TTL *time.Duration `json:"ttl"` + AutostartSchedule *string `json:"autostart_schedule,omitempty"` + TTLMillis *int64 `json:"ttl_ms,omitempty"` } // CreateWorkspaceBuildRequest provides options to update the latest workspace build. @@ -139,7 +139,7 @@ func (c *Client) WatchWorkspace(ctx context.Context, id uuid.UUID) (<-chan Works // UpdateWorkspaceAutostartRequest is a request to update a workspace's autostart schedule. type UpdateWorkspaceAutostartRequest struct { - Schedule string `json:"schedule"` + Schedule *string `json:"schedule"` } // UpdateWorkspaceAutostart sets the autostart schedule for workspace by id. @@ -159,7 +159,7 @@ func (c *Client) UpdateWorkspaceAutostart(ctx context.Context, id uuid.UUID, req // UpdateWorkspaceTTLRequest is a request to update a workspace's TTL. type UpdateWorkspaceTTLRequest struct { - TTL *time.Duration `json:"ttl"` + TTLMillis *int64 `json:"ttl_ms"` } // UpdateWorkspaceTTL sets the ttl for workspace by id. From 4c0405392a2d7f75a2fd7c8b706a51496601b783 Mon Sep 17 00:00:00 2001 From: johnstcn Date: Wed, 1 Jun 2022 12:47:49 +0000 Subject: [PATCH 2/8] make gen --- site/src/api/typesGenerated.ts | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/site/src/api/typesGenerated.ts b/site/src/api/typesGenerated.ts index 0b9872ea60e88..d0ce2c3fac371 100644 --- a/site/src/api/typesGenerated.ts +++ b/site/src/api/typesGenerated.ts @@ -101,8 +101,7 @@ export interface CreateWorkspaceRequest { readonly template_id: string readonly name: string readonly autostart_schedule?: string - // This is likely an enum in an external package ("time.Duration") - readonly ttl?: number + readonly ttl_ms?: number readonly parameter_values?: CreateParameterRequest[] } @@ -301,13 +300,12 @@ export interface UpdateUserProfileRequest { // From codersdk/workspaces.go:141:6 export interface UpdateWorkspaceAutostartRequest { - readonly schedule: string + readonly schedule?: string } // From codersdk/workspaces.go:161:6 export interface UpdateWorkspaceTTLRequest { - // This is likely an enum in an external package ("time.Duration") - readonly ttl?: number + readonly ttl_ms?: number } // From codersdk/files.go:16:6 @@ -372,9 +370,8 @@ export interface Workspace { readonly latest_build: WorkspaceBuild readonly outdated: boolean readonly name: string - readonly autostart_schedule: string - // This is likely an enum in an external package ("time.Duration") - readonly ttl?: number + readonly autostart_schedule?: string + readonly ttl_ms?: number } // From codersdk/workspaceresources.go:31:6 From 1af3630e84cb0781fea223293df01d67cc2c8edc Mon Sep 17 00:00:00 2001 From: johnstcn Date: Wed, 1 Jun 2022 13:12:34 +0000 Subject: [PATCH 3/8] refactor: typegen --- .../WorkspaceSchedule/WorkspaceSchedule.tsx | 8 ++++---- .../WorkspaceSchedulePage.test.tsx | 16 ++++++++-------- .../WorkspaceSchedulePage.tsx | 8 ++++---- site/src/testHelpers/entities.ts | 2 +- 4 files changed, 17 insertions(+), 17 deletions(-) diff --git a/site/src/components/WorkspaceSchedule/WorkspaceSchedule.tsx b/site/src/components/WorkspaceSchedule/WorkspaceSchedule.tsx index 6787a844945c4..ccb103f15f85e 100644 --- a/site/src/components/WorkspaceSchedule/WorkspaceSchedule.tsx +++ b/site/src/components/WorkspaceSchedule/WorkspaceSchedule.tsx @@ -20,13 +20,13 @@ dayjs.extend(duration) dayjs.extend(relativeTime) export const Language = { - autoStartDisplay: (schedule: string): string => { + autoStartDisplay: (schedule: string | undefined): string => { if (schedule) { return cronstrue.toString(stripTimezone(schedule), { throwExceptionOnParseError: false }) } return "Manual" }, - autoStartLabel: (schedule: string): string => { + autoStartLabel: (schedule: string | undefined): string => { const prefix = "Start" if (schedule) { @@ -40,7 +40,7 @@ export const Language = { // a mannual shutdown has a deadline of '"0001-01-01T00:00:00Z"' // SEE: #1834 const hasDeadline = deadline.year() > 1 - const ttl = workspace.ttl + const ttl = workspace.ttl_ms if (isWorkspaceOn(workspace) && hasDeadline) { // Workspace is on --> derive from latest_build.deadline. Note that the @@ -61,7 +61,7 @@ export const Language = { } else { // The workspace has a ttl set, but is either in an unknown state or is // not running. Therefore, we derive from workspace.ttl. - const duration = dayjs.duration(ttl / 1_000_000, "milliseconds") + const duration = dayjs.duration(ttl, "milliseconds") return `${duration.humanize()} after start` } }, diff --git a/site/src/pages/WorkspaceSchedulePage/WorkspaceSchedulePage.test.tsx b/site/src/pages/WorkspaceSchedulePage/WorkspaceSchedulePage.test.tsx index 3b91ca54ae7ff..5f9fee03d1853 100644 --- a/site/src/pages/WorkspaceSchedulePage/WorkspaceSchedulePage.test.tsx +++ b/site/src/pages/WorkspaceSchedulePage/WorkspaceSchedulePage.test.tsx @@ -123,7 +123,7 @@ describe("WorkspaceSchedulePage", () => { ttl: 0, }, { - ttl: undefined, + ttl_ms: undefined, }, ], [ @@ -133,7 +133,7 @@ describe("WorkspaceSchedulePage", () => { ttl: 2, }, { - ttl: 7_200_000_000_000, + ttl_ms: 7_200_000, }, ], [ @@ -143,7 +143,7 @@ describe("WorkspaceSchedulePage", () => { ttl: 8, }, { - ttl: 28_800_000_000_000, + ttl_ms: 28_800_000, }, ], ])(`formValuesToTTLRequest(%p) returns %p`, (values, request) => { @@ -157,8 +157,8 @@ describe("WorkspaceSchedulePage", () => { [ { ...Mocks.MockWorkspace, - autostart_schedule: "", - ttl: undefined, + autostart_schedule: undefined, + ttl_ms: undefined, }, { sunday: false, @@ -179,7 +179,7 @@ describe("WorkspaceSchedulePage", () => { { ...Mocks.MockWorkspace, autostart_schedule: "", - ttl: 7_200_000_000_000, + ttl_ms: 7_200_000, }, { sunday: false, @@ -203,7 +203,7 @@ describe("WorkspaceSchedulePage", () => { { ...Mocks.MockWorkspace, autostart_schedule: "CRON_TZ=UTC 30 9 * * 1-5", - ttl: 7_200_000_000_000, + ttl_ms: 7_200_000, }, { sunday: false, @@ -224,7 +224,7 @@ describe("WorkspaceSchedulePage", () => { { ...Mocks.MockWorkspace, autostart_schedule: "CRON_TZ=Canada/Eastern 20 16 * * 1,3-4,6", - ttl: 28_800_000_000_000, + ttl_ms: 28_800_000, }, { sunday: false, diff --git a/site/src/pages/WorkspaceSchedulePage/WorkspaceSchedulePage.tsx b/site/src/pages/WorkspaceSchedulePage/WorkspaceSchedulePage.tsx index 21ec0e71cdfb2..7f3cd4172c488 100644 --- a/site/src/pages/WorkspaceSchedulePage/WorkspaceSchedulePage.tsx +++ b/site/src/pages/WorkspaceSchedulePage/WorkspaceSchedulePage.tsx @@ -87,13 +87,13 @@ export const formValuesToAutoStartRequest = ( export const formValuesToTTLRequest = (values: WorkspaceScheduleFormValues): TypesGen.UpdateWorkspaceTTLRequest => { return { // minutes to nanoseconds - ttl: values.ttl ? values.ttl * 60 * 60 * 1000 * 1_000_000 : undefined, + ttl_ms: values.ttl ? values.ttl * 60 * 60 * 1000 : undefined, } } export const workspaceToInitialValues = (workspace: TypesGen.Workspace): WorkspaceScheduleFormValues => { const schedule = workspace.autostart_schedule - const ttl = workspace.ttl ? workspace.ttl / (1_000_000 * 1000 * 60 * 60) : 0 + const ttl = workspace.ttl_ms ? workspace.ttl_ms / (1000 * 60 * 60) : 0 if (!schedule) { return { @@ -106,7 +106,7 @@ export const workspaceToInitialValues = (workspace: TypesGen.Workspace): Workspa saturday: false, startTime: "", timezone: "", - ttl, + ttl: ttl, } } @@ -133,7 +133,7 @@ export const workspaceToInitialValues = (workspace: TypesGen.Workspace): Workspa saturday: weeklyFlags[6], startTime: `${HH.padStart(2, "0")}:${mm.padStart(2, "0")}`, timezone, - ttl, + ttl: ttl, } } diff --git a/site/src/testHelpers/entities.ts b/site/src/testHelpers/entities.ts index 615387fde640a..5d54fe970b540 100644 --- a/site/src/testHelpers/entities.ts +++ b/site/src/testHelpers/entities.ts @@ -164,7 +164,7 @@ export const MockWorkspace: TypesGen.Workspace = { owner_id: MockUser.id, owner_name: MockUser.username, autostart_schedule: MockWorkspaceAutostartEnabled.schedule, - ttl: 2 * 60 * 60 * 1000 * 1_000_000, // 2 hours as nanoseconds + ttl_ms: 2 * 60 * 60 * 1000 * 1_000_000, // 2 hours as nanoseconds latest_build: MockWorkspaceBuild, } From ee730b333febafd48b569ab7315a2f4f403bdab7 Mon Sep 17 00:00:00 2001 From: johnstcn Date: Wed, 1 Jun 2022 15:43:18 +0000 Subject: [PATCH 4/8] refactor: add and use a util/ptr helper package --- cli/autostart_test.go | 3 +- cli/create.go | 4 +- cli/list.go | 5 +- cli/root_test.go | 4 - cli/ssh.go | 3 +- cli/ttl_test.go | 3 +- .../executor/lifecycle_executor_test.go | 15 ++-- coderd/coderdtest/coderdtest.go | 9 +- coderd/util/ptr/ptr.go | 28 ++++++ coderd/util/ptr/ptr_test.go | 89 +++++++++++++++++++ coderd/workspaces.go | 6 +- coderd/workspaces_test.go | 41 ++++----- 12 files changed, 159 insertions(+), 51 deletions(-) create mode 100644 coderd/util/ptr/ptr.go create mode 100644 coderd/util/ptr/ptr_test.go diff --git a/cli/autostart_test.go b/cli/autostart_test.go index 741d67b8904b9..dd17105f3f9a9 100644 --- a/cli/autostart_test.go +++ b/cli/autostart_test.go @@ -11,6 +11,7 @@ import ( "github.com/coder/coder/cli/clitest" "github.com/coder/coder/coderd/coderdtest" + "github.com/coder/coder/coderd/util/ptr" "github.com/coder/coder/codersdk" ) @@ -34,7 +35,7 @@ func TestAutostart(t *testing.T) { ) err := client.UpdateWorkspaceAutostart(ctx, workspace.ID, codersdk.UpdateWorkspaceAutostartRequest{ - Schedule: ptr(sched), + Schedule: ptr.Ref(sched), }) require.NoError(t, err) diff --git a/cli/create.go b/cli/create.go index f576c683a9a2e..aab94ed3a9f67 100644 --- a/cli/create.go +++ b/cli/create.go @@ -11,6 +11,7 @@ import ( "github.com/coder/coder/cli/cliflag" "github.com/coder/coder/cli/cliui" "github.com/coder/coder/coderd/autobuild/schedule" + "github.com/coder/coder/coderd/util/ptr" "github.com/coder/coder/codersdk" ) @@ -222,12 +223,11 @@ func create() *cobra.Command { return err } - ttlMillis := ttl.Milliseconds() workspace, err := client.CreateWorkspace(cmd.Context(), organization.ID, codersdk.CreateWorkspaceRequest{ TemplateID: template.ID, Name: workspaceName, AutostartSchedule: &schedSpec, - TTLMillis: &ttlMillis, + TTLMillis: ptr.Ref(ttl.Milliseconds()), ParameterValues: parameters, }) if err != nil { diff --git a/cli/list.go b/cli/list.go index 3b39d09c5390f..47eae30d23a7b 100644 --- a/cli/list.go +++ b/cli/list.go @@ -11,6 +11,7 @@ import ( "github.com/coder/coder/cli/cliui" "github.com/coder/coder/coderd/autobuild/schedule" + "github.com/coder/coder/coderd/util/ptr" "github.com/coder/coder/codersdk" ) @@ -87,14 +88,14 @@ func list() *cobra.Command { duration := time.Now().UTC().Sub(workspace.LatestBuild.Job.CreatedAt).Truncate(time.Second) autostartDisplay := "-" - if workspace.AutostartSchedule != nil && *workspace.AutostartSchedule != "" { + if !ptr.NilOrEmpty(workspace.AutostartSchedule) { if sched, err := schedule.Weekly(*workspace.AutostartSchedule); err == nil { autostartDisplay = sched.Cron() } } autostopDisplay := "-" - if workspace.TTLMillis != nil && *workspace.TTLMillis > 0 { + if !ptr.NilOrZero(workspace.TTLMillis) { dur := time.Duration(*workspace.TTLMillis) * time.Millisecond autostopDisplay = durationDisplay(dur) if has, ext := hasExtension(workspace); has { diff --git a/cli/root_test.go b/cli/root_test.go index 3cfb7c0621911..28206cc46707f 100644 --- a/cli/root_test.go +++ b/cli/root_test.go @@ -20,7 +20,3 @@ func TestRoot(t *testing.T) { require.Contains(t, errStr, "Run 'coder delete --help' for usage.") }) } - -func ptr[T any](v T) *T { - return &v -} diff --git a/cli/ssh.go b/cli/ssh.go index b0ba71698b8f8..dcdf46a511018 100644 --- a/cli/ssh.go +++ b/cli/ssh.go @@ -22,6 +22,7 @@ import ( "github.com/coder/coder/cli/cliflag" "github.com/coder/coder/cli/cliui" "github.com/coder/coder/coderd/autobuild/notify" + "github.com/coder/coder/coderd/util/ptr" "github.com/coder/coder/codersdk" "github.com/coder/coder/cryptorand" ) @@ -290,7 +291,7 @@ func notifyCondition(ctx context.Context, client *codersdk.Client, workspaceID u return time.Time{}, nil } - if ws.TTLMillis == nil || *ws.TTLMillis == 0 { + if ptr.NilOrZero(ws.TTLMillis) { return time.Time{}, nil } diff --git a/cli/ttl_test.go b/cli/ttl_test.go index 5debf34a80cc7..7efe03ce27b7d 100644 --- a/cli/ttl_test.go +++ b/cli/ttl_test.go @@ -11,6 +11,7 @@ import ( "github.com/coder/coder/cli/clitest" "github.com/coder/coder/coderd/coderdtest" + "github.com/coder/coder/coderd/util/ptr" "github.com/coder/coder/codersdk" ) @@ -34,7 +35,7 @@ func TestTTL(t *testing.T) { ) err := client.UpdateWorkspaceTTL(ctx, workspace.ID, codersdk.UpdateWorkspaceTTLRequest{ - TTLMillis: ptr(ttl.Milliseconds()), + TTLMillis: ptr.Ref(ttl.Milliseconds()), }) require.NoError(t, err) diff --git a/coderd/autobuild/executor/lifecycle_executor_test.go b/coderd/autobuild/executor/lifecycle_executor_test.go index 1fe8db3a19ed9..a97897e1a0bbc 100644 --- a/coderd/autobuild/executor/lifecycle_executor_test.go +++ b/coderd/autobuild/executor/lifecycle_executor_test.go @@ -14,6 +14,7 @@ import ( "github.com/coder/coder/coderd/autobuild/schedule" "github.com/coder/coder/coderd/coderdtest" "github.com/coder/coder/coderd/database" + "github.com/coder/coder/coderd/util/ptr" "github.com/coder/coder/codersdk" "github.com/google/uuid" @@ -44,7 +45,7 @@ func TestExecutorAutostartOK(t *testing.T) { sched, err := schedule.Weekly("* * * * *") require.NoError(t, err) require.NoError(t, client.UpdateWorkspaceAutostart(ctx, workspace.ID, codersdk.UpdateWorkspaceAutostartRequest{ - Schedule: ptr(sched.String()), + Schedule: ptr.Ref(sched.String()), })) // When: the autobuild executor ticks @@ -95,7 +96,7 @@ func TestExecutorAutostartTemplateUpdated(t *testing.T) { sched, err := schedule.Weekly("* * * * *") require.NoError(t, err) require.NoError(t, client.UpdateWorkspaceAutostart(ctx, workspace.ID, codersdk.UpdateWorkspaceAutostartRequest{ - Schedule: ptr(sched.String()), + Schedule: ptr.Ref(sched.String()), })) // When: the autobuild executor ticks @@ -138,7 +139,7 @@ func TestExecutorAutostartAlreadyRunning(t *testing.T) { sched, err := schedule.Weekly("* * * * *") require.NoError(t, err) require.NoError(t, client.UpdateWorkspaceAutostart(ctx, workspace.ID, codersdk.UpdateWorkspaceAutostartRequest{ - Schedule: ptr(sched.String()), + Schedule: ptr.Ref(sched.String()), })) // When: the autobuild executor ticks @@ -359,7 +360,7 @@ func TestExecutorWorkspaceDeleted(t *testing.T) { sched, err := schedule.Weekly("* * * * *") require.NoError(t, err) require.NoError(t, client.UpdateWorkspaceAutostart(ctx, workspace.ID, codersdk.UpdateWorkspaceAutostartRequest{ - Schedule: ptr(sched.String()), + Schedule: ptr.Ref(sched.String()), })) // Given: workspace is deleted @@ -402,7 +403,7 @@ func TestExecutorWorkspaceAutostartTooEarly(t *testing.T) { sched, err := schedule.Weekly(futureTimeCron) require.NoError(t, err) require.NoError(t, client.UpdateWorkspaceAutostart(ctx, workspace.ID, codersdk.UpdateWorkspaceAutostartRequest{ - Schedule: ptr(sched.String()), + Schedule: ptr.Ref(sched.String()), })) // When: the autobuild executor ticks @@ -572,10 +573,6 @@ func mustWorkspace(t *testing.T, client *codersdk.Client, workspaceID uuid.UUID) return ws } -func ptr[T any](v T) *T { - return &v -} - func TestMain(m *testing.M) { goleak.VerifyTestMain(m) } diff --git a/coderd/coderdtest/coderdtest.go b/coderd/coderdtest/coderdtest.go index 5d4442005b8f4..c103dde98c13b 100644 --- a/coderd/coderdtest/coderdtest.go +++ b/coderd/coderdtest/coderdtest.go @@ -26,6 +26,7 @@ import ( "time" "github.com/coder/coder/coderd/rbac" + "github.com/coder/coder/coderd/util/ptr" "cloud.google.com/go/compute/metadata" "github.com/fullsailor/pkcs7" @@ -399,8 +400,8 @@ func CreateWorkspace(t *testing.T, client *codersdk.Client, organization uuid.UU req := codersdk.CreateWorkspaceRequest{ TemplateID: templateID, Name: randomUsername(), - AutostartSchedule: ptr("CRON_TZ=US/Central * * * * *"), - TTLMillis: ptr((8 * time.Hour).Milliseconds()), + AutostartSchedule: ptr.Ref("CRON_TZ=US/Central * * * * *"), + TTLMillis: ptr.Ref((8 * time.Hour).Milliseconds()), } for _, mutator := range mutators { mutator(&req) @@ -602,7 +603,3 @@ type roundTripper func(req *http.Request) (*http.Response, error) func (r roundTripper) RoundTrip(req *http.Request) (*http.Response, error) { return r(req) } - -func ptr[T any](x T) *T { - return &x -} diff --git a/coderd/util/ptr/ptr.go b/coderd/util/ptr/ptr.go new file mode 100644 index 0000000000000..307575c609480 --- /dev/null +++ b/coderd/util/ptr/ptr.go @@ -0,0 +1,28 @@ +// Package ptr contains some utility methods related to pointers. +package ptr + +import "golang.org/x/exp/constraints" + +type number interface { + constraints.Integer | constraints.Float +} + +// Ref returns a reference to v. +func Ref[T any](v T) *T { + return &v +} + +// Deref dereferences v. Opposite of Ptr. +func Deref[T any](v *T) T { + return *v +} + +// NilOrEmpty returns true if s is nil or the empty string. +func NilOrEmpty(s *string) bool { + return s == nil || *s == "" +} + +// NilOrZero returns true if v is nil or 0. +func NilOrZero[T number](v *T) bool { + return v == nil || *v == 0 +} diff --git a/coderd/util/ptr/ptr_test.go b/coderd/util/ptr/ptr_test.go new file mode 100644 index 0000000000000..5ee489815ff0b --- /dev/null +++ b/coderd/util/ptr/ptr_test.go @@ -0,0 +1,89 @@ +package ptr_test + +import ( + "testing" + "time" + + "github.com/stretchr/testify/assert" + + "github.com/coder/coder/coderd/util/ptr" +) + +func Test_Ref_Deref(t *testing.T) { + t.Parallel() + + t.Run("String", func(t *testing.T) { + t.Parallel() + val := "test" + p := ptr.Ref(val) + d := ptr.Deref(p) + assert.Equal(t, val, d) + assert.Equal(t, &val, p) + }) + + t.Run("Bool", func(t *testing.T) { + t.Parallel() + val := true + p := ptr.Ref(val) + d := ptr.Deref(p) + assert.Equal(t, val, d) + assert.Equal(t, &val, p) + }) + + t.Run("Int64", func(t *testing.T) { + t.Parallel() + val := int64(42) + p := ptr.Ref(val) + d := ptr.Deref(p) + assert.Equal(t, val, d) + assert.Equal(t, &val, p) + }) + + t.Run("Float64", func(t *testing.T) { + t.Parallel() + val := float64(3.14159) + p := ptr.Ref(val) + d := ptr.Deref(p) + assert.Equal(t, val, d) + assert.Equal(t, &val, p) + }) +} + +func Test_NilOrEmpty(t *testing.T) { + t.Parallel() + nilString := (*string)(nil) + emptyString := "" + nonEmptyString := "hi" + + assert.True(t, ptr.NilOrEmpty(nilString)) + assert.True(t, ptr.NilOrEmpty(&emptyString)) + assert.False(t, ptr.NilOrEmpty(&nonEmptyString)) +} + +func Test_NilOrZero(t *testing.T) { + t.Parallel() + + nilInt64 := (*int64)(nil) + nilFloat64 := (*float64)(nil) + nilDuration := (*time.Duration)(nil) + + zeroInt64 := int64(0) + zeroFloat64 := float64(0.0) + zeroDuration := time.Duration(0) + + nonZeroInt64 := int64(1) + nonZeroFloat64 := float64(3.14159) + nonZeroDuration := time.Hour + + assert.True(t, ptr.NilOrZero(nilInt64)) + assert.True(t, ptr.NilOrZero(nilFloat64)) + assert.True(t, ptr.NilOrZero(nilDuration)) + + assert.True(t, ptr.NilOrZero(&zeroInt64)) + assert.True(t, ptr.NilOrZero(&zeroFloat64)) + assert.True(t, ptr.NilOrZero(&zeroDuration)) + + assert.False(t, ptr.NilOrZero(&nonZeroInt64)) + assert.False(t, ptr.NilOrZero(&nonZeroFloat64)) + assert.False(t, ptr.NilOrZero(&nonZeroDuration)) +} diff --git a/coderd/workspaces.go b/coderd/workspaces.go index 47adebcc5a69d..c28b641396cb3 100644 --- a/coderd/workspaces.go +++ b/coderd/workspaces.go @@ -25,6 +25,7 @@ import ( "github.com/coder/coder/coderd/httpapi" "github.com/coder/coder/coderd/httpmw" "github.com/coder/coder/coderd/rbac" + "github.com/coder/coder/coderd/util/ptr" "github.com/coder/coder/codersdk" ) @@ -865,12 +866,11 @@ func convertWorkspaceTTLMillis(i sql.NullInt64) *int64 { } func validWorkspaceTTLMillis(millis *int64) (sql.NullInt64, error) { - if millis == nil { + if ptr.NilOrZero(millis) { return sql.NullInt64{}, nil } dur := time.Duration(*millis) * time.Millisecond - truncated := dur.Truncate(time.Minute) if truncated < time.Minute { return sql.NullInt64{}, xerrors.New("ttl must be at least one minute") @@ -909,7 +909,7 @@ func validWorkspaceDeadline(old, new time.Time) error { } func validWorkspaceSchedule(s *string) (sql.NullString, error) { - if s == nil || *s == "" { + if ptr.NilOrEmpty(s) { return sql.NullString{}, nil } diff --git a/coderd/workspaces_test.go b/coderd/workspaces_test.go index 8c6e1f47519f1..392007dcdf18a 100644 --- a/coderd/workspaces_test.go +++ b/coderd/workspaces_test.go @@ -8,6 +8,7 @@ import ( "time" "github.com/coder/coder/coderd/rbac" + "github.com/coder/coder/coderd/util/ptr" "github.com/google/uuid" "github.com/stretchr/testify/require" @@ -177,8 +178,8 @@ func TestPostWorkspacesByOrganization(t *testing.T) { req := codersdk.CreateWorkspaceRequest{ TemplateID: template.ID, Name: "testing", - AutostartSchedule: ptr("CRON_TZ=US/Central * * * * *"), - TTLMillis: ptr((59 * time.Second).Milliseconds()), + AutostartSchedule: ptr.Ref("CRON_TZ=US/Central * * * * *"), + TTLMillis: ptr.Ref((59 * time.Second).Milliseconds()), } _, err := client.CreateWorkspace(context.Background(), template.OrganizationID, req) require.Error(t, err) @@ -197,8 +198,8 @@ func TestPostWorkspacesByOrganization(t *testing.T) { req := codersdk.CreateWorkspaceRequest{ TemplateID: template.ID, Name: "testing", - AutostartSchedule: ptr("CRON_TZ=US/Central * * * * *"), - TTLMillis: ptr((24*7*time.Hour + time.Minute).Milliseconds()), + AutostartSchedule: ptr.Ref("CRON_TZ=US/Central * * * * *"), + TTLMillis: ptr.Ref((24*7*time.Hour + time.Minute).Milliseconds()), } _, err := client.CreateWorkspace(context.Background(), template.OrganizationID, req) require.Error(t, err) @@ -459,12 +460,12 @@ func TestWorkspaceUpdateAutostart(t *testing.T) { }{ { name: "disable autostart", - schedule: ptr(""), + schedule: ptr.Ref(""), expectedError: "", }, { name: "friday to monday", - schedule: ptr("CRON_TZ=Europe/Dublin 30 9 * * 1-5"), + schedule: ptr.Ref("CRON_TZ=Europe/Dublin 30 9 * * 1-5"), expectedError: "", at: time.Date(2022, 5, 6, 9, 31, 0, 0, dublinLoc), expectedNext: time.Date(2022, 5, 9, 9, 30, 0, 0, dublinLoc), @@ -472,7 +473,7 @@ func TestWorkspaceUpdateAutostart(t *testing.T) { }, { name: "monday to tuesday", - schedule: ptr("CRON_TZ=Europe/Dublin 30 9 * * 1-5"), + schedule: ptr.Ref("CRON_TZ=Europe/Dublin 30 9 * * 1-5"), expectedError: "", at: time.Date(2022, 5, 9, 9, 31, 0, 0, dublinLoc), expectedNext: time.Date(2022, 5, 10, 9, 30, 0, 0, dublinLoc), @@ -481,7 +482,7 @@ func TestWorkspaceUpdateAutostart(t *testing.T) { { // DST in Ireland began on Mar 27 in 2022 at 0100. Forward 1 hour. name: "DST start", - schedule: ptr("CRON_TZ=Europe/Dublin 30 9 * * *"), + schedule: ptr.Ref("CRON_TZ=Europe/Dublin 30 9 * * *"), expectedError: "", at: time.Date(2022, 3, 26, 9, 31, 0, 0, dublinLoc), expectedNext: time.Date(2022, 3, 27, 9, 30, 0, 0, dublinLoc), @@ -490,7 +491,7 @@ func TestWorkspaceUpdateAutostart(t *testing.T) { { // DST in Ireland ends on Oct 30 in 2022 at 0200. Back 1 hour. name: "DST end", - schedule: ptr("CRON_TZ=Europe/Dublin 30 9 * * *"), + schedule: ptr.Ref("CRON_TZ=Europe/Dublin 30 9 * * *"), expectedError: "", at: time.Date(2022, 10, 29, 9, 31, 0, 0, dublinLoc), expectedNext: time.Date(2022, 10, 30, 9, 30, 0, 0, dublinLoc), @@ -498,17 +499,17 @@ func TestWorkspaceUpdateAutostart(t *testing.T) { }, { name: "invalid location", - schedule: ptr("CRON_TZ=Imaginary/Place 30 9 * * 1-5"), + schedule: ptr.Ref("CRON_TZ=Imaginary/Place 30 9 * * 1-5"), expectedError: "status code 500: invalid autostart schedule: parse schedule: provided bad location Imaginary/Place: unknown time zone Imaginary/Place", }, { name: "invalid schedule", - schedule: ptr("asdf asdf asdf "), + schedule: ptr.Ref("asdf asdf asdf "), expectedError: `status code 500: invalid autostart schedule: validate weekly schedule: expected schedule to consist of 5 fields with an optional CRON_TZ= prefix`, }, { name: "only 3 values", - schedule: ptr("CRON_TZ=Europe/Dublin 30 9 *"), + schedule: ptr.Ref("CRON_TZ=Europe/Dublin 30 9 *"), expectedError: `status code 500: invalid autostart schedule: validate weekly schedule: expected schedule to consist of 5 fields with an optional CRON_TZ= prefix`, }, } @@ -571,7 +572,7 @@ func TestWorkspaceUpdateAutostart(t *testing.T) { _ = coderdtest.CreateFirstUser(t, client) wsid = uuid.New() req = codersdk.UpdateWorkspaceAutostartRequest{ - Schedule: ptr("9 30 1-5"), + Schedule: ptr.Ref("9 30 1-5"), } ) @@ -598,22 +599,22 @@ func TestWorkspaceUpdateTTL(t *testing.T) { }, { name: "below minimum ttl", - ttlMillis: ptr((30 * time.Second).Milliseconds()), + ttlMillis: ptr.Ref((30 * time.Second).Milliseconds()), expectedError: "ttl must be at least one minute", }, { name: "minimum ttl", - ttlMillis: ptr(time.Minute.Milliseconds()), + ttlMillis: ptr.Ref(time.Minute.Milliseconds()), expectedError: "", }, { name: "maximum ttl", - ttlMillis: ptr((24 * 7 * time.Hour).Milliseconds()), + ttlMillis: ptr.Ref((24 * 7 * time.Hour).Milliseconds()), expectedError: "", }, { name: "above maximum ttl", - ttlMillis: ptr((24*7*time.Hour + time.Minute).Milliseconds()), + ttlMillis: ptr.Ref((24*7*time.Hour + time.Minute).Milliseconds()), expectedError: "ttl must be less than 7 days", }, } @@ -663,7 +664,7 @@ func TestWorkspaceUpdateTTL(t *testing.T) { _ = coderdtest.CreateFirstUser(t, client) wsid = uuid.New() req = codersdk.UpdateWorkspaceTTLRequest{ - TTLMillis: ptr(time.Hour.Milliseconds()), + TTLMillis: ptr.Ref(time.Hour.Milliseconds()), } ) @@ -763,7 +764,3 @@ func mustLocation(t *testing.T, location string) *time.Location { return loc } - -func ptr[T any](x T) *T { - return &x -} From 085497adb0ba7e3cbbd2f2f96ff730119b5ae1a1 Mon Sep 17 00:00:00 2001 From: johnstcn Date: Wed, 1 Jun 2022 19:55:02 +0000 Subject: [PATCH 5/8] address PR comments --- coderd/util/ptr/ptr.go | 5 ----- coderd/util/ptr/ptr_test.go | 8 -------- .../pages/WorkspaceSchedulePage/WorkspaceSchedulePage.tsx | 4 ++-- site/src/testHelpers/entities.ts | 2 +- 4 files changed, 3 insertions(+), 16 deletions(-) diff --git a/coderd/util/ptr/ptr.go b/coderd/util/ptr/ptr.go index 307575c609480..dfed4c83ec3be 100644 --- a/coderd/util/ptr/ptr.go +++ b/coderd/util/ptr/ptr.go @@ -12,11 +12,6 @@ func Ref[T any](v T) *T { return &v } -// Deref dereferences v. Opposite of Ptr. -func Deref[T any](v *T) T { - return *v -} - // NilOrEmpty returns true if s is nil or the empty string. func NilOrEmpty(s *string) bool { return s == nil || *s == "" diff --git a/coderd/util/ptr/ptr_test.go b/coderd/util/ptr/ptr_test.go index 5ee489815ff0b..d43e9ccd1122f 100644 --- a/coderd/util/ptr/ptr_test.go +++ b/coderd/util/ptr/ptr_test.go @@ -16,8 +16,6 @@ func Test_Ref_Deref(t *testing.T) { t.Parallel() val := "test" p := ptr.Ref(val) - d := ptr.Deref(p) - assert.Equal(t, val, d) assert.Equal(t, &val, p) }) @@ -25,8 +23,6 @@ func Test_Ref_Deref(t *testing.T) { t.Parallel() val := true p := ptr.Ref(val) - d := ptr.Deref(p) - assert.Equal(t, val, d) assert.Equal(t, &val, p) }) @@ -34,8 +30,6 @@ func Test_Ref_Deref(t *testing.T) { t.Parallel() val := int64(42) p := ptr.Ref(val) - d := ptr.Deref(p) - assert.Equal(t, val, d) assert.Equal(t, &val, p) }) @@ -43,8 +37,6 @@ func Test_Ref_Deref(t *testing.T) { t.Parallel() val := float64(3.14159) p := ptr.Ref(val) - d := ptr.Deref(p) - assert.Equal(t, val, d) assert.Equal(t, &val, p) }) } diff --git a/site/src/pages/WorkspaceSchedulePage/WorkspaceSchedulePage.tsx b/site/src/pages/WorkspaceSchedulePage/WorkspaceSchedulePage.tsx index 7f3cd4172c488..d777c8249b400 100644 --- a/site/src/pages/WorkspaceSchedulePage/WorkspaceSchedulePage.tsx +++ b/site/src/pages/WorkspaceSchedulePage/WorkspaceSchedulePage.tsx @@ -106,7 +106,7 @@ export const workspaceToInitialValues = (workspace: TypesGen.Workspace): Workspa saturday: false, startTime: "", timezone: "", - ttl: ttl, + ttl, } } @@ -133,7 +133,7 @@ export const workspaceToInitialValues = (workspace: TypesGen.Workspace): Workspa saturday: weeklyFlags[6], startTime: `${HH.padStart(2, "0")}:${mm.padStart(2, "0")}`, timezone, - ttl: ttl, + ttl, } } diff --git a/site/src/testHelpers/entities.ts b/site/src/testHelpers/entities.ts index 5d54fe970b540..0a89b12f2808d 100644 --- a/site/src/testHelpers/entities.ts +++ b/site/src/testHelpers/entities.ts @@ -164,7 +164,7 @@ export const MockWorkspace: TypesGen.Workspace = { owner_id: MockUser.id, owner_name: MockUser.username, autostart_schedule: MockWorkspaceAutostartEnabled.schedule, - ttl_ms: 2 * 60 * 60 * 1000 * 1_000_000, // 2 hours as nanoseconds + ttl_ms: 2 * 60 * 60 * 1000, // 2 hours as milliseconds latest_build: MockWorkspaceBuild, } From 1b37ad66151c9dea3a0b8f3d920463feb075fac6 Mon Sep 17 00:00:00 2001 From: johnstcn Date: Wed, 1 Jun 2022 20:19:02 +0000 Subject: [PATCH 6/8] update storybook --- .../WorkspaceSchedule.stories.tsx | 24 +++++++++++++++---- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/site/src/components/WorkspaceSchedule/WorkspaceSchedule.stories.tsx b/site/src/components/WorkspaceSchedule/WorkspaceSchedule.stories.tsx index 83477970b2d07..fe0bbac283317 100644 --- a/site/src/components/WorkspaceSchedule/WorkspaceSchedule.stories.tsx +++ b/site/src/components/WorkspaceSchedule/WorkspaceSchedule.stories.tsx @@ -19,6 +19,20 @@ export default { const Template: Story = (args) => +export const NoScheduleNoTTL = Template.bind({}) +NoScheduleNoTTL.args = { + workspace: { + ...Mocks.MockWorkspace, + + latest_build: { + ...Mocks.MockWorkspaceBuild, + transition: "stop", + }, + autostart_schedule: undefined, + ttl_ms: undefined, + }, +} + export const NoTTL = Template.bind({}) NoTTL.args = { workspace: { @@ -29,7 +43,7 @@ NoTTL.args = { // SEE: #1834 deadline: "0001-01-01T00:00:00Z", }, - ttl: undefined, + ttl_ms: undefined, }, } @@ -42,7 +56,7 @@ ShutdownSoon.args = { deadline: dayjs().add(ONE, "hour").utc().format(), transition: "start", }, - ttl: 2 * 60 * 60 * 1000 * 1_000_000, // 2 hours + ttl_ms: 2 * 60 * 60 * 1000 // 2 hours }, } @@ -56,7 +70,7 @@ ShutdownLong.args = { deadline: dayjs().add(SEVEN, "days").utc().format(), transition: "start", }, - ttl: 7 * 24 * 60 * 60 * 1000 * 1_000_000, // 7 days + ttl_ms: 7 * 24 * 60 * 60 * 1000 // 7 days }, } @@ -69,7 +83,7 @@ WorkspaceOffShort.args = { ...Mocks.MockWorkspaceBuild, transition: "stop", }, - ttl: 2 * 60 * 60 * 1000 * 1_000_000, // 2 hours + ttl_ms: 2 * 60 * 60 * 1000, // 2 hours }, } @@ -82,6 +96,6 @@ WorkspaceOffLong.args = { ...Mocks.MockWorkspaceBuild, transition: "stop", }, - ttl: 2 * 365 * 24 * 60 * 60 * 1000 * 1_000_000, // 2 years + ttl_ms: 2 * 365 * 24 * 60 * 60 * 1000, // 2 years }, } From b9b3edfa866419e271e01e2e77b7ad22410db72a Mon Sep 17 00:00:00 2001 From: johnstcn Date: Wed, 1 Jun 2022 20:28:58 +0000 Subject: [PATCH 7/8] make fmt --- .../WorkspaceSchedule/WorkspaceSchedule.stories.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/site/src/components/WorkspaceSchedule/WorkspaceSchedule.stories.tsx b/site/src/components/WorkspaceSchedule/WorkspaceSchedule.stories.tsx index fe0bbac283317..fa941cf88f516 100644 --- a/site/src/components/WorkspaceSchedule/WorkspaceSchedule.stories.tsx +++ b/site/src/components/WorkspaceSchedule/WorkspaceSchedule.stories.tsx @@ -56,7 +56,7 @@ ShutdownSoon.args = { deadline: dayjs().add(ONE, "hour").utc().format(), transition: "start", }, - ttl_ms: 2 * 60 * 60 * 1000 // 2 hours + ttl_ms: 2 * 60 * 60 * 1000, // 2 hours }, } @@ -70,7 +70,7 @@ ShutdownLong.args = { deadline: dayjs().add(SEVEN, "days").utc().format(), transition: "start", }, - ttl_ms: 7 * 24 * 60 * 60 * 1000 // 7 days + ttl_ms: 7 * 24 * 60 * 60 * 1000, // 7 days }, } From c6cbde254fbffbf379d7e7f3ea0911304f24db6e Mon Sep 17 00:00:00 2001 From: johnstcn Date: Thu, 2 Jun 2022 10:10:05 +0000 Subject: [PATCH 8/8] make fmt; make lint --- coderd/workspaces.go | 2 -- examples/templates/aws-linux/main.tf | 2 +- examples/templates/aws-windows/main.tf | 2 +- 3 files changed, 2 insertions(+), 4 deletions(-) diff --git a/coderd/workspaces.go b/coderd/workspaces.go index c28b641396cb3..43c39140a7e53 100644 --- a/coderd/workspaces.go +++ b/coderd/workspaces.go @@ -826,14 +826,12 @@ func convertWorkspaces(ctx context.Context, db database.Store, workspaces []data } return apiWorkspaces, nil } - func convertWorkspace( workspace database.Workspace, workspaceBuild database.WorkspaceBuild, job database.ProvisionerJob, template database.Template, owner database.User) codersdk.Workspace { - var autostartSchedule *string if workspace.AutostartSchedule.Valid { autostartSchedule = &workspace.AutostartSchedule.String diff --git a/examples/templates/aws-linux/main.tf b/examples/templates/aws-linux/main.tf index 30cbbbb94aa8a..2a9d625c2634e 100644 --- a/examples/templates/aws-linux/main.tf +++ b/examples/templates/aws-linux/main.tf @@ -33,7 +33,7 @@ variable "region" { description = "What region should your workspace live in?" default = "us-east-1" validation { - condition = contains([ + condition = contains([ "ap-northeast-1", "ap-northeast-2", "ap-northeast-3", diff --git a/examples/templates/aws-windows/main.tf b/examples/templates/aws-windows/main.tf index 4300e326d523b..1135977994bd8 100644 --- a/examples/templates/aws-windows/main.tf +++ b/examples/templates/aws-windows/main.tf @@ -30,7 +30,7 @@ variable "region" { description = "What region should your workspace live in?" default = "us-east-1" validation { - condition = contains([ + condition = contains([ "ap-northeast-1", "ap-northeast-2", "ap-northeast-3",