Skip to content

Commit 5c8b293

Browse files
Add pg delete command (#445)
Implements `render ea pg delete` command. PR 3 of 3 for https://linear.app/render-com/issue/GROW-2121/pg-delete Stacked on top of https://github.com/renderinc/cli/pull/444 GitOrigin-RevId: 27892b26c18bb6d9f91bc2dd9d6361a723105762
1 parent a372a3d commit 5c8b293

5 files changed

Lines changed: 365 additions & 37 deletions

File tree

cmd/pg_test.go

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
package cmd
2+
3+
import (
4+
"bytes"
5+
"testing"
6+
7+
"github.com/stretchr/testify/require"
8+
9+
renderapi "github.com/render-oss/cli/internal/fakes/renderapi"
10+
"github.com/render-oss/cli/internal/testids"
11+
"github.com/render-oss/cli/pkg/client"
12+
"github.com/render-oss/cli/pkg/command"
13+
"github.com/render-oss/cli/pkg/dependencies"
14+
)
15+
16+
var pgActiveWorkspaceID = testids.WorkspaceID("active")
17+
18+
func executePGCommand(t *testing.T, server *renderapi.Server, args ...string) (CommandResult, error) {
19+
t.Helper()
20+
t.Setenv("RENDER_CLI_CONFIG_PATH", newTestConfigPath(t))
21+
t.Setenv("RENDER_API_KEY", "test-api-key")
22+
23+
c, err := client.NewClientWithResponses(server.URL())
24+
require.NoError(t, err)
25+
deps := dependencies.New(c)
26+
deps.DetectRuntimeSignals = func() (command.RuntimeSignals, error) {
27+
return command.RuntimeSignals{
28+
StdinTTY: false,
29+
StdoutTTY: false,
30+
StderrTTY: false,
31+
}, nil
32+
}
33+
34+
root := newRootCmd()
35+
ea := newEarlyAccessCmd()
36+
root.AddCommand(ea)
37+
setupPGCommands(ea, deps)
38+
setupRootCmdPersistentRun(root, deps)
39+
40+
var stdout, stderr bytes.Buffer
41+
root.SetOut(&stdout)
42+
root.SetErr(&stderr)
43+
root.SetArgs(args)
44+
45+
execErr := root.Execute()
46+
return CommandResult{Stdout: stdout.String(), Stderr: stderr.String()}, execErr
47+
}

cmd/pgcreate_test.go

Lines changed: 0 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package cmd
22

33
import (
4-
"bytes"
54
"encoding/json"
65
"testing"
76

@@ -12,12 +11,8 @@ import (
1211
"github.com/render-oss/cli/internal/testids"
1312
"github.com/render-oss/cli/pkg/client"
1413
pgclient "github.com/render-oss/cli/pkg/client/postgres"
15-
"github.com/render-oss/cli/pkg/command"
16-
"github.com/render-oss/cli/pkg/dependencies"
1714
)
1815

19-
var pgActiveWorkspaceID = testids.WorkspaceID("active")
20-
2116
func executePGCreate(t *testing.T, server *renderapi.Server, extraArgs ...string) (CommandResult, error) {
2217
t.Helper()
2318
server.Owners.Add(renderapi.NewOwner(client.Owner{Id: pgActiveWorkspaceID, Name: "Test Workspace"}))
@@ -26,37 +21,6 @@ func executePGCreate(t *testing.T, server *renderapi.Server, extraArgs ...string
2621
return executePGCommand(t, server, append([]string{"ea", "pg", "create"}, extraArgs...)...)
2722
}
2823

29-
func executePGCommand(t *testing.T, server *renderapi.Server, args ...string) (CommandResult, error) {
30-
t.Helper()
31-
t.Setenv("RENDER_CLI_CONFIG_PATH", newTestConfigPath(t))
32-
t.Setenv("RENDER_API_KEY", "test-api-key")
33-
34-
c, err := client.NewClientWithResponses(server.URL())
35-
require.NoError(t, err)
36-
deps := dependencies.New(c)
37-
deps.DetectRuntimeSignals = func() (command.RuntimeSignals, error) {
38-
return command.RuntimeSignals{
39-
StdinTTY: false,
40-
StdoutTTY: false,
41-
StderrTTY: false,
42-
}, nil
43-
}
44-
45-
root := newRootCmd()
46-
ea := newEarlyAccessCmd()
47-
root.AddCommand(ea)
48-
setupPGCommands(ea, deps)
49-
setupRootCmdPersistentRun(root, deps)
50-
51-
var stdout, stderr bytes.Buffer
52-
root.SetOut(&stdout)
53-
root.SetErr(&stderr)
54-
root.SetArgs(args)
55-
56-
execErr := root.Execute()
57-
return CommandResult{Stdout: stdout.String(), Stderr: stderr.String()}, execErr
58-
}
59-
6024
func TestPGCreate_ZeroFlags_AppliesDefaults(t *testing.T) {
6125
server := renderapi.NewServer(t)
6226
result, err := executePGCreate(t, server, "--output", "text")

cmd/pgdelete.go

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
package cmd
2+
3+
import (
4+
"github.com/spf13/cobra"
5+
6+
"github.com/render-oss/cli/pkg/client"
7+
"github.com/render-oss/cli/pkg/command"
8+
"github.com/render-oss/cli/pkg/dependencies"
9+
"github.com/render-oss/cli/pkg/postgres"
10+
"github.com/render-oss/cli/pkg/text"
11+
"github.com/render-oss/cli/pkg/types"
12+
)
13+
14+
type pgDeleteInput struct {
15+
IDOrName string `cli:"arg:0"`
16+
ProjectIDOrName *string `cli:"project"`
17+
EnvironmentIDOrName *string `cli:"environment"`
18+
}
19+
20+
func normalizePGDeleteInput(input pgDeleteInput) pgDeleteInput {
21+
input.ProjectIDOrName = types.OptionalNonZeroString(input.ProjectIDOrName)
22+
input.EnvironmentIDOrName = types.OptionalNonZeroString(input.EnvironmentIDOrName)
23+
return input
24+
}
25+
26+
type pgDeleteResult struct {
27+
Postgres *client.PostgresDetail `json:"postgres"`
28+
Deleted bool `json:"deleted"`
29+
}
30+
31+
func newPgDeleteCmd(deps *dependencies.Dependencies) *cobra.Command {
32+
cmd := &cobra.Command{
33+
Use: "delete <postgresID|postgresName>",
34+
Short: "Delete a Postgres database",
35+
Args: cobra.ExactArgs(1),
36+
SilenceUsage: true,
37+
Long: `Delete a Postgres database on Render.
38+
39+
Without --confirm, this command previews what would be deleted and makes no
40+
changes. Pass --confirm to actually delete the database.
41+
42+
The positional argument accepts either a Postgres ID (dpg-...) or a name.
43+
If the name matches more than one database, narrow the search with
44+
--project <id|name>, --environment <id|name>, or pass the Postgres ID directly.
45+
46+
Name lookup is scoped to your active workspace. If a name isn't found, switch
47+
workspaces with 'render workspace set <name|ID>' and try again, or pass the
48+
Postgres ID instead (which works across workspaces).`,
49+
Example: ` # Preview deletion (no changes made)
50+
render ea pg delete dpg-abc123def456ghi789jkl0
51+
52+
# Delete by ID
53+
render ea pg delete dpg-abc123def456ghi789jkl0 --confirm
54+
55+
# Delete by name
56+
render ea pg delete my-db --confirm
57+
58+
# Disambiguate a name that exists in multiple environments
59+
render ea pg delete my-db --environment production --confirm
60+
61+
# Disambiguate a name that exists in multiple projects
62+
render ea pg delete my-db --project analytics --confirm
63+
64+
# JSON output
65+
render ea pg delete dpg-abc123def456ghi789jkl0 --confirm --output json`,
66+
}
67+
68+
cmd.Flags().String("project", "",
69+
"Project ID or name (optional). Narrows name lookup when the same Postgres database name exists in multiple projects.")
70+
cmd.Flags().String("environment", "",
71+
"Environment ID or name (optional). Narrows name lookup when the same Postgres database name exists in multiple environments.")
72+
73+
cmd.RunE = func(cmd *cobra.Command, args []string) error {
74+
command.DefaultFormatNonInteractive(cmd)
75+
76+
var input pgDeleteInput
77+
if err := command.ParseCommand(cmd, args, &input); err != nil {
78+
return err
79+
}
80+
input = normalizePGDeleteInput(input)
81+
confirm := command.GetConfirmFromContext(cmd.Context())
82+
83+
loadData := func() (*pgDeleteResult, error) {
84+
pg, err := deps.PostgresService().Resolve(cmd.Context(), postgres.ResolveInput{
85+
IDOrName: input.IDOrName,
86+
ProjectIDOrName: input.ProjectIDOrName,
87+
EnvironmentIDOrName: input.EnvironmentIDOrName,
88+
})
89+
if err != nil {
90+
return nil, err
91+
}
92+
if confirm {
93+
if err := deps.PostgresService().Delete(cmd.Context(), pg.Id); err != nil {
94+
return nil, err
95+
}
96+
}
97+
return &pgDeleteResult{Postgres: pg, Deleted: confirm}, nil
98+
}
99+
100+
_, err := command.NonInteractive(cmd,
101+
loadData,
102+
pgDeleteTextOutput,
103+
)
104+
return err
105+
}
106+
107+
return cmd
108+
}
109+
110+
func pgDeleteTextOutput(r *pgDeleteResult) string {
111+
if r.Deleted {
112+
return "Deleted this Postgres database:\n\n" + text.PostgresDetail(r.Postgres) + "\n"
113+
}
114+
return "This command would delete this Postgres database:\n\n" +
115+
text.PostgresDetail(r.Postgres) +
116+
"\n\nRe-run with --confirm to proceed\n"
117+
}

0 commit comments

Comments
 (0)