1
1
package cli
2
2
3
3
import (
4
+ "context"
4
5
"fmt"
6
+ "io"
5
7
"strconv"
6
8
"time"
7
9
8
- "github.com/google/uuid"
9
-
10
10
"github.com/coder/pretty"
11
11
12
12
"github.com/coder/coder/v2/cli/clibase"
@@ -31,57 +31,62 @@ type workspaceListRow struct {
31
31
LastBuilt string `json:"-" table:"last built"`
32
32
Outdated bool `json:"-" table:"outdated"`
33
33
StartsAt string `json:"-" table:"starts at"`
34
+ StartsNext string `json:"-" table:"starts next"`
34
35
StopsAfter string `json:"-" table:"stops after"`
36
+ StopsNext string `json:"-" table:"stops next"`
35
37
DailyCost string `json:"-" table:"daily cost"`
36
38
}
37
39
38
- func workspaceListRowFromWorkspace (now time.Time , usersByID map [uuid. UUID ]codersdk. User , workspace codersdk.Workspace ) workspaceListRow {
40
+ func workspaceListRowFromWorkspace (now time.Time , workspace codersdk.Workspace ) workspaceListRow {
39
41
status := codersdk .WorkspaceDisplayStatus (workspace .LatestBuild .Job .Status , workspace .LatestBuild .Transition )
40
42
41
43
lastBuilt := now .UTC ().Sub (workspace .LatestBuild .Job .CreatedAt ).Truncate (time .Second )
42
44
autostartDisplay := "-"
45
+ nextStartDisplay := "-"
43
46
if ! ptr .NilOrEmpty (workspace .AutostartSchedule ) {
44
47
if sched , err := cron .Weekly (* workspace .AutostartSchedule ); err == nil {
45
48
autostartDisplay = fmt .Sprintf ("%s %s (%s)" , sched .Time (), sched .DaysOfWeek (), sched .Location ())
49
+ nextStartDisplay = relative (sched .Next (now ).Sub (now ))
46
50
}
47
51
}
48
52
49
53
autostopDisplay := "-"
54
+ nextStopDisplay := "-"
50
55
if ! ptr .NilOrZero (workspace .TTLMillis ) {
51
56
dur := time .Duration (* workspace .TTLMillis ) * time .Millisecond
52
57
autostopDisplay = durationDisplay (dur )
53
58
if ! workspace .LatestBuild .Deadline .IsZero () && workspace .LatestBuild .Deadline .Time .After (now ) && status == "Running" {
54
59
remaining := time .Until (workspace .LatestBuild .Deadline .Time )
55
- autostopDisplay = fmt .Sprintf ("%s (%s)" , autostopDisplay , relative (remaining ))
60
+ nextStopDisplay = fmt .Sprintf ("%s (%s)" , autostopDisplay , relative (remaining ))
56
61
}
57
62
}
58
63
59
64
healthy := ""
60
65
if status == "Starting" || status == "Started" {
61
66
healthy = strconv .FormatBool (workspace .Health .Healthy )
62
67
}
63
- user := usersByID [workspace .OwnerID ]
64
68
return workspaceListRow {
65
69
Workspace : workspace ,
66
- WorkspaceName : user . Username + "/" + workspace .Name ,
70
+ WorkspaceName : workspace . OwnerName + "/" + workspace .Name ,
67
71
Template : workspace .TemplateName ,
68
72
Status : status ,
69
73
Healthy : healthy ,
70
74
LastBuilt : durationDisplay (lastBuilt ),
71
75
Outdated : workspace .Outdated ,
72
76
StartsAt : autostartDisplay ,
77
+ StartsNext : nextStartDisplay ,
73
78
StopsAfter : autostopDisplay ,
79
+ StopsNext : nextStopDisplay ,
74
80
DailyCost : strconv .Itoa (int (workspace .LatestBuild .DailyCost )),
75
81
}
76
82
}
77
83
78
84
func (r * RootCmd ) list () * clibase.Cmd {
79
85
var (
80
- all bool
81
- defaultQuery = "owner:me"
82
- searchQuery string
83
- displayWorkspaces []workspaceListRow
84
- formatter = cliui .NewOutputFormatter (
86
+ all bool
87
+ defaultQuery = "owner:me"
88
+ searchQuery string
89
+ formatter = cliui .NewOutputFormatter (
85
90
cliui .TableFormat (
86
91
[]workspaceListRow {},
87
92
[]string {
@@ -109,48 +114,17 @@ func (r *RootCmd) list() *clibase.Cmd {
109
114
r .InitClient (client ),
110
115
),
111
116
Handler : func (inv * clibase.Invocation ) error {
112
- filter := codersdk.WorkspaceFilter {
113
- FilterQuery : searchQuery ,
114
- }
115
- if all && searchQuery == defaultQuery {
116
- filter .FilterQuery = ""
117
- }
118
-
119
- res , err := client .Workspaces (inv .Context (), filter )
120
- if err != nil {
121
- return err
122
- }
123
- if len (res .Workspaces ) == 0 {
124
- pretty .Fprintf (inv .Stderr , cliui .DefaultStyles .Prompt , "No workspaces found! Create one:\n " )
125
- _ , _ = fmt .Fprintln (inv .Stderr )
126
- _ , _ = fmt .Fprintln (inv .Stderr , " " + pretty .Sprint (cliui .DefaultStyles .Code , "coder create <name>" ))
127
- _ , _ = fmt .Fprintln (inv .Stderr )
128
- return nil
129
- }
130
-
131
- userRes , err := client .Users (inv .Context (), codersdk.UsersRequest {})
132
- if err != nil {
133
- return err
134
- }
135
-
136
- usersByID := map [uuid.UUID ]codersdk.User {}
137
- for _ , user := range userRes .Users {
138
- usersByID [user .ID ] = user
139
- }
140
-
141
- now := time .Now ()
142
- displayWorkspaces = make ([]workspaceListRow , len (res .Workspaces ))
143
- for i , workspace := range res .Workspaces {
144
- displayWorkspaces [i ] = workspaceListRowFromWorkspace (now , usersByID , workspace )
145
- }
146
-
147
- out , err := formatter .Format (inv .Context (), displayWorkspaces )
148
- if err != nil {
149
- return err
150
- }
151
-
152
- _ , err = fmt .Fprintln (inv .Stdout , out )
153
- return err
117
+ return handleList (
118
+ inv .Context (),
119
+ handleListArgs {
120
+ formatter : formatter ,
121
+ client : client ,
122
+ searchQuery : searchQuery ,
123
+ all : all ,
124
+ stdout : inv .Stdout ,
125
+ stderr : inv .Stderr ,
126
+ },
127
+ )
154
128
},
155
129
}
156
130
cmd .Options = clibase.OptionSet {
@@ -172,3 +146,46 @@ func (r *RootCmd) list() *clibase.Cmd {
172
146
formatter .AttachOptions (& cmd .Options )
173
147
return cmd
174
148
}
149
+
150
+ type handleListArgs struct {
151
+ formatter * cliui.OutputFormatter
152
+ client * codersdk.Client
153
+ searchQuery string
154
+ all bool
155
+ stdout , stderr io.Writer
156
+ }
157
+
158
+ func handleList (ctx context.Context , args handleListArgs ) error {
159
+ filter := codersdk.WorkspaceFilter {
160
+ FilterQuery : args .searchQuery ,
161
+ }
162
+ if args .all && args .searchQuery == "owner:me" {
163
+ filter .FilterQuery = ""
164
+ }
165
+
166
+ res , err := args .client .Workspaces (ctx , filter )
167
+ if err != nil {
168
+ return err
169
+ }
170
+ if len (res .Workspaces ) == 0 {
171
+ pretty .Fprintf (args .stderr , cliui .DefaultStyles .Prompt , "No workspaces found! Create one:\n " )
172
+ _ , _ = fmt .Fprintln (args .stderr )
173
+ _ , _ = fmt .Fprintln (args .stderr , " " + pretty .Sprint (cliui .DefaultStyles .Code , "coder create <name>" ))
174
+ _ , _ = fmt .Fprintln (args .stderr )
175
+ return nil
176
+ }
177
+
178
+ now := time .Now ()
179
+ displayWorkspaces := make ([]workspaceListRow , len (res .Workspaces ))
180
+ for i , workspace := range res .Workspaces {
181
+ displayWorkspaces [i ] = workspaceListRowFromWorkspace (now , workspace )
182
+ }
183
+
184
+ out , err := args .formatter .Format (ctx , displayWorkspaces )
185
+ if err != nil {
186
+ return err
187
+ }
188
+
189
+ _ , err = fmt .Fprintln (args .stdout , out )
190
+ return err
191
+ }
0 commit comments