1
1
package cli
2
2
3
3
import (
4
- "errors"
5
4
"fmt"
6
5
"sort"
7
6
"time"
8
7
9
- "github.com/fatih/color"
10
- "github.com/manifoldco/promptui"
11
8
"github.com/spf13/cobra"
12
9
"golang.org/x/xerrors"
13
10
11
+ "github.com/coder/coder/cli/cliflag"
14
12
"github.com/coder/coder/cli/cliui"
15
13
"github.com/coder/coder/coderd/database"
16
14
"github.com/coder/coder/codersdk"
17
15
)
18
16
19
17
func workspaceCreate ()* cobra.Command {
20
18
var (
21
- templateName string
19
+ workspaceName string
22
20
)
23
21
cmd := & cobra.Command {
24
- Use :"create <name>" ,
25
- Args :cobra .ExactArgs (1 ),
22
+ Use :"create [template]" ,
26
23
Short :"Create a workspace from a template" ,
27
24
RunE :func (cmd * cobra.Command ,args []string )error {
28
25
client ,err := createClient (cmd )
@@ -34,9 +31,14 @@ func workspaceCreate() *cobra.Command {
34
31
return err
35
32
}
36
33
34
+ templateName := ""
35
+ if len (args )>= 1 {
36
+ templateName = args [0 ]
37
+ }
38
+
37
39
var template codersdk.Template
38
40
if templateName == "" {
39
- _ ,_ = fmt .Fprintln (cmd .OutOrStdout (),cliui .Styles .Wrap .Render ("Select a template:" ))
41
+ _ ,_ = fmt .Fprintln (cmd .OutOrStdout (),cliui .Styles .Wrap .Render ("Select a template below to preview the provisioned infrastructure :" ))
40
42
41
43
templateNames := []string {}
42
44
templateByName := map [string ]codersdk.Template {}
@@ -45,8 +47,16 @@ func workspaceCreate() *cobra.Command {
45
47
return err
46
48
}
47
49
for _ ,template := range templates {
48
- templateNames = append (templateNames ,template .Name )
49
- templateByName [template .Name ]= template
50
+ templateName := template .Name
51
+ if template .WorkspaceOwnerCount > 0 {
52
+ developerText := "developer"
53
+ if template .WorkspaceOwnerCount != 1 {
54
+ developerText = "developers"
55
+ }
56
+ templateName += cliui .Styles .Placeholder .Render (fmt .Sprintf (" (used by %d %s)" ,template .WorkspaceOwnerCount ,developerText ))
57
+ }
58
+ templateNames = append (templateNames ,templateName )
59
+ templateByName [templateName ]= template
50
60
}
51
61
sort .Slice (templateNames ,func (i ,j int )bool {
52
62
return templateByName [templateNames [i ]].WorkspaceOwnerCount > templateByName [templateNames [j ]].WorkspaceOwnerCount
@@ -70,10 +80,22 @@ func workspaceCreate() *cobra.Command {
70
80
}
71
81
}
72
82
73
- _ ,_ = fmt .Fprintln (cmd .OutOrStdout ())
74
- _ ,_ = fmt .Fprintln (cmd .OutOrStdout (),cliui .Styles .Prompt .String ()+ "Creating with the " + cliui .Styles .Field .Render (template .Name )+ " template..." )
83
+ if workspaceName == "" {
84
+ workspaceName ,err = cliui .Prompt (cmd , cliui.PromptOptions {
85
+ Text :"Specify a name for your workspace:" ,
86
+ Validate :func (workspaceName string )error {
87
+ _ ,err = client .WorkspaceByName (cmd .Context (),codersdk .Me ,workspaceName )
88
+ if err == nil {
89
+ return xerrors .Errorf ("A workspace already exists named %q!" ,workspaceName )
90
+ }
91
+ return nil
92
+ },
93
+ })
94
+ if err != nil {
95
+ return err
96
+ }
97
+ }
75
98
76
- workspaceName := args [0 ]
77
99
_ ,err = client .WorkspaceByName (cmd .Context (),codersdk .Me ,workspaceName )
78
100
if err == nil {
79
101
return xerrors .Errorf ("A workspace already exists named %q!" ,workspaceName )
@@ -95,10 +117,9 @@ func workspaceCreate() *cobra.Command {
95
117
continue
96
118
}
97
119
if ! printed {
98
- _ ,_ = fmt .Fprintln (cmd .OutOrStdout (),cliui .Styles .Paragraph .Render ("This template has customizable parameters! These can be changed after create, but may have unintended side effects (like data loss)." )+ "\r \n " )
120
+ _ ,_ = fmt .Fprintln (cmd .OutOrStdout (),cliui .Styles .Paragraph .Render ("This template has customizable parameters. Values can be changed after create, but may have unintended side effects (like data loss)." )+ "\r \n " )
99
121
printed = true
100
122
}
101
-
102
123
value ,err := cliui .ParameterSchema (cmd ,parameterSchema )
103
124
if err != nil {
104
125
return err
@@ -110,11 +131,8 @@ func workspaceCreate() *cobra.Command {
110
131
DestinationScheme :parameterSchema .DefaultDestinationScheme ,
111
132
})
112
133
}
113
- if printed {
114
- _ ,_ = fmt .Fprintln (cmd .OutOrStdout ())
115
- _ ,_ = fmt .Fprintln (cmd .OutOrStdout (),cliui .Styles .FocusedPrompt .String ()+ "Previewing resources..." )
116
- _ ,_ = fmt .Fprintln (cmd .OutOrStdout ())
117
- }
134
+ _ ,_ = fmt .Fprintln (cmd .OutOrStdout ())
135
+
118
136
resources ,err := client .TemplateVersionResources (cmd .Context (),templateVersion .ID )
119
137
if err != nil {
120
138
return err
@@ -123,20 +141,17 @@ func workspaceCreate() *cobra.Command {
123
141
WorkspaceName :workspaceName ,
124
142
// Since agent's haven't connected yet, hiding this makes more sense.
125
143
HideAgentState :true ,
144
+ Title :"Workspace Preview" ,
126
145
})
127
146
if err != nil {
128
147
return err
129
148
}
130
149
131
150
_ ,err = cliui .Prompt (cmd , cliui.PromptOptions {
132
- Text :fmt .Sprintf ("Create workspace %s?" ,color .HiCyanString (workspaceName )),
133
- Default :"yes" ,
151
+ Text :"Confirm create?" ,
134
152
IsConfirm :true ,
135
153
})
136
154
if err != nil {
137
- if errors .Is (err ,promptui .ErrAbort ) {
138
- return nil
139
- }
140
155
return err
141
156
}
142
157
@@ -149,29 +164,26 @@ func workspaceCreate() *cobra.Command {
149
164
if err != nil {
150
165
return err
151
166
}
152
- err = cliui .ProvisionerJob (cmd .Context (),cmd .OutOrStdout (), cliui.ProvisionerJobOptions {
153
- Fetch :func () (codersdk.ProvisionerJob ,error ) {
154
- build ,err := client .WorkspaceBuild (cmd .Context (),workspace .LatestBuild .ID )
155
- return build .Job ,err
156
- },
157
- Cancel :func ()error {
158
- return client .CancelWorkspaceBuild (cmd .Context (),workspace .LatestBuild .ID )
159
- },
160
- Logs :func () (<- chan codersdk.ProvisionerJobLog ,error ) {
161
- return client .WorkspaceBuildLogsAfter (cmd .Context (),workspace .LatestBuild .ID ,before )
162
- },
163
- })
167
+ err = cliui .WorkspaceBuild (cmd .Context (),cmd .OutOrStdout (),client ,workspace .LatestBuild .ID ,before )
168
+ if err != nil {
169
+ return err
170
+ }
171
+ resources ,err = client .WorkspaceResourcesByBuild (cmd .Context (),workspace .LatestBuild .ID )
164
172
if err != nil {
165
173
return err
166
174
}
167
- _ ,_ = fmt .Fprintf (cmd .OutOrStdout (),"\n The %s workspace has been created!\n \n " ,cliui .Styles .Keyword .Render (workspace .Name ))
168
- _ ,_ = fmt .Fprintln (cmd .OutOrStdout ()," " + cliui .Styles .Code .Render ("coder ssh " + workspace .Name ))
169
- _ ,_ = fmt .Fprintln (cmd .OutOrStdout ())
170
175
171
- return err
176
+ err = cliui .WorkspaceResources (cmd .OutOrStdout (),resources , cliui.WorkspaceResourcesOptions {
177
+ WorkspaceName :workspaceName ,
178
+ })
179
+ if err != nil {
180
+ return err
181
+ }
182
+ _ ,_ = fmt .Fprintf (cmd .OutOrStdout (),"The %s workspace has been created!\n " ,cliui .Styles .Keyword .Render (workspace .Name ))
183
+ return nil
172
184
},
173
185
}
174
- cmd .Flags (). StringVarP ( & templateName ,"template " ,"p " ,"" ,"Specify atemplate name." )
186
+ cliflag . StringVarP ( cmd .Flags (), & workspaceName ,"name " ,"n " ,"CODER_WORKSPACE_NAME " ,"" , " Specify aworkspace name." )
175
187
176
188
return cmd
177
189
}