diff --git a/cli/app.go b/cli/app.go index b9bf1fe1c..813b25887 100644 --- a/cli/app.go +++ b/cli/app.go @@ -145,7 +145,7 @@ type App struct { upgradeOwnerID string doNotWaitForUpgrade bool - errorNotifications bool + errorNotifications string currentAction string onExitCallbacks []func() @@ -248,10 +248,6 @@ func (c *App) passwordPersistenceStrategy() passwordpersist.Strategy { return passwordpersist.File() } -func (c *App) enableErrorNotifications() bool { - return c.errorNotifications -} - func (c *App) setup(app *kingpin.Application) { app.PreAction(func(pc *kingpin.ParseContext) error { if sc := pc.SelectedCommand; sc != nil { @@ -286,7 +282,10 @@ func (c *App) setup(app *kingpin.Application) { app.Flag("dump-allocator-stats", "Dump allocator stats at the end of execution.").Hidden().Envar(c.EnvName("KOPIA_DUMP_ALLOCATOR_STATS")).BoolVar(&c.dumpAllocatorStats) app.Flag("upgrade-owner-id", "Repository format upgrade owner-id.").Hidden().Envar(c.EnvName("KOPIA_REPO_UPGRADE_OWNER_ID")).StringVar(&c.upgradeOwnerID) app.Flag("upgrade-no-block", "Do not block when repository format upgrade is in progress, instead exit with a message.").Hidden().Default("false").Envar(c.EnvName("KOPIA_REPO_UPGRADE_NO_BLOCK")).BoolVar(&c.doNotWaitForUpgrade) - app.Flag("error-notifications", "Send notification on errors").Hidden().Envar(c.EnvName("KOPIA_SEND_ERROR_NOTIFICATIONS")).Default("true").BoolVar(&c.errorNotifications) + app.Flag("error-notifications", "Send notification on errors").Hidden(). + Envar(c.EnvName("KOPIA_SEND_ERROR_NOTIFICATIONS")). + Default(errorNotificationsNonInteractive). + EnumVar(&c.errorNotifications, errorNotificationsAlways, errorNotificationsNever, errorNotificationsNonInteractive) if c.enableTestOnlyFlags() { app.Flag("ignore-missing-required-features", "Open repository despite missing features (VERY DANGEROUS, ONLY FOR TESTING)").Hidden().BoolVar(&c.testonlyIgnoreMissingRequiredFeatures) @@ -585,7 +584,7 @@ func (c *App) maybeRepositoryAction(act func(ctx context.Context, rep repo.Repos } } - if err != nil && rep != nil && c.errorNotifications { + if err != nil && c.enableErrorNotifications() && rep != nil { notification.Send(ctx, rep, "generic-error", notifydata.NewErrorInfo( c.currentActionName(), c.currentActionName(), diff --git a/cli/error_notifications.go b/cli/error_notifications.go new file mode 100644 index 000000000..4061b0c13 --- /dev/null +++ b/cli/error_notifications.go @@ -0,0 +1,38 @@ +package cli + +import ( + "os" + + "github.com/mattn/go-isatty" +) + +const ( + errorNotificationsNever = "never" + errorNotificationsAlways = "always" + errorNotificationsNonInteractive = "non-interactive" +) + +func (c *App) enableErrorNotifications() bool { + switch c.errorNotifications { + case errorNotificationsNever: + return false + + case errorNotificationsAlways: + return true + + case errorNotificationsNonInteractive: + if c.isInProcessTest { + return false + } + + if isatty.IsTerminal(os.Stdout.Fd()) || isatty.IsCygwinTerminal(os.Stdout.Fd()) { + // interactive terminal, don't send notifications + return false + } + + return true + + default: + return false + } +} diff --git a/go.mod b/go.mod index 629475d0d..c0df07da8 100644 --- a/go.mod +++ b/go.mod @@ -31,6 +31,7 @@ require ( github.com/kopia/htmluibuild v0.0.1-0.20241105060252-108f70b353de github.com/kylelemons/godebug v1.1.0 github.com/mattn/go-colorable v0.1.13 + github.com/mattn/go-isatty v0.0.20 github.com/minio/minio-go/v7 v7.0.80 github.com/mocktools/go-smtp-mock/v2 v2.3.1 github.com/mxk/go-vss v1.2.0 @@ -122,7 +123,6 @@ require ( github.com/klauspost/cpuid/v2 v2.2.8 // indirect github.com/kr/fs v0.1.0 // indirect github.com/mailru/easyjson v0.7.7 // indirect - github.com/mattn/go-isatty v0.0.20 // indirect github.com/minio/md5-simd v1.1.2 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect