Skip to content

Commit bee913a

Browse files
authored
feat(cli): pause notifications (coder#13873)
1 parent f36b816 commit bee913a

12 files changed

+313
-3
lines changed

cli/notifications.go

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
package cli
2+
3+
import (
4+
"fmt"
5+
6+
"golang.org/x/xerrors"
7+
8+
"github.com/coder/serpent"
9+
10+
"github.com/coder/coder/v2/codersdk"
11+
)
12+
13+
func (r *RootCmd) notifications() *serpent.Command {
14+
cmd := &serpent.Command{
15+
Use: "notifications",
16+
Short: "Manage Coder notifications",
17+
Long: "Administrators can use these commands to change notification settings.\n" + FormatExamples(
18+
Example{
19+
Description: "Pause Coder notifications. Administrators can temporarily stop notifiers from dispatching messages in case of the target outage (for example: unavailable SMTP server or Webhook not responding).",
20+
Command: "coder notifications pause",
21+
},
22+
Example{
23+
Description: "Resume Coder notifications",
24+
Command: "coder notifications resume",
25+
},
26+
),
27+
Aliases: []string{"notification"},
28+
Handler: func(inv *serpent.Invocation) error {
29+
return inv.Command.HelpHandler(inv)
30+
},
31+
Children: []*serpent.Command{
32+
r.pauseNotifications(),
33+
r.resumeNotifications(),
34+
},
35+
}
36+
return cmd
37+
}
38+
39+
func (r *RootCmd) pauseNotifications() *serpent.Command {
40+
client := new(codersdk.Client)
41+
cmd := &serpent.Command{
42+
Use: "pause",
43+
Short: "Pause notifications",
44+
Middleware: serpent.Chain(
45+
serpent.RequireNArgs(0),
46+
r.InitClient(client),
47+
),
48+
Handler: func(inv *serpent.Invocation) error {
49+
err := client.PutNotificationsSettings(inv.Context(), codersdk.NotificationsSettings{
50+
NotifierPaused: true,
51+
})
52+
if err != nil {
53+
return xerrors.Errorf("unable to pause notifications: %w", err)
54+
}
55+
56+
_, _ = fmt.Fprintln(inv.Stderr, "Notifications are now paused.")
57+
return nil
58+
},
59+
}
60+
return cmd
61+
}
62+
63+
func (r *RootCmd) resumeNotifications() *serpent.Command {
64+
client := new(codersdk.Client)
65+
cmd := &serpent.Command{
66+
Use: "resume",
67+
Short: "Resume notifications",
68+
Middleware: serpent.Chain(
69+
serpent.RequireNArgs(0),
70+
r.InitClient(client),
71+
),
72+
Handler: func(inv *serpent.Invocation) error {
73+
err := client.PutNotificationsSettings(inv.Context(), codersdk.NotificationsSettings{
74+
NotifierPaused: false,
75+
})
76+
if err != nil {
77+
return xerrors.Errorf("unable to resume notifications: %w", err)
78+
}
79+
80+
_, _ = fmt.Fprintln(inv.Stderr, "Notifications are now resumed.")
81+
return nil
82+
},
83+
}
84+
return cmd
85+
}

cli/notifications_test.go

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
package cli_test
2+
3+
import (
4+
"bytes"
5+
"context"
6+
"encoding/json"
7+
"net/http"
8+
"testing"
9+
10+
"github.com/stretchr/testify/assert"
11+
"github.com/stretchr/testify/require"
12+
13+
"github.com/coder/coder/v2/cli/clitest"
14+
"github.com/coder/coder/v2/coderd/coderdtest"
15+
"github.com/coder/coder/v2/codersdk"
16+
"github.com/coder/coder/v2/testutil"
17+
)
18+
19+
func TestNotifications(t *testing.T) {
20+
t.Parallel()
21+
22+
tests := []struct {
23+
name string
24+
command string
25+
expectPaused bool
26+
}{
27+
{
28+
name: "PauseNotifications",
29+
command: "pause",
30+
expectPaused: true,
31+
},
32+
{
33+
name: "ResumeNotifications",
34+
command: "resume",
35+
expectPaused: false,
36+
},
37+
}
38+
39+
for _, tt := range tests {
40+
tt := tt
41+
t.Run(tt.name, func(t *testing.T) {
42+
t.Parallel()
43+
44+
// given
45+
ownerClient, db := coderdtest.NewWithDatabase(t, nil)
46+
_ = coderdtest.CreateFirstUser(t, ownerClient)
47+
48+
// when
49+
inv, root := clitest.New(t, "notifications", tt.command)
50+
clitest.SetupConfig(t, ownerClient, root)
51+
52+
var buf bytes.Buffer
53+
inv.Stdout = &buf
54+
err := inv.Run()
55+
require.NoError(t, err)
56+
57+
// then
58+
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitShort)
59+
t.Cleanup(cancel)
60+
settingsJSON, err := db.GetNotificationsSettings(ctx)
61+
require.NoError(t, err)
62+
63+
var settings codersdk.NotificationsSettings
64+
err = json.Unmarshal([]byte(settingsJSON), &settings)
65+
require.NoError(t, err)
66+
require.Equal(t, tt.expectPaused, settings.NotifierPaused)
67+
})
68+
}
69+
}
70+
71+
func TestPauseNotifications_RegularUser(t *testing.T) {
72+
t.Parallel()
73+
74+
// given
75+
ownerClient, db := coderdtest.NewWithDatabase(t, nil)
76+
owner := coderdtest.CreateFirstUser(t, ownerClient)
77+
anotherClient, _ := coderdtest.CreateAnotherUser(t, ownerClient, owner.OrganizationID)
78+
79+
// when
80+
inv, root := clitest.New(t, "notifications", "pause")
81+
clitest.SetupConfig(t, anotherClient, root)
82+
83+
var buf bytes.Buffer
84+
inv.Stdout = &buf
85+
err := inv.Run()
86+
var sdkError *codersdk.Error
87+
require.Error(t, err)
88+
require.ErrorAsf(t, err, &sdkError, "error should be of type *codersdk.Error")
89+
assert.Equal(t, http.StatusForbidden, sdkError.StatusCode())
90+
assert.Contains(t, sdkError.Message, "Insufficient permissions to update notifications settings.")
91+
92+
// then
93+
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitShort)
94+
t.Cleanup(cancel)
95+
settingsJSON, err := db.GetNotificationsSettings(ctx)
96+
require.NoError(t, err)
97+
98+
var settings codersdk.NotificationsSettings
99+
err = json.Unmarshal([]byte(settingsJSON), &settings)
100+
require.NoError(t, err)
101+
require.False(t, settings.NotifierPaused) // still running
102+
}

cli/root.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,8 @@ func (r *RootCmd) CoreSubcommands() []*serpent.Command {
8787
r.login(),
8888
r.logout(),
8989
r.netcheck(),
90+
r.notifications(),
91+
r.organizations(),
9092
r.portForward(),
9193
r.publickey(),
9294
r.resetPassword(),
@@ -95,7 +97,6 @@ func (r *RootCmd) CoreSubcommands() []*serpent.Command {
9597
r.tokens(),
9698
r.users(),
9799
r.version(defaultVersionInfo),
98-
r.organizations(),
99100

100101
// Workspace Commands
101102
r.autoupdate(),
@@ -120,11 +121,11 @@ func (r *RootCmd) CoreSubcommands() []*serpent.Command {
120121
r.whoami(),
121122

122123
// Hidden
124+
r.expCmd(),
123125
r.gitssh(),
126+
r.support(),
124127
r.vscodeSSH(),
125128
r.workspaceAgent(),
126-
r.expCmd(),
127-
r.support(),
128129
}
129130
}
130131

cli/testdata/coder_--help.golden

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ SUBCOMMANDS:
2727
login Authenticate with Coder deployment
2828
logout Unauthenticate your local session
2929
netcheck Print network debug information for DERP and STUN
30+
notifications Manage Coder notifications
3031
open Open a workspace
3132
ping Ping a workspace
3233
port-forward Forward ports from a workspace to the local machine. For
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
coder v0.0.0-devel
2+
3+
USAGE:
4+
coder notifications
5+
6+
Manage Coder notifications
7+
8+
Aliases: notification
9+
10+
Administrators can use these commands to change notification settings.
11+
- Pause Coder notifications. Administrators can temporarily stop notifiers
12+
from
13+
dispatching messages in case of the target outage (for example: unavailable
14+
SMTP
15+
server or Webhook not responding).:
16+
17+
$ coder notifications pause
18+
19+
- Resume Coder notifications:
20+
21+
$ coder notifications resume
22+
23+
SUBCOMMANDS:
24+
pause Pause notifications
25+
resume Resume notifications
26+
27+
———
28+
Run `coder --help` for a list of global options.
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
coder v0.0.0-devel
2+
3+
USAGE:
4+
coder notifications pause
5+
6+
Pause notifications
7+
8+
———
9+
Run `coder --help` for a list of global options.
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
coder v0.0.0-devel
2+
3+
USAGE:
4+
coder notifications resume
5+
6+
Resume notifications
7+
8+
———
9+
Run `coder --help` for a list of global options.

docs/cli.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ Coder — A tool for provisioning self-hosted development environments with Terr
3030
| [<code>login</code>](./cli/login.md) | Authenticate with Coder deployment |
3131
| [<code>logout</code>](./cli/logout.md) | Unauthenticate your local session |
3232
| [<code>netcheck</code>](./cli/netcheck.md) | Print network debug information for DERP and STUN |
33+
| [<code>notifications</code>](./cli/notifications.md) | Manage Coder notifications |
3334
| [<code>port-forward</code>](./cli/port-forward.md) | Forward ports from a workspace to the local machine. For reverse port forwarding, use "coder ssh -R". |
3435
| [<code>publickey</code>](./cli/publickey.md) | Output your Coder public key used for Git operations |
3536
| [<code>reset-password</code>](./cli/reset-password.md) | Directly connect to the database to reset a user's password |

docs/cli/notifications.md

Lines changed: 37 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

docs/cli/notifications_pause.md

Lines changed: 11 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

docs/cli/notifications_resume.md

Lines changed: 11 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

docs/manifest.json

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -755,6 +755,21 @@
755755
"description": "Print network debug information for DERP and STUN",
756756
"path": "cli/netcheck.md"
757757
},
758+
{
759+
"title": "notifications",
760+
"description": "Manage Coder notifications",
761+
"path": "cli/notifications.md"
762+
},
763+
{
764+
"title": "notifications pause",
765+
"description": "Pause notifications",
766+
"path": "cli/notifications_pause.md"
767+
},
768+
{
769+
"title": "notifications resume",
770+
"description": "Resume notifications",
771+
"path": "cli/notifications_resume.md"
772+
},
758773
{
759774
"title": "open",
760775
"description": "Open a workspace",

0 commit comments

Comments
 (0)