Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

feat(cli): add CLI support for listing presets#18910

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Open
ssncferreira wants to merge1 commit intomain
base:main
Choose a base branch
Loading
fromssncferreira/cli-presets-list
Open
Show file tree
Hide file tree
Changes fromall commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
137 changes: 137 additions & 0 deletionscli/templateversionpresets.go
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
package cli

import (
"fmt"
"strconv"
"strings"

"golang.org/x/xerrors"

"github.com/coder/coder/v2/cli/cliui"
"github.com/coder/coder/v2/codersdk"
"github.com/coder/serpent"
)

func (r*RootCmd)templateVersionPresets()*serpent.Command {
cmd:=&serpent.Command{
Use:"presets",
Short:"Manage presets of the specified template version",
Aliases: []string{"preset"},
Long:FormatExamples(
Example{
Description:"List presets of a specific template version",
Command:"coder templates versions presets list my-template my-template-version",
Copy link
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Currently, thecoder templates versions presets list command requires both a template and a template version as positional arguments. However, it might be more user-friendly to only require the template name, andby default use the active template version.

We could also introduce a--template-version flag for cases where the user wants to explicitly list the presets of a specific template version.

Example usage:

# Lists presets for the active version of the templatecoder templates versions presets list my-template# Lists presets for a specific template versioncoder templates versions presets list my-template --template-version my-template-version

Let me know what you think

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

coder templates versions presets list is too verbose. Since we're requiring the template name / version as args/flags, there's no need to mention them in the command IMHO.coder presets should suffice.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

I likecoder presets. I recall seeing the termpreset used in unrelated work in the frontend a few months ago. Perhaps just check that we won't have any namespacing conflicts if we shorten the command but otherwise I think its a good idea.

I think template version flag should be optional with the active version as a default.

},
),
Handler:func(inv*serpent.Invocation)error {
returninv.Command.HelpHandler(inv)
},
Children: []*serpent.Command{
r.templateVersionPresetsList(),
},
}

returncmd
}

func (r*RootCmd)templateVersionPresetsList()*serpent.Command {
defaultColumns:= []string{
"name",
"parameters",
"default",
"prebuilds",
}
formatter:=cliui.NewOutputFormatter(
cliui.TableFormat([]templateVersionPresetRow{},defaultColumns),
cliui.JSONFormat(),
)
client:=new(codersdk.Client)
orgContext:=NewOrganizationContext()

cmd:=&serpent.Command{
Use:"list <template> <version>",
Middleware:serpent.Chain(
serpent.RequireNArgs(2),
r.InitClient(client),
),
Short:"List all the presets of the specified template version",
Options: serpent.OptionSet{},
Handler:func(inv*serpent.Invocation)error {
organization,err:=orgContext.Selected(inv,client)
iferr!=nil {
returnxerrors.Errorf("get current organization: %w",err)
}

template,err:=client.TemplateByName(inv.Context(),organization.ID,inv.Args[0])
iferr!=nil {
returnxerrors.Errorf("get template by name: %w",err)
}

version,err:=client.TemplateVersionByName(inv.Context(),template.ID,inv.Args[1])
iferr!=nil {
returnxerrors.Errorf("get template version by name: %w",err)
}

presets,err:=client.TemplateVersionPresets(inv.Context(),version.ID)
iferr!=nil {
returnxerrors.Errorf("get template versions presets by template version: %w",err)
}

iflen(presets)==0 {
returnxerrors.Errorf("no presets found for template %q and template-version %q",template.Name,version.Name)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Should this be an error? Or just an empty list?

}

rows:=templateVersionPresetsToRows(presets...)
out,err:=formatter.Format(inv.Context(),rows)
iferr!=nil {
returnxerrors.Errorf("render table: %w",err)
}

_,err=fmt.Fprintln(inv.Stdout,out)
returnerr
},
}

orgContext.AttachOptions(cmd)
formatter.AttachOptions(&cmd.Options)
returncmd
}

typetemplateVersionPresetRowstruct {
// For json format:
TemplateVersionPreset codersdk.Preset`table:"-"`

// For table format:
Namestring`json:"-" table:"name,default_sort"`
Parametersstring`json:"-" table:"parameters"`
Defaultbool`json:"-" table:"default"`
Prebuildsstring`json:"-" table:"prebuilds"`
}

funcformatPresetParameters(params []codersdk.PresetParameter)string {
varparamsStr []string
for_,p:=rangeparams {
paramsStr=append(paramsStr,fmt.Sprintf("%s=%s",p.Name,p.Value))
}
returnstrings.Join(paramsStr,",")
}

// templateVersionPresetsToRows converts a list of presets to a list of rows
// for outputting.
functemplateVersionPresetsToRows(presets...codersdk.Preset) []templateVersionPresetRow {
rows:=make([]templateVersionPresetRow,len(presets))
fori,preset:=rangepresets {
prebuilds:="-"
ifpreset.Prebuilds!=nil {
prebuilds=strconv.Itoa(*preset.Prebuilds)
}
rows[i]=templateVersionPresetRow{
Name:preset.Name,
Parameters:formatPresetParameters(preset.Parameters),
Default:preset.Default,
Prebuilds:prebuilds,
}
}

returnrows
}
137 changes: 137 additions & 0 deletionscli/templateversionpresets_test.go
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
package cli_test

import (
"fmt"
"testing"

"github.com/coder/coder/v2/provisioner/echo"
"github.com/coder/coder/v2/provisionersdk/proto"

"github.com/stretchr/testify/require"

"github.com/coder/coder/v2/cli/clitest"
"github.com/coder/coder/v2/coderd/coderdtest"
"github.com/coder/coder/v2/pty/ptytest"
)

func TestTemplateVersionPresets(t *testing.T) {
t.Parallel()

t.Run("ListPresets", func(t *testing.T) {
t.Parallel()

client := coderdtest.New(t, &coderdtest.Options{IncludeProvisionerDaemon: true})
owner := coderdtest.CreateFirstUser(t, client)
member, _ := coderdtest.CreateAnotherUser(t, client, owner.OrganizationID)

// Given: a template version that includes presets
presets := []*proto.Preset{
{
Name: "preset-multiple-params",
Parameters: []*proto.PresetParameter{
{
Name: "k1",
Value: "v1",
}, {
Name: "k2",
Value: "v2",
},
},
},
{
Name: "preset-default",
Default: true,
Parameters: []*proto.PresetParameter{
{
Name: "k1",
Value: "v2",
},
},
Prebuild: &proto.Prebuild{
Instances: 0,
},
},
{
Name: "preset-prebuilds",
Parameters: []*proto.PresetParameter{},
Prebuild: &proto.Prebuild{
Instances: 2,
},
},
}
version := coderdtest.CreateTemplateVersion(t, client, owner.OrganizationID, templateWithPresets(presets))
_ = coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID)
template := coderdtest.CreateTemplate(t, client, owner.OrganizationID, version.ID)

// When: listing presets for that template and template version
inv, root := clitest.New(t, "templates", "versions", "presets", "list", template.Name, version.Name)
clitest.SetupConfig(t, member, root)

pty := ptytest.New(t).Attach(inv)
doneChan := make(chan struct{})
var runErr error
go func() {
defer close(doneChan)
runErr = inv.Run()
}()

<-doneChan
require.NoError(t, runErr)

// Should: return the presets sorted by name
pty.ExpectRegexMatch(`preset-default\s+k1=v2\s+true\s+0`)
// The parameter order is not guaranteed in the output, so we match both possible orders
pty.ExpectRegexMatch(`preset-multiple-params\s+(k1=v1,k2=v2)|(k2=v2,k1=v1)\s+false\s+-`)
pty.ExpectRegexMatch(`preset-prebuilds\s+\s+false\s+2`)
})

t.Run("NoPresets", func(t *testing.T) {
t.Parallel()

client := coderdtest.New(t, &coderdtest.Options{IncludeProvisionerDaemon: true})
owner := coderdtest.CreateFirstUser(t, client)
member, _ := coderdtest.CreateAnotherUser(t, client, owner.OrganizationID)

// Given: a template version without presets
version := coderdtest.CreateTemplateVersion(t, client, owner.OrganizationID, templateWithPresets([]*proto.Preset{}))
_ = coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID)
template := coderdtest.CreateTemplate(t, client, owner.OrganizationID, version.ID)

// When: listing presets for that template and template version
inv, root := clitest.New(t, "templates", "versions", "presets", "list", template.Name, version.Name)
clitest.SetupConfig(t, member, root)

ptytest.New(t).Attach(inv)
doneChan := make(chan struct{})
var runErr error
go func() {
defer close(doneChan)
runErr = inv.Run()
}()
<-doneChan

// Should return an error when no presets are found for the given template and version.
require.Error(t, runErr)
expectedErr := fmt.Sprintf(
"no presets found for template %q and template-version %q",
template.Name,
version.Name,
)
require.Contains(t, runErr.Error(), expectedErr)
})
}

func templateWithPresets(presets []*proto.Preset) *echo.Responses {
return &echo.Responses{
Parse: echo.ParseComplete,
ProvisionPlan: []*proto.Response{
{
Type: &proto.Response_Plan{
Plan: &proto.PlanComplete{
Presets: presets,
},
},
},
},
}
}
1 change: 1 addition & 0 deletionscli/templateversions.go
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -33,6 +33,7 @@ func (r *RootCmd) templateVersions() *serpent.Command {
r.archiveTemplateVersion(),
r.unarchiveTemplateVersion(),
r.templateVersionsPromote(),
r.templateVersionPresets(),
},
}

Expand Down
1 change: 1 addition & 0 deletionscli/testdata/coder_templates_versions_--help.golden
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -14,6 +14,7 @@ USAGE:
SUBCOMMANDS:
archive Archive a template version(s).
list List all the versions of the specified template
presets Manage presets of the specified template version
promote Promote a template version to active.
unarchive Unarchive a template version(s).

Expand Down
18 changes: 18 additions & 0 deletionscli/testdata/coder_templates_versions_presets_--help.golden
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
coder v0.0.0-devel

USAGE:
coder templates versions presets

Manage presets of the specified template version

Aliases: preset

- List presets of a specific template version:

$ coder templates versions presets list my-template my-template-version

SUBCOMMANDS:
list List all the presets of the specified template version

———
Run `coder --help` for a list of global options.
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
coder v0.0.0-devel

USAGE:
coder templates versions presets

Manage presets of the specified template version

Aliases: preset

- List presets of a specific template version:

$ coder templates versions presets list my-template my-template-version

SUBCOMMANDS:
list List all the presets of the specified template version

———
Run `coder --help` for a list of global options.
3 changes: 3 additions & 0 deletionscoderd/apidoc/docs.go
View file
Open in desktop

Some generated files are not rendered by default. Learn more abouthow customized files appear on GitHub.

3 changes: 3 additions & 0 deletionscoderd/apidoc/swagger.json
View file
Open in desktop

Some generated files are not rendered by default. Learn more abouthow customized files appear on GitHub.

16 changes: 13 additions & 3 deletionscoderd/presets.go
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
package coderd

import (
"database/sql"
"net/http"

"github.com/coder/coder/v2/coderd/httpapi"
Expand DownExpand Up@@ -38,12 +39,21 @@ func (api *API) templateVersionPresets(rw http.ResponseWriter, r *http.Request)
return
}

getPrebuildInstances:=func(desiredInstances sql.NullInt32)*int {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

this name implies fetching from somewhere, but it only does a type conversion. perhaps consider a more descriptive name?

ifdesiredInstances.Valid {
value:=int(desiredInstances.Int32)
return&value
}
returnnil
}

varres []codersdk.Preset
for_,preset:=rangepresets {
sdkPreset:= codersdk.Preset{
ID:preset.ID,
Name:preset.Name,
Default:preset.IsDefault,
ID:preset.ID,
Name:preset.Name,
Default:preset.IsDefault,
Prebuilds:getPrebuildInstances(preset.DesiredInstances),
}
for_,presetParam:=rangepresetParams {
ifpresetParam.TemplateVersionPresetID!=preset.ID {
Expand Down
1 change: 1 addition & 0 deletionscodersdk/presets.go
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -15,6 +15,7 @@ type Preset struct {
Namestring
Parameters []PresetParameter
Defaultbool
Prebuilds*int
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Consider clarifying the naming to communicate whether this is the desired number of prebuilds or the eligible number of prebuilds. I can see from elsewhere that its the desired number, but we've spoken in the past about showing how many prebuilds are eligible in the frontend before. Would be good to leave room for both.

}

typePresetParameterstruct {
Expand Down
Loading
Loading

[8]ページ先頭

©2009-2025 Movatter.jp