Skip to content

Commit 5d02426

Browse files
committed
Recover from corrupt update state
1 parent 2fab10e commit 5d02426

2 files changed

Lines changed: 17 additions & 8 deletions

File tree

internal/commands/update.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package commands
33
import (
44
"context"
55
"encoding/json"
6+
"errors"
67
"fmt"
78
"io"
89
"net/http"
@@ -128,7 +129,11 @@ func shouldCheckForUpdate() bool {
128129
func checkForUpdate(ctx context.Context, client *http.Client, stateFilePath, currentVersion string) (*releaseInfo, error) {
129130
stateEntry, err := getUpdateStateEntry(stateFilePath)
130131
if err != nil && !os.IsNotExist(err) {
131-
return nil, err
132+
var pathErr *os.PathError
133+
if errors.As(err, &pathErr) {
134+
return nil, err
135+
}
136+
stateEntry = nil
132137
}
133138
if stateEntry != nil && time.Since(stateEntry.CheckedForUpdateAt).Hours() < 24 {
134139
return nil, nil

internal/commands/update_test.go

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ func TestCheckForUpdateFindsNewRelease(t *testing.T) {
3939
}
4040
}
4141

42-
func TestCheckForUpdateReturnsStateReadErrors(t *testing.T) {
42+
func TestCheckForUpdateRecoversCorruptState(t *testing.T) {
4343
stateFile := filepath.Join(t.TempDir(), "state.yml")
4444
if err := os.WriteFile(stateFile, []byte("checked_for_update_at: ["), 0o600); err != nil {
4545
t.Fatalf("failed to write state: %v", err)
@@ -48,15 +48,19 @@ func TestCheckForUpdateReturnsStateReadErrors(t *testing.T) {
4848
called := false
4949
client := &http.Client{Transport: roundTripFunc(func(req *http.Request) (*http.Response, error) {
5050
called = true
51-
return &http.Response{StatusCode: http.StatusOK, Body: io.NopCloser(strings.NewReader(`{}`))}, nil
51+
body := `{"tag_name":"v3.0.3","html_url":"https://github.com/basecamp/fizzy-cli/releases/tag/v3.0.3","published_at":"2026-03-02T21:19:42Z"}`
52+
return &http.Response{StatusCode: http.StatusOK, Body: io.NopCloser(strings.NewReader(body))}, nil
5253
})}
5354

54-
_, err := checkForUpdate(context.Background(), client, stateFile, "v3.0.2")
55-
if err == nil {
56-
t.Fatal("expected state read error")
55+
rel, err := checkForUpdate(context.Background(), client, stateFile, "v3.0.2")
56+
if err != nil {
57+
t.Fatalf("unexpected error: %v", err)
5758
}
58-
if called {
59-
t.Fatal("expected state read error to skip HTTP request")
59+
if !called {
60+
t.Fatal("expected corrupt state to fetch latest release")
61+
}
62+
if rel == nil || rel.Version != "v3.0.3" {
63+
t.Fatalf("release = %#v, want v3.0.3", rel)
6064
}
6165
}
6266

0 commit comments

Comments
 (0)