Skip to content

Commit 17bc693

Browse files
feat: add CLI command to get and update organizations (#3763)
Closes #3634 ## Summary - Add `superplane organizations get` command to view current organization details - Add `superplane organizations update` command with `--name`, `--description`, and `--versioning-enabled` flags - Register new `organizations` command (aliases: `org`, `orgs`) in the CLI root ## Usage ```sh superplane org get superplane org update --name "My Org" superplane org update --description "New description" --versioning-enabled=true ``` Test plan - superplane org get returns organization details in text/json/yaml formats - superplane org update --name "Test" updates only the name - superplane org update --description "Desc" updates only the description - superplane org update --versioning-enabled=false disables versioning - superplane org update with no flags returns an error - superplane org update --name "duplicate" with a taken name returns an error - make lint && make check.build.app pass ## Command output <img width="943" height="138" alt="Screenshot 2026-03-27 153009" src="https://github.com/user-attachments/assets/9c1452be-8518-413f-8bd7-6f21aa6a8789" /> <img width="601" height="135" alt="Screenshot 2026-03-27 152941" src="https://github.com/user-attachments/assets/30752eee-88df-4952-ad55-b735e4ad64f5" /> <img width="443" height="140" alt="Screenshot 2026-03-27 152901" src="https://github.com/user-attachments/assets/37547dcb-75ca-4beb-95ae-85405581dd5b" /> --------- Signed-off-by: Vukotije <vukanradojevicc@gmail.com> Co-authored-by: Pedro Leão <60622592+forestileao@users.noreply.github.com>
1 parent e3dbab0 commit 17bc693

File tree

13 files changed

+184
-33
lines changed

13 files changed

+184
-33
lines changed
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package organizations
2+
3+
import (
4+
"fmt"
5+
"io"
6+
"time"
7+
8+
"github.com/superplanehq/superplane/pkg/openapi_client"
9+
)
10+
11+
func renderOrganization(stdout io.Writer, org openapi_client.OrganizationsOrganization) error {
12+
metadata := org.GetMetadata()
13+
14+
_, _ = fmt.Fprintf(stdout, "ID: %s\n", metadata.GetId())
15+
_, _ = fmt.Fprintf(stdout, "Name: %s\n", metadata.GetName())
16+
_, _ = fmt.Fprintf(stdout, "Description: %s\n", metadata.GetDescription())
17+
_, _ = fmt.Fprintf(stdout, "Versioning Enabled: %t\n", metadata.GetVersioningEnabled())
18+
if metadata.HasCreatedAt() {
19+
_, _ = fmt.Fprintf(stdout, "Created At: %s\n", metadata.GetCreatedAt().Format(time.RFC3339))
20+
}
21+
if metadata.HasUpdatedAt() {
22+
_, _ = fmt.Fprintf(stdout, "Updated At: %s\n", metadata.GetUpdatedAt().Format(time.RFC3339))
23+
}
24+
25+
return nil
26+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
package organizations
2+
3+
import (
4+
"io"
5+
6+
"github.com/superplanehq/superplane/pkg/cli/core"
7+
)
8+
9+
type getCommand struct{}
10+
11+
func (c *getCommand) Execute(ctx core.CommandContext) error {
12+
organizationID, err := core.ResolveOrganizationID(ctx)
13+
if err != nil {
14+
return err
15+
}
16+
17+
response, _, err := ctx.API.OrganizationAPI.
18+
OrganizationsDescribeOrganization(ctx.Context, organizationID).
19+
Execute()
20+
if err != nil {
21+
return err
22+
}
23+
24+
if !ctx.Renderer.IsText() {
25+
return ctx.Renderer.Render(response)
26+
}
27+
28+
org := response.GetOrganization()
29+
return ctx.Renderer.RenderText(func(stdout io.Writer) error {
30+
return renderOrganization(stdout, org)
31+
})
32+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
package organizations
2+
3+
import (
4+
"github.com/spf13/cobra"
5+
"github.com/superplanehq/superplane/pkg/cli/core"
6+
)
7+
8+
func NewCommand(options core.BindOptions) *cobra.Command {
9+
root := &cobra.Command{
10+
Use: "organizations",
11+
Short: "Manage organizations",
12+
Aliases: []string{"org", "orgs"},
13+
}
14+
15+
getCmd := &cobra.Command{
16+
Use: "get",
17+
Short: "Get details for the current organization",
18+
Args: cobra.NoArgs,
19+
}
20+
core.Bind(getCmd, &getCommand{}, options)
21+
22+
var updateName string
23+
var updateDescription string
24+
var updateVersioningEnabled bool
25+
updateCmd := &cobra.Command{
26+
Use: "update",
27+
Short: "Update the current organization",
28+
Args: cobra.NoArgs,
29+
}
30+
updateCmd.Flags().StringVar(&updateName, "name", "", "organization name")
31+
updateCmd.Flags().StringVar(&updateDescription, "description", "", "organization description")
32+
updateCmd.Flags().BoolVar(&updateVersioningEnabled, "versioning-enabled", false, "enable or disable global versioning")
33+
core.Bind(updateCmd, &updateCommand{
34+
name: &updateName,
35+
description: &updateDescription,
36+
versioningEnabled: &updateVersioningEnabled,
37+
}, options)
38+
39+
root.AddCommand(getCmd)
40+
root.AddCommand(updateCmd)
41+
42+
return root
43+
}
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
package organizations
2+
3+
import (
4+
"fmt"
5+
"io"
6+
7+
"github.com/superplanehq/superplane/pkg/cli/core"
8+
"github.com/superplanehq/superplane/pkg/openapi_client"
9+
)
10+
11+
type updateCommand struct {
12+
name *string
13+
description *string
14+
versioningEnabled *bool
15+
}
16+
17+
func (c *updateCommand) Execute(ctx core.CommandContext) error {
18+
if !ctx.Cmd.Flags().Changed("name") &&
19+
!ctx.Cmd.Flags().Changed("description") &&
20+
!ctx.Cmd.Flags().Changed("versioning-enabled") {
21+
return fmt.Errorf("at least one flag must be provided: --name, --description, or --versioning-enabled")
22+
}
23+
24+
organizationID, err := core.ResolveOrganizationID(ctx)
25+
if err != nil {
26+
return err
27+
}
28+
29+
metadata := openapi_client.OrganizationsOrganizationMetadata{}
30+
if ctx.Cmd.Flags().Changed("name") {
31+
metadata.SetName(*c.name)
32+
}
33+
if ctx.Cmd.Flags().Changed("description") {
34+
metadata.SetDescription(*c.description)
35+
}
36+
if ctx.Cmd.Flags().Changed("versioning-enabled") {
37+
metadata.SetVersioningEnabled(*c.versioningEnabled)
38+
}
39+
40+
org := openapi_client.OrganizationsOrganization{}
41+
org.SetMetadata(metadata)
42+
43+
body := openapi_client.OrganizationsUpdateOrganizationBody{}
44+
body.SetOrganization(org)
45+
46+
response, _, err := ctx.API.OrganizationAPI.
47+
OrganizationsUpdateOrganization(ctx.Context, organizationID).
48+
Body(body).
49+
Execute()
50+
if err != nil {
51+
return err
52+
}
53+
54+
if !ctx.Renderer.IsText() {
55+
return ctx.Renderer.Render(response)
56+
}
57+
58+
updated := response.GetOrganization()
59+
return ctx.Renderer.RenderText(func(stdout io.Writer) error {
60+
return renderOrganization(stdout, updated)
61+
})
62+
}

pkg/cli/commands/secrets/common.go

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import (
55
"io"
66
"os"
77
"sort"
8-
"strings"
98
"text/tabwriter"
109
"time"
1110

@@ -25,19 +24,6 @@ type secretResource struct {
2524
Spec *openapi_client.SecretsSecretSpec `json:"spec,omitempty"`
2625
}
2726

28-
func resolveOrganizationID(ctx core.CommandContext) (string, error) {
29-
me, _, err := ctx.API.MeAPI.MeMe(ctx.Context).Execute()
30-
if err != nil {
31-
return "", err
32-
}
33-
34-
if !me.HasOrganizationId() || strings.TrimSpace(me.GetOrganizationId()) == "" {
35-
return "", fmt.Errorf("organization id not found for authenticated user")
36-
}
37-
38-
return me.GetOrganizationId(), nil
39-
}
40-
4127
func organizationDomainType() openapi_client.AuthorizationDomainType {
4228
return openapi_client.AUTHORIZATIONDOMAINTYPE_DOMAIN_TYPE_ORGANIZATION
4329
}

pkg/cli/commands/secrets/create.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ func (c *createCommand) Execute(ctx core.CommandContext) error {
2121
return fmt.Errorf("--file is required")
2222
}
2323

24-
organizationID, err := resolveOrganizationID(ctx)
24+
organizationID, err := core.ResolveOrganizationID(ctx)
2525
if err != nil {
2626
return err
2727
}

pkg/cli/commands/secrets/delete.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import (
1010
type deleteCommand struct{}
1111

1212
func (c *deleteCommand) Execute(ctx core.CommandContext) error {
13-
organizationID, err := resolveOrganizationID(ctx)
13+
organizationID, err := core.ResolveOrganizationID(ctx)
1414
if err != nil {
1515
return err
1616
}

pkg/cli/commands/secrets/get.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import (
99
type getCommand struct{}
1010

1111
func (c *getCommand) Execute(ctx core.CommandContext) error {
12-
organizationID, err := resolveOrganizationID(ctx)
12+
organizationID, err := core.ResolveOrganizationID(ctx)
1313
if err != nil {
1414
return err
1515
}

pkg/cli/commands/secrets/list.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import (
99
type listCommand struct{}
1010

1111
func (c *listCommand) Execute(ctx core.CommandContext) error {
12-
organizationID, err := resolveOrganizationID(ctx)
12+
organizationID, err := core.ResolveOrganizationID(ctx)
1313
if err != nil {
1414
return err
1515
}

pkg/cli/commands/secrets/update.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ func (c *updateCommand) Execute(ctx core.CommandContext) error {
2424
return fmt.Errorf("update does not accept positional arguments")
2525
}
2626

27-
organizationID, err := resolveOrganizationID(ctx)
27+
organizationID, err := core.ResolveOrganizationID(ctx)
2828
if err != nil {
2929
return err
3030
}

0 commit comments

Comments
 (0)