@@ -23,6 +23,7 @@ import (
"github.com/charmbracelet/crush/internal/pubsub"
"github.com/charmbracelet/crush/internal/session"
"github.com/charmbracelet/crush/internal/update"
+ "github.com/charmbracelet/crush/internal/version"
"github.com/charmbracelet/x/ansi"
)
@@ -352,12 +353,12 @@ func (app *App) Shutdown() {
func (app *App) checkForUpdates(ctx context.Context) {
checkCtx, cancel := context.WithTimeout(ctx, 30*time.Second)
defer cancel()
- info, err := update.Check(checkCtx, update.Default)
+ info, err := update.Check(checkCtx, version.Version, update.Default)
if err != nil || !info.Available() {
return
}
app.events <- pubsub.UpdateAvailableMsg{
- CurrentVersion: info.CurrentVersion,
- LatestVersion: info.LatestVersion,
+ CurrentVersion: info.Current,
+ LatestVersion: info.Latest,
}
}
@@ -8,8 +8,6 @@ import (
"net/http"
"strings"
"time"
-
- "github.com/charmbracelet/crush/internal/version"
)
const (
@@ -22,22 +20,41 @@ var Default Client = &github{}
// Info contains information about an available update.
type Info struct {
- CurrentVersion string
- LatestVersion string
- ReleaseURL string
+ Current string
+ Latest string
+ URL string
}
// Available returns true if there's an update available.
-func (i Info) Available() bool { return i.CurrentVersion != i.LatestVersion }
+//
+// If both current and latest are stable versions, returns true if versions are
+// different.
+// If current is a pre-release and latest isn't, returns true.
+// If latest is a pre-release and current isn't, returns false.
+func (i Info) Available() bool {
+ cpr := strings.Contains(i.Current, "-")
+ lpr := strings.Contains(i.Latest, "-")
+ // current is pre release
+ if cpr {
+ // latest isn't a prerelease
+ if !lpr {
+ return true
+ }
+ }
+ if lpr && !cpr {
+ return false
+ }
+ return i.Current != i.Latest
+}
// Check checks if a new version is available.
-func Check(ctx context.Context, client Client) (Info, error) {
+func Check(ctx context.Context, current string, client Client) (Info, error) {
info := Info{
- CurrentVersion: version.Version,
- LatestVersion: version.Version,
+ Current: current,
+ Latest: current,
}
- if info.CurrentVersion == "devel" || info.CurrentVersion == "unknown" {
+ if info.Current == "devel" || info.Current == "unknown" {
return info, nil
}
@@ -46,8 +63,8 @@ func Check(ctx context.Context, client Client) (Info, error) {
return info, fmt.Errorf("failed to fetch latest release: %w", err)
}
- info.LatestVersion = strings.TrimPrefix(release.TagName, "v")
- info.ReleaseURL = release.HTMLURL
+ info.Latest = strings.TrimPrefix(release.TagName, "v")
+ info.URL = release.HTMLURL
return info, nil
}
@@ -4,41 +4,50 @@ import (
"context"
"testing"
- "github.com/charmbracelet/crush/internal/version"
"github.com/stretchr/testify/require"
)
func TestCheckForUpdate_DevelopmentVersion(t *testing.T) {
- originalVersion := version.Version
- version.Version = "unknown"
- t.Cleanup(func() {
- version.Version = originalVersion
- })
-
- info, err := Check(t.Context(), testClient{})
+ info, err := Check(t.Context(), "unknown", testClient{"v0.11.0"})
require.NoError(t, err)
require.NotNil(t, info)
require.False(t, info.Available())
}
func TestCheckForUpdate_Old(t *testing.T) {
- originalVersion := version.Version
- version.Version = "0.10.0"
- t.Cleanup(func() {
- version.Version = originalVersion
- })
- info, err := Check(t.Context(), testClient{})
+ info, err := Check(t.Context(), "v0.10.0", testClient{"v0.11.0"})
require.NoError(t, err)
require.NotNil(t, info)
require.True(t, info.Available())
}
-type testClient struct{}
+func TestCheckForUpdate_Beta(t *testing.T) {
+ t.Run("current is stable", func(t *testing.T) {
+ info, err := Check(t.Context(), "v0.10.0", testClient{"v0.11.0-beta.1"})
+ require.NoError(t, err)
+ require.NotNil(t, info)
+ require.False(t, info.Available())
+ })
+ t.Run("current is also beta", func(t *testing.T) {
+ info, err := Check(t.Context(), "v0.11.0-beta.1", testClient{"v0.11.0-beta.2"})
+ require.NoError(t, err)
+ require.NotNil(t, info)
+ require.True(t, info.Available())
+ })
+ t.Run("current is beta, latest isn't", func(t *testing.T) {
+ info, err := Check(t.Context(), "v0.11.0-beta.1", testClient{"v0.11.0"})
+ require.NoError(t, err)
+ require.NotNil(t, info)
+ require.True(t, info.Available())
+ })
+}
+
+type testClient struct{ tag string }
// Latest implements Client.
func (t testClient) Latest(ctx context.Context) (*Release, error) {
return &Release{
- TagName: "v0.11.0",
+ TagName: t.tag,
HTMLURL: "https://example.org",
}, nil
}