Skip to content

Commit 49fa000

Browse files
committed
feat: Check for new version of the CLI when running commands
Signed-off-by: Arthur Amstutz <arthur.amstutz@corp.ovh.com>
1 parent 8b3ccdd commit 49fa000

File tree

1 file changed

+50
-3
lines changed

1 file changed

+50
-3
lines changed

internal/cmd/root.go

Lines changed: 50 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,11 @@ package cmd
77
import (
88
"encoding/json"
99
"fmt"
10+
"log"
11+
"net/http"
1012
"os"
13+
"runtime"
14+
"sync/atomic"
1115

1216
"github.com/spf13/cobra"
1317
"github.com/spf13/pflag"
@@ -16,7 +20,8 @@ import (
1620
"github.com/ovh/ovhcloud-cli/internal/config"
1721
"github.com/ovh/ovhcloud-cli/internal/display"
1822
"github.com/ovh/ovhcloud-cli/internal/flags"
19-
"github.com/ovh/ovhcloud-cli/internal/http"
23+
httplib "github.com/ovh/ovhcloud-cli/internal/http"
24+
"github.com/ovh/ovhcloud-cli/internal/version"
2025
)
2126

2227
// rootCmd represents the base command when called without any subcommands
@@ -116,16 +121,58 @@ Examples:
116121
--format '(nbFieldA + nbFieldB) * 10' (to compute values from numeric fields)`)
117122
rootCmd.MarkFlagsMutuallyExclusive("json", "yaml", "interactive", "format")
118123

124+
var newVersionMessage atomic.Pointer[string]
119125
rootCmd.PersistentPreRun = func(cmd *cobra.Command, args []string) {
120-
if http.Client == nil {
126+
// Check if a new version is available in a separate goroutine
127+
// Don't do it when running in WASM binary
128+
if !(runtime.GOARCH == "wasm" && runtime.GOOS == "js") {
129+
go func() {
130+
// Skip version check if version is undefined (development mode)
131+
if version.Version == "undefined" {
132+
return
133+
}
134+
135+
const latestURL = "https://github.com/ovh/ovhcloud-cli/releases/latest"
136+
req, err := http.NewRequest("GET", latestURL, nil)
137+
if err != nil {
138+
return
139+
}
140+
req.Header.Set("Accept", "application/json")
141+
resp, err := http.DefaultClient.Do(req)
142+
if err != nil {
143+
return
144+
}
145+
defer resp.Body.Close()
146+
var data struct {
147+
TagName string `json:"tag_name"`
148+
}
149+
if err := json.NewDecoder(resp.Body).Decode(&data); err != nil {
150+
return
151+
}
152+
if data.TagName != "" && data.TagName != version.Version {
153+
message := fmt.Sprintf("A new version of ovhcloud-cli is available: %s (current: %s)", data.TagName, version.Version)
154+
newVersionMessage.Store(&message)
155+
}
156+
}()
157+
}
158+
159+
// Check if the API client is initialized
160+
if httplib.Client == nil {
121161
display.OutputError(&flags.OutputFormatConfig, "API client is not initialized, please run `ovhcloud login` to authenticate")
122162
os.Exit(1) // Force os.Exit even in WASM mode
123163
}
124164
}
165+
166+
// Set PostRun to display the new version message if available
167+
rootCmd.PersistentPostRun = func(cmd *cobra.Command, args []string) {
168+
if msg := newVersionMessage.Load(); msg != nil {
169+
log.Println(*msg)
170+
}
171+
}
125172
}
126173

127174
func init() {
128-
http.InitClient()
175+
httplib.InitClient()
129176

130177
// Load configuration files by order of increasing priority. All configuration
131178
// files are optional. Only load file from user home if home could be resolve

0 commit comments

Comments
 (0)