2 Commits
Author SHA1 Message Date
VeillaxandClaude Sonnet 5.5 122fade954 selfupdate: add Check to see the newest release without installing
CI / test (push) Successful in 1m41s
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-26 15:59:26 -06:00
VeillaxandClaude Sonnet 5.5 416b921d71 Export selfupdate.Restart
CI / test (push) Successful in 5m31s
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-26 13:58:02 -06:00
4 changed files with 64 additions and 18 deletions

No files matched your search

+2 -2
View File
@@ -7,7 +7,7 @@ import (
"syscall" "syscall"
) )
// restart replaces this process with the new binary, with the same arguments and environment. // Restart replaces this process with the new binary, with the same arguments and environment.
func restart(exe string) error { func Restart(exe string) error {
return syscall.Exec(exe, os.Args, os.Environ()) return syscall.Exec(exe, os.Args, os.Environ())
} }
+1 -1
View File
@@ -2,6 +2,6 @@ package selfupdate
import "errors" import "errors"
func restart(string) error { func Restart(string) error {
return errors.New("restarting in place is not supported on Windows") return errors.New("restarting in place is not supported on Windows")
} }
+44 -15
View File
@@ -72,7 +72,7 @@ func (c *Config) defaults() {
c.Verify = verifyRuns(c.App) c.Verify = verifyRuns(c.App)
} }
if c.Restart == nil { if c.Restart == nil {
c.Restart = restart c.Restart = Restart
} }
c.Server = strings.TrimRight(c.Server, "/") c.Server = strings.TrimRight(c.Server, "/")
} }
@@ -111,21 +111,9 @@ func CheckOnce(ctx context.Context, cfg Config) (string, error) {
if !ok { if !ok {
return "", fmt.Errorf("%q is not a release version", cfg.Current) return "", fmt.Errorf("%q is not a release version", cfg.Current)
} }
var rel struct { rel, err := latestRelease(ctx, cfg)
Tag string `json:"tag_name"`
Prerelease bool `json:"prerelease"`
Draft bool `json:"draft"`
Assets []struct {
Name string `json:"name"`
URL string `json:"browser_download_url"`
} `json:"assets"`
}
body, err := get(ctx, cfg.HTTP, cfg.Server+"/api/v1/repos/"+cfg.Repo+"/releases/latest", 1<<20)
if err != nil { if err != nil {
return "", fmt.Errorf("checking for a new release: %w", err) return "", err
}
if err := json.Unmarshal(body, &rel); err != nil {
return "", fmt.Errorf("reading the latest release: %w", err)
} }
if rel.Prerelease || rel.Draft { if rel.Prerelease || rel.Draft {
return "", nil return "", nil
@@ -208,6 +196,47 @@ func CheckOnce(ctx context.Context, cfg Config) (string, error) {
return rel.Tag, nil return rel.Tag, nil
} }
type release struct {
Tag string `json:"tag_name"`
Prerelease bool `json:"prerelease"`
Draft bool `json:"draft"`
Assets []struct {
Name string `json:"name"`
URL string `json:"browser_download_url"`
} `json:"assets"`
}
func latestRelease(ctx context.Context, cfg Config) (release, error) {
var rel release
body, err := get(ctx, cfg.HTTP, cfg.Server+"/api/v1/repos/"+cfg.Repo+"/releases/latest", 1<<20)
if err != nil {
return rel, fmt.Errorf("checking for a new release: %w", err)
}
if err := json.Unmarshal(body, &rel); err != nil {
return rel, fmt.Errorf("reading the latest release: %w", err)
}
return rel, nil
}
// Check reports the newest full release and whether it is newer than cfg.Current, without
// installing anything. A development build (a Current that isn't vX.Y.Z) is never "newer".
func Check(ctx context.Context, cfg Config) (latest string, newer bool, err error) {
cfg.defaults()
rel, err := latestRelease(ctx, cfg)
if err != nil {
return "", false, err
}
if rel.Prerelease || rel.Draft {
return "", false, nil
}
l, ok := parseVersion(rel.Tag)
if !ok {
return rel.Tag, false, nil
}
cur, ok := parseVersion(cfg.Current)
return rel.Tag, ok && l.newerThan(cur), nil
}
func get(ctx context.Context, c *http.Client, url string, max int64) ([]byte, error) { func get(ctx context.Context, c *http.Client, url string, max int64) ([]byte, error) {
req, err := http.NewRequestWithContext(ctx, "GET", url, nil) req, err := http.NewRequestWithContext(ctx, "GET", url, nil)
if err != nil { if err != nil {
+17
View File
@@ -135,3 +135,20 @@ func TestVersionOrdering(t *testing.T) {
} }
} }
} }
func TestCheckReportsWithoutInstalling(t *testing.T) {
srv := fakeGitea(t, "v0.2.0", false, false)
for _, c := range []struct {
current string
newer bool
}{{"v0.1.0", true}, {"v0.2.0", false}, {"v0.3.0", false}, {"dev", false}, {"v0.1.0-local", false}} {
cfg, exe, restarted := setup(t, srv, c.current)
tag, newer, err := Check(context.Background(), cfg)
if err != nil || tag != "v0.2.0" || newer != c.newer {
t.Errorf("%s: tag=%q newer=%v err=%v", c.current, tag, newer, err)
}
if b, _ := os.ReadFile(exe); string(b) != "OLD-BINARY" || *restarted != "" {
t.Errorf("%s: Check changed things", c.current)
}
}
}