Add release automation and self-update functionality#22
Conversation
- Update description to remove leading article
- Use bin/"devx" syntax instead of "#{bin}/devx" in test
These changes address brew audit warnings for better formula style compliance.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Implements automatic update checking and self-update capabilities: - Background update checks on startup (configurable interval, default 24h) - CLI commands for checking and installing updates - TUI integration with update banner and 'u' key binding - Installation method detection (Homebrew vs manual vs go install) - Rate limiting with cached state to avoid excessive API calls - Graceful handling of dev versions and private repositories New features: - `devx update` - Download and install latest version - `devx version --check-updates` - Check for available updates - Config options: auto_check_updates, update_check_interval - Update notifications in TUI with visual banner - Smart detection to skip self-update for Homebrew installations 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
WalkthroughAdds a non-blocking auto-update subsystem: background and on-demand update checks with cached state and notification suppression, CLI update command and version-check flag, TUI banner and interactive update flow, install-method detection and self-update execution, persistence/tests, and small release/config adjustments. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
participant User
participant CLI as devx (startup)
participant Cfg as config
participant Update as update.checker
Note over CLI: Startup triggers non-blocking check
CLI->>Cfg: LoadUpdateCheckState()
CLI->>Update: CheckForUpdatesWithCache(interval)
Update->>Cfg: Evaluate ShouldCheckForUpdates / SaveUpdateCheckState
Update-->>CLI: UpdateInfo, checked?
CLI-->>User: Print notification if ShouldNotifyUser (async)
sequenceDiagram
autonumber
participant User
participant CLI as devx update cmd
participant Detect as update.detector
participant Update as update.checker/installer
User->>CLI: devx update [--check|--force]
alt --check
CLI->>Update: CheckForUpdates()
Update-->>CLI: UpdateInfo
CLI-->>User: Print current/latest, availability, URL
else perform update
CLI->>Detect: CanSelfUpdate()
alt Cannot self-update (Homebrew)
Detect-->>CLI: false
CLI-->>User: Print Homebrew upgrade instructions
else Self-update allowed
CLI->>Update: CheckForUpdates()
alt update available or --force
CLI->>Update: PerformUpdate(force)
Update-->>CLI: success/error
CLI-->>User: Print status and release notes
else up-to-date
CLI-->>User: Confirm latest
end
end
end
sequenceDiagram
autonumber
participant User
participant TUI as devx TUI
participant Update as update.checker/installer
participant Detect as update.detector
Note over TUI: Init performs async check
TUI->>Update: CheckForUpdates (async)
Update-->>TUI: updateAvailableMsg(current, latest)
TUI-->>User: Show update banner
User->>TUI: Press 'u' (Update)
TUI->>Detect: CanSelfUpdate()
alt self-update allowed
TUI-->>User: Confirm update?
User->>TUI: Yes
TUI->>Update: PerformUpdate(false)
Update-->>TUI: Result
TUI-->>User: Success/failure message
else not allowed
TUI-->>User: Show install instructions
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Suggested labels
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests
Comment |
There was a problem hiding this comment.
Actionable comments posted: 6
🧹 Nitpick comments (2)
update/detector.go (2)
45-68: Consider supporting custom Homebrew prefixes.The current implementation hardcodes common Homebrew paths (
/usr/local,/opt/homebrew), which covers most cases. However, users can set custom prefixes viaHOMEBREW_PREFIX. For completeness, consider checking this environment variable.func isHomebrewManaged(path string) bool { + // Check HOMEBREW_PREFIX if set + if prefix := os.Getenv("HOMEBREW_PREFIX"); prefix != "" { + if strings.Contains(path, filepath.Join(prefix, "Cellar", "devx")) { + return true + } + } + // Check for Cellar paths (direct installation) if strings.Contains(path, "/usr/local/Cellar/devx") ||
77-91: Consider centralizing the repository path.The GitHub repository path is hardcoded at line 85. For maintainability, consider defining it as a package-level constant or configuration value, especially since it's likely used in other parts of the update system.
+const ( + defaultRepo = "github.com/jfox85/devx" +) + func GetUpdateInstructions() string { method := DetectInstallMethod() switch method { case InstallMethodHomebrew: return "Please update using Homebrew:\n brew upgrade devx\n\nOr:\n brew update && brew upgrade devx" case InstallMethodGoInstall: - return "Please update using go install:\n go install github.com/jfox85/devx@latest" + return fmt.Sprintf("Please update using go install:\n go install %s@latest", defaultRepo)Note: This would require adding
fmtto imports.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
go.sumis excluded by!**/*.sum
📒 Files selected for processing (14)
.gitignore(1 hunks).goreleaser.yaml(2 hunks)cmd/root.go(3 hunks)cmd/update.go(1 hunks)cmd/version.go(3 hunks)config/updatecheck.go(1 hunks)config/updatecheck_test.go(1 hunks)go.mod(3 hunks)tui/model.go(12 hunks)update/checker.go(1 hunks)update/checker_test.go(1 hunks)update/detector.go(1 hunks)update/detector_test.go(1 hunks)update/installer.go(1 hunks)
🧰 Additional context used
📓 Path-based instructions (7)
**/*.go
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.go: Format all Go code with gofmt before committing
Wrap errors consistently with context throughout the codebase
Files:
update/checker_test.goupdate/installer.gocmd/version.gocmd/root.goconfig/updatecheck.goupdate/checker.gotui/model.goconfig/updatecheck_test.goupdate/detector_test.goupdate/detector.gocmd/update.go
**/*_test.go
📄 CodeRabbit inference engine (CLAUDE.md)
**/*_test.go: Place unit tests alongside source files using the *_test.go naming convention
Use the standard Go testing package for tests
Files:
update/checker_test.goconfig/updatecheck_test.goupdate/detector_test.go
cmd/**/*.go
📄 CodeRabbit inference engine (CLAUDE.md)
cmd/**/*.go: Place all CLI commands using Cobra under cmd/
When modifying CLI commands, update help text and examples
Files:
cmd/version.gocmd/root.gocmd/update.go
cmd/root.go
📄 CodeRabbit inference engine (CLAUDE.md)
Keep base command setup and TUI launcher in cmd/root.go
Files:
cmd/root.go
config/**/*.go
📄 CodeRabbit inference engine (CLAUDE.md)
config/**/*.go: Keep configuration and settings management under config/ (Viper, discovery, projects)
Respect the configuration hierarchy in configuration-related changes
Files:
config/updatecheck.goconfig/updatecheck_test.go
go.mod
📄 CodeRabbit inference engine (CLAUDE.md)
Ensure go.mod is tidy before committing
Files:
go.mod
tui/**/*.go
📄 CodeRabbit inference engine (CLAUDE.md)
tui/**/*.go: Implement the Bubble Tea TUI under tui/ (model, run, styles)
Preserve keyboard navigation patterns when changing the TUI
Files:
tui/model.go
🧠 Learnings (1)
📚 Learning: 2025-10-01T21:30:09.446Z
Learnt from: CR
PR: jfox85/devx#0
File: CLAUDE.md:0-0
Timestamp: 2025-10-01T21:30:09.446Z
Learning: Follow configuration hierarchy: project .devx/ overrides global ~/.config/devx/ and env vars override both
Applied to files:
.gitignore
🧬 Code graph analysis (8)
update/installer.go (2)
version/version.go (1)
Version(10-10)update/checker.go (2)
GitHubRepo(19-19)CheckForUpdates(32-64)
cmd/version.go (1)
update/checker.go (1)
CheckForUpdates(32-64)
cmd/root.go (1)
update/checker.go (2)
CheckForUpdatesWithCache(67-96)ShouldNotifyUser(102-114)
config/updatecheck.go (1)
config/discovery.go (1)
GetConfigDir(97-110)
update/checker.go (2)
version/version.go (1)
Version(10-10)config/updatecheck.go (3)
LoadUpdateCheckState(23-44)ShouldCheckForUpdates(67-72)SaveUpdateCheckState(47-64)
tui/model.go (4)
update/detector.go (2)
CanSelfUpdate(71-75)GetUpdateInstructions(78-91)update/installer.go (1)
PerformUpdate(13-51)update/checker.go (1)
CheckForUpdates(32-64)version/version.go (1)
Version(10-10)
config/updatecheck_test.go (1)
config/updatecheck.go (4)
UpdateCheckState(11-14)SaveUpdateCheckState(47-64)LoadUpdateCheckState(23-44)ShouldCheckForUpdates(67-72)
update/detector_test.go (1)
update/detector.go (8)
DetectInstallMethod(20-43)InstallMethod(10-10)InstallMethodHomebrew(13-13)InstallMethodGoInstall(14-14)InstallMethodManual(15-15)InstallMethodUnknown(16-16)CanSelfUpdate(71-75)GetUpdateInstructions(78-91)
🪛 GitHub Actions: Lint
config/updatecheck_test.go
[error] 22-22: golangci-lint: os.Chdir error return value is not checked (errcheck)
🪛 GitHub Check: Lint
config/updatecheck_test.go
[failure] 108-108:
Error return value of os.Chdir is not checked (errcheck)
[failure] 23-23:
Error return value of os.Chdir is not checked (errcheck)
[failure] 22-22:
Error return value of os.Chdir is not checked (errcheck)
🪛 OSV Scanner (2.2.2)
go.mod
[HIGH] 54-54: golang.org/x/crypto 0.32.0: Potential denial of service in golang.org/x/crypto
(GO-2025-3487)
[HIGH] 54-54: golang.org/x/crypto 0.32.0: golang.org/x/crypto Vulnerable to Denial of Service (DoS) via Slow or Incomplete Key Exchange
[HIGH] 56-56: golang.org/x/oauth2 0.25.0: Unexpected memory consumption during token parsing in golang.org/x/oauth2
(GO-2025-3488)
[HIGH] 56-56: golang.org/x/oauth2 0.25.0: golang.org/x/oauth2 Improper Validation of Syntactic Correctness of Input vulnerability
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
- GitHub Check: Build
- GitHub Check: Build
- GitHub Check: Test Windows
🔇 Additional comments (4)
.gitignore (1)
3-5: Ignore build and config artifacts correctly.Adding
dist/and.devx/keeps release outputs and local config out of Git; reordering.tmuxp.yamlis harmless.update/detector.go (3)
1-7: LGTM!Clean package declaration and minimal standard library imports appropriate for the file's functionality.
9-17: LGTM!Type-safe enum pattern with clear constant values covering all expected installation methods plus an appropriate fallback.
70-75: LGTM!Clear logic that correctly prevents self-update for Homebrew installations, directing those users to
brew upgradeinstead.
| originalWd, _ := os.Getwd() | ||
| os.Chdir(tempDir) | ||
| defer os.Chdir(originalWd) | ||
|
|
There was a problem hiding this comment.
Handle os.Chdir errors so lint and tests pass.
The new tests ignore the return value of os.Chdir, which trips golangci-lint’s errcheck (and currently fails CI). Please assert the error and fail fast on failure when swapping directories. Example:
- originalWd, _ := os.Getwd()
- os.Chdir(tempDir)
- defer os.Chdir(originalWd)
+ originalWd, err := os.Getwd()
+ if err != nil {
+ t.Fatalf("getwd: %v", err)
+ }
+ if err := os.Chdir(tempDir); err != nil {
+ t.Fatalf("chdir temp dir: %v", err)
+ }
+ t.Cleanup(func() {
+ if err := os.Chdir(originalWd); err != nil {
+ t.Fatalf("restore cwd: %v", err)
+ }
+ })Apply the same pattern to the other os.Chdir call in this file.
Also applies to: 107-110
🧰 Tools
🪛 GitHub Actions: Lint
[error] 22-22: golangci-lint: os.Chdir error return value is not checked (errcheck)
🪛 GitHub Check: Lint
[failure] 23-23:
Error return value of os.Chdir is not checked (errcheck)
[failure] 22-22:
Error return value of os.Chdir is not checked (errcheck)
🤖 Prompt for AI Agents
In config/updatecheck_test.go around lines 21 to 24 (and similarly at 107-110),
the os.Chdir calls ignore returned errors; change both to check the error and
fail the test immediately on error (e.g. if err := os.Chdir(tempDir); err != nil
{ t.Fatalf("chdir to tempDir failed: %v", err) }) and likewise for restoring the
original working dir (if err := os.Chdir(originalWd); err != nil {
t.Fatalf("restore wd failed: %v", err) }), ensuring both occurrences are updated
so lint (errcheck) and tests pass.
| if strings.Contains(exePath, "/go/bin/") { | ||
| return InstallMethodGoInstall | ||
| } |
There was a problem hiding this comment.
Fragile detection pattern for go install.
The substring check /go/bin/ can produce false positives (e.g., /myapp/go/bin/) and doesn't respect GOBIN or GOPATH. Consider a more robust check that examines the actual Go environment or matches standard Go paths more precisely.
Example improvement:
- // Check for go install
- if strings.Contains(exePath, "/go/bin/") {
- return InstallMethodGoInstall
- }
+ // Check for go install (GOPATH/bin or GOBIN)
+ if strings.Contains(exePath, "/go/bin/devx") ||
+ strings.HasSuffix(exePath, "/bin/devx") && (strings.Contains(exePath, filepath.Join("go", "bin")) {
+ return InstallMethodGoInstall
+ }Alternatively, check for GOPATH or GOBIN environment variables and compare against those paths.
Committable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
In update/detector.go around lines 37 to 39, the current
strings.Contains(exePath, "/go/bin/") check is fragile and can yield false
positives; replace it with a robust comparison that determines the actual Go
install bin directory(s): obtain GOBIN and GOPATH (first via os.Getenv("GOBIN")
and os.Getenv("GOPATH"), falling back to running `go env GOBIN GOPATH` or using
the default GOPATH if empty), derive the bin path(s) (GOBIN and
filepath.Join(GOPATH, "bin")), normalize them with filepath.Clean, then check
exePath against those directories using filepath.Rel or a path-segment-aware
prefix check (ensure matches a directory boundary) and return
InstallMethodGoInstall only if exePath resides exactly in one of those bin dirs.
errcheck was complaining about unchecked os.Chdir error returns. Added proper error handling with t.Fatalf for initial chdir and t.Errorf for deferred directory restoration.
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (1)
update/checker_test.go (1)
11-63: Consider removing redundant description field.The test cases are well-structured and provide good coverage. However, the
descriptionfield on lines 17, 28, 39, 50, and 61 largely duplicates the information already present in thenamefield. Since the description is only used in the error message on line 99, you could simplify by usingtt.namedirectly in the error message instead.Apply this diff to remove the redundant field:
func TestShouldNotifyUser(t *testing.T) { tests := []struct { - name string - info *UpdateInfo - lastNotified string - expected bool - description string + name string + info *UpdateInfo + lastNotified string + expected bool }{ { name: "new update available, never notified", info: &UpdateInfo{ CurrentVersion: "0.1.0", LatestVersion: "0.2.0", Available: true, }, lastNotified: "", expected: true, - description: "Should notify when update is available and never notified", }, { name: "same update already notified", info: &UpdateInfo{ CurrentVersion: "0.1.0", LatestVersion: "0.2.0", Available: true, }, lastNotified: "0.2.0", expected: false, - description: "Should not notify if already notified about this version", }, { name: "newer update available than last notification", info: &UpdateInfo{ CurrentVersion: "0.1.0", LatestVersion: "0.3.0", Available: true, }, lastNotified: "0.2.0", expected: true, - description: "Should notify if a newer version is available than last notified", }, { name: "no update available", info: &UpdateInfo{ CurrentVersion: "0.2.0", LatestVersion: "0.2.0", Available: false, }, lastNotified: "", expected: false, - description: "Should not notify when no update is available", }, }And update the error message:
if result != tt.expected { - t.Errorf("%s: got %v, want %v", tt.description, result, tt.expected) + t.Errorf("%s: got %v, want %v", tt.name, result, tt.expected) }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
config/updatecheck_test.go(1 hunks)update/checker_test.go(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- config/updatecheck_test.go
🧰 Additional context used
📓 Path-based instructions (2)
**/*.go
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.go: Format all Go code with gofmt before committing
Wrap errors consistently with context throughout the codebase
Files:
update/checker_test.go
**/*_test.go
📄 CodeRabbit inference engine (CLAUDE.md)
**/*_test.go: Place unit tests alongside source files using the *_test.go naming convention
Use the standard Go testing package for tests
Files:
update/checker_test.go
🧬 Code graph analysis (1)
update/checker_test.go (2)
update/checker.go (2)
UpdateInfo(23-29)ShouldNotifyUser(102-114)config/updatecheck.go (2)
UpdateCheckState(11-14)SaveUpdateCheckState(47-64)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
- GitHub Check: Build
- GitHub Check: Test Windows
- GitHub Check: Test (1.23)
🔇 Additional comments (1)
update/checker_test.go (1)
1-9: LGTM!Package declaration and imports are clean and follow standard Go conventions.
Address CodeRabbit review feedback: 1. Fix notification flow bug (CRITICAL) - Moved LastNotifiedVersion update AFTER showing notification - Added MarkUpdateNotified() function for proper state management - Users now correctly see update notifications on first check 2. Fix dev version handling (CRITICAL) - Non-semver versions (like "dev") now treated as 0.0.0 - Allows self-update to work from development builds - Mirrors the logic already in CheckForUpdates() 3. Update vulnerable dependencies (CRITICAL) - golang.org/x/crypto: v0.32.0 → v0.35.0 (fixes DoS vulnerability) - golang.org/x/oauth2: v0.25.0 → v0.27.0 (fixes memory exhaustion) - golang.org/x/text: v0.21.0 → v0.22.0 (transitive update) All tests passing. Security vulnerabilities resolved.
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
go.mod (1)
8-8: Consider upgrading to blang/semver/v4 for module compatibility.The current dependency uses
v3.5.1+incompatiblebecause v3 lacks ago.modfile. The v4 release is module-aware and provides better Go modules compatibility with a proper module path. Based on learnings.To migrate to v4, update the import path in your code:
- "github.com/blang/semver" + "github.com/blang/semver/v4"And update go.mod:
- github.com/blang/semver v3.5.1+incompatible + github.com/blang/semver/v4 v4.0.0Then run
go mod tidy.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
go.sumis excluded by!**/*.sum
📒 Files selected for processing (4)
cmd/root.go(3 hunks)go.mod(3 hunks)update/checker.go(1 hunks)update/installer.go(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- cmd/root.go
🧰 Additional context used
📓 Path-based instructions (2)
**/*.go
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.go: Format all Go code with gofmt before committing
Wrap errors consistently with context throughout the codebase
Files:
update/checker.goupdate/installer.go
go.mod
📄 CodeRabbit inference engine (CLAUDE.md)
Ensure go.mod is tidy before committing
Files:
go.mod
🧬 Code graph analysis (2)
update/checker.go (2)
version/version.go (1)
Version(10-10)config/updatecheck.go (4)
LoadUpdateCheckState(23-44)ShouldCheckForUpdates(67-72)SaveUpdateCheckState(47-64)UpdateCheckState(11-14)
update/installer.go (2)
version/version.go (1)
Version(10-10)update/checker.go (2)
GitHubRepo(19-19)CheckForUpdates(32-64)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
- GitHub Check: Build
- GitHub Check: Build
- GitHub Check: Test Windows
- GitHub Check: Test (1.22)
🔇 Additional comments (9)
go.mod (2)
54-54: Security vulnerabilities resolved.The critical DoS vulnerabilities in
golang.org/x/cryptoandgolang.org/x/oauth2have been addressed by upgrading to the patched versions (v0.35.0 and v0.27.0 respectively).Also applies to: 56-56
1-60: go.mod tidiness verified. Runninggo mod tidyproduced no changes to go.mod or go.sum, confirming the files are clean.update/checker.go (5)
14-20: LGTM!The default 24-hour check interval and repository constant are appropriate for update checking functionality.
22-29: LGTM!The
UpdateInfostruct provides a clean public API for update information with all necessary fields.
31-64: LGTM!The function correctly handles dev versions by treating unparseable versions as
0.0.0, ensuring update checks work in development builds. Error wrapping is consistent throughout.
66-93: Past review concern resolved.The function now correctly updates only
LastCheckand leavesLastNotifiedVersionfor the separateMarkUpdateNotifiedflow. This ensures the first update notification is not suppressed. The comment on line 85 explicitly documents this fix.
95-111: LGTM!The notification logic correctly determines when to alert users based on version tracking. The default-to-notify behavior on state load errors ensures users don't miss updates.
update/installer.go (2)
12-56: Past review concern resolved.The function now gracefully handles dev versions by falling back to
0.0.0(lines 18-20), mirroring the pattern inCheckForUpdates. This allowsdevx updateto work correctly in development builds.
58-66: LGTM!The function provides a clean, lightweight API for checking update availability without triggering a download.
| // MarkUpdateNotified marks an update version as having been shown to the user | ||
| // This should be called after successfully displaying an update notification | ||
| func MarkUpdateNotified(latestVersion string) error { | ||
| state, err := config.LoadUpdateCheckState() | ||
| if err != nil { | ||
| // If we can't load state, create a new one | ||
| state = &config.UpdateCheckState{} | ||
| } | ||
|
|
||
| state.LastNotifiedVersion = latestVersion | ||
| if err := config.SaveUpdateCheckState(state); err != nil { | ||
| return fmt.Errorf("saving notification state: %w", err) | ||
| } | ||
|
|
||
| return nil | ||
| } |
There was a problem hiding this comment.
🧩 Analysis chain
Verify callers invoke MarkUpdateNotified after displaying notifications.
The function correctly persists notification state, but ensure all code paths that display update notifications (TUI banner, CLI output) call this function afterward to prevent duplicate notifications.
🏁 Script executed:
#!/bin/bash
# Search for update notification display logic and verify MarkUpdateNotified is called
rg -nC5 --type=go 'MarkUpdateNotified|update.*banner|update.*available' \
-g '!update/checker.go' -g '!update/checker_test.go'Length of output: 148
🏁 Script executed:
#!/bin/bash
# Search for calls to MarkUpdateNotified in all Go files except the checker itself
rg -nC5 'MarkUpdateNotified' --glob '*.go' --invert-glob 'update/checker.go'
# Search for “update available” or similar display logic in all Go files
rg -nC5 '(?i)update.*available' --glob '*.go'Length of output: 12666
Add MarkUpdateNotified calls after displaying update notifications
- In cmd/root.go, immediately after the
fmt.Printf("\n💡 devx %s is available…")on line 135, invokeupdate.MarkUpdateNotified(info.LatestVersion) - In cmd/version.go, immediately after the
fmt.Printf("🆙 A newer version is available:…")on line 76, invokeupdate.MarkUpdateNotified(updateInfo.LatestVersion)
🤖 Prompt for AI Agents
In update/checker.go lines 113-128, the MarkUpdateNotified function exists but
the review requests calling it where notifications are printed: add
update.MarkUpdateNotified(info.LatestVersion) in cmd/root.go immediately after
the fmt.Printf("\n💡 devx %s is available…") call around line 135, and add
update.MarkUpdateNotified(updateInfo.LatestVersion) in cmd/version.go
immediately after the fmt.Printf("🆙 A newer version is available:…") call
around line 76; ensure you import the update package where needed and handle the
returned error (log it or ignore with a comment) so notification state is saved
after the message is shown.
Ensure notification state is saved after showing update message in 'devx version --check-updates' to prevent repeated notifications. Addresses CodeRabbit review feedback.
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (1)
cmd/version.go (1)
58-85: Clean implementation with minor style suggestion.The update checking logic is well-structured with appropriate error handling and user feedback. The silent failure for
MarkUpdateNotifiedis correctly handled since notification state is non-critical.Minor style suggestion: Line 83's explicit
_ = errassignment is redundant. You can simply not callMarkUpdateNotifiedwithout assigning its return value, or remove the blank identifier assignment:// Mark as notified so we don't spam on every command if err := update.MarkUpdateNotified(updateInfo.LatestVersion); err != nil { // Silently ignore - notification state is not critical - _ = err }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
cmd/version.go(3 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.go
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.go: Format all Go code with gofmt before committing
Wrap errors consistently with context throughout the codebase
Files:
cmd/version.go
cmd/**/*.go
📄 CodeRabbit inference engine (CLAUDE.md)
cmd/**/*.go: Place all CLI commands using Cobra under cmd/
When modifying CLI commands, update help text and examples
Files:
cmd/version.go
🧬 Code graph analysis (1)
cmd/version.go (1)
update/checker.go (2)
CheckForUpdates(32-64)MarkUpdateNotified(115-128)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
- GitHub Check: Build
- GitHub Check: Build
- GitHub Check: Test Windows
🔇 Additional comments (4)
cmd/version.go (4)
7-7: LGTM!The import is necessary for the new update checking functionality and is correctly placed.
15-15: LGTM!The flag variable follows existing patterns and naming conventions.
29-29: LGTM!Flag registration follows Cobra conventions with clear help text.
As per coding guidelines
50-56: LGTM!The conditional update check is well-integrated with clear separation from version output.
Summary
This PR adds comprehensive release automation and self-update capabilities to devx:
Release Automation
brew installsupportSelf-Update Feature
devx updatecommand to download and install latest versiondevx version --check-updatesflag to check for updatesbrew upgradeConfiguration
New config options:
auto_check_updates- Enable/disable automatic update checking (default: true)update_check_interval- How often to check for updates (default: 24h)Testing
Notes
Installation Methods After Merge
🤖 Generated with Claude Code
Summary by CodeRabbit
New Features
Tests
Chores