diff --git a/docs/docs/changelog.md b/docs/docs/changelog.md index 6daf027..ee3c374 100644 --- a/docs/docs/changelog.md +++ b/docs/docs/changelog.md @@ -5,6 +5,8 @@ title: Changelog ## [Unreleased](https://github.com/lets-cli/lets/releases/tag/v0.0.X) +* `[Fixed]` Prevent `lets self upgrade` from overwriting Homebrew-managed installs. Issue [#338](https://github.com/lets-cli/lets/issues/338) + ## [0.0.60](https://github.com/lets-cli/lets/releases/tag/v0.0.60) * `[Dependency]` update go to `1.26` diff --git a/internal/upgrade/upgrade.go b/internal/upgrade/upgrade.go index 0dce348..86878cd 100644 --- a/internal/upgrade/upgrade.go +++ b/internal/upgrade/upgrade.go @@ -41,6 +41,10 @@ func NewBinaryUpgrader(reg registry.RepoRegistry, currentVersion string) (*Binar } func (up *BinaryUpgrader) Upgrade(ctx context.Context) error { + if isHomebrewInstall(up.binaryPath) { + return fmt.Errorf("homebrew-managed lets install must be upgraded with %q", "brew upgrade lets-cli/tap/lets") + } + latestVersion, err := up.registry.GetLatestRelease(ctx) if err != nil { return fmt.Errorf("failed to get latest release version: %w", err) diff --git a/internal/upgrade/upgrade_test.go b/internal/upgrade/upgrade_test.go index 4316ff8..af2a55d 100644 --- a/internal/upgrade/upgrade_test.go +++ b/internal/upgrade/upgrade_test.go @@ -5,6 +5,7 @@ import ( "fmt" "os" "path" + "strings" "testing" "time" @@ -144,4 +145,44 @@ func TestSelfUpgrade(t *testing.T) { t.Errorf("binary must not been updated") } }) + + t.Run("should not self-upgrade homebrew-managed binary", func(t *testing.T) { + currentVersion := "v0.0.1" + latestVersion := "v0.0.2" + + tempDir := t.TempDir() + binaryPath := path.Join(tempDir, "Cellar", "lets", currentVersion, "bin", "lets") + if err := os.MkdirAll(path.Dir(binaryPath), 0o755); err != nil { + t.Fatalf("failed to create homebrew binary dir: %s", err) + } + + if err := os.WriteFile(binaryPath, []byte(currentVersion), 0o755); err != nil { + t.Fatalf("failed to write homebrew binary: %s", err) + } + + upgrader := &BinaryUpgrader{ + registry: &MockRegistry{latestVersion: latestVersion}, + currentVersion: currentVersion, + binaryPath: binaryPath, + downloadPath: path.Join(tempDir, "lets.download"), + backupPath: path.Join(tempDir, "lets.backup"), + } + + err := upgrader.Upgrade(context.Background()) + if err == nil { + t.Fatal("expected homebrew upgrade error") + } + + if !strings.Contains(err.Error(), "brew upgrade lets-cli/tap/lets") { + t.Fatalf("expected homebrew upgrade command in error, got %q", err.Error()) + } + + if !testVersion(binaryPath, currentVersion) { + t.Errorf("expected version %s", currentVersion) + } + + if _, err := os.Stat(upgrader.downloadPath); !os.IsNotExist(err) { + t.Fatalf("expected no downloaded binary, got err %v", err) + } + }) }