Skip to content

Commit a4680e9

Browse files
Update mechanism change (#281)
* Replace auto-update with notify + manual update command - Remove silent auto-update mechanism, replace with update check that notifies users when a new version is available - Add `deepsource update` subcommand for explicit manual updates - Remove AutoUpdate config option since updates are now user-initiated - Rename ShouldAutoUpdate to ShouldCheckForUpdate to reflect new behavior * Bump version to 2.0.47 * Use plain output for up-to-date message in update command - Replace style.Successf with fmt.Fprintf for the "already up to date" message - Keeps output simple and consistent with non-styled update flow * Bump version to 2.0.48 * Polish update and help UX - Skip update check when running update command - Colorize update notification - Show examples only with --help -v - Simplify update success message * Bump version to 2.0.49 * Bump version to 2.0.50 * Use actual binary name in update notification - Derive binary name from os.Args[0] instead of hardcoding 'deepsource' - Replace em dash with comma in the message * Bump version to 2.0.51
1 parent d444ee5 commit a4680e9

File tree

7 files changed

+97
-44
lines changed

7 files changed

+97
-44
lines changed

VERSION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
2.0.46
1+
2.0.51

cmd/deepsource/main.go

Lines changed: 11 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"log"
77
"net/http"
88
"os"
9+
"path/filepath"
910
"strings"
1011
"time"
1112

@@ -16,6 +17,7 @@ import (
1617
clierrors "github.com/deepsourcelabs/cli/internal/errors"
1718
"github.com/deepsourcelabs/cli/internal/update"
1819
"github.com/getsentry/sentry-go"
20+
"github.com/pterm/pterm"
1921
)
2022

2123
var (
@@ -71,28 +73,20 @@ func mainRun() (exitCode int) {
7173
func run() int {
7274
v.SetBuildInfo(version, Date, buildMode)
7375

74-
// Two-phase auto-update: apply pending update or check for new one
75-
if update.ShouldAutoUpdate() {
76+
// Check for available updates and notify (skip when running "update" itself)
77+
isUpdateCmd := len(os.Args) >= 2 && os.Args[1] == "update"
78+
if !isUpdateCmd && update.ShouldCheckForUpdate() {
79+
client := &http.Client{Timeout: 3 * time.Second}
80+
if err := update.CheckForUpdate(client); err != nil {
81+
debug.Log("update: %v", err)
82+
}
83+
7684
state, err := update.ReadUpdateState()
7785
if err != nil {
7886
debug.Log("update: %v", err)
7987
}
80-
8188
if state != nil {
82-
// Phase 2: a previous run found a newer version — apply it now
83-
client := &http.Client{Timeout: 30 * time.Second}
84-
newVer, err := update.ApplyUpdate(client)
85-
if err != nil {
86-
debug.Log("update: %v", err)
87-
} else if newVer != "" {
88-
fmt.Fprintf(os.Stderr, "%s\n", style.Yellow("Updated DeepSource CLI to v%s", newVer))
89-
}
90-
} else {
91-
// Phase 1: check manifest and write state file for next run
92-
client := &http.Client{Timeout: 3 * time.Second}
93-
if err := update.CheckForUpdate(client); err != nil {
94-
debug.Log("update: %v", err)
95-
}
89+
fmt.Fprintln(os.Stderr, pterm.Yellow(fmt.Sprintf("Update available: v%s, run '%s update' to install.", state.Version, filepath.Base(os.Args[0]))))
9690
}
9791
}
9892

command/root.go

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"github.com/deepsourcelabs/cli/buildinfo"
99
"github.com/deepsourcelabs/cli/command/auth"
1010
completionCmd "github.com/deepsourcelabs/cli/command/completion"
11+
updateCmd "github.com/deepsourcelabs/cli/command/update"
1112
"github.com/deepsourcelabs/cli/command/issues"
1213
"github.com/deepsourcelabs/cli/command/metrics"
1314
"github.com/deepsourcelabs/cli/command/report"
@@ -89,7 +90,12 @@ func NewCmdRoot() *cobra.Command {
8990
completionC.GroupID = "setup"
9091
cmd.AddCommand(completionC)
9192

93+
updateC := updateCmd.NewCmdUpdate()
94+
updateC.GroupID = "setup"
95+
cmd.AddCommand(updateC)
96+
9297
cmd.PersistentFlags().Bool("skip-tls-verify", false, "Skip TLS certificate verification (for self-signed certs)")
98+
cmd.Flags().BoolP("verbose", "v", false, "Show detailed output including examples")
9399

94100
cmd.InitDefaultHelpFlag()
95101
cmd.InitDefaultVersionFlag()
@@ -167,13 +173,19 @@ func rootHelpFunc(cmd *cobra.Command, _ []string) {
167173
}
168174
}
169175

170-
// Examples
171-
examples := buildExampleText()
172-
if examples != "" {
173-
fmt.Fprintf(out, "%s\n", style.BoldCyan("Examples:"))
174-
for _, line := range strings.Split(examples, "\n") {
175-
fmt.Fprintf(out, " %s\n", line)
176+
// Examples (shown only with --verbose / -v)
177+
verbose, _ := cmd.Flags().GetBool("verbose")
178+
if verbose {
179+
examples := buildExampleText()
180+
if examples != "" {
181+
fmt.Fprintf(out, "%s\n", style.BoldCyan("Examples:"))
182+
for _, line := range strings.Split(examples, "\n") {
183+
fmt.Fprintf(out, " %s\n", line)
184+
}
185+
fmt.Fprintln(out)
176186
}
187+
} else {
188+
fmt.Fprintln(out, pterm.Gray("Use --help -v to see usage examples."))
177189
fmt.Fprintln(out)
178190
}
179191

command/update/update.go

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
package update
2+
3+
import (
4+
"fmt"
5+
"net/http"
6+
"time"
7+
8+
"github.com/deepsourcelabs/cli/buildinfo"
9+
"github.com/deepsourcelabs/cli/internal/update"
10+
"github.com/spf13/cobra"
11+
)
12+
13+
func NewCmdUpdate() *cobra.Command {
14+
return &cobra.Command{
15+
Use: "update",
16+
Short: "Update DeepSource CLI to the latest version",
17+
RunE: func(cmd *cobra.Command, _ []string) error {
18+
return runUpdate(cmd)
19+
},
20+
}
21+
}
22+
23+
func runUpdate(cmd *cobra.Command) error {
24+
w := cmd.ErrOrStderr()
25+
26+
// Check for the latest version
27+
checkClient := &http.Client{Timeout: 10 * time.Second}
28+
if err := update.CheckForUpdate(checkClient); err != nil {
29+
return fmt.Errorf("checking for updates: %w", err)
30+
}
31+
32+
state, err := update.ReadUpdateState()
33+
if err != nil {
34+
return fmt.Errorf("reading update state: %w", err)
35+
}
36+
37+
if state == nil {
38+
bi := buildinfo.GetBuildInfo()
39+
fmt.Fprintf(w, "Already up to date (v%s)\n", bi.Version)
40+
return nil
41+
}
42+
43+
fmt.Fprintf(w, "Updating to v%s...\n", state.Version)
44+
45+
applyClient := &http.Client{Timeout: 30 * time.Second}
46+
newVer, err := update.ApplyUpdate(applyClient)
47+
if err != nil {
48+
return fmt.Errorf("applying update: %w", err)
49+
}
50+
51+
if newVer != "" {
52+
fmt.Fprintf(w, "Updated to v%s\n", newVer)
53+
}
54+
55+
return nil
56+
}

config/config.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,7 @@ type CLIConfig struct {
1616
User string `toml:"user"`
1717
Token string `toml:"token"`
1818
TokenExpiresIn time.Time `toml:"token_expires_in,omitempty"`
19-
AutoUpdate *bool `toml:"auto_update,omitempty"`
20-
SkipTLSVerify bool `toml:"skip_tls_verify,omitempty"`
19+
SkipTLSVerify bool `toml:"skip_tls_verify,omitempty"`
2120
TokenFromEnv bool `toml:"-"`
2221
}
2322

internal/update/updater.go

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ import (
1919
"time"
2020

2121
"github.com/deepsourcelabs/cli/buildinfo"
22-
"github.com/deepsourcelabs/cli/config"
2322
"github.com/deepsourcelabs/cli/internal/debug"
2423
)
2524

@@ -179,8 +178,8 @@ func ApplyUpdate(client *http.Client) (string, error) {
179178
return state.Version, nil
180179
}
181180

182-
// ShouldAutoUpdate reports whether the auto-updater should run.
183-
func ShouldAutoUpdate() bool {
181+
// ShouldCheckForUpdate reports whether the update check should run.
182+
func ShouldCheckForUpdate() bool {
184183
bi := buildinfo.GetBuildInfo()
185184
if bi == nil {
186185
return false
@@ -204,13 +203,6 @@ func ShouldAutoUpdate() bool {
204203
}
205204
}
206205

207-
// Check config
208-
cfg, err := config.GetConfig()
209-
if err == nil && cfg.AutoUpdate != nil && !*cfg.AutoUpdate {
210-
debug.Log("update: skipping (disabled in config)")
211-
return false
212-
}
213-
214206
return true
215207
}
216208

internal/update/updater_test.go

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ func TestReplaceBinary(t *testing.T) {
100100
}
101101
}
102102

103-
func TestShouldAutoUpdate_DevBuild(t *testing.T) {
103+
func TestShouldCheckForUpdate_DevBuild(t *testing.T) {
104104
buildinfo.SetBuildInfo("2.0.3", "", "dev")
105105

106106
// Clear CI vars so they don't interfere
@@ -109,27 +109,27 @@ func TestShouldAutoUpdate_DevBuild(t *testing.T) {
109109
t.Setenv(v, "")
110110
}
111111

112-
if !ShouldAutoUpdate() {
112+
if !ShouldCheckForUpdate() {
113113
t.Error("expected true for dev build with real version")
114114
}
115115
}
116116

117-
func TestShouldAutoUpdate_DevelopmentVersion(t *testing.T) {
117+
func TestShouldCheckForUpdate_DevelopmentVersion(t *testing.T) {
118118
buildinfo.SetBuildInfo("development", "", "")
119-
if ShouldAutoUpdate() {
119+
if ShouldCheckForUpdate() {
120120
t.Error("expected false for development version")
121121
}
122122
}
123123

124-
func TestShouldAutoUpdate_CI(t *testing.T) {
124+
func TestShouldCheckForUpdate_CI(t *testing.T) {
125125
buildinfo.SetBuildInfo("2.0.3", "", "prod")
126126
t.Setenv("CI", "true")
127-
if ShouldAutoUpdate() {
127+
if ShouldCheckForUpdate() {
128128
t.Error("expected false in CI")
129129
}
130130
}
131131

132-
func TestShouldAutoUpdate_Prod(t *testing.T) {
132+
func TestShouldCheckForUpdate_Prod(t *testing.T) {
133133
buildinfo.SetBuildInfo("2.0.3", "", "prod")
134134

135135
// Clear CI vars
@@ -138,7 +138,7 @@ func TestShouldAutoUpdate_Prod(t *testing.T) {
138138
t.Setenv(v, "")
139139
}
140140

141-
if !ShouldAutoUpdate() {
141+
if !ShouldCheckForUpdate() {
142142
t.Error("expected true for prod build outside CI")
143143
}
144144
}

0 commit comments

Comments
 (0)