Skip to content

Commit 11c79ee

Browse files
committed
Add webhook show command
1 parent f4d3458 commit 11c79ee

File tree

5 files changed

+194
-2
lines changed

5 files changed

+194
-2
lines changed

internal/cmd/webhook/create.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ func CreateCmd(ch *cmdutil.Helper) *cobra.Command {
5656

5757
end()
5858

59-
return ch.Printer.PrintResource(toWebhook(webhook))
59+
return ch.Printer.PrintResource(toWebhookWithSecret(webhook))
6060
},
6161
}
6262

internal/cmd/webhook/create_test.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ func TestWebhook_CreateCmd(t *testing.T) {
3131
webhook := &ps.Webhook{
3232
ID: "webhook-123",
3333
URL: url,
34+
Secret: "abcdefgh",
3435
Enabled: true,
3536
Events: events,
3637
CreatedAt: createdAt,
@@ -65,7 +66,7 @@ func TestWebhook_CreateCmd(t *testing.T) {
6566
c.Assert(err, qt.IsNil)
6667
c.Assert(svc.CreateFnInvoked, qt.IsTrue)
6768

68-
res := &Webhook{orig: webhook}
69+
res := &WebhookWithSecret{orig: webhook}
6970
c.Assert(buf.String(), qt.JSONEquals, res)
7071
}
7172

internal/cmd/webhook/show.go

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
package webhook
2+
3+
import (
4+
"fmt"
5+
6+
"github.com/planetscale/cli/internal/cmdutil"
7+
"github.com/planetscale/cli/internal/printer"
8+
"github.com/planetscale/planetscale-go/planetscale"
9+
"github.com/spf13/cobra"
10+
)
11+
12+
func ShowCmd(ch *cmdutil.Helper) *cobra.Command {
13+
cmd := &cobra.Command{
14+
Use: "show <database> <webhook-id>",
15+
Short: "Show a webhook for a database",
16+
Args: cmdutil.RequiredArgs("database", "webhook-id"),
17+
RunE: func(cmd *cobra.Command, args []string) error {
18+
ctx := cmd.Context()
19+
database := args[0]
20+
webhookID := args[1]
21+
22+
client, err := ch.Client()
23+
if err != nil {
24+
return err
25+
}
26+
27+
end := ch.Printer.PrintProgress(fmt.Sprintf("Fetching webhook %s for %s", printer.BoldBlue(webhookID), printer.BoldBlue(database)))
28+
defer end()
29+
30+
webhook, err := client.Webhooks.Get(ctx, &planetscale.GetWebhookRequest{
31+
Organization: ch.Config.Organization,
32+
Database: database,
33+
ID: webhookID,
34+
})
35+
if err != nil {
36+
switch cmdutil.ErrCode(err) {
37+
case planetscale.ErrNotFound:
38+
return fmt.Errorf("webhook %s does not exist in database %s (organization: %s)",
39+
printer.BoldBlue(webhookID), printer.BoldBlue(database), printer.BoldBlue(ch.Config.Organization))
40+
default:
41+
return cmdutil.HandleError(err)
42+
}
43+
}
44+
45+
end()
46+
47+
return ch.Printer.PrintResource(toWebhookWithSecret(webhook))
48+
},
49+
}
50+
51+
return cmd
52+
}

internal/cmd/webhook/show_test.go

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
package webhook
2+
3+
import (
4+
"bytes"
5+
"context"
6+
"testing"
7+
"time"
8+
9+
qt "github.com/frankban/quicktest"
10+
"github.com/planetscale/cli/internal/cmdutil"
11+
"github.com/planetscale/cli/internal/config"
12+
"github.com/planetscale/cli/internal/mock"
13+
"github.com/planetscale/cli/internal/printer"
14+
ps "github.com/planetscale/planetscale-go/planetscale"
15+
)
16+
17+
func TestWebhook_ShowCmd(t *testing.T) {
18+
c := qt.New(t)
19+
20+
var buf bytes.Buffer
21+
format := printer.JSON
22+
p := printer.NewPrinter(&format)
23+
p.SetResourceOutput(&buf)
24+
25+
org := "planetscale"
26+
db := "mydb"
27+
webhookID := "webhook-123"
28+
createdAt := time.Date(2025, 1, 15, 10, 30, 0, 0, time.UTC)
29+
30+
webhook := &ps.Webhook{
31+
ID: webhookID,
32+
URL: "https://example.com/webhook",
33+
Secret: "abcdefgh",
34+
Enabled: true,
35+
Events: []string{"branch.created", "branch.deleted"},
36+
CreatedAt: createdAt,
37+
}
38+
39+
svc := &mock.WebhooksService{
40+
GetFn: func(ctx context.Context, req *ps.GetWebhookRequest) (*ps.Webhook, error) {
41+
c.Assert(req.Organization, qt.Equals, org)
42+
c.Assert(req.Database, qt.Equals, db)
43+
c.Assert(req.ID, qt.Equals, webhookID)
44+
return webhook, nil
45+
},
46+
}
47+
48+
ch := &cmdutil.Helper{
49+
Printer: p,
50+
Config: &config.Config{
51+
Organization: org,
52+
},
53+
Client: func() (*ps.Client, error) {
54+
return &ps.Client{
55+
Webhooks: svc,
56+
}, nil
57+
},
58+
}
59+
60+
cmd := ShowCmd(ch)
61+
cmd.SetArgs([]string{db, webhookID})
62+
err := cmd.Execute()
63+
64+
c.Assert(err, qt.IsNil)
65+
c.Assert(svc.GetFnInvoked, qt.IsTrue)
66+
67+
res := &WebhookWithSecret{orig: webhook}
68+
c.Assert(buf.String(), qt.JSONEquals, res)
69+
}
70+
71+
func TestWebhook_ShowCmd_NotFound(t *testing.T) {
72+
c := qt.New(t)
73+
74+
var buf bytes.Buffer
75+
format := printer.Human
76+
p := printer.NewPrinter(&format)
77+
p.SetHumanOutput(&buf)
78+
79+
org := "planetscale"
80+
db := "mydb"
81+
webhookID := "webhook-123"
82+
83+
svc := &mock.WebhooksService{
84+
GetFn: func(ctx context.Context, req *ps.GetWebhookRequest) (*ps.Webhook, error) {
85+
return nil, &ps.Error{Code: ps.ErrNotFound}
86+
},
87+
}
88+
89+
ch := &cmdutil.Helper{
90+
Printer: p,
91+
Config: &config.Config{
92+
Organization: org,
93+
},
94+
Client: func() (*ps.Client, error) {
95+
return &ps.Client{
96+
Webhooks: svc,
97+
}, nil
98+
},
99+
}
100+
101+
cmd := ShowCmd(ch)
102+
cmd.SetArgs([]string{db, webhookID})
103+
err := cmd.Execute()
104+
105+
c.Assert(err, qt.IsNotNil)
106+
c.Assert(err.Error(), qt.Contains, "does not exist")
107+
}

internal/cmd/webhook/webhook.go

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ func WebhookCmd(ch *cmdutil.Helper) *cobra.Command {
2424
cmd.AddCommand(CreateCmd(ch))
2525
cmd.AddCommand(DeleteCmd(ch))
2626
cmd.AddCommand(ListCmd(ch))
27+
cmd.AddCommand(ShowCmd(ch))
2728
cmd.AddCommand(UpdateCmd(ch))
2829

2930
return cmd
@@ -65,3 +66,34 @@ func toWebhooks(webhooks []*ps.Webhook) []*Webhook {
6566
}
6667
return results
6768
}
69+
70+
// WebhookWithSecret includes the webhook secret for display.
71+
type WebhookWithSecret struct {
72+
ID string `header:"id" json:"id"`
73+
URL string `header:"url" json:"url"`
74+
Secret string `header:"secret" json:"secret"`
75+
Events string `header:"events" json:"events"`
76+
Enabled bool `header:"enabled" json:"enabled"`
77+
CreatedAt int64 `header:"created_at,timestamp(ms|utc|human)" json:"created_at"`
78+
UpdatedAt int64 `header:"updated_at,timestamp(ms|utc|human)" json:"updated_at"`
79+
80+
orig *ps.Webhook
81+
}
82+
83+
func (w *WebhookWithSecret) MarshalJSON() ([]byte, error) {
84+
return json.MarshalIndent(w.orig, "", " ")
85+
}
86+
87+
// toWebhookWithSecret returns a struct that includes the webhook secret.
88+
func toWebhookWithSecret(webhook *ps.Webhook) *WebhookWithSecret {
89+
return &WebhookWithSecret{
90+
ID: webhook.ID,
91+
URL: webhook.URL,
92+
Secret: webhook.Secret,
93+
Events: strings.Join(webhook.Events, ", "),
94+
Enabled: webhook.Enabled,
95+
CreatedAt: printer.GetMilliseconds(webhook.CreatedAt),
96+
UpdatedAt: printer.GetMilliseconds(webhook.UpdatedAt),
97+
orig: webhook,
98+
}
99+
}

0 commit comments

Comments
 (0)