@@ -18,11 +18,12 @@ import (
1818
1919func (r * RootCmd )create ()* clibase.Cmd {
2020var (
21- richParameterFile string
22- templateName string
23- startAt string
24- stopAfter time.Duration
25- workspaceName string
21+ templateName string
22+ startAt string
23+ stopAfter time.Duration
24+ workspaceName string
25+
26+ parameterFlags workspaceParameterFlags
2627)
2728client := new (codersdk.Client )
2829cmd := & clibase.Cmd {
@@ -129,10 +130,18 @@ func (r *RootCmd) create() *clibase.Cmd {
129130schedSpec = ptr .Ref (sched .String ())
130131}
131132
132- buildParams ,err := prepWorkspaceBuild (inv ,client ,prepWorkspaceBuildArgs {
133- Template :template ,
134- RichParameterFile :richParameterFile ,
135- NewWorkspaceName :workspaceName ,
133+ cliRichParameters ,err := asWorkspaceBuildParameters (parameterFlags .richParameters )
134+ if err != nil {
135+ return xerrors .Errorf ("can't parse given parameter values: %w" ,err )
136+ }
137+
138+ richParameters ,err := prepWorkspaceBuild (inv ,client ,prepWorkspaceBuildArgs {
139+ Action :WorkspaceCreate ,
140+ Template :template ,
141+ NewWorkspaceName :workspaceName ,
142+
143+ RichParameterFile :parameterFlags .richParameterFile ,
144+ RichParameters :cliRichParameters ,
136145})
137146if err != nil {
138147return xerrors .Errorf ("prepare build: %w" ,err )
@@ -156,7 +165,7 @@ func (r *RootCmd) create() *clibase.Cmd {
156165Name :workspaceName ,
157166AutostartSchedule :schedSpec ,
158167TTLMillis :ttlMillis ,
159- RichParameterValues :buildParams . richParameters ,
168+ RichParameterValues :richParameters ,
160169})
161170if err != nil {
162171return xerrors .Errorf ("create workspace: %w" ,err )
@@ -179,12 +188,6 @@ func (r *RootCmd) create() *clibase.Cmd {
179188Description :"Specify a template name." ,
180189Value :clibase .StringOf (& templateName ),
181190},
182- clibase.Option {
183- Flag :"rich-parameter-file" ,
184- Env :"CODER_RICH_PARAMETER_FILE" ,
185- Description :"Specify a file path with values for rich parameters defined in the template." ,
186- Value :clibase .StringOf (& richParameterFile ),
187- },
188191clibase.Option {
189192Flag :"start-at" ,
190193Env :"CODER_WORKSPACE_START_AT" ,
@@ -199,99 +202,59 @@ func (r *RootCmd) create() *clibase.Cmd {
199202},
200203cliui .SkipPromptOption (),
201204)
205+ cmd .Options = append (cmd .Options ,parameterFlags .cliParameters ()... )
202206return cmd
203207}
204208
205209type prepWorkspaceBuildArgs struct {
206- Template codersdk. Template
207- ExistingRichParams [] codersdk.WorkspaceBuildParameter
208- RichParameterFile string
209- NewWorkspaceName string
210-
211- UpdateWorkspace bool
212- BuildOptions bool
213- WorkspaceID uuid. UUID
214- }
210+ Action WorkspaceCLIAction
211+ Template codersdk.Template
212+ NewWorkspaceName string
213+ WorkspaceID uuid. UUID
214+
215+ LastBuildParameters []codersdk. WorkspaceBuildParameter
216+
217+ PromptBuildOptions bool
218+ BuildOptions []codersdk. WorkspaceBuildParameter
215219
216- type buildParameters struct {
217- // Rich parameters stores values for build parameters annotated with description, icon, type, etc.
218- richParameters []codersdk. WorkspaceBuildParameter
220+ PromptRichParameters bool
221+ RichParameters []codersdk. WorkspaceBuildParameter
222+ RichParameterFile string
219223}
220224
221225// prepWorkspaceBuild will ensure a workspace build will succeed on the latest template version.
222- // Any missing params will be prompted to the user. It supportslegacy and rich parameters.
223- func prepWorkspaceBuild (inv * clibase.Invocation ,client * codersdk.Client ,args prepWorkspaceBuildArgs ) (* buildParameters ,error ) {
226+ // Any missing params will be prompted to the user. It supports rich parameters.
227+ func prepWorkspaceBuild (inv * clibase.Invocation ,client * codersdk.Client ,args prepWorkspaceBuildArgs ) ([]codersdk. WorkspaceBuildParameter ,error ) {
224228ctx := inv .Context ()
225229
226230templateVersion ,err := client .TemplateVersion (ctx ,args .Template .ActiveVersionID )
227231if err != nil {
228- return nil ,err
232+ return nil ,xerrors . Errorf ( "get template version: %w" , err )
229233}
230234
231- // Rich parameters
232235templateVersionParameters ,err := client .TemplateVersionRichParameters (inv .Context (),templateVersion .ID )
233236if err != nil {
234237return nil ,xerrors .Errorf ("get template version rich parameters: %w" ,err )
235238}
236239
237- parameterMapFromFile := map [string ]string {}
238- useParamFile := false
240+ parameterFile := map [string ]string {}
239241if args .RichParameterFile != "" {
240- useParamFile = true
241- _ ,_ = fmt .Fprintln (inv .Stdout ,cliui .DefaultStyles .Paragraph .Render ("Attempting to read the variables from the rich parameter file." )+ "\r \n " )
242- parameterMapFromFile ,err = createParameterMapFromFile (args .RichParameterFile )
243- if err != nil {
244- return nil ,err
245- }
246- }
247- disclaimerPrinted := false
248- richParameters := make ([]codersdk.WorkspaceBuildParameter ,0 )
249- PromptRichParamLoop:
250- for _ ,templateVersionParameter := range templateVersionParameters {
251- if ! args .BuildOptions && templateVersionParameter .Ephemeral {
252- continue
253- }
254-
255- if ! disclaimerPrinted {
256- _ ,_ = fmt .Fprintln (inv .Stdout ,cliui .DefaultStyles .Paragraph .Render ("This template has customizable parameters. Values can be changed after create, but may have unintended side effects (like data loss)." )+ "\r \n " )
257- disclaimerPrinted = true
258- }
259-
260- // Param file is all or nothing
261- if ! useParamFile && ! templateVersionParameter .Ephemeral {
262- for _ ,e := range args .ExistingRichParams {
263- if e .Name == templateVersionParameter .Name {
264- // If the param already exists, we do not need to prompt it again.
265- // The workspace scope will reuse params for each build.
266- continue PromptRichParamLoop
267- }
268- }
269- }
270-
271- if args .UpdateWorkspace && ! templateVersionParameter .Mutable {
272- // Check if the immutable parameter was used in the previous build. If so, then it isn't a fresh one
273- // and the user should be warned.
274- exists ,err := workspaceBuildParameterExists (ctx ,client ,args .WorkspaceID ,templateVersionParameter )
275- if err != nil {
276- return nil ,err
277- }
278-
279- if exists {
280- _ ,_ = fmt .Fprintln (inv .Stdout ,cliui .DefaultStyles .Warn .Render (fmt .Sprintf (`Parameter %q is not mutable, so can't be customized after workspace creation.` ,templateVersionParameter .Name )))
281- continue
282- }
283- }
284-
285- parameterValue ,err := getWorkspaceBuildParameterValueFromMapOrInput (inv ,parameterMapFromFile ,templateVersionParameter )
242+ parameterFile ,err = parseParameterMapFile (args .RichParameterFile )
286243if err != nil {
287- return nil ,err
244+ return nil ,xerrors . Errorf ( "can't parse parameter map file: %w" , err )
288245}
289-
290- richParameters = append (richParameters ,* parameterValue )
291246}
292247
293- if disclaimerPrinted {
294- _ ,_ = fmt .Fprintln (inv .Stdout )
248+ resolver := new (ParameterResolver ).
249+ WithLastBuildParameters (args .LastBuildParameters ).
250+ WithPromptBuildOptions (args .PromptBuildOptions ).
251+ WithBuildOptions (args .BuildOptions ).
252+ WithPromptRichParameters (args .PromptRichParameters ).
253+ WithRichParameters (args .RichParameters ).
254+ WithRichParametersFile (parameterFile )
255+ buildParameters ,err := resolver .Resolve (inv ,args .Action ,templateVersionParameters )
256+ if err != nil {
257+ return nil ,err
295258}
296259
297260err = cliui .GitAuth (ctx ,inv .Stdout , cliui.GitAuthOptions {
@@ -306,7 +269,7 @@ PromptRichParamLoop:
306269// Run a dry-run with the given parameters to check correctness
307270dryRun ,err := client .CreateTemplateVersionDryRun (inv .Context (),templateVersion .ID , codersdk.CreateTemplateVersionDryRunRequest {
308271WorkspaceName :args .NewWorkspaceName ,
309- RichParameterValues :richParameters ,
272+ RichParameterValues :buildParameters ,
310273})
311274if err != nil {
312275return nil ,xerrors .Errorf ("begin workspace dry-run: %w" ,err )
@@ -346,21 +309,5 @@ PromptRichParamLoop:
346309return nil ,xerrors .Errorf ("get resources: %w" ,err )
347310}
348311
349- return & buildParameters {
350- richParameters :richParameters ,
351- },nil
352- }
353-
354- func workspaceBuildParameterExists (ctx context.Context ,client * codersdk.Client ,workspaceID uuid.UUID ,templateVersionParameter codersdk.TemplateVersionParameter ) (bool ,error ) {
355- lastBuildParameters ,err := client .WorkspaceBuildParameters (ctx ,workspaceID )
356- if err != nil {
357- return false ,xerrors .Errorf ("can't fetch last workspace build parameters: %w" ,err )
358- }
359-
360- for _ ,p := range lastBuildParameters {
361- if p .Name == templateVersionParameter .Name {
362- return true ,nil
363- }
364- }
365- return false ,nil
312+ return buildParameters ,nil
366313}