diff --git a/internal/plugin/store.go b/internal/plugin/store.go index acfba5fc..65e952c3 100644 --- a/internal/plugin/store.go +++ b/internal/plugin/store.go @@ -476,22 +476,33 @@ func notPlugin(target string) error { return errors.New(why) } -// Update installs the version of each npm plugin its spec says now -// (latest, for the most part: npm's newest, asked now, installAt), and -// fetches each git one again. +// Update installs npm's newest version (asked now, installAt) of each npm +// plugin, and fetches each git one again. A plugin pinned to a version +// that npm has a newer one of is updated too, and unpinned, as its row's +// Update does: the page counts it in Update all, and the CLI's update +// says it installs the newest of each (ARNO on Discord: a plugin updated +// with Update all still said an update was out, pinned where it was). A +// pinned one already at npm's newest stays as its spec says. func Update(ctx context.Context) error { var errs []error for _, e := range Load().Plugins { if !IsPath(e.Spec) { v := "" - if !IsGit(e.Spec) && !Pinned(e.Spec) { + if !IsGit(e.Spec) { v = newestOf(ctx, Name(e.Spec)) } var err error - if v != "" { + switch { + case v != "" && Pinned(e.Spec): + if update.Newer(v, Installed(e.Spec)) { + _, err = add(ctx, Name(e.Spec), v) + } else { + err = reinstall(ctx, e.Spec) + } + case v != "": err = installAt(ctx, Name(e.Spec), v) - } else { - // pinned, a git one, or npm not answering: as its spec says + default: + // a git one, or npm not answering: as its spec says err = reinstall(ctx, e.Spec) } if err != nil { diff --git a/internal/plugin/update_held_test.go b/internal/plugin/update_held_test.go index e181c816..dcc046f3 100644 --- a/internal/plugin/update_held_test.go +++ b/internal/plugin/update_held_test.go @@ -163,3 +163,67 @@ func TestAgeText(t *testing.T) { } } } + +// Update all (and magpie plugin update) brings a plugin pinned to an older +// version to npm's newest, unpinned, as its row's Update does: the page +// counts it among the updates, and before, Update all installed the pinned +// version again, said "Plugins updated", and the row still said the newer +// one was out (ARNO on Discord: 非官方插件…更新到最新版,magpie依然提示有更新). +// A pinned one already at npm's newest stays pinned. +func TestUpdateAllUpdatesAPinnedPlugin(t *testing.T) { + sandbox(t) + const pkg = "opencode-someones-auth" + heldRegistry(t, pkg, map[string]time.Time{"1.0.0": time.Now().Add(-72 * time.Hour), "2.0.0": time.Now().Add(-48 * time.Hour)}, "2.0.0") + ctx, cancel := context.WithTimeout(context.Background(), 3*time.Minute) + defer cancel() + + if _, err := Add(ctx, pkg+"@1.0.0"); err != nil { + t.Fatal(err) + } + if !Pinned(Load().Plugins[0].Spec) || Installed(pkg) != "1.0.0" { + t.Fatalf("added %+v at %s, want it pinned at 1.0.0", Load().Plugins, Installed(pkg)) + } + if err := Prefer(pkg, "someone"); err != nil { + t.Fatal(err) + } + if _, err := CheckUpdates(ctx); err != nil { + t.Fatal(err) + } + if w := PendingUpdates().Waiting; len(w) != 1 || w[0].Latest != "2.0.0" { + t.Fatalf("waiting before Update all = %+v, want 2.0.0", w) + } + + if err := Update(ctx); err != nil { + t.Fatal(err) + } + if v := Installed(pkg); v != "2.0.0" { + t.Fatalf("Update all left %s at %s, want 2.0.0", pkg, v) + } + l := Load() + if len(l.Plugins) != 1 || l.Plugins[0].Spec != pkg+"@latest" { + t.Fatalf("plugins after Update all = %+v, want %s@latest", l.Plugins, pkg) + } + if l.Prefer["someone"] != pkg+"@latest" { + t.Fatalf("the provider picked for it = %q, want it kept on %s@latest", l.Prefer["someone"], pkg) + } + if w := PendingUpdates().Waiting; len(w) != 0 { + t.Fatalf("still waiting after Update all: %+v", w) + } + if _, err := CheckUpdates(ctx); err != nil { + t.Fatal(err) + } + if w := PendingUpdates().Waiting; len(w) != 0 { + t.Fatalf("the next look found an update again: %+v", w) + } + + // pinned at the newest: Update all leaves its pin + if _, err := Add(ctx, pkg+"@2.0.0"); err != nil { + t.Fatal(err) + } + if err := Update(ctx); err != nil { + t.Fatal(err) + } + if l := Load().Plugins; len(l) != 1 || l[0].Spec != pkg+"@2.0.0" || Installed(pkg) != "2.0.0" { + t.Fatalf("plugins = %+v at %s, want %s@2.0.0 kept", l, Installed(pkg), pkg) + } +} diff --git a/site/public/docs/ja/plugins.html b/site/public/docs/ja/plugins.html index 33ff9334..67679ec8 100644 --- a/site/public/docs/ja/plugins.html +++ b/site/public/docs/ja/plugins.html @@ -213,7 +213,7 @@ magpie quota # acme · Pro · 5h 37%

magpie が設定フォルダ(~/.config/magpie または $XDG_CONFIG_HOME/magpie)に保存するもの:

diff --git a/site/public/docs/plugins.html b/site/public/docs/plugins.html index 5f671e1c..82bd014f 100644 --- a/site/public/docs/plugins.html +++ b/site/public/docs/plugins.html @@ -213,7 +213,7 @@ magpie quota # acme · Pro · 5h 37%

What magpie keeps, in its config folder (~/.config/magpie, or $XDG_CONFIG_HOME/magpie):

diff --git a/site/public/docs/zh/plugins.html b/site/public/docs/zh/plugins.html index 17b59b90..e6fdc99c 100644 --- a/site/public/docs/zh/plugins.html +++ b/site/public/docs/zh/plugins.html @@ -213,7 +213,7 @@ magpie quota # acme · Pro · 5h 37%
  • 社区的包(@magpie-community/*)在 magpie 启动后不久自动更新,之后每六小时一次。
  • 其他包有新版本时,插件上会出现一个小圆点,用户点一下或运行 magpie plugin update 更新。
  • -
  • 固定了版本的写法(name@1.2.3)会停在那个版本。
  • +
  • 固定了版本的写法(name@1.2.3)会停在那个版本,直到用户自己更新:更新到 …、全部更新和 magpie plugin update 会装上最新版并取消固定。

magpie 在它的配置目录(~/.config/magpie 或 $XDG_CONFIG_HOME/magpie)里保存这些: