mirror of
https://github.com/coder/coder.git
synced 2025-07-13 21:36:50 +00:00
chore: remove org context switcher in the cli (#13674)
* chore: remove org context switcher in the cli
This commit is contained in:
@ -29,6 +29,7 @@ func (r *RootCmd) create() *serpent.Command {
|
|||||||
parameterFlags workspaceParameterFlags
|
parameterFlags workspaceParameterFlags
|
||||||
autoUpdates string
|
autoUpdates string
|
||||||
copyParametersFrom string
|
copyParametersFrom string
|
||||||
|
orgContext = NewOrganizationContext()
|
||||||
)
|
)
|
||||||
client := new(codersdk.Client)
|
client := new(codersdk.Client)
|
||||||
cmd := &serpent.Command{
|
cmd := &serpent.Command{
|
||||||
@ -43,7 +44,7 @@ func (r *RootCmd) create() *serpent.Command {
|
|||||||
),
|
),
|
||||||
Middleware: serpent.Chain(r.InitClient(client)),
|
Middleware: serpent.Chain(r.InitClient(client)),
|
||||||
Handler: func(inv *serpent.Invocation) error {
|
Handler: func(inv *serpent.Invocation) error {
|
||||||
organization, err := CurrentOrganization(r, inv, client)
|
organization, err := orgContext.Selected(inv, client)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -269,6 +270,7 @@ func (r *RootCmd) create() *serpent.Command {
|
|||||||
)
|
)
|
||||||
cmd.Options = append(cmd.Options, parameterFlags.cliParameters()...)
|
cmd.Options = append(cmd.Options, parameterFlags.cliParameters()...)
|
||||||
cmd.Options = append(cmd.Options, parameterFlags.cliParameterDefaults()...)
|
cmd.Options = append(cmd.Options, parameterFlags.cliParameterDefaults()...)
|
||||||
|
orgContext.AttachOptions(cmd)
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -358,13 +358,6 @@ func (r *RootCmd) login() *serpent.Command {
|
|||||||
return xerrors.Errorf("write server url: %w", err)
|
return xerrors.Errorf("write server url: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the current organization cannot be fetched, then reset the organization context.
|
|
||||||
// Otherwise, organization cli commands will fail.
|
|
||||||
_, err = CurrentOrganization(r, inv, client)
|
|
||||||
if err != nil {
|
|
||||||
_ = config.Organization().Delete()
|
|
||||||
}
|
|
||||||
|
|
||||||
_, _ = fmt.Fprintf(inv.Stdout, Caret+"Welcome to Coder, %s! You're authenticated.\n", pretty.Sprint(cliui.DefaultStyles.Keyword, resp.Username))
|
_, _ = fmt.Fprintf(inv.Stdout, Caret+"Welcome to Coder, %s! You're authenticated.\n", pretty.Sprint(cliui.DefaultStyles.Keyword, resp.Username))
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
|
@ -5,11 +5,9 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
"os"
|
|
||||||
"runtime"
|
"runtime"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/google/uuid"
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
@ -424,29 +422,6 @@ func TestLogin(t *testing.T) {
|
|||||||
require.NotEqual(t, client.SessionToken(), sessionFile)
|
require.NotEqual(t, client.SessionToken(), sessionFile)
|
||||||
})
|
})
|
||||||
|
|
||||||
// Login should reset the configured organization if the user is not a member
|
|
||||||
t.Run("ResetOrganization", func(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
client := coderdtest.New(t, nil)
|
|
||||||
coderdtest.CreateFirstUser(t, client)
|
|
||||||
root, cfg := clitest.New(t, "login", client.URL.String(), "--token", client.SessionToken())
|
|
||||||
|
|
||||||
notRealOrg := uuid.NewString()
|
|
||||||
err := cfg.Organization().Write(notRealOrg)
|
|
||||||
require.NoError(t, err, "write bad org to config")
|
|
||||||
|
|
||||||
err = root.Run()
|
|
||||||
require.NoError(t, err)
|
|
||||||
sessionFile, err := cfg.Session().Read()
|
|
||||||
require.NoError(t, err)
|
|
||||||
require.NotEqual(t, client.SessionToken(), sessionFile)
|
|
||||||
|
|
||||||
// Organization config should be deleted since the org does not exist
|
|
||||||
selected, err := cfg.Organization().Read()
|
|
||||||
require.ErrorIs(t, err, os.ErrNotExist)
|
|
||||||
require.NotEqual(t, selected, notRealOrg)
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("KeepOrganizationContext", func(t *testing.T) {
|
t.Run("KeepOrganizationContext", func(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
client := coderdtest.New(t, nil)
|
client := coderdtest.New(t, nil)
|
||||||
|
@ -1,22 +1,19 @@
|
|||||||
package cli
|
package cli
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
|
||||||
"slices"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"golang.org/x/xerrors"
|
"golang.org/x/xerrors"
|
||||||
|
|
||||||
"github.com/coder/coder/v2/cli/cliui"
|
"github.com/coder/coder/v2/cli/cliui"
|
||||||
"github.com/coder/coder/v2/cli/config"
|
|
||||||
"github.com/coder/coder/v2/codersdk"
|
"github.com/coder/coder/v2/codersdk"
|
||||||
"github.com/coder/pretty"
|
|
||||||
"github.com/coder/serpent"
|
"github.com/coder/serpent"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (r *RootCmd) organizations() *serpent.Command {
|
func (r *RootCmd) organizations() *serpent.Command {
|
||||||
|
orgContext := NewOrganizationContext()
|
||||||
|
|
||||||
cmd := &serpent.Command{
|
cmd := &serpent.Command{
|
||||||
Use: "organizations [subcommand]",
|
Use: "organizations [subcommand]",
|
||||||
Short: "Organization related commands",
|
Short: "Organization related commands",
|
||||||
@ -26,188 +23,18 @@ func (r *RootCmd) organizations() *serpent.Command {
|
|||||||
return inv.Command.HelpHandler(inv)
|
return inv.Command.HelpHandler(inv)
|
||||||
},
|
},
|
||||||
Children: []*serpent.Command{
|
Children: []*serpent.Command{
|
||||||
r.currentOrganization(),
|
r.showOrganization(orgContext),
|
||||||
r.switchOrganization(),
|
|
||||||
r.createOrganization(),
|
r.createOrganization(),
|
||||||
r.organizationMembers(),
|
r.organizationMembers(orgContext),
|
||||||
r.organizationRoles(),
|
r.organizationRoles(orgContext),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd.Options = serpent.OptionSet{}
|
orgContext.AttachOptions(cmd)
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *RootCmd) switchOrganization() *serpent.Command {
|
func (r *RootCmd) showOrganization(orgContext *OrganizationContext) *serpent.Command {
|
||||||
client := new(codersdk.Client)
|
|
||||||
|
|
||||||
cmd := &serpent.Command{
|
|
||||||
Use: "set <organization name | ID>",
|
|
||||||
Short: "set the organization used by the CLI. Pass an empty string to reset to the default organization.",
|
|
||||||
Long: "set the organization used by the CLI. Pass an empty string to reset to the default organization.\n" + FormatExamples(
|
|
||||||
Example{
|
|
||||||
Description: "Remove the current organization and defer to the default.",
|
|
||||||
Command: "coder organizations set ''",
|
|
||||||
},
|
|
||||||
Example{
|
|
||||||
Description: "Switch to a custom organization.",
|
|
||||||
Command: "coder organizations set my-org",
|
|
||||||
},
|
|
||||||
),
|
|
||||||
Middleware: serpent.Chain(
|
|
||||||
r.InitClient(client),
|
|
||||||
serpent.RequireRangeArgs(0, 1),
|
|
||||||
),
|
|
||||||
Options: serpent.OptionSet{},
|
|
||||||
Handler: func(inv *serpent.Invocation) error {
|
|
||||||
conf := r.createConfig()
|
|
||||||
orgs, err := client.OrganizationsByUser(inv.Context(), codersdk.Me)
|
|
||||||
if err != nil {
|
|
||||||
return xerrors.Errorf("failed to get organizations: %w", err)
|
|
||||||
}
|
|
||||||
// Keep the list of orgs sorted
|
|
||||||
slices.SortFunc(orgs, func(a, b codersdk.Organization) int {
|
|
||||||
return strings.Compare(a.Name, b.Name)
|
|
||||||
})
|
|
||||||
|
|
||||||
var switchToOrg string
|
|
||||||
if len(inv.Args) == 0 {
|
|
||||||
// Pull switchToOrg from a prompt selector, rather than command line
|
|
||||||
// args.
|
|
||||||
switchToOrg, err = promptUserSelectOrg(inv, conf, orgs)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
switchToOrg = inv.Args[0]
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the user passes an empty string, we want to remove the organization
|
|
||||||
// from the config file. This will defer to default behavior.
|
|
||||||
if switchToOrg == "" {
|
|
||||||
err := conf.Organization().Delete()
|
|
||||||
if err != nil && !errors.Is(err, os.ErrNotExist) {
|
|
||||||
return xerrors.Errorf("failed to unset organization: %w", err)
|
|
||||||
}
|
|
||||||
_, _ = fmt.Fprintf(inv.Stdout, "Organization unset\n")
|
|
||||||
} else {
|
|
||||||
// Find the selected org in our list.
|
|
||||||
index := slices.IndexFunc(orgs, func(org codersdk.Organization) bool {
|
|
||||||
return org.Name == switchToOrg || org.ID.String() == switchToOrg
|
|
||||||
})
|
|
||||||
if index < 0 {
|
|
||||||
// Using this error for better error message formatting
|
|
||||||
err := &codersdk.Error{
|
|
||||||
Response: codersdk.Response{
|
|
||||||
Message: fmt.Sprintf("Organization %q not found. Is the name correct, and are you a member of it?", switchToOrg),
|
|
||||||
Detail: "Ensure the organization argument is correct and you are a member of it.",
|
|
||||||
},
|
|
||||||
Helper: fmt.Sprintf("Valid organizations you can switch to: %s", strings.Join(orgNames(orgs), ", ")),
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Always write the uuid to the config file. Names can change.
|
|
||||||
err := conf.Organization().Write(orgs[index].ID.String())
|
|
||||||
if err != nil {
|
|
||||||
return xerrors.Errorf("failed to write organization to config file: %w", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Verify it worked.
|
|
||||||
current, err := CurrentOrganization(r, inv, client)
|
|
||||||
if err != nil {
|
|
||||||
// An SDK error could be a permission error. So offer the advice to unset the org
|
|
||||||
// and reset the context.
|
|
||||||
var sdkError *codersdk.Error
|
|
||||||
if errors.As(err, &sdkError) {
|
|
||||||
if sdkError.Helper == "" && sdkError.StatusCode() != 500 {
|
|
||||||
sdkError.Helper = `If this error persists, try unsetting your org with 'coder organizations set ""'`
|
|
||||||
}
|
|
||||||
return sdkError
|
|
||||||
}
|
|
||||||
return xerrors.Errorf("failed to get current organization: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
_, _ = fmt.Fprintf(inv.Stdout, "Current organization context set to %s (%s)\n", current.Name, current.ID.String())
|
|
||||||
return nil
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
return cmd
|
|
||||||
}
|
|
||||||
|
|
||||||
// promptUserSelectOrg will prompt the user to select an organization from a list
|
|
||||||
// of their organizations.
|
|
||||||
func promptUserSelectOrg(inv *serpent.Invocation, conf config.Root, orgs []codersdk.Organization) (string, error) {
|
|
||||||
// Default choice
|
|
||||||
var defaultOrg string
|
|
||||||
// Comes from config file
|
|
||||||
if conf.Organization().Exists() {
|
|
||||||
defaultOrg, _ = conf.Organization().Read()
|
|
||||||
}
|
|
||||||
|
|
||||||
// No config? Comes from default org in the list
|
|
||||||
if defaultOrg == "" {
|
|
||||||
defIndex := slices.IndexFunc(orgs, func(org codersdk.Organization) bool {
|
|
||||||
return org.IsDefault
|
|
||||||
})
|
|
||||||
if defIndex >= 0 {
|
|
||||||
defaultOrg = orgs[defIndex].Name
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Defer to first org
|
|
||||||
if defaultOrg == "" && len(orgs) > 0 {
|
|
||||||
defaultOrg = orgs[0].Name
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ensure the `defaultOrg` value is an org name, not a uuid.
|
|
||||||
// If it is a uuid, change it to the org name.
|
|
||||||
index := slices.IndexFunc(orgs, func(org codersdk.Organization) bool {
|
|
||||||
return org.ID.String() == defaultOrg || org.Name == defaultOrg
|
|
||||||
})
|
|
||||||
if index >= 0 {
|
|
||||||
defaultOrg = orgs[index].Name
|
|
||||||
}
|
|
||||||
|
|
||||||
// deselectOption is the option to delete the organization config file and defer
|
|
||||||
// to default behavior.
|
|
||||||
const deselectOption = "[Default]"
|
|
||||||
if defaultOrg == "" {
|
|
||||||
defaultOrg = deselectOption
|
|
||||||
}
|
|
||||||
|
|
||||||
// Pull value from a prompt
|
|
||||||
_, _ = fmt.Fprintln(inv.Stdout, pretty.Sprint(cliui.DefaultStyles.Wrap, "Select an organization below to set the current CLI context to:"))
|
|
||||||
value, err := cliui.Select(inv, cliui.SelectOptions{
|
|
||||||
Options: append([]string{deselectOption}, orgNames(orgs)...),
|
|
||||||
Default: defaultOrg,
|
|
||||||
Size: 10,
|
|
||||||
HideSearch: false,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
// Deselect is an alias for ""
|
|
||||||
if value == deselectOption {
|
|
||||||
value = ""
|
|
||||||
}
|
|
||||||
|
|
||||||
return value, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// orgNames is a helper function to turn a list of organizations into a list of
|
|
||||||
// their names as strings.
|
|
||||||
func orgNames(orgs []codersdk.Organization) []string {
|
|
||||||
names := make([]string, 0, len(orgs))
|
|
||||||
for _, org := range orgs {
|
|
||||||
names = append(names, org.Name)
|
|
||||||
}
|
|
||||||
return names
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *RootCmd) currentOrganization() *serpent.Command {
|
|
||||||
var (
|
var (
|
||||||
stringFormat func(orgs []codersdk.Organization) (string, error)
|
stringFormat func(orgs []codersdk.Organization) (string, error)
|
||||||
client = new(codersdk.Client)
|
client = new(codersdk.Client)
|
||||||
@ -226,8 +53,29 @@ func (r *RootCmd) currentOrganization() *serpent.Command {
|
|||||||
onlyID = false
|
onlyID = false
|
||||||
)
|
)
|
||||||
cmd := &serpent.Command{
|
cmd := &serpent.Command{
|
||||||
Use: "show [current|me|uuid]",
|
Use: "show [\"selected\"|\"me\"|uuid|org_name]",
|
||||||
Short: "Show the organization, if no argument is given, the organization currently in use will be shown.",
|
Short: "Show the organization. " +
|
||||||
|
"Using \"selected\" will show the selected organization from the \"--org\" flag. " +
|
||||||
|
"Using \"me\" will show all organizations you are a member of.",
|
||||||
|
Long: FormatExamples(
|
||||||
|
Example{
|
||||||
|
Description: "coder org show selected",
|
||||||
|
Command: "Shows the organizations selected with '--org=<org_name>'. " +
|
||||||
|
"This organization is the organization used by the cli.",
|
||||||
|
},
|
||||||
|
Example{
|
||||||
|
Description: "coder org show me",
|
||||||
|
Command: "List of all organizations you are a member of.",
|
||||||
|
},
|
||||||
|
Example{
|
||||||
|
Description: "coder org show developers",
|
||||||
|
Command: "Show organization with name 'developers'",
|
||||||
|
},
|
||||||
|
Example{
|
||||||
|
Description: "coder org show 90ee1875-3db5-43b3-828e-af3687522e43",
|
||||||
|
Command: "Show organization with the given ID.",
|
||||||
|
},
|
||||||
|
),
|
||||||
Middleware: serpent.Chain(
|
Middleware: serpent.Chain(
|
||||||
r.InitClient(client),
|
r.InitClient(client),
|
||||||
serpent.RequireRangeArgs(0, 1),
|
serpent.RequireRangeArgs(0, 1),
|
||||||
@ -242,7 +90,7 @@ func (r *RootCmd) currentOrganization() *serpent.Command {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
Handler: func(inv *serpent.Invocation) error {
|
Handler: func(inv *serpent.Invocation) error {
|
||||||
orgArg := "current"
|
orgArg := "selected"
|
||||||
if len(inv.Args) >= 1 {
|
if len(inv.Args) >= 1 {
|
||||||
orgArg = inv.Args[0]
|
orgArg = inv.Args[0]
|
||||||
}
|
}
|
||||||
@ -250,14 +98,14 @@ func (r *RootCmd) currentOrganization() *serpent.Command {
|
|||||||
var orgs []codersdk.Organization
|
var orgs []codersdk.Organization
|
||||||
var err error
|
var err error
|
||||||
switch strings.ToLower(orgArg) {
|
switch strings.ToLower(orgArg) {
|
||||||
case "current":
|
case "selected":
|
||||||
stringFormat = func(orgs []codersdk.Organization) (string, error) {
|
stringFormat = func(orgs []codersdk.Organization) (string, error) {
|
||||||
if len(orgs) != 1 {
|
if len(orgs) != 1 {
|
||||||
return "", xerrors.Errorf("expected 1 organization, got %d", len(orgs))
|
return "", xerrors.Errorf("expected 1 organization, got %d", len(orgs))
|
||||||
}
|
}
|
||||||
return fmt.Sprintf("Current CLI Organization: %s (%s)\n", orgs[0].Name, orgs[0].ID.String()), nil
|
return fmt.Sprintf("Current CLI Organization: %s (%s)\n", orgs[0].Name, orgs[0].ID.String()), nil
|
||||||
}
|
}
|
||||||
org, err := CurrentOrganization(r, inv, client)
|
org, err := orgContext.Selected(inv, client)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -43,7 +43,7 @@ func TestCurrentOrganization(t *testing.T) {
|
|||||||
defer srv.Close()
|
defer srv.Close()
|
||||||
|
|
||||||
client := codersdk.New(must(url.Parse(srv.URL)))
|
client := codersdk.New(must(url.Parse(srv.URL)))
|
||||||
inv, root := clitest.New(t, "organizations", "show", "current")
|
inv, root := clitest.New(t, "organizations", "show", "selected")
|
||||||
clitest.SetupConfig(t, client, root)
|
clitest.SetupConfig(t, client, root)
|
||||||
pty := ptytest.New(t).Attach(inv)
|
pty := ptytest.New(t).Attach(inv)
|
||||||
errC := make(chan error)
|
errC := make(chan error)
|
||||||
@ -70,7 +70,7 @@ func TestCurrentOrganization(t *testing.T) {
|
|||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
inv, root := clitest.New(t, "organizations", "show", "--only-id")
|
inv, root := clitest.New(t, "organizations", "show", "--only-id", "--org="+first.OrganizationID.String())
|
||||||
clitest.SetupConfig(t, client, root)
|
clitest.SetupConfig(t, client, root)
|
||||||
pty := ptytest.New(t).Attach(inv)
|
pty := ptytest.New(t).Attach(inv)
|
||||||
errC := make(chan error)
|
errC := make(chan error)
|
||||||
@ -101,7 +101,7 @@ func TestCurrentOrganization(t *testing.T) {
|
|||||||
orgs[orgName] = org
|
orgs[orgName] = org
|
||||||
}
|
}
|
||||||
|
|
||||||
inv, root := clitest.New(t, "organizations", "show", "current", "--only-id", "-z=bar")
|
inv, root := clitest.New(t, "organizations", "show", "selected", "--only-id", "-O=bar")
|
||||||
clitest.SetupConfig(t, client, root)
|
clitest.SetupConfig(t, client, root)
|
||||||
pty := ptytest.New(t).Attach(inv)
|
pty := ptytest.New(t).Attach(inv)
|
||||||
errC := make(chan error)
|
errC := make(chan error)
|
||||||
@ -113,40 +113,6 @@ func TestCurrentOrganization(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestOrganizationSwitch(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
|
|
||||||
t.Run("Switch", func(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
ownerClient := coderdtest.New(t, nil)
|
|
||||||
first := coderdtest.CreateFirstUser(t, ownerClient)
|
|
||||||
// Owner is required to make orgs
|
|
||||||
client, _ := coderdtest.CreateAnotherUser(t, ownerClient, first.OrganizationID, rbac.RoleOwner())
|
|
||||||
|
|
||||||
ctx := testutil.Context(t, testutil.WaitMedium)
|
|
||||||
orgs := []string{"foo", "bar"}
|
|
||||||
for _, orgName := range orgs {
|
|
||||||
_, err := client.CreateOrganization(ctx, codersdk.CreateOrganizationRequest{
|
|
||||||
Name: orgName,
|
|
||||||
})
|
|
||||||
require.NoError(t, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
exp, err := client.OrganizationByName(ctx, "foo")
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
inv, root := clitest.New(t, "organizations", "set", "foo")
|
|
||||||
clitest.SetupConfig(t, client, root)
|
|
||||||
pty := ptytest.New(t).Attach(inv)
|
|
||||||
errC := make(chan error)
|
|
||||||
go func() {
|
|
||||||
errC <- inv.Run()
|
|
||||||
}()
|
|
||||||
require.NoError(t, <-errC)
|
|
||||||
pty.ExpectMatch(exp.ID.String())
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func must[V any](v V, err error) V {
|
func must[V any](v V, err error) V {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
|
@ -11,16 +11,16 @@ import (
|
|||||||
"github.com/coder/serpent"
|
"github.com/coder/serpent"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (r *RootCmd) organizationMembers() *serpent.Command {
|
func (r *RootCmd) organizationMembers(orgContext *OrganizationContext) *serpent.Command {
|
||||||
cmd := &serpent.Command{
|
cmd := &serpent.Command{
|
||||||
Use: "members",
|
Use: "members",
|
||||||
Aliases: []string{"member"},
|
Aliases: []string{"member"},
|
||||||
Short: "Manage organization members",
|
Short: "Manage organization members",
|
||||||
Children: []*serpent.Command{
|
Children: []*serpent.Command{
|
||||||
r.listOrganizationMembers(),
|
r.listOrganizationMembers(orgContext),
|
||||||
r.assignOrganizationRoles(),
|
r.assignOrganizationRoles(orgContext),
|
||||||
r.addOrganizationMember(),
|
r.addOrganizationMember(orgContext),
|
||||||
r.removeOrganizationMember(),
|
r.removeOrganizationMember(orgContext),
|
||||||
},
|
},
|
||||||
Handler: func(inv *serpent.Invocation) error {
|
Handler: func(inv *serpent.Invocation) error {
|
||||||
return inv.Command.HelpHandler(inv)
|
return inv.Command.HelpHandler(inv)
|
||||||
@ -30,7 +30,7 @@ func (r *RootCmd) organizationMembers() *serpent.Command {
|
|||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *RootCmd) removeOrganizationMember() *serpent.Command {
|
func (r *RootCmd) removeOrganizationMember(orgContext *OrganizationContext) *serpent.Command {
|
||||||
client := new(codersdk.Client)
|
client := new(codersdk.Client)
|
||||||
|
|
||||||
cmd := &serpent.Command{
|
cmd := &serpent.Command{
|
||||||
@ -42,7 +42,7 @@ func (r *RootCmd) removeOrganizationMember() *serpent.Command {
|
|||||||
),
|
),
|
||||||
Handler: func(inv *serpent.Invocation) error {
|
Handler: func(inv *serpent.Invocation) error {
|
||||||
ctx := inv.Context()
|
ctx := inv.Context()
|
||||||
organization, err := CurrentOrganization(r, inv, client)
|
organization, err := orgContext.Selected(inv, client)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -61,7 +61,7 @@ func (r *RootCmd) removeOrganizationMember() *serpent.Command {
|
|||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *RootCmd) addOrganizationMember() *serpent.Command {
|
func (r *RootCmd) addOrganizationMember(orgContext *OrganizationContext) *serpent.Command {
|
||||||
client := new(codersdk.Client)
|
client := new(codersdk.Client)
|
||||||
|
|
||||||
cmd := &serpent.Command{
|
cmd := &serpent.Command{
|
||||||
@ -73,7 +73,7 @@ func (r *RootCmd) addOrganizationMember() *serpent.Command {
|
|||||||
),
|
),
|
||||||
Handler: func(inv *serpent.Invocation) error {
|
Handler: func(inv *serpent.Invocation) error {
|
||||||
ctx := inv.Context()
|
ctx := inv.Context()
|
||||||
organization, err := CurrentOrganization(r, inv, client)
|
organization, err := orgContext.Selected(inv, client)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -92,7 +92,7 @@ func (r *RootCmd) addOrganizationMember() *serpent.Command {
|
|||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *RootCmd) assignOrganizationRoles() *serpent.Command {
|
func (r *RootCmd) assignOrganizationRoles(orgContext *OrganizationContext) *serpent.Command {
|
||||||
client := new(codersdk.Client)
|
client := new(codersdk.Client)
|
||||||
|
|
||||||
cmd := &serpent.Command{
|
cmd := &serpent.Command{
|
||||||
@ -104,7 +104,7 @@ func (r *RootCmd) assignOrganizationRoles() *serpent.Command {
|
|||||||
),
|
),
|
||||||
Handler: func(inv *serpent.Invocation) error {
|
Handler: func(inv *serpent.Invocation) error {
|
||||||
ctx := inv.Context()
|
ctx := inv.Context()
|
||||||
organization, err := CurrentOrganization(r, inv, client)
|
organization, err := orgContext.Selected(inv, client)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -135,7 +135,7 @@ func (r *RootCmd) assignOrganizationRoles() *serpent.Command {
|
|||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *RootCmd) listOrganizationMembers() *serpent.Command {
|
func (r *RootCmd) listOrganizationMembers(orgContext *OrganizationContext) *serpent.Command {
|
||||||
formatter := cliui.NewOutputFormatter(
|
formatter := cliui.NewOutputFormatter(
|
||||||
cliui.TableFormat([]codersdk.OrganizationMemberWithName{}, []string{"username", "organization_roles"}),
|
cliui.TableFormat([]codersdk.OrganizationMemberWithName{}, []string{"username", "organization_roles"}),
|
||||||
cliui.JSONFormat(),
|
cliui.JSONFormat(),
|
||||||
@ -151,7 +151,7 @@ func (r *RootCmd) listOrganizationMembers() *serpent.Command {
|
|||||||
),
|
),
|
||||||
Handler: func(inv *serpent.Invocation) error {
|
Handler: func(inv *serpent.Invocation) error {
|
||||||
ctx := inv.Context()
|
ctx := inv.Context()
|
||||||
organization, err := CurrentOrganization(r, inv, client)
|
organization, err := orgContext.Selected(inv, client)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -56,7 +56,7 @@ func TestAddOrganizationMembers(t *testing.T) {
|
|||||||
})
|
})
|
||||||
require.NoError(t, err, "create another organization")
|
require.NoError(t, err, "create another organization")
|
||||||
|
|
||||||
inv, root := clitest.New(t, "organization", "members", "add", "--organization", otherOrg.ID.String(), user.Username)
|
inv, root := clitest.New(t, "organization", "members", "add", "-O", otherOrg.ID.String(), user.Username)
|
||||||
//nolint:gocritic // must be an owner
|
//nolint:gocritic // must be an owner
|
||||||
clitest.SetupConfig(t, ownerClient, root)
|
clitest.SetupConfig(t, ownerClient, root)
|
||||||
|
|
||||||
@ -86,7 +86,7 @@ func TestRemoveOrganizationMembers(t *testing.T) {
|
|||||||
|
|
||||||
ctx := testutil.Context(t, testutil.WaitMedium)
|
ctx := testutil.Context(t, testutil.WaitMedium)
|
||||||
|
|
||||||
inv, root := clitest.New(t, "organization", "members", "remove", "--organization", owner.OrganizationID.String(), user.Username)
|
inv, root := clitest.New(t, "organization", "members", "remove", "-O", owner.OrganizationID.String(), user.Username)
|
||||||
clitest.SetupConfig(t, orgAdminClient, root)
|
clitest.SetupConfig(t, orgAdminClient, root)
|
||||||
|
|
||||||
buf := new(bytes.Buffer)
|
buf := new(bytes.Buffer)
|
||||||
@ -109,7 +109,7 @@ func TestRemoveOrganizationMembers(t *testing.T) {
|
|||||||
|
|
||||||
ctx := testutil.Context(t, testutil.WaitMedium)
|
ctx := testutil.Context(t, testutil.WaitMedium)
|
||||||
|
|
||||||
inv, root := clitest.New(t, "organization", "members", "remove", "--organization", owner.OrganizationID.String(), "random_name")
|
inv, root := clitest.New(t, "organization", "members", "remove", "-O", owner.OrganizationID.String(), "random_name")
|
||||||
clitest.SetupConfig(t, orgAdminClient, root)
|
clitest.SetupConfig(t, orgAdminClient, root)
|
||||||
|
|
||||||
buf := new(bytes.Buffer)
|
buf := new(bytes.Buffer)
|
||||||
|
@ -16,7 +16,7 @@ import (
|
|||||||
"github.com/coder/serpent"
|
"github.com/coder/serpent"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (r *RootCmd) organizationRoles() *serpent.Command {
|
func (r *RootCmd) organizationRoles(orgContext *OrganizationContext) *serpent.Command {
|
||||||
cmd := &serpent.Command{
|
cmd := &serpent.Command{
|
||||||
Use: "roles",
|
Use: "roles",
|
||||||
Short: "Manage organization roles.",
|
Short: "Manage organization roles.",
|
||||||
@ -26,14 +26,14 @@ func (r *RootCmd) organizationRoles() *serpent.Command {
|
|||||||
},
|
},
|
||||||
Hidden: true,
|
Hidden: true,
|
||||||
Children: []*serpent.Command{
|
Children: []*serpent.Command{
|
||||||
r.showOrganizationRoles(),
|
r.showOrganizationRoles(orgContext),
|
||||||
r.editOrganizationRole(),
|
r.editOrganizationRole(orgContext),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *RootCmd) showOrganizationRoles() *serpent.Command {
|
func (r *RootCmd) showOrganizationRoles(orgContext *OrganizationContext) *serpent.Command {
|
||||||
formatter := cliui.NewOutputFormatter(
|
formatter := cliui.NewOutputFormatter(
|
||||||
cliui.ChangeFormatterData(
|
cliui.ChangeFormatterData(
|
||||||
cliui.TableFormat([]roleTableRow{}, []string{"name", "display_name", "site_permissions", "organization_permissions", "user_permissions"}),
|
cliui.TableFormat([]roleTableRow{}, []string{"name", "display_name", "site_permissions", "organization_permissions", "user_permissions"}),
|
||||||
@ -63,7 +63,7 @@ func (r *RootCmd) showOrganizationRoles() *serpent.Command {
|
|||||||
),
|
),
|
||||||
Handler: func(inv *serpent.Invocation) error {
|
Handler: func(inv *serpent.Invocation) error {
|
||||||
ctx := inv.Context()
|
ctx := inv.Context()
|
||||||
org, err := CurrentOrganization(r, inv, client)
|
org, err := orgContext.Selected(inv, client)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -100,7 +100,7 @@ func (r *RootCmd) showOrganizationRoles() *serpent.Command {
|
|||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *RootCmd) editOrganizationRole() *serpent.Command {
|
func (r *RootCmd) editOrganizationRole(orgContext *OrganizationContext) *serpent.Command {
|
||||||
formatter := cliui.NewOutputFormatter(
|
formatter := cliui.NewOutputFormatter(
|
||||||
cliui.ChangeFormatterData(
|
cliui.ChangeFormatterData(
|
||||||
cliui.TableFormat([]roleTableRow{}, []string{"name", "display_name", "site_permissions", "organization_permissions", "user_permissions"}),
|
cliui.TableFormat([]roleTableRow{}, []string{"name", "display_name", "site_permissions", "organization_permissions", "user_permissions"}),
|
||||||
@ -148,7 +148,7 @@ func (r *RootCmd) editOrganizationRole() *serpent.Command {
|
|||||||
),
|
),
|
||||||
Handler: func(inv *serpent.Invocation) error {
|
Handler: func(inv *serpent.Invocation) error {
|
||||||
ctx := inv.Context()
|
ctx := inv.Context()
|
||||||
org, err := CurrentOrganization(r, inv, client)
|
org, err := orgContext.Selected(inv, client)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
74
cli/root.go
74
cli/root.go
@ -29,6 +29,7 @@ import (
|
|||||||
"golang.org/x/mod/semver"
|
"golang.org/x/mod/semver"
|
||||||
"golang.org/x/xerrors"
|
"golang.org/x/xerrors"
|
||||||
|
|
||||||
|
"github.com/coder/coder/v2/coderd/database/db2sdk"
|
||||||
"github.com/coder/pretty"
|
"github.com/coder/pretty"
|
||||||
|
|
||||||
"github.com/coder/coder/v2/buildinfo"
|
"github.com/coder/coder/v2/buildinfo"
|
||||||
@ -64,7 +65,6 @@ const (
|
|||||||
varNoFeatureWarning = "no-feature-warning"
|
varNoFeatureWarning = "no-feature-warning"
|
||||||
varForceTty = "force-tty"
|
varForceTty = "force-tty"
|
||||||
varVerbose = "verbose"
|
varVerbose = "verbose"
|
||||||
varOrganizationSelect = "organization"
|
|
||||||
varDisableDirect = "disable-direct-connections"
|
varDisableDirect = "disable-direct-connections"
|
||||||
|
|
||||||
notLoggedInMessage = "You are not logged in. Try logging in using 'coder login <url>'."
|
notLoggedInMessage = "You are not logged in. Try logging in using 'coder login <url>'."
|
||||||
@ -451,15 +451,6 @@ func (r *RootCmd) Command(subcommands []*serpent.Command) (*serpent.Command, err
|
|||||||
Value: serpent.StringOf(&r.globalConfig),
|
Value: serpent.StringOf(&r.globalConfig),
|
||||||
Group: globalGroup,
|
Group: globalGroup,
|
||||||
},
|
},
|
||||||
{
|
|
||||||
Flag: varOrganizationSelect,
|
|
||||||
FlagShorthand: "z",
|
|
||||||
Env: "CODER_ORGANIZATION",
|
|
||||||
Description: "Select which organization (uuid or name) to use This overrides what is present in the config file.",
|
|
||||||
Value: serpent.StringOf(&r.organizationSelect),
|
|
||||||
Hidden: true,
|
|
||||||
Group: globalGroup,
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
Flag: "version",
|
Flag: "version",
|
||||||
// This was requested by a customer to assist with their migration.
|
// This was requested by a customer to assist with their migration.
|
||||||
@ -487,7 +478,6 @@ type RootCmd struct {
|
|||||||
forceTTY bool
|
forceTTY bool
|
||||||
noOpen bool
|
noOpen bool
|
||||||
verbose bool
|
verbose bool
|
||||||
organizationSelect string
|
|
||||||
versionFlag bool
|
versionFlag bool
|
||||||
disableDirect bool
|
disableDirect bool
|
||||||
debugHTTP bool
|
debugHTTP bool
|
||||||
@ -632,52 +622,58 @@ func (r *RootCmd) createAgentClient() (*agentsdk.Client, error) {
|
|||||||
return client, nil
|
return client, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// CurrentOrganization returns the currently active organization for the authenticated user.
|
type OrganizationContext struct {
|
||||||
func CurrentOrganization(r *RootCmd, inv *serpent.Invocation, client *codersdk.Client) (codersdk.Organization, error) {
|
// FlagSelect is the value passed in via the --org flag
|
||||||
conf := r.createConfig()
|
FlagSelect string
|
||||||
selected := r.organizationSelect
|
}
|
||||||
if selected == "" && conf.Organization().Exists() {
|
|
||||||
org, err := conf.Organization().Read()
|
|
||||||
if err != nil {
|
|
||||||
return codersdk.Organization{}, xerrors.Errorf("read selected organization from config file %q: %w", conf.Organization(), err)
|
|
||||||
}
|
|
||||||
selected = org
|
|
||||||
}
|
|
||||||
|
|
||||||
// Verify the org exists and the user is a member
|
func NewOrganizationContext() *OrganizationContext {
|
||||||
|
return &OrganizationContext{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *OrganizationContext) AttachOptions(cmd *serpent.Command) {
|
||||||
|
cmd.Options = append(cmd.Options, serpent.Option{
|
||||||
|
Name: "Organization",
|
||||||
|
Description: "Select which organization (uuid or name) to use.",
|
||||||
|
// Only required if the user is a part of more than 1 organization.
|
||||||
|
// Otherwise, we can assume a default value.
|
||||||
|
Required: false,
|
||||||
|
Flag: "org",
|
||||||
|
FlagShorthand: "O",
|
||||||
|
Env: "CODER_ORGANIZATION",
|
||||||
|
Value: serpent.StringOf(&o.FlagSelect),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *OrganizationContext) Selected(inv *serpent.Invocation, client *codersdk.Client) (codersdk.Organization, error) {
|
||||||
|
// Fetch the set of organizations the user is a member of.
|
||||||
orgs, err := client.OrganizationsByUser(inv.Context(), codersdk.Me)
|
orgs, err := client.OrganizationsByUser(inv.Context(), codersdk.Me)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return codersdk.Organization{}, err
|
return codersdk.Organization{}, xerrors.Errorf("get organizations: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// User manually selected an organization
|
// User manually selected an organization
|
||||||
if selected != "" {
|
if o.FlagSelect != "" {
|
||||||
index := slices.IndexFunc(orgs, func(org codersdk.Organization) bool {
|
index := slices.IndexFunc(orgs, func(org codersdk.Organization) bool {
|
||||||
return org.Name == selected || org.ID.String() == selected
|
return org.Name == o.FlagSelect || org.ID.String() == o.FlagSelect
|
||||||
})
|
})
|
||||||
|
|
||||||
if index < 0 {
|
if index < 0 {
|
||||||
return codersdk.Organization{}, xerrors.Errorf("organization %q not found, are you sure you are a member of this organization? If unsure, run 'coder organizations set \"\" ' to reset your current context.", selected)
|
names := db2sdk.List(orgs, func(f codersdk.Organization) string {
|
||||||
|
return f.Name
|
||||||
|
})
|
||||||
|
return codersdk.Organization{}, xerrors.Errorf("organization %q not found, are you sure you are a member of this organization? "+
|
||||||
|
"Valid options for '--org=' are [%s].", o.FlagSelect, strings.Join(names, ", "))
|
||||||
}
|
}
|
||||||
return orgs[index], nil
|
return orgs[index], nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// User did not select an organization, so use the default.
|
|
||||||
index := slices.IndexFunc(orgs, func(org codersdk.Organization) bool {
|
|
||||||
return org.IsDefault
|
|
||||||
})
|
|
||||||
if index < 0 {
|
|
||||||
if len(orgs) == 1 {
|
if len(orgs) == 1 {
|
||||||
// If there is no "isDefault", but only 1 org is present. We can just
|
|
||||||
// assume the single organization is correct. This is mainly a helper
|
|
||||||
// for cli hitting an old instance, or a user that belongs to a single
|
|
||||||
// org that is not the default.
|
|
||||||
return orgs[0], nil
|
return orgs[0], nil
|
||||||
}
|
}
|
||||||
return codersdk.Organization{}, xerrors.Errorf("unable to determine current organization. Use 'coder org set <org>' to select an organization to use")
|
|
||||||
}
|
|
||||||
|
|
||||||
return orgs[index], nil
|
// No org selected, and we are more than 1? Return an error.
|
||||||
|
return codersdk.Organization{}, xerrors.Errorf("Must select an organization with --org=<org_name>.")
|
||||||
}
|
}
|
||||||
|
|
||||||
func splitNamedWorkspace(identifier string) (owner string, workspaceName string, err error) {
|
func splitNamedWorkspace(identifier string) (owner string, workspaceName string, err error) {
|
||||||
|
@ -31,6 +31,7 @@ func (r *RootCmd) templateCreate() *serpent.Command {
|
|||||||
dormancyAutoDeletion time.Duration
|
dormancyAutoDeletion time.Duration
|
||||||
|
|
||||||
uploadFlags templateUploadFlags
|
uploadFlags templateUploadFlags
|
||||||
|
orgContext = NewOrganizationContext()
|
||||||
)
|
)
|
||||||
client := new(codersdk.Client)
|
client := new(codersdk.Client)
|
||||||
cmd := &serpent.Command{
|
cmd := &serpent.Command{
|
||||||
@ -68,7 +69,7 @@ func (r *RootCmd) templateCreate() *serpent.Command {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
organization, err := CurrentOrganization(r, inv, client)
|
organization, err := orgContext.Selected(inv, client)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -15,6 +15,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func (r *RootCmd) templateDelete() *serpent.Command {
|
func (r *RootCmd) templateDelete() *serpent.Command {
|
||||||
|
orgContext := NewOrganizationContext()
|
||||||
client := new(codersdk.Client)
|
client := new(codersdk.Client)
|
||||||
cmd := &serpent.Command{
|
cmd := &serpent.Command{
|
||||||
Use: "delete [name...]",
|
Use: "delete [name...]",
|
||||||
@ -32,7 +33,7 @@ func (r *RootCmd) templateDelete() *serpent.Command {
|
|||||||
templates = []codersdk.Template{}
|
templates = []codersdk.Template{}
|
||||||
)
|
)
|
||||||
|
|
||||||
organization, err := CurrentOrganization(r, inv, client)
|
organization, err := orgContext.Selected(inv, client)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -81,6 +82,7 @@ func (r *RootCmd) templateDelete() *serpent.Command {
|
|||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
orgContext.AttachOptions(cmd)
|
||||||
|
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
@ -36,6 +36,7 @@ func (r *RootCmd) templateEdit() *serpent.Command {
|
|||||||
requireActiveVersion bool
|
requireActiveVersion bool
|
||||||
deprecationMessage string
|
deprecationMessage string
|
||||||
disableEveryone bool
|
disableEveryone bool
|
||||||
|
orgContext = NewOrganizationContext()
|
||||||
)
|
)
|
||||||
client := new(codersdk.Client)
|
client := new(codersdk.Client)
|
||||||
|
|
||||||
@ -77,7 +78,7 @@ func (r *RootCmd) templateEdit() *serpent.Command {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
organization, err := CurrentOrganization(r, inv, client)
|
organization, err := orgContext.Selected(inv, client)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return xerrors.Errorf("get current organization: %w", err)
|
return xerrors.Errorf("get current organization: %w", err)
|
||||||
}
|
}
|
||||||
@ -324,6 +325,7 @@ func (r *RootCmd) templateEdit() *serpent.Command {
|
|||||||
},
|
},
|
||||||
cliui.SkipPromptOption(),
|
cliui.SkipPromptOption(),
|
||||||
}
|
}
|
||||||
|
orgContext.AttachOptions(cmd)
|
||||||
|
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
@ -11,6 +11,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func (r *RootCmd) templateList() *serpent.Command {
|
func (r *RootCmd) templateList() *serpent.Command {
|
||||||
|
orgContext := NewOrganizationContext()
|
||||||
formatter := cliui.NewOutputFormatter(
|
formatter := cliui.NewOutputFormatter(
|
||||||
cliui.TableFormat([]templateTableRow{}, []string{"name", "last updated", "used by"}),
|
cliui.TableFormat([]templateTableRow{}, []string{"name", "last updated", "used by"}),
|
||||||
cliui.JSONFormat(),
|
cliui.JSONFormat(),
|
||||||
@ -25,7 +26,7 @@ func (r *RootCmd) templateList() *serpent.Command {
|
|||||||
r.InitClient(client),
|
r.InitClient(client),
|
||||||
),
|
),
|
||||||
Handler: func(inv *serpent.Invocation) error {
|
Handler: func(inv *serpent.Invocation) error {
|
||||||
organization, err := CurrentOrganization(r, inv, client)
|
organization, err := orgContext.Selected(inv, client)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -52,5 +53,6 @@ func (r *RootCmd) templateList() *serpent.Command {
|
|||||||
}
|
}
|
||||||
|
|
||||||
formatter.AttachOptions(&cmd.Options)
|
formatter.AttachOptions(&cmd.Options)
|
||||||
|
orgContext.AttachOptions(cmd)
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
@ -20,6 +20,7 @@ func (r *RootCmd) templatePull() *serpent.Command {
|
|||||||
tarMode bool
|
tarMode bool
|
||||||
zipMode bool
|
zipMode bool
|
||||||
versionName string
|
versionName string
|
||||||
|
orgContext = NewOrganizationContext()
|
||||||
)
|
)
|
||||||
|
|
||||||
client := new(codersdk.Client)
|
client := new(codersdk.Client)
|
||||||
@ -45,7 +46,7 @@ func (r *RootCmd) templatePull() *serpent.Command {
|
|||||||
return xerrors.Errorf("either tar or zip can be selected")
|
return xerrors.Errorf("either tar or zip can be selected")
|
||||||
}
|
}
|
||||||
|
|
||||||
organization, err := CurrentOrganization(r, inv, client)
|
organization, err := orgContext.Selected(inv, client)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return xerrors.Errorf("get current organization: %w", err)
|
return xerrors.Errorf("get current organization: %w", err)
|
||||||
}
|
}
|
||||||
@ -187,6 +188,7 @@ func (r *RootCmd) templatePull() *serpent.Command {
|
|||||||
},
|
},
|
||||||
cliui.SkipPromptOption(),
|
cliui.SkipPromptOption(),
|
||||||
}
|
}
|
||||||
|
orgContext.AttachOptions(cmd)
|
||||||
|
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
@ -34,6 +34,7 @@ func (r *RootCmd) templatePush() *serpent.Command {
|
|||||||
provisionerTags []string
|
provisionerTags []string
|
||||||
uploadFlags templateUploadFlags
|
uploadFlags templateUploadFlags
|
||||||
activate bool
|
activate bool
|
||||||
|
orgContext = NewOrganizationContext()
|
||||||
)
|
)
|
||||||
client := new(codersdk.Client)
|
client := new(codersdk.Client)
|
||||||
cmd := &serpent.Command{
|
cmd := &serpent.Command{
|
||||||
@ -46,7 +47,7 @@ func (r *RootCmd) templatePush() *serpent.Command {
|
|||||||
Handler: func(inv *serpent.Invocation) error {
|
Handler: func(inv *serpent.Invocation) error {
|
||||||
uploadFlags.setWorkdir(workdir)
|
uploadFlags.setWorkdir(workdir)
|
||||||
|
|
||||||
organization, err := CurrentOrganization(r, inv, client)
|
organization, err := orgContext.Selected(inv, client)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -226,6 +227,7 @@ func (r *RootCmd) templatePush() *serpent.Command {
|
|||||||
cliui.SkipPromptOption(),
|
cliui.SkipPromptOption(),
|
||||||
}
|
}
|
||||||
cmd.Options = append(cmd.Options, uploadFlags.options()...)
|
cmd.Options = append(cmd.Options, uploadFlags.options()...)
|
||||||
|
orgContext.AttachOptions(cmd)
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,6 +31,7 @@ func (r *RootCmd) setArchiveTemplateVersion(archive bool) *serpent.Command {
|
|||||||
pastVerb = "unarchived"
|
pastVerb = "unarchived"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
orgContext := NewOrganizationContext()
|
||||||
client := new(codersdk.Client)
|
client := new(codersdk.Client)
|
||||||
cmd := &serpent.Command{
|
cmd := &serpent.Command{
|
||||||
Use: presentVerb + " <template-name> [template-version-names...] ",
|
Use: presentVerb + " <template-name> [template-version-names...] ",
|
||||||
@ -47,7 +48,7 @@ func (r *RootCmd) setArchiveTemplateVersion(archive bool) *serpent.Command {
|
|||||||
versions []codersdk.TemplateVersion
|
versions []codersdk.TemplateVersion
|
||||||
)
|
)
|
||||||
|
|
||||||
organization, err := CurrentOrganization(r, inv, client)
|
organization, err := orgContext.Selected(inv, client)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -92,6 +93,7 @@ func (r *RootCmd) setArchiveTemplateVersion(archive bool) *serpent.Command {
|
|||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
orgContext.AttachOptions(cmd)
|
||||||
|
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
@ -99,6 +101,7 @@ func (r *RootCmd) setArchiveTemplateVersion(archive bool) *serpent.Command {
|
|||||||
func (r *RootCmd) archiveTemplateVersions() *serpent.Command {
|
func (r *RootCmd) archiveTemplateVersions() *serpent.Command {
|
||||||
var all serpent.Bool
|
var all serpent.Bool
|
||||||
client := new(codersdk.Client)
|
client := new(codersdk.Client)
|
||||||
|
orgContext := NewOrganizationContext()
|
||||||
cmd := &serpent.Command{
|
cmd := &serpent.Command{
|
||||||
Use: "archive [template-name...] ",
|
Use: "archive [template-name...] ",
|
||||||
Short: "Archive unused or failed template versions from a given template(s)",
|
Short: "Archive unused or failed template versions from a given template(s)",
|
||||||
@ -121,7 +124,7 @@ func (r *RootCmd) archiveTemplateVersions() *serpent.Command {
|
|||||||
templates = []codersdk.Template{}
|
templates = []codersdk.Template{}
|
||||||
)
|
)
|
||||||
|
|
||||||
organization, err := CurrentOrganization(r, inv, client)
|
organization, err := orgContext.Selected(inv, client)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -179,6 +182,7 @@ func (r *RootCmd) archiveTemplateVersions() *serpent.Command {
|
|||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
orgContext.AttachOptions(cmd)
|
||||||
|
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
@ -51,6 +51,7 @@ func (r *RootCmd) templateVersionsList() *serpent.Command {
|
|||||||
cliui.JSONFormat(),
|
cliui.JSONFormat(),
|
||||||
)
|
)
|
||||||
client := new(codersdk.Client)
|
client := new(codersdk.Client)
|
||||||
|
orgContext := NewOrganizationContext()
|
||||||
|
|
||||||
var includeArchived serpent.Bool
|
var includeArchived serpent.Bool
|
||||||
|
|
||||||
@ -93,7 +94,7 @@ func (r *RootCmd) templateVersionsList() *serpent.Command {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
Handler: func(inv *serpent.Invocation) error {
|
Handler: func(inv *serpent.Invocation) error {
|
||||||
organization, err := CurrentOrganization(r, inv, client)
|
organization, err := orgContext.Selected(inv, client)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return xerrors.Errorf("get current organization: %w", err)
|
return xerrors.Errorf("get current organization: %w", err)
|
||||||
}
|
}
|
||||||
@ -122,6 +123,7 @@ func (r *RootCmd) templateVersionsList() *serpent.Command {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
orgContext.AttachOptions(cmd)
|
||||||
formatter.AttachOptions(&cmd.Options)
|
formatter.AttachOptions(&cmd.Options)
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
3
cli/testdata/coder_create_--help.golden
vendored
3
cli/testdata/coder_create_--help.golden
vendored
@ -10,6 +10,9 @@ USAGE:
|
|||||||
$ coder create <username>/<workspace_name>
|
$ coder create <username>/<workspace_name>
|
||||||
|
|
||||||
OPTIONS:
|
OPTIONS:
|
||||||
|
-O, --org string, $CODER_ORGANIZATION
|
||||||
|
Select which organization (uuid or name) to use.
|
||||||
|
|
||||||
--automatic-updates string, $CODER_WORKSPACE_AUTOMATIC_UPDATES (default: never)
|
--automatic-updates string, $CODER_WORKSPACE_AUTOMATIC_UPDATES (default: never)
|
||||||
Specify automatic updates setting for the workspace (accepts 'always'
|
Specify automatic updates setting for the workspace (accepts 'always'
|
||||||
or 'never').
|
or 'never').
|
||||||
|
@ -6,6 +6,9 @@ USAGE:
|
|||||||
Archive unused or failed template versions from a given template(s)
|
Archive unused or failed template versions from a given template(s)
|
||||||
|
|
||||||
OPTIONS:
|
OPTIONS:
|
||||||
|
-O, --org string, $CODER_ORGANIZATION
|
||||||
|
Select which organization (uuid or name) to use.
|
||||||
|
|
||||||
--all bool
|
--all bool
|
||||||
Include all unused template versions. By default, only failed template
|
Include all unused template versions. By default, only failed template
|
||||||
versions are archived.
|
versions are archived.
|
||||||
|
@ -8,6 +8,9 @@ USAGE:
|
|||||||
Aliases: rm
|
Aliases: rm
|
||||||
|
|
||||||
OPTIONS:
|
OPTIONS:
|
||||||
|
-O, --org string, $CODER_ORGANIZATION
|
||||||
|
Select which organization (uuid or name) to use.
|
||||||
|
|
||||||
-y, --yes bool
|
-y, --yes bool
|
||||||
Bypass prompts.
|
Bypass prompts.
|
||||||
|
|
||||||
|
@ -6,6 +6,9 @@ USAGE:
|
|||||||
Edit the metadata of a template by name.
|
Edit the metadata of a template by name.
|
||||||
|
|
||||||
OPTIONS:
|
OPTIONS:
|
||||||
|
-O, --org string, $CODER_ORGANIZATION
|
||||||
|
Select which organization (uuid or name) to use.
|
||||||
|
|
||||||
--activity-bump duration
|
--activity-bump duration
|
||||||
Edit the template activity bump - workspaces created from this
|
Edit the template activity bump - workspaces created from this
|
||||||
template will have their shutdown time bumped by this value when
|
template will have their shutdown time bumped by this value when
|
||||||
|
@ -8,6 +8,9 @@ USAGE:
|
|||||||
Aliases: ls
|
Aliases: ls
|
||||||
|
|
||||||
OPTIONS:
|
OPTIONS:
|
||||||
|
-O, --org string, $CODER_ORGANIZATION
|
||||||
|
Select which organization (uuid or name) to use.
|
||||||
|
|
||||||
-c, --column string-array (default: name,last updated,used by)
|
-c, --column string-array (default: name,last updated,used by)
|
||||||
Columns to display in table output. Available columns: name, created
|
Columns to display in table output. Available columns: name, created
|
||||||
at, last updated, organization id, provisioner, active version id,
|
at, last updated, organization id, provisioner, active version id,
|
||||||
|
@ -6,6 +6,9 @@ USAGE:
|
|||||||
Download the active, latest, or specified version of a template to a path.
|
Download the active, latest, or specified version of a template to a path.
|
||||||
|
|
||||||
OPTIONS:
|
OPTIONS:
|
||||||
|
-O, --org string, $CODER_ORGANIZATION
|
||||||
|
Select which organization (uuid or name) to use.
|
||||||
|
|
||||||
--tar bool
|
--tar bool
|
||||||
Output the template as a tar archive to stdout.
|
Output the template as a tar archive to stdout.
|
||||||
|
|
||||||
|
@ -6,6 +6,9 @@ USAGE:
|
|||||||
Create or update a template from the current directory or as specified by flag
|
Create or update a template from the current directory or as specified by flag
|
||||||
|
|
||||||
OPTIONS:
|
OPTIONS:
|
||||||
|
-O, --org string, $CODER_ORGANIZATION
|
||||||
|
Select which organization (uuid or name) to use.
|
||||||
|
|
||||||
--activate bool (default: true)
|
--activate bool (default: true)
|
||||||
Whether the new template will be marked active.
|
Whether the new template will be marked active.
|
||||||
|
|
||||||
|
@ -7,6 +7,9 @@ USAGE:
|
|||||||
Archive a template version(s).
|
Archive a template version(s).
|
||||||
|
|
||||||
OPTIONS:
|
OPTIONS:
|
||||||
|
-O, --org string, $CODER_ORGANIZATION
|
||||||
|
Select which organization (uuid or name) to use.
|
||||||
|
|
||||||
-y, --yes bool
|
-y, --yes bool
|
||||||
Bypass prompts.
|
Bypass prompts.
|
||||||
|
|
||||||
|
@ -6,6 +6,9 @@ USAGE:
|
|||||||
List all the versions of the specified template
|
List all the versions of the specified template
|
||||||
|
|
||||||
OPTIONS:
|
OPTIONS:
|
||||||
|
-O, --org string, $CODER_ORGANIZATION
|
||||||
|
Select which organization (uuid or name) to use.
|
||||||
|
|
||||||
-c, --column string-array (default: Name,Created At,Created By,Status,Active)
|
-c, --column string-array (default: Name,Created At,Created By,Status,Active)
|
||||||
Columns to display in table output. Available columns: name, created
|
Columns to display in table output. Available columns: name, created
|
||||||
at, created by, status, active, archived.
|
at, created by, status, active, archived.
|
||||||
|
@ -7,6 +7,9 @@ USAGE:
|
|||||||
Unarchive a template version(s).
|
Unarchive a template version(s).
|
||||||
|
|
||||||
OPTIONS:
|
OPTIONS:
|
||||||
|
-O, --org string, $CODER_ORGANIZATION
|
||||||
|
Select which organization (uuid or name) to use.
|
||||||
|
|
||||||
-y, --yes bool
|
-y, --yes bool
|
||||||
Bypass prompts.
|
Bypass prompts.
|
||||||
|
|
||||||
|
@ -4,6 +4,9 @@ USAGE:
|
|||||||
coder users create [flags]
|
coder users create [flags]
|
||||||
|
|
||||||
OPTIONS:
|
OPTIONS:
|
||||||
|
-O, --org string, $CODER_ORGANIZATION
|
||||||
|
Select which organization (uuid or name) to use.
|
||||||
|
|
||||||
-e, --email string
|
-e, --email string
|
||||||
Specifies an email address for the new user.
|
Specifies an email address for the new user.
|
||||||
|
|
||||||
|
@ -24,6 +24,7 @@ func (r *RootCmd) userCreate() *serpent.Command {
|
|||||||
password string
|
password string
|
||||||
disableLogin bool
|
disableLogin bool
|
||||||
loginType string
|
loginType string
|
||||||
|
orgContext = NewOrganizationContext()
|
||||||
)
|
)
|
||||||
client := new(codersdk.Client)
|
client := new(codersdk.Client)
|
||||||
cmd := &serpent.Command{
|
cmd := &serpent.Command{
|
||||||
@ -33,7 +34,7 @@ func (r *RootCmd) userCreate() *serpent.Command {
|
|||||||
r.InitClient(client),
|
r.InitClient(client),
|
||||||
),
|
),
|
||||||
Handler: func(inv *serpent.Invocation) error {
|
Handler: func(inv *serpent.Invocation) error {
|
||||||
organization, err := CurrentOrganization(r, inv, client)
|
organization, err := orgContext.Selected(inv, client)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -175,5 +176,7 @@ Create a workspace `+pretty.Sprint(cliui.DefaultStyles.Code, "coder create")+`!
|
|||||||
Value: serpent.StringOf(&loginType),
|
Value: serpent.StringOf(&loginType),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
orgContext.AttachOptions(cmd)
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
9
docs/cli/create.md
generated
9
docs/cli/create.md
generated
@ -100,3 +100,12 @@ Specify a file path with values for rich parameters defined in the template.
|
|||||||
| Environment | <code>$CODER_RICH_PARAMETER_DEFAULT</code> |
|
| Environment | <code>$CODER_RICH_PARAMETER_DEFAULT</code> |
|
||||||
|
|
||||||
Rich parameter default values in the format "name=value".
|
Rich parameter default values in the format "name=value".
|
||||||
|
|
||||||
|
### -O, --org
|
||||||
|
|
||||||
|
| | |
|
||||||
|
| ----------- | -------------------------------- |
|
||||||
|
| Type | <code>string</code> |
|
||||||
|
| Environment | <code>$CODER_ORGANIZATION</code> |
|
||||||
|
|
||||||
|
Select which organization (uuid or name) to use.
|
||||||
|
9
docs/cli/groups_create.md
generated
9
docs/cli/groups_create.md
generated
@ -29,3 +29,12 @@ Set an avatar for a group.
|
|||||||
| Environment | <code>$CODER_DISPLAY_NAME</code> |
|
| Environment | <code>$CODER_DISPLAY_NAME</code> |
|
||||||
|
|
||||||
Optional human friendly name for the group.
|
Optional human friendly name for the group.
|
||||||
|
|
||||||
|
### -O, --org
|
||||||
|
|
||||||
|
| | |
|
||||||
|
| ----------- | -------------------------------- |
|
||||||
|
| Type | <code>string</code> |
|
||||||
|
| Environment | <code>$CODER_ORGANIZATION</code> |
|
||||||
|
|
||||||
|
Select which organization (uuid or name) to use.
|
||||||
|
13
docs/cli/groups_delete.md
generated
13
docs/cli/groups_delete.md
generated
@ -11,5 +11,16 @@ Aliases:
|
|||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
```console
|
```console
|
||||||
coder groups delete <name>
|
coder groups delete [flags] <name>
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Options
|
||||||
|
|
||||||
|
### -O, --org
|
||||||
|
|
||||||
|
| | |
|
||||||
|
| ----------- | -------------------------------- |
|
||||||
|
| Type | <code>string</code> |
|
||||||
|
| Environment | <code>$CODER_ORGANIZATION</code> |
|
||||||
|
|
||||||
|
Select which organization (uuid or name) to use.
|
||||||
|
9
docs/cli/groups_edit.md
generated
9
docs/cli/groups_edit.md
generated
@ -52,3 +52,12 @@ Add users to the group. Accepts emails or IDs.
|
|||||||
| Type | <code>string-array</code> |
|
| Type | <code>string-array</code> |
|
||||||
|
|
||||||
Remove users to the group. Accepts emails or IDs.
|
Remove users to the group. Accepts emails or IDs.
|
||||||
|
|
||||||
|
### -O, --org
|
||||||
|
|
||||||
|
| | |
|
||||||
|
| ----------- | -------------------------------- |
|
||||||
|
| Type | <code>string</code> |
|
||||||
|
| Environment | <code>$CODER_ORGANIZATION</code> |
|
||||||
|
|
||||||
|
Select which organization (uuid or name) to use.
|
||||||
|
9
docs/cli/groups_list.md
generated
9
docs/cli/groups_list.md
generated
@ -29,3 +29,12 @@ Columns to display in table output. Available columns: name, display name, organ
|
|||||||
| Default | <code>table</code> |
|
| Default | <code>table</code> |
|
||||||
|
|
||||||
Output format. Available formats: table, json.
|
Output format. Available formats: table, json.
|
||||||
|
|
||||||
|
### -O, --org
|
||||||
|
|
||||||
|
| | |
|
||||||
|
| ----------- | -------------------------------- |
|
||||||
|
| Type | <code>string</code> |
|
||||||
|
| Environment | <code>$CODER_ORGANIZATION</code> |
|
||||||
|
|
||||||
|
Select which organization (uuid or name) to use.
|
||||||
|
9
docs/cli/templates_archive.md
generated
9
docs/cli/templates_archive.md
generated
@ -27,3 +27,12 @@ Bypass prompts.
|
|||||||
| Type | <code>bool</code> |
|
| Type | <code>bool</code> |
|
||||||
|
|
||||||
Include all unused template versions. By default, only failed template versions are archived.
|
Include all unused template versions. By default, only failed template versions are archived.
|
||||||
|
|
||||||
|
### -O, --org
|
||||||
|
|
||||||
|
| | |
|
||||||
|
| ----------- | -------------------------------- |
|
||||||
|
| Type | <code>string</code> |
|
||||||
|
| Environment | <code>$CODER_ORGANIZATION</code> |
|
||||||
|
|
||||||
|
Select which organization (uuid or name) to use.
|
||||||
|
9
docs/cli/templates_delete.md
generated
9
docs/cli/templates_delete.md
generated
@ -23,3 +23,12 @@ coder templates delete [flags] [name...]
|
|||||||
| Type | <code>bool</code> |
|
| Type | <code>bool</code> |
|
||||||
|
|
||||||
Bypass prompts.
|
Bypass prompts.
|
||||||
|
|
||||||
|
### -O, --org
|
||||||
|
|
||||||
|
| | |
|
||||||
|
| ----------- | -------------------------------- |
|
||||||
|
| Type | <code>string</code> |
|
||||||
|
| Environment | <code>$CODER_ORGANIZATION</code> |
|
||||||
|
|
||||||
|
Select which organization (uuid or name) to use.
|
||||||
|
9
docs/cli/templates_edit.md
generated
9
docs/cli/templates_edit.md
generated
@ -171,3 +171,12 @@ Disable the default behavior of granting template access to the 'everyone' group
|
|||||||
| Type | <code>bool</code> |
|
| Type | <code>bool</code> |
|
||||||
|
|
||||||
Bypass prompts.
|
Bypass prompts.
|
||||||
|
|
||||||
|
### -O, --org
|
||||||
|
|
||||||
|
| | |
|
||||||
|
| ----------- | -------------------------------- |
|
||||||
|
| Type | <code>string</code> |
|
||||||
|
| Environment | <code>$CODER_ORGANIZATION</code> |
|
||||||
|
|
||||||
|
Select which organization (uuid or name) to use.
|
||||||
|
9
docs/cli/templates_list.md
generated
9
docs/cli/templates_list.md
generated
@ -33,3 +33,12 @@ Columns to display in table output. Available columns: name, created at, last up
|
|||||||
| Default | <code>table</code> |
|
| Default | <code>table</code> |
|
||||||
|
|
||||||
Output format. Available formats: table, json.
|
Output format. Available formats: table, json.
|
||||||
|
|
||||||
|
### -O, --org
|
||||||
|
|
||||||
|
| | |
|
||||||
|
| ----------- | -------------------------------- |
|
||||||
|
| Type | <code>string</code> |
|
||||||
|
| Environment | <code>$CODER_ORGANIZATION</code> |
|
||||||
|
|
||||||
|
Select which organization (uuid or name) to use.
|
||||||
|
9
docs/cli/templates_pull.md
generated
9
docs/cli/templates_pull.md
generated
@ -43,3 +43,12 @@ The name of the template version to pull. Use 'active' to pull the active versio
|
|||||||
| Type | <code>bool</code> |
|
| Type | <code>bool</code> |
|
||||||
|
|
||||||
Bypass prompts.
|
Bypass prompts.
|
||||||
|
|
||||||
|
### -O, --org
|
||||||
|
|
||||||
|
| | |
|
||||||
|
| ----------- | -------------------------------- |
|
||||||
|
| Type | <code>string</code> |
|
||||||
|
| Environment | <code>$CODER_ORGANIZATION</code> |
|
||||||
|
|
||||||
|
Select which organization (uuid or name) to use.
|
||||||
|
9
docs/cli/templates_push.md
generated
9
docs/cli/templates_push.md
generated
@ -102,3 +102,12 @@ Ignore warnings about not having a .terraform.lock.hcl file present in the templ
|
|||||||
| Type | <code>string</code> |
|
| Type | <code>string</code> |
|
||||||
|
|
||||||
Specify a message describing the changes in this version of the template. Messages longer than 72 characters will be displayed as truncated.
|
Specify a message describing the changes in this version of the template. Messages longer than 72 characters will be displayed as truncated.
|
||||||
|
|
||||||
|
### -O, --org
|
||||||
|
|
||||||
|
| | |
|
||||||
|
| ----------- | -------------------------------- |
|
||||||
|
| Type | <code>string</code> |
|
||||||
|
| Environment | <code>$CODER_ORGANIZATION</code> |
|
||||||
|
|
||||||
|
Select which organization (uuid or name) to use.
|
||||||
|
9
docs/cli/templates_versions_archive.md
generated
9
docs/cli/templates_versions_archive.md
generated
@ -19,3 +19,12 @@ coder templates versions archive [flags] <template-name> [template-version-names
|
|||||||
| Type | <code>bool</code> |
|
| Type | <code>bool</code> |
|
||||||
|
|
||||||
Bypass prompts.
|
Bypass prompts.
|
||||||
|
|
||||||
|
### -O, --org
|
||||||
|
|
||||||
|
| | |
|
||||||
|
| ----------- | -------------------------------- |
|
||||||
|
| Type | <code>string</code> |
|
||||||
|
| Environment | <code>$CODER_ORGANIZATION</code> |
|
||||||
|
|
||||||
|
Select which organization (uuid or name) to use.
|
||||||
|
9
docs/cli/templates_versions_list.md
generated
9
docs/cli/templates_versions_list.md
generated
@ -20,6 +20,15 @@ coder templates versions list [flags] <template>
|
|||||||
|
|
||||||
Include archived versions in the result list.
|
Include archived versions in the result list.
|
||||||
|
|
||||||
|
### -O, --org
|
||||||
|
|
||||||
|
| | |
|
||||||
|
| ----------- | -------------------------------- |
|
||||||
|
| Type | <code>string</code> |
|
||||||
|
| Environment | <code>$CODER_ORGANIZATION</code> |
|
||||||
|
|
||||||
|
Select which organization (uuid or name) to use.
|
||||||
|
|
||||||
### -c, --column
|
### -c, --column
|
||||||
|
|
||||||
| | |
|
| | |
|
||||||
|
9
docs/cli/templates_versions_unarchive.md
generated
9
docs/cli/templates_versions_unarchive.md
generated
@ -19,3 +19,12 @@ coder templates versions unarchive [flags] <template-name> [template-version-nam
|
|||||||
| Type | <code>bool</code> |
|
| Type | <code>bool</code> |
|
||||||
|
|
||||||
Bypass prompts.
|
Bypass prompts.
|
||||||
|
|
||||||
|
### -O, --org
|
||||||
|
|
||||||
|
| | |
|
||||||
|
| ----------- | -------------------------------- |
|
||||||
|
| Type | <code>string</code> |
|
||||||
|
| Environment | <code>$CODER_ORGANIZATION</code> |
|
||||||
|
|
||||||
|
Select which organization (uuid or name) to use.
|
||||||
|
9
docs/cli/users_create.md
generated
9
docs/cli/users_create.md
generated
@ -49,3 +49,12 @@ Specifies a password for the new user.
|
|||||||
| Type | <code>string</code> |
|
| Type | <code>string</code> |
|
||||||
|
|
||||||
Optionally specify the login type for the user. Valid values are: password, none, github, oidc. Using 'none' prevents the user from authenticating and requires an API key/token to be generated by an admin.
|
Optionally specify the login type for the user. Valid values are: password, none, github, oidc. Using 'none' prevents the user from authenticating and requires an API key/token to be generated by an admin.
|
||||||
|
|
||||||
|
### -O, --org
|
||||||
|
|
||||||
|
| | |
|
||||||
|
| ----------- | -------------------------------- |
|
||||||
|
| Type | <code>string</code> |
|
||||||
|
| Environment | <code>$CODER_ORGANIZATION</code> |
|
||||||
|
|
||||||
|
Select which organization (uuid or name) to use.
|
||||||
|
@ -16,6 +16,7 @@ func (r *RootCmd) groupCreate() *serpent.Command {
|
|||||||
var (
|
var (
|
||||||
avatarURL string
|
avatarURL string
|
||||||
displayName string
|
displayName string
|
||||||
|
orgContext = agpl.NewOrganizationContext()
|
||||||
)
|
)
|
||||||
|
|
||||||
client := new(codersdk.Client)
|
client := new(codersdk.Client)
|
||||||
@ -29,7 +30,7 @@ func (r *RootCmd) groupCreate() *serpent.Command {
|
|||||||
Handler: func(inv *serpent.Invocation) error {
|
Handler: func(inv *serpent.Invocation) error {
|
||||||
ctx := inv.Context()
|
ctx := inv.Context()
|
||||||
|
|
||||||
org, err := agpl.CurrentOrganization(&r.RootCmd, inv, client)
|
org, err := orgContext.Selected(inv, client)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return xerrors.Errorf("current organization: %w", err)
|
return xerrors.Errorf("current organization: %w", err)
|
||||||
}
|
}
|
||||||
@ -63,6 +64,7 @@ func (r *RootCmd) groupCreate() *serpent.Command {
|
|||||||
Value: serpent.StringOf(&displayName),
|
Value: serpent.StringOf(&displayName),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
orgContext.AttachOptions(cmd)
|
||||||
|
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
@ -13,6 +13,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func (r *RootCmd) groupDelete() *serpent.Command {
|
func (r *RootCmd) groupDelete() *serpent.Command {
|
||||||
|
orgContext := agpl.NewOrganizationContext()
|
||||||
client := new(codersdk.Client)
|
client := new(codersdk.Client)
|
||||||
cmd := &serpent.Command{
|
cmd := &serpent.Command{
|
||||||
Use: "delete <name>",
|
Use: "delete <name>",
|
||||||
@ -27,7 +28,7 @@ func (r *RootCmd) groupDelete() *serpent.Command {
|
|||||||
groupName = inv.Args[0]
|
groupName = inv.Args[0]
|
||||||
)
|
)
|
||||||
|
|
||||||
org, err := agpl.CurrentOrganization(&r.RootCmd, inv, client)
|
org, err := orgContext.Selected(inv, client)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return xerrors.Errorf("current organization: %w", err)
|
return xerrors.Errorf("current organization: %w", err)
|
||||||
}
|
}
|
||||||
@ -46,6 +47,7 @@ func (r *RootCmd) groupDelete() *serpent.Command {
|
|||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
orgContext.AttachOptions(cmd)
|
||||||
|
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
@ -22,6 +22,7 @@ func (r *RootCmd) groupEdit() *serpent.Command {
|
|||||||
displayName string
|
displayName string
|
||||||
addUsers []string
|
addUsers []string
|
||||||
rmUsers []string
|
rmUsers []string
|
||||||
|
orgContext = agpl.NewOrganizationContext()
|
||||||
)
|
)
|
||||||
client := new(codersdk.Client)
|
client := new(codersdk.Client)
|
||||||
cmd := &serpent.Command{
|
cmd := &serpent.Command{
|
||||||
@ -37,7 +38,7 @@ func (r *RootCmd) groupEdit() *serpent.Command {
|
|||||||
groupName = inv.Args[0]
|
groupName = inv.Args[0]
|
||||||
)
|
)
|
||||||
|
|
||||||
org, err := agpl.CurrentOrganization(&r.RootCmd, inv, client)
|
org, err := orgContext.Selected(inv, client)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return xerrors.Errorf("current organization: %w", err)
|
return xerrors.Errorf("current organization: %w", err)
|
||||||
}
|
}
|
||||||
@ -116,6 +117,7 @@ func (r *RootCmd) groupEdit() *serpent.Command {
|
|||||||
Value: serpent.StringArrayOf(&rmUsers),
|
Value: serpent.StringArrayOf(&rmUsers),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
orgContext.AttachOptions(cmd)
|
||||||
|
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,7 @@ func (r *RootCmd) groupList() *serpent.Command {
|
|||||||
cliui.TableFormat([]groupTableRow{}, nil),
|
cliui.TableFormat([]groupTableRow{}, nil),
|
||||||
cliui.JSONFormat(),
|
cliui.JSONFormat(),
|
||||||
)
|
)
|
||||||
|
orgContext := agpl.NewOrganizationContext()
|
||||||
|
|
||||||
client := new(codersdk.Client)
|
client := new(codersdk.Client)
|
||||||
cmd := &serpent.Command{
|
cmd := &serpent.Command{
|
||||||
@ -30,7 +31,7 @@ func (r *RootCmd) groupList() *serpent.Command {
|
|||||||
Handler: func(inv *serpent.Invocation) error {
|
Handler: func(inv *serpent.Invocation) error {
|
||||||
ctx := inv.Context()
|
ctx := inv.Context()
|
||||||
|
|
||||||
org, err := agpl.CurrentOrganization(&r.RootCmd, inv, client)
|
org, err := orgContext.Selected(inv, client)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return xerrors.Errorf("current organization: %w", err)
|
return xerrors.Errorf("current organization: %w", err)
|
||||||
}
|
}
|
||||||
@ -58,6 +59,7 @@ func (r *RootCmd) groupList() *serpent.Command {
|
|||||||
}
|
}
|
||||||
|
|
||||||
formatter.AttachOptions(&cmd.Options)
|
formatter.AttachOptions(&cmd.Options)
|
||||||
|
orgContext.AttachOptions(cmd)
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,6 +6,9 @@ USAGE:
|
|||||||
Create a user group
|
Create a user group
|
||||||
|
|
||||||
OPTIONS:
|
OPTIONS:
|
||||||
|
-O, --org string, $CODER_ORGANIZATION
|
||||||
|
Select which organization (uuid or name) to use.
|
||||||
|
|
||||||
-u, --avatar-url string, $CODER_AVATAR_URL
|
-u, --avatar-url string, $CODER_AVATAR_URL
|
||||||
Set an avatar for a group.
|
Set an avatar for a group.
|
||||||
|
|
||||||
|
@ -1,11 +1,15 @@
|
|||||||
coder v0.0.0-devel
|
coder v0.0.0-devel
|
||||||
|
|
||||||
USAGE:
|
USAGE:
|
||||||
coder groups delete <name>
|
coder groups delete [flags] <name>
|
||||||
|
|
||||||
Delete a user group
|
Delete a user group
|
||||||
|
|
||||||
Aliases: rm
|
Aliases: rm
|
||||||
|
|
||||||
|
OPTIONS:
|
||||||
|
-O, --org string, $CODER_ORGANIZATION
|
||||||
|
Select which organization (uuid or name) to use.
|
||||||
|
|
||||||
———
|
———
|
||||||
Run `coder --help` for a list of global options.
|
Run `coder --help` for a list of global options.
|
||||||
|
@ -6,6 +6,9 @@ USAGE:
|
|||||||
Edit a user group
|
Edit a user group
|
||||||
|
|
||||||
OPTIONS:
|
OPTIONS:
|
||||||
|
-O, --org string, $CODER_ORGANIZATION
|
||||||
|
Select which organization (uuid or name) to use.
|
||||||
|
|
||||||
-a, --add-users string-array
|
-a, --add-users string-array
|
||||||
Add users to the group. Accepts emails or IDs.
|
Add users to the group. Accepts emails or IDs.
|
||||||
|
|
||||||
|
@ -6,6 +6,9 @@ USAGE:
|
|||||||
List user groups
|
List user groups
|
||||||
|
|
||||||
OPTIONS:
|
OPTIONS:
|
||||||
|
-O, --org string, $CODER_ORGANIZATION
|
||||||
|
Select which organization (uuid or name) to use.
|
||||||
|
|
||||||
-c, --column string-array (default: name,display name,organization id,members,avatar url)
|
-c, --column string-array (default: name,display name,organization id,members,avatar url)
|
||||||
Columns to display in table output. Available columns: name, display
|
Columns to display in table output. Available columns: name, display
|
||||||
name, organization id, members, avatar url.
|
name, organization id, members, avatar url.
|
||||||
|
Reference in New Issue
Block a user