Files
kopia/cli/command_notification_configure_common.go
Jarek Kowalski c0bd372d29 feat(cli): support for defining notification profiles and templates via CLI (#4034)
* feat(cli): support for defining notification profiles via CLI

Profile management:

```
$ kopia notification profile configure email \
    --profile-name=X \
    --smtp-server=smtp.gmail.com \
    --smtp-port=587 \
    --smtp-username=X \
    --smtp-password=X \
    --mail-from=X \
    --mail-to=X \
    --format=html|txt \
    [--send-test-notification]

$ kopia notification profile configure pushover --profile-name=X \
    --user-key=X \
    --app-token=X \
    --format=html|txt \
    [--send-test-notification]

$ kopia notification profile configure webhook --profile-name=X \
    --endpooint=http://some-address:port/path \
    --method=POST|PUT \
    --format=html|txt \
    [--send-test-notification]

$ kopia notification profile test --profile-name=X

$ kopia notification profile delete --profile-name=X

$ kopia notification profile list
```

Template management:

```
$ kopia notification template show X

$ kopia notification template set X \
   --from-stdin | --from-file=X | --editor

$ kopia notification template remove X

$ kopia notification template list

```

Implements #1958

* additional refactoring for testability, various naming tweaks
2024-10-06 16:28:39 +00:00

105 lines
3.2 KiB
Go

package cli
import (
"context"
"golang.org/x/exp/maps"
"github.com/alecthomas/kingpin/v2"
"github.com/pkg/errors"
"github.com/kopia/kopia/notification"
"github.com/kopia/kopia/notification/notifyprofile"
"github.com/kopia/kopia/notification/sender"
"github.com/kopia/kopia/repo"
)
// commonNotificationOptions is a common configuration for notification methods.
type commonNotificationOptions struct {
notificationProfileFlag
sendTestNotification bool
minSeverity string
}
func (c *commonNotificationOptions) setup(svc appServices, cmd *kingpin.CmdClause) {
c.notificationProfileFlag.setup(svc, cmd)
cmd.Flag("send-test-notification", "Test the notification").BoolVar(&c.sendTestNotification)
cmd.Flag("min-severity", "Minimum severity").EnumVar(&c.minSeverity, maps.Keys(notification.SeverityToNumber)...)
}
// configureNotificationAction is a helper function that creates a Kingpin action that
// configures a notification method.
// it will read the existing profile, merge the provided options, and save the profile back
// or send a test notification based on the flags.
func configureNotificationAction[T comparable](
svc appServices,
c *commonNotificationOptions,
senderMethod sender.Method,
opt *T,
merge func(src T, dst *T, isUpdate bool),
) func(ctx *kingpin.ParseContext) error {
return svc.directRepositoryWriteAction(func(ctx context.Context, rep repo.DirectRepositoryWriter) error {
var (
defaultT T
previousOptions *T
)
// read the existing profile, if any.
oldProfile, exists, err := notifyprofile.GetProfile(ctx, rep, c.profileName)
if err != nil {
return errors.Wrap(err, "unable to get notification profile")
}
sev := notification.SeverityDefault
if exists {
if oldProfile.MethodConfig.Type != senderMethod {
return errors.Errorf("profile %q already exists but is not of type %q", c.profileName, senderMethod)
}
var parsedT T
if err := oldProfile.MethodConfig.Options(&parsedT); err != nil {
return errors.Wrapf(err, "profile %q already exists but is not of type %q", c.profileName, senderMethod)
}
previousOptions = &parsedT
sev = oldProfile.MinSeverity
} else {
previousOptions = &defaultT
}
if *opt != defaultT {
// any options provided on the command line, merge them with the existing ones.
merge(*opt, previousOptions, exists)
}
if c.minSeverity != "" {
// severity is specified on the command line, override the one from the profile.
sev = notification.SeverityToNumber[c.minSeverity]
}
s, err := sender.GetSender(ctx, c.profileName, senderMethod, previousOptions)
if err != nil {
return errors.Wrap(err, "unable to get notification provider")
}
if c.sendTestNotification {
if err := notification.SendTestNotification(ctx, rep, s); err != nil {
return errors.Wrap(err, "unable to send test notification")
}
}
log(ctx).Infof("Saving notification profile %q of type %q with severity %q.", c.profileName, senderMethod, notification.SeverityToString[sev])
return notifyprofile.SaveProfile(ctx, rep, notifyprofile.Config{
ProfileName: c.profileName,
MethodConfig: sender.MethodConfig{
Type: senderMethod,
Config: previousOptions,
},
MinSeverity: sev,
})
})
}