diff --git a/pkg/cmd/codespace/create.go b/pkg/cmd/codespace/create.go index 41ad9af37..610c3a519 100644 --- a/pkg/cmd/codespace/create.go +++ b/pkg/cmd/codespace/create.go @@ -23,6 +23,40 @@ var ( DEFAULT_DEVCONTAINER_DEFINITIONS = []string{".devcontainer.json", ".devcontainer/devcontainer.json"} ) +type NullableDuration struct { + *time.Duration +} + +func (d *NullableDuration) String() string { + if d.Duration != nil { + return d.Duration.String() + } + + return "" +} + +func (d *NullableDuration) Set(str string) error { + duration, err := time.ParseDuration(str) + if err != nil { + return fmt.Errorf("error parsing duration: %w", err) + } + d.Duration = &duration + return nil +} + +func (d *NullableDuration) Type() string { + return "duration" +} + +func (d *NullableDuration) Minutes() *int { + if d.Duration != nil { + retentionMinutes := int(d.Duration.Minutes()) + return &retentionMinutes + } + + return nil +} + type createOptions struct { repo string branch string @@ -32,7 +66,7 @@ type createOptions struct { permissionsOptOut bool devContainerPath string idleTimeout time.Duration - retentionPeriod time.Duration + retentionPeriod NullableDuration } func newCreateCmd(app *App) *cobra.Command { @@ -54,7 +88,7 @@ func newCreateCmd(app *App) *cobra.Command { createCmd.Flags().BoolVarP(&opts.permissionsOptOut, "default-permissions", "", false, "do not prompt to accept additional permissions requested by the codespace") createCmd.Flags().BoolVarP(&opts.showStatus, "status", "s", false, "show status of post-create command and dotfiles") createCmd.Flags().DurationVar(&opts.idleTimeout, "idle-timeout", 0, "allowed inactivity before codespace is stopped, e.g. \"10m\", \"1h\"") - // createCmd.Flags().DurationVar(&opts.retentionPeriod, "retention-period", 0, "allowed time after going idle before codespace is automatically deleted (maximum 30 days), e.g. \"1h\", \"72h\"") + // createCmd.Flags().Var(&opts.retentionPeriod, "retention-period", "allowed time after shutting down before the codespace is automatically deleted (maximum 30 days), e.g. \"1h\", \"72h\"") createCmd.Flags().StringVar(&opts.devContainerPath, "devcontainer-path", "", "path to the devcontainer.json file to use when creating codespace") return createCmd @@ -178,8 +212,6 @@ func (a *App) Create(ctx context.Context, opts createOptions) error { return errors.New("there are no available machine types for this repository") } - retentionPeriod := int(opts.retentionPeriod.Minutes()) - createParams := &api.CreateCodespaceParams{ RepositoryID: repository.ID, Branch: branch, @@ -188,7 +220,7 @@ func (a *App) Create(ctx context.Context, opts createOptions) error { VSCSTarget: vscsTarget, VSCSTargetURL: vscsTargetUrl, IdleTimeoutMinutes: int(opts.idleTimeout.Minutes()), - RetentionPeriodMinutes: &retentionPeriod, + RetentionPeriodMinutes: opts.retentionPeriod.Minutes(), DevContainerPath: devContainerPath, PermissionsOptOut: opts.permissionsOptOut, } diff --git a/pkg/cmd/codespace/create_test.go b/pkg/cmd/codespace/create_test.go index 6e2325ac9..cc7ff3700 100644 --- a/pkg/cmd/codespace/create_test.go +++ b/pkg/cmd/codespace/create_test.go @@ -55,7 +55,7 @@ func TestApp_Create(t *testing.T) { return nil, fmt.Errorf("idle timeout minutes was %v", params.IdleTimeoutMinutes) } if *params.RetentionPeriodMinutes != 2880 { - return nil, fmt.Errorf("retention period minutes was %v", params.RetentionPeriodMinutes) + return nil, fmt.Errorf("retention period minutes expected 2880, was %v", params.RetentionPeriodMinutes) } return &api.Codespace{ Name: "monalisa-dotfiles-abcd1234", @@ -72,7 +72,7 @@ func TestApp_Create(t *testing.T) { machine: "GIGA", showStatus: false, idleTimeout: 30 * time.Minute, - retentionPeriod: 48 * time.Hour, + retentionPeriod: NullableDuration{durationPtr(48 * time.Hour)}, }, wantStdout: "monalisa-dotfiles-abcd1234\n", }, @@ -105,6 +105,9 @@ func TestApp_Create(t *testing.T) { if params.IdleTimeoutMinutes != 30 { return nil, fmt.Errorf("idle timeout minutes was %v", params.IdleTimeoutMinutes) } + if params.RetentionPeriodMinutes != nil { + return nil, fmt.Errorf("retention period minutes expected nil, was %v", params.RetentionPeriodMinutes) + } if params.DevContainerPath != ".devcontainer/foobar/devcontainer.json" { return nil, fmt.Errorf("got dev container path %q, want %q", params.DevContainerPath, ".devcontainer/foobar/devcontainer.json") } @@ -325,14 +328,20 @@ Alternatively, you can run "create" with the "--default-permissions" option to c apiClient: tt.fields.apiClient, } - if err := a.Create(context.Background(), tt.opts); err != nil && tt.wantErr != nil { + err := a.Create(context.Background(), tt.opts) + if err != nil && tt.wantErr != nil { assert.EqualError(t, err, tt.wantErr.Error()) } + if err != nil && tt.wantErr == nil { + t.Logf(err.Error()) + } if got := stdout.String(); got != tt.wantStdout { - t.Errorf("stdout = %v, want %v", got, tt.wantStdout) + t.Logf(t.Name()) + t.Errorf(" stdout = %v, want %v", got, tt.wantStdout) } if got := stderr.String(); got != tt.wantStderr { - t.Errorf("stderr = %v, want %v", got, tt.wantStderr) + t.Logf(t.Name()) + t.Errorf(" stderr = %v, want %v", got, tt.wantStderr) } }) } @@ -375,3 +384,7 @@ func TestBuildDisplayName(t *testing.T) { }) } } + +func durationPtr(d time.Duration) *time.Duration { + return &d +}