Skip to content

Commit ee730b3

Browse files
committed
refactor: add and use a util/ptr helper package
1 parent 1af3630 commit ee730b3

File tree

12 files changed

+159
-51
lines changed

12 files changed

+159
-51
lines changed

cli/autostart_test.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111

1212
"github.com/coder/coder/cli/clitest"
1313
"github.com/coder/coder/coderd/coderdtest"
14+
"github.com/coder/coder/coderd/util/ptr"
1415
"github.com/coder/coder/codersdk"
1516
)
1617

@@ -34,7 +35,7 @@ func TestAutostart(t *testing.T) {
3435
)
3536

3637
err := client.UpdateWorkspaceAutostart(ctx, workspace.ID, codersdk.UpdateWorkspaceAutostartRequest{
37-
Schedule: ptr(sched),
38+
Schedule: ptr.Ref(sched),
3839
})
3940
require.NoError(t, err)
4041

cli/create.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
"github.com/coder/coder/cli/cliflag"
1212
"github.com/coder/coder/cli/cliui"
1313
"github.com/coder/coder/coderd/autobuild/schedule"
14+
"github.com/coder/coder/coderd/util/ptr"
1415
"github.com/coder/coder/codersdk"
1516
)
1617

@@ -222,12 +223,11 @@ func create() *cobra.Command {
222223
return err
223224
}
224225

225-
ttlMillis := ttl.Milliseconds()
226226
workspace, err := client.CreateWorkspace(cmd.Context(), organization.ID, codersdk.CreateWorkspaceRequest{
227227
TemplateID: template.ID,
228228
Name: workspaceName,
229229
AutostartSchedule: &schedSpec,
230-
TTLMillis: &ttlMillis,
230+
TTLMillis: ptr.Ref(ttl.Milliseconds()),
231231
ParameterValues: parameters,
232232
})
233233
if err != nil {

cli/list.go

+3-2
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111

1212
"github.com/coder/coder/cli/cliui"
1313
"github.com/coder/coder/coderd/autobuild/schedule"
14+
"github.com/coder/coder/coderd/util/ptr"
1415
"github.com/coder/coder/codersdk"
1516
)
1617

@@ -87,14 +88,14 @@ func list() *cobra.Command {
8788

8889
duration := time.Now().UTC().Sub(workspace.LatestBuild.Job.CreatedAt).Truncate(time.Second)
8990
autostartDisplay := "-"
90-
if workspace.AutostartSchedule != nil && *workspace.AutostartSchedule != "" {
91+
if !ptr.NilOrEmpty(workspace.AutostartSchedule) {
9192
if sched, err := schedule.Weekly(*workspace.AutostartSchedule); err == nil {
9293
autostartDisplay = sched.Cron()
9394
}
9495
}
9596

9697
autostopDisplay := "-"
97-
if workspace.TTLMillis != nil && *workspace.TTLMillis > 0 {
98+
if !ptr.NilOrZero(workspace.TTLMillis) {
9899
dur := time.Duration(*workspace.TTLMillis) * time.Millisecond
99100
autostopDisplay = durationDisplay(dur)
100101
if has, ext := hasExtension(workspace); has {

cli/root_test.go

-4
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,3 @@ func TestRoot(t *testing.T) {
2020
require.Contains(t, errStr, "Run 'coder delete --help' for usage.")
2121
})
2222
}
23-
24-
func ptr[T any](v T) *T {
25-
return &v
26-
}

cli/ssh.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import (
2222
"github.com/coder/coder/cli/cliflag"
2323
"github.com/coder/coder/cli/cliui"
2424
"github.com/coder/coder/coderd/autobuild/notify"
25+
"github.com/coder/coder/coderd/util/ptr"
2526
"github.com/coder/coder/codersdk"
2627
"github.com/coder/coder/cryptorand"
2728
)
@@ -290,7 +291,7 @@ func notifyCondition(ctx context.Context, client *codersdk.Client, workspaceID u
290291
return time.Time{}, nil
291292
}
292293

293-
if ws.TTLMillis == nil || *ws.TTLMillis == 0 {
294+
if ptr.NilOrZero(ws.TTLMillis) {
294295
return time.Time{}, nil
295296
}
296297

cli/ttl_test.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111

1212
"github.com/coder/coder/cli/clitest"
1313
"github.com/coder/coder/coderd/coderdtest"
14+
"github.com/coder/coder/coderd/util/ptr"
1415
"github.com/coder/coder/codersdk"
1516
)
1617

@@ -34,7 +35,7 @@ func TestTTL(t *testing.T) {
3435
)
3536

3637
err := client.UpdateWorkspaceTTL(ctx, workspace.ID, codersdk.UpdateWorkspaceTTLRequest{
37-
TTLMillis: ptr(ttl.Milliseconds()),
38+
TTLMillis: ptr.Ref(ttl.Milliseconds()),
3839
})
3940
require.NoError(t, err)
4041

coderd/autobuild/executor/lifecycle_executor_test.go

+6-9
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import (
1414
"github.com/coder/coder/coderd/autobuild/schedule"
1515
"github.com/coder/coder/coderd/coderdtest"
1616
"github.com/coder/coder/coderd/database"
17+
"github.com/coder/coder/coderd/util/ptr"
1718
"github.com/coder/coder/codersdk"
1819

1920
"github.com/google/uuid"
@@ -44,7 +45,7 @@ func TestExecutorAutostartOK(t *testing.T) {
4445
sched, err := schedule.Weekly("* * * * *")
4546
require.NoError(t, err)
4647
require.NoError(t, client.UpdateWorkspaceAutostart(ctx, workspace.ID, codersdk.UpdateWorkspaceAutostartRequest{
47-
Schedule: ptr(sched.String()),
48+
Schedule: ptr.Ref(sched.String()),
4849
}))
4950

5051
// When: the autobuild executor ticks
@@ -95,7 +96,7 @@ func TestExecutorAutostartTemplateUpdated(t *testing.T) {
9596
sched, err := schedule.Weekly("* * * * *")
9697
require.NoError(t, err)
9798
require.NoError(t, client.UpdateWorkspaceAutostart(ctx, workspace.ID, codersdk.UpdateWorkspaceAutostartRequest{
98-
Schedule: ptr(sched.String()),
99+
Schedule: ptr.Ref(sched.String()),
99100
}))
100101

101102
// When: the autobuild executor ticks
@@ -138,7 +139,7 @@ func TestExecutorAutostartAlreadyRunning(t *testing.T) {
138139
sched, err := schedule.Weekly("* * * * *")
139140
require.NoError(t, err)
140141
require.NoError(t, client.UpdateWorkspaceAutostart(ctx, workspace.ID, codersdk.UpdateWorkspaceAutostartRequest{
141-
Schedule: ptr(sched.String()),
142+
Schedule: ptr.Ref(sched.String()),
142143
}))
143144

144145
// When: the autobuild executor ticks
@@ -359,7 +360,7 @@ func TestExecutorWorkspaceDeleted(t *testing.T) {
359360
sched, err := schedule.Weekly("* * * * *")
360361
require.NoError(t, err)
361362
require.NoError(t, client.UpdateWorkspaceAutostart(ctx, workspace.ID, codersdk.UpdateWorkspaceAutostartRequest{
362-
Schedule: ptr(sched.String()),
363+
Schedule: ptr.Ref(sched.String()),
363364
}))
364365

365366
// Given: workspace is deleted
@@ -402,7 +403,7 @@ func TestExecutorWorkspaceAutostartTooEarly(t *testing.T) {
402403
sched, err := schedule.Weekly(futureTimeCron)
403404
require.NoError(t, err)
404405
require.NoError(t, client.UpdateWorkspaceAutostart(ctx, workspace.ID, codersdk.UpdateWorkspaceAutostartRequest{
405-
Schedule: ptr(sched.String()),
406+
Schedule: ptr.Ref(sched.String()),
406407
}))
407408

408409
// When: the autobuild executor ticks
@@ -572,10 +573,6 @@ func mustWorkspace(t *testing.T, client *codersdk.Client, workspaceID uuid.UUID)
572573
return ws
573574
}
574575

575-
func ptr[T any](v T) *T {
576-
return &v
577-
}
578-
579576
func TestMain(m *testing.M) {
580577
goleak.VerifyTestMain(m)
581578
}

coderd/coderdtest/coderdtest.go

+3-6
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import (
2626
"time"
2727

2828
"github.com/coder/coder/coderd/rbac"
29+
"github.com/coder/coder/coderd/util/ptr"
2930

3031
"cloud.google.com/go/compute/metadata"
3132
"github.com/fullsailor/pkcs7"
@@ -399,8 +400,8 @@ func CreateWorkspace(t *testing.T, client *codersdk.Client, organization uuid.UU
399400
req := codersdk.CreateWorkspaceRequest{
400401
TemplateID: templateID,
401402
Name: randomUsername(),
402-
AutostartSchedule: ptr("CRON_TZ=US/Central * * * * *"),
403-
TTLMillis: ptr((8 * time.Hour).Milliseconds()),
403+
AutostartSchedule: ptr.Ref("CRON_TZ=US/Central * * * * *"),
404+
TTLMillis: ptr.Ref((8 * time.Hour).Milliseconds()),
404405
}
405406
for _, mutator := range mutators {
406407
mutator(&req)
@@ -602,7 +603,3 @@ type roundTripper func(req *http.Request) (*http.Response, error)
602603
func (r roundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
603604
return r(req)
604605
}
605-
606-
func ptr[T any](x T) *T {
607-
return &x
608-
}

coderd/util/ptr/ptr.go

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// Package ptr contains some utility methods related to pointers.
2+
package ptr
3+
4+
import "golang.org/x/exp/constraints"
5+
6+
type number interface {
7+
constraints.Integer | constraints.Float
8+
}
9+
10+
// Ref returns a reference to v.
11+
func Ref[T any](v T) *T {
12+
return &v
13+
}
14+
15+
// Deref dereferences v. Opposite of Ptr.
16+
func Deref[T any](v *T) T {
17+
return *v
18+
}
19+
20+
// NilOrEmpty returns true if s is nil or the empty string.
21+
func NilOrEmpty(s *string) bool {
22+
return s == nil || *s == ""
23+
}
24+
25+
// NilOrZero returns true if v is nil or 0.
26+
func NilOrZero[T number](v *T) bool {
27+
return v == nil || *v == 0
28+
}

coderd/util/ptr/ptr_test.go

+89
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
package ptr_test
2+
3+
import (
4+
"testing"
5+
"time"
6+
7+
"github.com/stretchr/testify/assert"
8+
9+
"github.com/coder/coder/coderd/util/ptr"
10+
)
11+
12+
func Test_Ref_Deref(t *testing.T) {
13+
t.Parallel()
14+
15+
t.Run("String", func(t *testing.T) {
16+
t.Parallel()
17+
val := "test"
18+
p := ptr.Ref(val)
19+
d := ptr.Deref(p)
20+
assert.Equal(t, val, d)
21+
assert.Equal(t, &val, p)
22+
})
23+
24+
t.Run("Bool", func(t *testing.T) {
25+
t.Parallel()
26+
val := true
27+
p := ptr.Ref(val)
28+
d := ptr.Deref(p)
29+
assert.Equal(t, val, d)
30+
assert.Equal(t, &val, p)
31+
})
32+
33+
t.Run("Int64", func(t *testing.T) {
34+
t.Parallel()
35+
val := int64(42)
36+
p := ptr.Ref(val)
37+
d := ptr.Deref(p)
38+
assert.Equal(t, val, d)
39+
assert.Equal(t, &val, p)
40+
})
41+
42+
t.Run("Float64", func(t *testing.T) {
43+
t.Parallel()
44+
val := float64(3.14159)
45+
p := ptr.Ref(val)
46+
d := ptr.Deref(p)
47+
assert.Equal(t, val, d)
48+
assert.Equal(t, &val, p)
49+
})
50+
}
51+
52+
func Test_NilOrEmpty(t *testing.T) {
53+
t.Parallel()
54+
nilString := (*string)(nil)
55+
emptyString := ""
56+
nonEmptyString := "hi"
57+
58+
assert.True(t, ptr.NilOrEmpty(nilString))
59+
assert.True(t, ptr.NilOrEmpty(&emptyString))
60+
assert.False(t, ptr.NilOrEmpty(&nonEmptyString))
61+
}
62+
63+
func Test_NilOrZero(t *testing.T) {
64+
t.Parallel()
65+
66+
nilInt64 := (*int64)(nil)
67+
nilFloat64 := (*float64)(nil)
68+
nilDuration := (*time.Duration)(nil)
69+
70+
zeroInt64 := int64(0)
71+
zeroFloat64 := float64(0.0)
72+
zeroDuration := time.Duration(0)
73+
74+
nonZeroInt64 := int64(1)
75+
nonZeroFloat64 := float64(3.14159)
76+
nonZeroDuration := time.Hour
77+
78+
assert.True(t, ptr.NilOrZero(nilInt64))
79+
assert.True(t, ptr.NilOrZero(nilFloat64))
80+
assert.True(t, ptr.NilOrZero(nilDuration))
81+
82+
assert.True(t, ptr.NilOrZero(&zeroInt64))
83+
assert.True(t, ptr.NilOrZero(&zeroFloat64))
84+
assert.True(t, ptr.NilOrZero(&zeroDuration))
85+
86+
assert.False(t, ptr.NilOrZero(&nonZeroInt64))
87+
assert.False(t, ptr.NilOrZero(&nonZeroFloat64))
88+
assert.False(t, ptr.NilOrZero(&nonZeroDuration))
89+
}

coderd/workspaces.go

+3-3
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import (
2525
"github.com/coder/coder/coderd/httpapi"
2626
"github.com/coder/coder/coderd/httpmw"
2727
"github.com/coder/coder/coderd/rbac"
28+
"github.com/coder/coder/coderd/util/ptr"
2829
"github.com/coder/coder/codersdk"
2930
)
3031

@@ -865,12 +866,11 @@ func convertWorkspaceTTLMillis(i sql.NullInt64) *int64 {
865866
}
866867

867868
func validWorkspaceTTLMillis(millis *int64) (sql.NullInt64, error) {
868-
if millis == nil {
869+
if ptr.NilOrZero(millis) {
869870
return sql.NullInt64{}, nil
870871
}
871872

872873
dur := time.Duration(*millis) * time.Millisecond
873-
874874
truncated := dur.Truncate(time.Minute)
875875
if truncated < time.Minute {
876876
return sql.NullInt64{}, xerrors.New("ttl must be at least one minute")
@@ -909,7 +909,7 @@ func validWorkspaceDeadline(old, new time.Time) error {
909909
}
910910

911911
func validWorkspaceSchedule(s *string) (sql.NullString, error) {
912-
if s == nil || *s == "" {
912+
if ptr.NilOrEmpty(s) {
913913
return sql.NullString{}, nil
914914
}
915915

0 commit comments

Comments
 (0)