Skip to content

Commit 86f73d4

Browse files
committed
feat(update): show notification after any command
- Move PrintUpdateNotification() to PersistentPostRun (runs after all commands) - Add 100ms timeout for cached results (imperceptible but allows disk reads) - Remove individual calls from scan_repo.go and scan_image.go This aligns with gh CLI behavior - update notifications appear after any command, not just scans. First run populates cache, subsequent runs show notification instantly from cache.
1 parent 27f674e commit 86f73d4

4 files changed

Lines changed: 14 additions & 9 deletions

File tree

internal/cmd/root.go

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"fmt"
77
"os"
88
"strings"
9+
"time"
910

1011
"github.com/ArmisSecurity/armis-cli/internal/auth"
1112
"github.com/ArmisSecurity/armis-cli/internal/cli"
@@ -71,6 +72,10 @@ var rootCmd = &cobra.Command{
7172
Version: version,
7273
SilenceUsage: true,
7374
SilenceErrors: true,
75+
PersistentPostRun: func(cmd *cobra.Command, args []string) {
76+
// Show update notification after any command completes (like gh CLI)
77+
PrintUpdateNotification()
78+
},
7479
PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
7580
// Initialize colors based on --color flag
7681
mode := cli.ColorMode(colorFlag)
@@ -176,14 +181,16 @@ func PrintUpdateNotification() {
176181
return
177182
}
178183

179-
// Non-blocking read: only show if result is already available
184+
// Wait briefly for cached results (100ms is imperceptible but enough for disk reads).
185+
// Fresh network requests (10s timeout) won't complete in time -- that's fine,
186+
// the notification will show on the next run once the cache is populated.
180187
select {
181188
case result, ok := <-updateResultCh:
182189
if ok && result != nil {
183190
msg := update.FormatNotification(result.CurrentVersion, result.LatestVersion, output.IconDependency)
184191
fmt.Fprint(os.Stderr, msg)
185192
}
186-
default:
193+
case <-time.After(100 * time.Millisecond):
187194
// Check hasn't completed yet -- silently skip
188195
}
189196
}

internal/cmd/root_test.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -579,14 +579,14 @@ func TestPrintUpdateNotification(t *testing.T) {
579579
PrintUpdateNotification()
580580
})
581581

582-
t.Run("empty channel does not block", func(t *testing.T) {
582+
t.Run("empty channel times out gracefully", func(t *testing.T) {
583583
originalUpdateResultCh := updateResultCh
584584
defer func() { updateResultCh = originalUpdateResultCh }()
585585

586586
// Create an unbuffered channel with no value
587587
updateResultCh = make(chan *update.CheckResult)
588588

589-
// Should return immediately without blocking
589+
// Should return after ~100ms timeout (not block indefinitely)
590590
done := make(chan bool, 1)
591591
go func() {
592592
PrintUpdateNotification()
@@ -595,9 +595,9 @@ func TestPrintUpdateNotification(t *testing.T) {
595595

596596
select {
597597
case <-done:
598-
// Success - function returned
599-
case <-time.After(100 * time.Millisecond):
600-
t.Error("PrintUpdateNotification blocked on empty channel")
598+
// Success - function returned after timeout
599+
case <-time.After(200 * time.Millisecond):
600+
t.Error("PrintUpdateNotification blocked indefinitely on empty channel")
601601
}
602602
})
603603
}

internal/cmd/scan_image.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,6 @@ var scanImageCmd = &cobra.Command{
138138
return fmt.Errorf("failed to format output: %w", err)
139139
}
140140

141-
PrintUpdateNotification()
142141
output.ExitIfNeeded(result, failOnSeverities, exitCode)
143142
return nil
144143
},

internal/cmd/scan_repo.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,6 @@ var scanRepoCmd = &cobra.Command{
126126
return fmt.Errorf("failed to format output: %w", err)
127127
}
128128

129-
PrintUpdateNotification()
130129
output.ExitIfNeeded(result, failOnSeverities, exitCode)
131130
return nil
132131
},

0 commit comments

Comments
 (0)