Skip to content

Commit 4e7331a

Browse files
authored
feat(cli): support description in create and presets list CLI commands (#19079)
## Description This PR improves the `coder templates presets` and `coder create` CLI commands to include preset descriptions. ## Changes * Added a `description` column to the `coder templates presets list` CLI command. * Fixed the `-o json` output for `coder templates presets list` to correctly include and format data. * Updated the `coder create` CLI command to display the preset's description in the selection menu. Follow-up from: * #18910 * #18912 * #18977
1 parent 415273f commit 4e7331a

File tree

6 files changed

+105
-23
lines changed

6 files changed

+105
-23
lines changed

cli/create.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -472,7 +472,12 @@ func promptPresetSelection(inv *serpent.Invocation, presets []codersdk.Preset) (
472472
var presetOptions []string
473473

474474
for _, preset := range presets {
475-
option := preset.Name
475+
var option string
476+
if preset.Description == "" {
477+
option = preset.Name
478+
} else {
479+
option = fmt.Sprintf("%s: %s", preset.Name, preset.Description)
480+
}
476481
presetOptions = append(presetOptions, option)
477482
presetMap[option] = &preset
478483
}

cli/create_test.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -882,7 +882,8 @@ func TestCreateWithPreset(t *testing.T) {
882882

883883
// Given: a template and a template version with two presets
884884
preset := proto.Preset{
885-
Name: "preset-test",
885+
Name: "preset-test",
886+
Description: "Preset Test.",
886887
Parameters: []*proto.PresetParameter{
887888
{Name: firstParameterName, Value: secondOptionalParameterValue},
888889
{Name: thirdParameterName, Value: thirdParameterValue},

cli/templatepresets.go

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -41,12 +41,13 @@ func (r *RootCmd) templatePresets() *serpent.Command {
4141
func (r *RootCmd) templatePresetsList() *serpent.Command {
4242
defaultColumns := []string{
4343
"name",
44+
"description",
4445
"parameters",
4546
"default",
4647
"desired prebuild instances",
4748
}
4849
formatter := cliui.NewOutputFormatter(
49-
cliui.TableFormat([]templatePresetRow{}, defaultColumns),
50+
cliui.TableFormat([]TemplatePresetRow{}, defaultColumns),
5051
cliui.JSONFormat(),
5152
)
5253
client := new(codersdk.Client)
@@ -108,10 +109,13 @@ func (r *RootCmd) templatePresetsList() *serpent.Command {
108109
return nil
109110
}
110111

111-
cliui.Infof(
112-
inv.Stdout,
113-
"Showing presets for template %q and template version %q.\n", template.Name, version.Name,
114-
)
112+
// Only display info message for table output
113+
if formatter.FormatID() == "table" {
114+
cliui.Infof(
115+
inv.Stdout,
116+
"Showing presets for template %q and template version %q.\n", template.Name, version.Name,
117+
)
118+
}
115119
rows := templatePresetsToRows(presets...)
116120
out, err := formatter.Format(inv.Context(), rows)
117121
if err != nil {
@@ -128,12 +132,13 @@ func (r *RootCmd) templatePresetsList() *serpent.Command {
128132
return cmd
129133
}
130134

131-
type templatePresetRow struct {
132-
// For json format:
135+
type TemplatePresetRow struct {
136+
// For json format
133137
TemplatePreset codersdk.Preset `table:"-"`
134138

135139
// For table format:
136140
Name string `json:"-" table:"name,default_sort"`
141+
Description string `json:"-" table:"description"`
137142
Parameters string `json:"-" table:"parameters"`
138143
Default bool `json:"-" table:"default"`
139144
DesiredPrebuildInstances string `json:"-" table:"desired prebuild instances"`
@@ -149,15 +154,19 @@ func formatPresetParameters(params []codersdk.PresetParameter) string {
149154

150155
// templatePresetsToRows converts a list of presets to a list of rows
151156
// for outputting.
152-
func templatePresetsToRows(presets ...codersdk.Preset) []templatePresetRow {
153-
rows := make([]templatePresetRow, len(presets))
157+
func templatePresetsToRows(presets ...codersdk.Preset) []TemplatePresetRow {
158+
rows := make([]TemplatePresetRow, len(presets))
154159
for i, preset := range presets {
155160
prebuildInstances := "-"
156161
if preset.DesiredPrebuildInstances != nil {
157162
prebuildInstances = strconv.Itoa(*preset.DesiredPrebuildInstances)
158163
}
159-
rows[i] = templatePresetRow{
164+
rows[i] = TemplatePresetRow{
165+
// For json format
166+
TemplatePreset: preset,
167+
// For table format
160168
Name: preset.Name,
169+
Description: preset.Description,
161170
Parameters: formatPresetParameters(preset.Parameters),
162171
Default: preset.Default,
163172
DesiredPrebuildInstances: prebuildInstances,

cli/templatepresets_test.go

Lines changed: 73 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
package cli_test
22

33
import (
4+
"bytes"
5+
"encoding/json"
46
"fmt"
57
"testing"
68

79
"github.com/stretchr/testify/require"
810

11+
"github.com/coder/coder/v2/cli"
912
"github.com/coder/coder/v2/cli/clitest"
1013
"github.com/coder/coder/v2/coderd/coderdtest"
1114
"github.com/coder/coder/v2/codersdk"
@@ -84,8 +87,9 @@ func TestTemplatePresets(t *testing.T) {
8487
},
8588
},
8689
{
87-
Name: "preset-prebuilds",
88-
Parameters: []*proto.PresetParameter{},
90+
Name: "preset-prebuilds",
91+
Description: "Preset without parameters and 2 prebuild instances.",
92+
Parameters: []*proto.PresetParameter{},
8993
Prebuild: &proto.Prebuild{
9094
Instances: 2,
9195
},
@@ -117,7 +121,7 @@ func TestTemplatePresets(t *testing.T) {
117121
pty.ExpectRegexMatch(`preset-default\s+k1=v2\s+true\s+0`)
118122
// The parameter order is not guaranteed in the output, so we match both possible orders
119123
pty.ExpectRegexMatch(`preset-multiple-params\s+(k1=v1,k2=v2)|(k2=v2,k1=v1)\s+false\s+-`)
120-
pty.ExpectRegexMatch(`preset-prebuilds\s+\s+false\s+2`)
124+
pty.ExpectRegexMatch(`preset-prebuilds\s+Preset without parameters and 2 prebuild instances.\s+\s+false\s+2`)
121125
})
122126

123127
t.Run("ListsPresetsForSpecifiedTemplateVersion", func(t *testing.T) {
@@ -158,8 +162,9 @@ func TestTemplatePresets(t *testing.T) {
158162
},
159163
},
160164
{
161-
Name: "preset-prebuilds",
162-
Parameters: []*proto.PresetParameter{},
165+
Name: "preset-prebuilds",
166+
Description: "Preset without parameters and 2 prebuild instances.",
167+
Parameters: []*proto.PresetParameter{},
163168
Prebuild: &proto.Prebuild{
164169
Instances: 2,
165170
},
@@ -208,7 +213,69 @@ func TestTemplatePresets(t *testing.T) {
208213
pty.ExpectRegexMatch(`preset-default\s+k1=v2\s+true\s+0`)
209214
// The parameter order is not guaranteed in the output, so we match both possible orders
210215
pty.ExpectRegexMatch(`preset-multiple-params\s+(k1=v1,k2=v2)|(k2=v2,k1=v1)\s+false\s+-`)
211-
pty.ExpectRegexMatch(`preset-prebuilds\s+\s+false\s+2`)
216+
pty.ExpectRegexMatch(`preset-prebuilds\s+Preset without parameters and 2 prebuild instances.\s+\s+false\s+2`)
217+
})
218+
219+
t.Run("ListsPresetsJSON", func(t *testing.T) {
220+
t.Parallel()
221+
222+
client := coderdtest.New(t, &coderdtest.Options{IncludeProvisionerDaemon: true})
223+
owner := coderdtest.CreateFirstUser(t, client)
224+
member, _ := coderdtest.CreateAnotherUser(t, client, owner.OrganizationID)
225+
226+
// Given: an active template version that includes presets
227+
preset := proto.Preset{
228+
Name: "preset-default",
229+
Description: "Preset with parameters and 2 prebuild instances.",
230+
Icon: "/emojis/1f60e.png",
231+
Default: true,
232+
Parameters: []*proto.PresetParameter{
233+
{
234+
Name: "k1",
235+
Value: "v2",
236+
},
237+
},
238+
Prebuild: &proto.Prebuild{
239+
Instances: 2,
240+
},
241+
}
242+
243+
version := coderdtest.CreateTemplateVersion(t, client, owner.OrganizationID, templateWithPresets([]*proto.Preset{&preset}))
244+
_ = coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID)
245+
template := coderdtest.CreateTemplate(t, client, owner.OrganizationID, version.ID)
246+
require.Equal(t, version.ID, template.ActiveVersionID)
247+
248+
// When: listing presets for that template
249+
inv, root := clitest.New(t, "templates", "presets", "list", template.Name, "-o", "json")
250+
clitest.SetupConfig(t, member, root)
251+
252+
buf := bytes.NewBuffer(nil)
253+
inv.Stdout = buf
254+
doneChan := make(chan struct{})
255+
var runErr error
256+
go func() {
257+
defer close(doneChan)
258+
runErr = inv.Run()
259+
}()
260+
261+
<-doneChan
262+
require.NoError(t, runErr)
263+
264+
// Should: return the active version's preset
265+
var jsonPresets []cli.TemplatePresetRow
266+
err := json.Unmarshal(buf.Bytes(), &jsonPresets)
267+
require.NoError(t, err, "unmarshal JSON output")
268+
require.Len(t, jsonPresets, 1)
269+
270+
jsonPreset := jsonPresets[0].TemplatePreset
271+
require.Equal(t, preset.Name, jsonPreset.Name)
272+
require.Equal(t, preset.Description, jsonPreset.Description)
273+
require.Equal(t, preset.Icon, jsonPreset.Icon)
274+
require.Equal(t, preset.Default, jsonPreset.Default)
275+
require.Equal(t, len(preset.Parameters), len(jsonPreset.Parameters))
276+
require.Equal(t, preset.Parameters[0].Name, jsonPreset.Parameters[0].Name)
277+
require.Equal(t, preset.Parameters[0].Value, jsonPreset.Parameters[0].Value)
278+
require.Equal(t, int(preset.Prebuild.Instances), *jsonPreset.DesiredPrebuildInstances)
212279
})
213280
}
214281

cli/testdata/coder_templates_presets_list_--help.golden

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ OPTIONS:
1010
-O, --org string, $CODER_ORGANIZATION
1111
Select which organization (uuid or name) to use.
1212

13-
-c, --column [name|parameters|default|desired prebuild instances] (default: name,parameters,default,desired prebuild instances)
13+
-c, --column [name|description|parameters|default|desired prebuild instances] (default: name,description,parameters,default,desired prebuild instances)
1414
Columns to display in table output.
1515

1616
-o, --output table|json (default: table)

docs/reference/cli/templates_presets_list.md

Lines changed: 4 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy