Skip to content
Open
Show file tree
Hide file tree
Changes from all 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.40
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"`
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