Skip to content

Commit b7c8c44

Browse files
committed
feat: begin work to implement switching orgs in the cli
1 parent c3a7b13 commit b7c8c44

18 files changed

+132
-25
lines changed

cli/config/file.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,14 @@ func (r Root) PostgresPort() File {
7070
// File provides convenience methods for interacting with *os.File.
7171
type File string
7272

73+
func (f File) Exists() bool {
74+
if f == "" {
75+
return false
76+
}
77+
_, err := os.Stat(string(f))
78+
return err == nil
79+
}
80+
7381
// Delete deletes the file.
7482
func (f File) Delete() error {
7583
if f == "" {

cli/create.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ func (r *RootCmd) create() *clibase.Cmd {
4343
),
4444
Middleware: clibase.Chain(r.InitClient(client)),
4545
Handler: func(inv *clibase.Invocation) error {
46-
organization, err := CurrentOrganization(inv, client)
46+
organization, err := CurrentOrganization(r, inv, client)
4747
if err != nil {
4848
return err
4949
}

cli/organization.go

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
package cli
2+
3+
import (
4+
"fmt"
5+
6+
"github.com/coder/coder/v2/cli/clibase"
7+
"github.com/coder/coder/v2/cli/cliui"
8+
"github.com/coder/coder/v2/codersdk"
9+
)
10+
11+
func (r *RootCmd) organizations() *clibase.Cmd {
12+
cmd := &clibase.Cmd{
13+
Annotations: workspaceCommand,
14+
Use: "organizations { current }",
15+
Short: "Organization related commands",
16+
Aliases: []string{"organization", "org", "orgs"},
17+
18+
Handler: func(inv *clibase.Invocation) error {
19+
return inv.Command.HelpHandler(inv)
20+
},
21+
Children: []*clibase.Cmd{
22+
r.currentOrganization(),
23+
},
24+
}
25+
26+
cmd.Options = clibase.OptionSet{}
27+
return cmd
28+
}
29+
30+
func (r *RootCmd) currentOrganization() *clibase.Cmd {
31+
var (
32+
client = new(codersdk.Client)
33+
formatter = cliui.NewOutputFormatter(
34+
cliui.ChangeFormatterData(cliui.TextFormat(), func(data any) (any, error) {
35+
typed := data.([]codersdk.Organization)
36+
if len(typed) != 1 {
37+
return "", fmt.Errorf("expected 1 organization, got %d", len(typed))
38+
}
39+
return fmt.Sprintf("Current organization: %s (%s)\n", typed[0].Name, typed[0].ID.String()), nil
40+
}),
41+
cliui.TableFormat([]codersdk.Organization{}, []string{"id", "name", "default"}),
42+
cliui.JSONFormat(),
43+
)
44+
)
45+
cmd := &clibase.Cmd{
46+
Use: "current",
47+
Short: "Show the current selected organization the cli will use",
48+
Middleware: clibase.Chain(
49+
r.InitClient(client),
50+
),
51+
Handler: func(inv *clibase.Invocation) error {
52+
org, err := CurrentOrganization(r, inv, client)
53+
if err != nil {
54+
return err
55+
}
56+
57+
out, err := formatter.Format(inv.Context(), []codersdk.Organization{org})
58+
if err != nil {
59+
return err
60+
}
61+
_, err = fmt.Fprintln(inv.Stdout, out)
62+
return nil
63+
},
64+
}
65+
formatter.AttachOptions(&cmd.Options)
66+
67+
return cmd
68+
}

cli/root.go

Lines changed: 36 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ func (r *RootCmd) Core() []*clibase.Cmd {
9494
r.tokens(),
9595
r.users(),
9696
r.version(defaultVersionInfo),
97+
r.organizations(),
9798

9899
// Workspace Commands
99100
r.autoupdate(),
@@ -698,14 +699,44 @@ func (r *RootCmd) createAgentClient() (*agentsdk.Client, error) {
698699
}
699700

700701
// CurrentOrganization returns the currently active organization for the authenticated user.
701-
func CurrentOrganization(inv *clibase.Invocation, client *codersdk.Client) (codersdk.Organization, error) {
702+
func CurrentOrganization(r *RootCmd, inv *clibase.Invocation, client *codersdk.Client) (codersdk.Organization, error) {
703+
conf := r.createConfig()
704+
selected := ""
705+
if conf.Organization().Exists() {
706+
org, err := conf.Organization().Read()
707+
if err != nil {
708+
return codersdk.Organization{}, fmt.Errorf("read selected organization from config file %q: %w", conf.Organization(), err)
709+
}
710+
selected = org
711+
}
712+
713+
// Verify the org exists and the user is a member
702714
orgs, err := client.OrganizationsByUser(inv.Context(), codersdk.Me)
703715
if err != nil {
704-
return codersdk.Organization{}, nil
716+
return codersdk.Organization{}, err
705717
}
706-
// For now, we won't use the config to set this.
707-
// Eventually, we will support changing using "coder switch <org>"
708-
return orgs[0], nil
718+
719+
// User manually selected an organization
720+
if selected != "" {
721+
index := slices.IndexFunc(orgs, func(org codersdk.Organization) bool {
722+
return org.Name == selected || org.ID.String() == selected
723+
})
724+
725+
if index < 0 {
726+
return codersdk.Organization{}, xerrors.Errorf("organization %q not found, are you sure you are a member of this organization?", selected)
727+
}
728+
return orgs[index], nil
729+
}
730+
731+
// User did not select an organization, so use the default.
732+
index := slices.IndexFunc(orgs, func(org codersdk.Organization) bool {
733+
return org.IsDefault
734+
})
735+
if index < 0 {
736+
return codersdk.Organization{}, xerrors.Errorf("unable to determine current organization. Use 'coder switch <org>' to select an organization to use")
737+
}
738+
739+
return orgs[index], nil
709740
}
710741

711742
func splitNamedWorkspace(identifier string) (owner string, workspaceName string, err error) {

cli/templatecreate.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ func (r *RootCmd) templateCreate() *clibase.Cmd {
6969
}
7070
}
7171

72-
organization, err := CurrentOrganization(inv, client)
72+
organization, err := CurrentOrganization(r, inv, client)
7373
if err != nil {
7474
return err
7575
}

cli/templatedelete.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ func (r *RootCmd) templateDelete() *clibase.Cmd {
3232
templates = []codersdk.Template{}
3333
)
3434

35-
organization, err := CurrentOrganization(inv, client)
35+
organization, err := CurrentOrganization(r, inv, client)
3636
if err != nil {
3737
return err
3838
}

cli/templateedit.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ func (r *RootCmd) templateEdit() *clibase.Cmd {
7979
}
8080
}
8181

82-
organization, err := CurrentOrganization(inv, client)
82+
organization, err := CurrentOrganization(r, inv, client)
8383
if err != nil {
8484
return xerrors.Errorf("get current organization: %w", err)
8585
}

cli/templatelist.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ func (r *RootCmd) templateList() *clibase.Cmd {
2525
r.InitClient(client),
2626
),
2727
Handler: func(inv *clibase.Invocation) error {
28-
organization, err := CurrentOrganization(inv, client)
28+
organization, err := CurrentOrganization(r, inv, client)
2929
if err != nil {
3030
return err
3131
}

cli/templatepull.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ func (r *RootCmd) templatePull() *clibase.Cmd {
4444
return xerrors.Errorf("either tar or zip can be selected")
4545
}
4646

47-
organization, err := CurrentOrganization(inv, client)
47+
organization, err := CurrentOrganization(r, inv, client)
4848
if err != nil {
4949
return xerrors.Errorf("get current organization: %w", err)
5050
}

cli/templatepush.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ func (r *RootCmd) templatePush() *clibase.Cmd {
4646
Handler: func(inv *clibase.Invocation) error {
4747
uploadFlags.setWorkdir(workdir)
4848

49-
organization, err := CurrentOrganization(inv, client)
49+
organization, err := CurrentOrganization(r, inv, client)
5050
if err != nil {
5151
return err
5252
}

cli/templateversionarchive.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ func (r *RootCmd) setArchiveTemplateVersion(archive bool) *clibase.Cmd {
4747
versions []codersdk.TemplateVersion
4848
)
4949

50-
organization, err := CurrentOrganization(inv, client)
50+
organization, err := CurrentOrganization(r, inv, client)
5151
if err != nil {
5252
return err
5353
}
@@ -121,7 +121,7 @@ func (r *RootCmd) archiveTemplateVersions() *clibase.Cmd {
121121
templates = []codersdk.Template{}
122122
)
123123

124-
organization, err := CurrentOrganization(inv, client)
124+
organization, err := CurrentOrganization(r, inv, client)
125125
if err != nil {
126126
return err
127127
}

cli/templateversions.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ func (r *RootCmd) templateVersionsList() *clibase.Cmd {
9393
},
9494
},
9595
Handler: func(inv *clibase.Invocation) error {
96-
organization, err := CurrentOrganization(inv, client)
96+
organization, err := CurrentOrganization(r, inv, client)
9797
if err != nil {
9898
return xerrors.Errorf("get current organization: %w", err)
9999
}

cli/usercreate.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ func (r *RootCmd) userCreate() *clibase.Cmd {
3131
r.InitClient(client),
3232
),
3333
Handler: func(inv *clibase.Invocation) error {
34-
organization, err := CurrentOrganization(inv, client)
34+
organization, err := CurrentOrganization(r, inv, client)
3535
if err != nil {
3636
return err
3737
}

codersdk/organizations.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,11 @@ const (
2626

2727
// Organization is the JSON representation of a Coder organization.
2828
type Organization struct {
29-
ID uuid.UUID `json:"id" validate:"required" format:"uuid"`
30-
Name string `json:"name" validate:"required"`
31-
CreatedAt time.Time `json:"created_at" validate:"required" format:"date-time"`
32-
UpdatedAt time.Time `json:"updated_at" validate:"required" format:"date-time"`
33-
IsDefault bool `json:"is_default" validate:"required"`
29+
ID uuid.UUID `table:"id" json:"id" validate:"required" format:"uuid"`
30+
Name string `table:"name,default_sort" json:"name" validate:"required"`
31+
CreatedAt time.Time `table:"created_at" json:"created_at" validate:"required" format:"date-time"`
32+
UpdatedAt time.Time `table:"updated_at" json:"updated_at" validate:"required" format:"date-time"`
33+
IsDefault bool `table:"default" json:"is_default" validate:"required"`
3434
}
3535

3636
type OrganizationMember struct {

enterprise/cli/groupcreate.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ func (r *RootCmd) groupCreate() *clibase.Cmd {
2929
Handler: func(inv *clibase.Invocation) error {
3030
ctx := inv.Context()
3131

32-
org, err := agpl.CurrentOrganization(inv, client)
32+
org, err := agpl.CurrentOrganization(&r.RootCmd, inv, client)
3333
if err != nil {
3434
return xerrors.Errorf("current organization: %w", err)
3535
}

enterprise/cli/groupdelete.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ func (r *RootCmd) groupDelete() *clibase.Cmd {
2727
groupName = inv.Args[0]
2828
)
2929

30-
org, err := agpl.CurrentOrganization(inv, client)
30+
org, err := agpl.CurrentOrganization(&r.RootCmd, inv, client)
3131
if err != nil {
3232
return xerrors.Errorf("current organization: %w", err)
3333
}

enterprise/cli/groupedit.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ func (r *RootCmd) groupEdit() *clibase.Cmd {
3737
groupName = inv.Args[0]
3838
)
3939

40-
org, err := agpl.CurrentOrganization(inv, client)
40+
org, err := agpl.CurrentOrganization(&r.RootCmd, inv, client)
4141
if err != nil {
4242
return xerrors.Errorf("current organization: %w", err)
4343
}

enterprise/cli/grouplist.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ func (r *RootCmd) groupList() *clibase.Cmd {
3030
Handler: func(inv *clibase.Invocation) error {
3131
ctx := inv.Context()
3232

33-
org, err := agpl.CurrentOrganization(inv, client)
33+
org, err := agpl.CurrentOrganization(&r.RootCmd, inv, client)
3434
if err != nil {
3535
return xerrors.Errorf("current organization: %w", err)
3636
}

0 commit comments

Comments
 (0)