Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
2.0.43
2.0.45
5 changes: 3 additions & 2 deletions buildinfo/version.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,9 @@ var buildInfo *BuildInfo

// App identity variables. Defaults are prod values; overridden in main.go for dev builds.
var (
AppName = "deepsource" // binary name / display name
ConfigDirName = ".deepsource" // ~/<this>/
AppName = "deepsource" // binary name / display name
ConfigDirName = ".deepsource" // ~/<this>/
BaseURL = "https://cli.deepsource.com" // CDN base for manifest and archives
)

// BuildInfo describes the compile time information.
Expand Down
35 changes: 33 additions & 2 deletions cmd/deepsource/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,17 @@ import (
"errors"
"fmt"
"log"
"net/http"
"os"
"strings"
"time"

v "github.com/deepsourcelabs/cli/buildinfo"
"github.com/deepsourcelabs/cli/command"
"github.com/deepsourcelabs/cli/internal/cli/style"
"github.com/deepsourcelabs/cli/internal/debug"
clierrors "github.com/deepsourcelabs/cli/internal/errors"
"github.com/deepsourcelabs/cli/internal/update"
"github.com/getsentry/sentry-go"
)

Expand Down Expand Up @@ -40,6 +43,7 @@ func mainRun() (exitCode int) {
if buildMode == "dev" {
v.AppName = "deepsource-dev"
v.ConfigDirName = ".deepsource-dev"
v.BaseURL = "https://cli.deepsource.one"
}

// Init sentry
Expand Down Expand Up @@ -67,6 +71,32 @@ func mainRun() (exitCode int) {
func run() int {
v.SetBuildInfo(version, Date, buildMode)

// Two-phase auto-update: apply pending update or check for new one
if update.ShouldAutoUpdate() {
state, err := update.ReadUpdateState()
if err != nil {
debug.Log("update: %v", err)
}

if state != nil {
// Phase 2: a previous run found a newer version — apply it now
client := &http.Client{Timeout: 30 * time.Second}
newVer, err := update.ApplyUpdate(client)
if err != nil {
debug.Log("update: %v", err)
} else if newVer != "" {
fmt.Fprintf(os.Stderr, "%s\n", style.Yellow("Updated DeepSource CLI to v%s", newVer))
}
} else {
// Phase 1: check manifest and write state file for next run
client := &http.Client{Timeout: 3 * time.Second}
if err := update.CheckForUpdate(client); err != nil {
debug.Log("update: %v", err)
}
}
}

exitCode := 0
if err := command.Execute(); err != nil {
var cliErr *clierrors.CLIError
if errors.As(err, &cliErr) {
Expand All @@ -78,7 +108,8 @@ func run() int {
sentry.CaptureException(err)
}
sentry.Flush(2 * time.Second)
return 1
exitCode = 1
}
return 0

return exitCode
}
1 change: 1 addition & 0 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ type CLIConfig struct {
User string `toml:"user"`
Token string `toml:"token"`
TokenExpiresIn time.Time `toml:"token_expires_in,omitempty"`
AutoUpdate *bool `toml:"auto_update,omitempty"`
SkipTLSVerify bool `toml:"skip_tls_verify,omitempty"`
TokenFromEnv bool `toml:"-"`
}
Expand Down
53 changes: 53 additions & 0 deletions internal/update/manifest.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package update

import (
"encoding/json"
"fmt"
"io"
"net/http"
"runtime"

"github.com/deepsourcelabs/cli/buildinfo"
)

// Manifest represents the CLI release manifest served by the CDN.
type Manifest struct {
Version string `json:"version"`
BuildTime string `json:"buildTime"`
Platforms map[string]PlatformInfo `json:"platforms"`
}

// PlatformInfo holds the archive filename and checksum for a platform.
type PlatformInfo struct {
Archive string `json:"archive"`
SHA256 string `json:"sha256"`
}

// FetchManifest downloads and parses the release manifest.
func FetchManifest(client *http.Client) (*Manifest, error) {
resp, err := client.Get(buildinfo.BaseURL + "/manifest.json")
if err != nil {
return nil, fmt.Errorf("fetching manifest: %w", err)
}
defer resp.Body.Close()

if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("manifest returned HTTP %d", resp.StatusCode)
}

body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("reading manifest body: %w", err)
}

var m Manifest
if err := json.Unmarshal(body, &m); err != nil {
return nil, fmt.Errorf("parsing manifest JSON: %w", err)
}
return &m, nil
}

// PlatformKey returns the manifest key for the current OS/arch.
func PlatformKey() string {
return runtime.GOOS + "_" + runtime.GOARCH
}
Loading
Loading