diff --git a/cli/organization.go b/cli/organization.go index 528f9f0d34..6ebd28f9ff 100644 --- a/cli/organization.go +++ b/cli/organization.go @@ -23,6 +23,7 @@ func (r *RootCmd) organizations() *serpent.Command { }, Children: []*serpent.Command{ r.showOrganization(orgContext), + r.listOrganizations(), r.createOrganization(), r.deleteOrganization(orgContext), r.organizationMembers(orgContext), diff --git a/cli/organization_test.go b/cli/organization_test.go index 83f49b9cb7..8c4997f4ae 100644 --- a/cli/organization_test.go +++ b/cli/organization_test.go @@ -1,6 +1,7 @@ package cli_test import ( + "bytes" "encoding/json" "fmt" "net/http" @@ -58,6 +59,48 @@ func TestCurrentOrganization(t *testing.T) { }) } +func TestOrganizationList(t *testing.T) { + t.Parallel() + + t.Run("OK", func(t *testing.T) { + t.Parallel() + + orgID := uuid.New() + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + switch { + case r.Method == http.MethodGet && r.URL.Path == "/api/v2/organizations": + _ = json.NewEncoder(w).Encode([]codersdk.Organization{ + { + MinimalOrganization: codersdk.MinimalOrganization{ + ID: orgID, + Name: "my-org", + DisplayName: "My Org", + }, + CreatedAt: time.Now(), + UpdatedAt: time.Now(), + }, + }) + default: + t.Errorf("unexpected request: %s %s", r.Method, r.URL.Path) + w.WriteHeader(http.StatusNotFound) + } + })) + defer server.Close() + + client := codersdk.New(must(url.Parse(server.URL))) + inv, root := clitest.New(t, "organizations", "list") + clitest.SetupConfig(t, client, root) + + buf := new(bytes.Buffer) + inv.Stdout = buf + + require.NoError(t, inv.Run()) + require.Contains(t, buf.String(), "my-org") + require.Contains(t, buf.String(), "My Org") + require.Contains(t, buf.String(), orgID.String()) + }) +} + func TestOrganizationDelete(t *testing.T) { t.Parallel() diff --git a/cli/organizationlist.go b/cli/organizationlist.go new file mode 100644 index 0000000000..e943e76478 --- /dev/null +++ b/cli/organizationlist.go @@ -0,0 +1,53 @@ +package cli + +import ( + "fmt" + + "github.com/coder/coder/v2/cli/cliui" + "github.com/coder/coder/v2/codersdk" + "github.com/coder/serpent" +) + +func (r *RootCmd) listOrganizations() *serpent.Command { + formatter := cliui.NewOutputFormatter( + cliui.TableFormat([]codersdk.Organization{}, []string{"name", "display name", "id", "default"}), + cliui.JSONFormat(), + ) + + cmd := &serpent.Command{ + Use: "list", + Short: "List all organizations", + Long: "List all organizations. Requires a role which grants ResourceOrganization: read.", + Aliases: []string{"ls"}, + Middleware: serpent.Chain( + serpent.RequireNArgs(0), + ), + Handler: func(inv *serpent.Invocation) error { + client, err := r.InitClient(inv) + if err != nil { + return err + } + + organizations, err := client.Organizations(inv.Context()) + if err != nil { + return err + } + + out, err := formatter.Format(inv.Context(), organizations) + if err != nil { + return err + } + + if out == "" { + cliui.Infof(inv.Stderr, "No organizations found.") + return nil + } + + _, err = fmt.Fprintln(inv.Stdout, out) + return err + }, + } + + formatter.AttachOptions(&cmd.Options) + return cmd +} diff --git a/cli/testdata/coder_organizations_--help.golden b/cli/testdata/coder_organizations_--help.golden index 417ba5edb9..46f5d56a21 100644 --- a/cli/testdata/coder_organizations_--help.golden +++ b/cli/testdata/coder_organizations_--help.golden @@ -10,6 +10,7 @@ USAGE: SUBCOMMANDS: create Create a new organization. delete Delete an organization + list List all organizations members Manage organization members roles Manage organization roles. settings Manage organization settings. diff --git a/cli/testdata/coder_organizations_list_--help.golden b/cli/testdata/coder_organizations_list_--help.golden new file mode 100644 index 0000000000..8197886411 --- /dev/null +++ b/cli/testdata/coder_organizations_list_--help.golden @@ -0,0 +1,21 @@ +coder v0.0.0-devel + +USAGE: + coder organizations list [flags] + + List all organizations + + Aliases: ls + + List all organizations. Requires a role which grants ResourceOrganization: + read. + +OPTIONS: + -c, --column [id|name|display name|icon|description|created at|updated at|default] (default: name,display name,id,default) + Columns to display in table output. + + -o, --output table|json (default: table) + Output format. + +——— +Run `coder --help` for a list of global options. diff --git a/docs/manifest.json b/docs/manifest.json index c669a58cfb..84b7c4428f 100644 --- a/docs/manifest.json +++ b/docs/manifest.json @@ -1637,6 +1637,11 @@ "description": "Delete an organization", "path": "reference/cli/organizations_delete.md" }, + { + "title": "organizations list", + "description": "List all organizations", + "path": "reference/cli/organizations_list.md" + }, { "title": "organizations members", "description": "Manage organization members", diff --git a/docs/reference/cli/organizations.md b/docs/reference/cli/organizations.md index 0d4cc7f6a2..e487735e8c 100644 --- a/docs/reference/cli/organizations.md +++ b/docs/reference/cli/organizations.md @@ -20,6 +20,7 @@ coder organizations [flags] [subcommand] | Name | Purpose | |------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------| | [show](./organizations_show.md) | 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. | +| [list](./organizations_list.md) | List all organizations | | [create](./organizations_create.md) | Create a new organization. | | [delete](./organizations_delete.md) | Delete an organization | | [members](./organizations_members.md) | Manage organization members | diff --git a/docs/reference/cli/organizations_list.md b/docs/reference/cli/organizations_list.md new file mode 100644 index 0000000000..5f866caf5a --- /dev/null +++ b/docs/reference/cli/organizations_list.md @@ -0,0 +1,40 @@ + +# organizations list + +List all organizations + +Aliases: + +* ls + +## Usage + +```console +coder organizations list [flags] +``` + +## Description + +```console +List all organizations. Requires a role which grants ResourceOrganization: read. +``` + +## Options + +### -c, --column + +| | | +|---------|-------------------------------------------------------------------------------------------| +| Type | [id\|name\|display name\|icon\|description\|created at\|updated at\|default] | +| Default | name,display name,id,default | + +Columns to display in table output. + +### -o, --output + +| | | +|---------|--------------------------| +| Type | table\|json | +| Default | table | + +Output format.