chore: use workspace name as arg in coder workspaces create (#1007)

This commit is contained in:
Colin Adler
2022-04-14 13:23:20 -04:00
committed by GitHub
parent 7090227d38
commit f803e37505
5 changed files with 79 additions and 59 deletions

View File

@ -26,13 +26,14 @@ func templateCreate() *cobra.Command {
provisioner string
)
cmd := &cobra.Command{
Use: "create <directory> [name]",
Use: "create [name]",
Short: "Create a template from the current directory",
RunE: func(cmd *cobra.Command, args []string) error {
client, err := createClient(cmd)
if err != nil {
return err
}
organization, err := currentOrganization(cmd, client)
if err != nil {
return err
@ -44,6 +45,7 @@ func templateCreate() *cobra.Command {
} else {
templateName = args[0]
}
_, err = client.TemplateByName(cmd.Context(), organization.ID, templateName)
if err == nil {
return xerrors.Errorf("A template already exists named %q!", templateName)
@ -113,7 +115,7 @@ func templateCreate() *cobra.Command {
"The "+cliui.Styles.Keyword.Render(templateName)+" template has been created! "+
"Developers can provision a workspace with this template using:")+"\n")
_, _ = fmt.Fprintln(cmd.OutOrStdout(), " "+cliui.Styles.Code.Render("coder workspaces create "+templateName))
_, _ = fmt.Fprintln(cmd.OutOrStdout(), " "+cliui.Styles.Code.Render(fmt.Sprintf("coder workspaces create --template=%q [workspace name]", templateName)))
_, _ = fmt.Fprintln(cmd.OutOrStdout())
return nil
@ -214,9 +216,15 @@ func createValidTemplateVersion(cmd *cobra.Command, client *codersdk.Client, org
if err != nil {
return nil, nil, err
}
return &version, parameters, cliui.WorkspaceResources(cmd.OutOrStdout(), resources, cliui.WorkspaceResourcesOptions{
err = cliui.WorkspaceResources(cmd.OutOrStdout(), resources, cliui.WorkspaceResourcesOptions{
HideAgentState: true,
HideAccess: true,
Title: "Template Preview",
})
if err != nil {
return nil, nil, xerrors.Errorf("preview template resources: %w", err)
}
return &version, parameters, nil
}

View File

@ -2,10 +2,10 @@ package cli
import (
"fmt"
"sort"
"time"
"github.com/spf13/cobra"
"golang.org/x/exp/slices"
"golang.org/x/xerrors"
"github.com/coder/coder/cli/cliflag"
@ -17,67 +17,24 @@ import (
func workspaceCreate() *cobra.Command {
var (
workspaceName string
templateName string
)
cmd := &cobra.Command{
Use: "create [template]",
Use: "create [name]",
Short: "Create a workspace from a template",
RunE: func(cmd *cobra.Command, args []string) error {
client, err := createClient(cmd)
if err != nil {
return err
}
organization, err := currentOrganization(cmd, client)
if err != nil {
return err
}
templateName := ""
if len(args) >= 1 {
templateName = args[0]
}
var template codersdk.Template
if templateName == "" {
_, _ = fmt.Fprintln(cmd.OutOrStdout(), cliui.Styles.Wrap.Render("Select a template below to preview the provisioned infrastructure:"))
templateNames := []string{}
templateByName := map[string]codersdk.Template{}
templates, err := client.TemplatesByOrganization(cmd.Context(), organization.ID)
if err != nil {
return err
}
for _, template := range templates {
templateName := template.Name
if template.WorkspaceOwnerCount > 0 {
developerText := "developer"
if template.WorkspaceOwnerCount != 1 {
developerText = "developers"
}
templateName += cliui.Styles.Placeholder.Render(fmt.Sprintf(" (used by %d %s)", template.WorkspaceOwnerCount, developerText))
}
templateNames = append(templateNames, templateName)
templateByName[templateName] = template
}
sort.Slice(templateNames, func(i, j int) bool {
return templateByName[templateNames[i]].WorkspaceOwnerCount > templateByName[templateNames[j]].WorkspaceOwnerCount
})
// Move the cursor up a single line for nicer display!
option, err := cliui.Select(cmd, cliui.SelectOptions{
Options: templateNames,
HideSearch: true,
})
if err != nil {
return err
}
template = templateByName[option]
} else {
template, err = client.TemplateByName(cmd.Context(), organization.ID, templateName)
if err != nil {
return xerrors.Errorf("get template by name: %w", err)
}
if err != nil {
return err
}
workspaceName = args[0]
}
if workspaceName == "" {
@ -101,6 +58,55 @@ func workspaceCreate() *cobra.Command {
return xerrors.Errorf("A workspace already exists named %q!", workspaceName)
}
var template codersdk.Template
if templateName == "" {
_, _ = fmt.Fprintln(cmd.OutOrStdout(), cliui.Styles.Wrap.Render("Select a template below to preview the provisioned infrastructure:"))
templates, err := client.TemplatesByOrganization(cmd.Context(), organization.ID)
if err != nil {
return err
}
slices.SortFunc(templates, func(a, b codersdk.Template) bool {
return a.WorkspaceOwnerCount > b.WorkspaceOwnerCount
})
templateNames := make([]string, 0, len(templates))
templateByName := make(map[string]codersdk.Template, len(templates))
for _, template := range templates {
templateName := template.Name
if template.WorkspaceOwnerCount > 0 {
developerText := "developer"
if template.WorkspaceOwnerCount != 1 {
developerText = "developers"
}
templateName += cliui.Styles.Placeholder.Render(fmt.Sprintf(" (used by %d %s)", template.WorkspaceOwnerCount, developerText))
}
templateNames = append(templateNames, templateName)
templateByName[templateName] = template
}
// Move the cursor up a single line for nicer display!
option, err := cliui.Select(cmd, cliui.SelectOptions{
Options: templateNames,
HideSearch: true,
})
if err != nil {
return err
}
template = templateByName[option]
} else {
template, err = client.TemplateByName(cmd.Context(), organization.ID, templateName)
if err != nil {
return xerrors.Errorf("get template by name: %w", err)
}
}
templateVersion, err := client.TemplateVersion(cmd.Context(), template.ActiveVersionID)
if err != nil {
return err
@ -164,10 +170,12 @@ func workspaceCreate() *cobra.Command {
if err != nil {
return err
}
err = cliui.WorkspaceBuild(cmd.Context(), cmd.OutOrStdout(), client, workspace.LatestBuild.ID, before)
if err != nil {
return err
}
resources, err = client.WorkspaceResourcesByBuild(cmd.Context(), workspace.LatestBuild.ID)
if err != nil {
return err
@ -179,11 +187,12 @@ func workspaceCreate() *cobra.Command {
if err != nil {
return err
}
_, _ = fmt.Fprintf(cmd.OutOrStdout(), "The %s workspace has been created!\n", cliui.Styles.Keyword.Render(workspace.Name))
return nil
},
}
cliflag.StringVarP(cmd.Flags(), &workspaceName, "name", "n", "CODER_WORKSPACE_NAME", "", "Specify a workspace name.")
cliflag.StringVarP(cmd.Flags(), &templateName, "template", "t", "CODER_TEMPLATE_NAME", "", "Specify a template name.")
return cmd
}

View File

@ -22,7 +22,7 @@ func TestWorkspaceCreate(t *testing.T) {
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil)
coderdtest.AwaitTemplateVersionJob(t, client, version.ID)
template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID)
cmd, root := clitest.New(t, "workspaces", "create", template.Name, "--name", "my-workspace")
cmd, root := clitest.New(t, "workspaces", "create", "my-workspace", "--template", template.Name)
clitest.SetupConfig(t, client, root)
doneChan := make(chan struct{})
pty := ptytest.New(t)
@ -52,7 +52,7 @@ func TestWorkspaceCreate(t *testing.T) {
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil)
coderdtest.AwaitTemplateVersionJob(t, client, version.ID)
_ = coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID)
cmd, root := clitest.New(t, "workspaces", "create", "--name", "my-workspace")
cmd, root := clitest.New(t, "workspaces", "create", "my-workspace")
clitest.SetupConfig(t, client, root)
doneChan := make(chan struct{})
pty := ptytest.New(t)
@ -82,7 +82,7 @@ func TestWorkspaceCreate(t *testing.T) {
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil)
coderdtest.AwaitTemplateVersionJob(t, client, version.ID)
_ = coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID)
cmd, root := clitest.New(t, "workspaces", "create", "--name", "")
cmd, root := clitest.New(t, "workspaces", "create", "")
clitest.SetupConfig(t, client, root)
doneChan := make(chan struct{})
pty := ptytest.New(t)
@ -134,7 +134,7 @@ func TestWorkspaceCreate(t *testing.T) {
})
coderdtest.AwaitTemplateVersionJob(t, client, version.ID)
_ = coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID)
cmd, root := clitest.New(t, "workspaces", "create", "--name", "")
cmd, root := clitest.New(t, "workspaces", "create", "")
clitest.SetupConfig(t, client, root)
doneChan := make(chan struct{})
pty := ptytest.New(t)

3
go.mod
View File

@ -92,7 +92,8 @@ require (
go.uber.org/atomic v1.9.0
go.uber.org/goleak v1.1.12
golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd
golang.org/x/mod v0.5.1
golang.org/x/exp v0.0.0-20220414153411-bcd21879b8fd
golang.org/x/mod v0.6.0-dev.0.20211013180041-c96bc1413d57
golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c
golang.org/x/sys v0.0.0-20220328115105-d36c6a25d886

6
go.sum
View File

@ -1787,6 +1787,8 @@ golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EH
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
golang.org/x/exp v0.0.0-20200901203048-c4f52b2c50aa/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
golang.org/x/exp v0.0.0-20200908183739-ae8ad444f925/go.mod h1:1phAWC201xIgDyaFpmDeZkgf70Q4Pd/CNqfRtVPtxNw=
golang.org/x/exp v0.0.0-20220414153411-bcd21879b8fd h1:zVFyTKZN/Q7mNRWSs1GOYnHM9NiFSJ54YVRsD0rNWT4=
golang.org/x/exp v0.0.0-20220414153411-bcd21879b8fd/go.mod h1:lgLbSvA5ygNOMpwM/9anMpWVlVJ7Z+cHWq/eFuinpGE=
golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs=
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
@ -1821,8 +1823,8 @@ golang.org/x/mod v0.3.1-0.20200828183125-ce943fd02449/go.mod h1:s0Qsj1ACt9ePp/hM
golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.5.1 h1:OJxoQ/rynoF0dcCdI7cLPktw/hR2cueqYfjm43oqK38=
golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
golang.org/x/mod v0.6.0-dev.0.20211013180041-c96bc1413d57 h1:LQmS1nU0twXLA96Kt7U9qtHJEbBk3z6Q0V4UXjZkpr4=
golang.org/x/mod v0.6.0-dev.0.20211013180041-c96bc1413d57/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY=
golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180530234432-1e491301e022/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=