Skip to content

Commit 458a655

Browse files
hugosantosampagent
andauthored
cli: throttle 'new version available' notification to once per day (#1809)
Record the last time we emitted the update-available notification in `$XDG_CONFIG_HOME/ns/version-notify`, and skip both the remote version check and the notification on subsequent invocations within 24h. The throttle is global across all commands (`nsc`, `ns`, ...). --------- Co-authored-by: Amp <amp@ampcode.com>
1 parent 4e56f19 commit 458a655

1 file changed

Lines changed: 43 additions & 0 deletions

File tree

  • internal/cli/fncobra

internal/cli/fncobra/do.go

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,25 @@
55
package fncobra
66

77
import (
8+
"bytes"
89
"context"
910
"fmt"
11+
"os"
12+
"path/filepath"
13+
"time"
1014

1115
"github.com/spf13/cobra"
1216
"github.com/spf13/pflag"
1317
"namespacelabs.dev/foundation/internal/cli/version"
1418
"namespacelabs.dev/foundation/internal/cli/versioncheck"
1519
"namespacelabs.dev/foundation/internal/compute"
1620
"namespacelabs.dev/foundation/internal/console"
21+
"namespacelabs.dev/foundation/internal/workspace/dirs"
1722
"namespacelabs.dev/foundation/std/tasks"
1823
)
1924

25+
const updateNotifyInterval = 24 * time.Hour
26+
2027
type CmdHandler func(context.Context, []string) error
2128

2229
type ArgsParser interface {
@@ -41,6 +48,10 @@ func DeferCheckVersion(ctx context.Context, command string) {
4148
return
4249
}
4350

51+
if !shouldNotifyUpdate() {
52+
return
53+
}
54+
4455
compute.On(ctx).BestEffort(tasks.Action(command+".check-updated"), func(ctx context.Context) error {
4556
status, err := versioncheck.CheckRemote(ctx, ver, command)
4657
if err != nil {
@@ -54,6 +65,7 @@ func DeferCheckVersion(ctx context.Context, command string) {
5465

5566
if status.NewVersion {
5667
compute.On(ctx).Cleanup(tasks.Action(command+".check-updated.notify").LogLevel(1), func(ctx context.Context) error {
68+
_ = markUpdateNotified()
5769
fmt.Fprintf(console.Info(ctx), "\n\n A new version of %s is available (%s).\n\n", command, status.Version)
5870
return nil
5971
})
@@ -63,6 +75,37 @@ func DeferCheckVersion(ctx context.Context, command string) {
6375
})
6476
}
6577

78+
func updateNotifyPath() (string, error) {
79+
return dirs.ConfigSubdir("version-notify")
80+
}
81+
82+
func shouldNotifyUpdate() bool {
83+
path, err := updateNotifyPath()
84+
if err != nil {
85+
return true
86+
}
87+
data, err := os.ReadFile(path)
88+
if err != nil {
89+
return true
90+
}
91+
last, err := time.Parse(time.RFC3339, string(bytes.TrimSpace(data)))
92+
if err != nil {
93+
return true
94+
}
95+
return time.Since(last) >= updateNotifyInterval
96+
}
97+
98+
func markUpdateNotified() error {
99+
path, err := updateNotifyPath()
100+
if err != nil {
101+
return err
102+
}
103+
if err := os.MkdirAll(filepath.Dir(path), 0755); err != nil {
104+
return err
105+
}
106+
return os.WriteFile(path, []byte(time.Now().UTC().Format(time.RFC3339)), 0644)
107+
}
108+
66109
func RunInContext(ctx context.Context, handler func(context.Context) error) error {
67110
ctx, cancel := WithSigIntCancel(ctx)
68111
defer cancel()

0 commit comments

Comments
 (0)