feat(client): sync --force to escape the locally-modified skip
Managed items with local modifications were kept (skip + warn) with no escape hatch other than deleting the deployed file by hand — after an upstream change the deployed content silently stayed old, which reads exactly like a stale cache. --force turns the two skip cases into update (repository version wins) and remove (upstream deleted + modified). Unmanaged items and never- managed path occupancies stay untouched even with --force; the default behavior is unchanged.
This commit is contained in:
1 parent
2017329015
commit
1ab97bff43
6 files changed
+164
-14
No files matched your search
@@ -0,0 +1,83 @@
|
||||
package e2e
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// TestSyncForceOverwritesLocallyModified pins the --force escape hatch:
|
||||
// locally modified managed items are overwritten with the repository
|
||||
// version, upstream-deleted modified items are removed, and unmanaged
|
||||
// local items are never touched.
|
||||
func TestSyncForceOverwritesLocallyModified(t *testing.T) {
|
||||
h := newHarness(t)
|
||||
env := newSyncEnv(t, h)
|
||||
buildWorkRepo(t, h, env.workRepo)
|
||||
env.writeConfig(t, env.workRepo, "")
|
||||
env.run(t)
|
||||
|
||||
// local drift on a managed item + upstream change to the same item
|
||||
deployed := filepath.Join(env.home, ".config/opencode/commands/deploy.md")
|
||||
os.WriteFile(deployed, []byte("---\nname: Deploy\n---\nlocal drift\n"), 0o644)
|
||||
upstream := filepath.Join(env.workRepo, "commands/deploy.md")
|
||||
os.WriteFile(upstream, []byte("---\nname: Deploy\ndescription: updated\n---\nnew body\n"), 0o644)
|
||||
|
||||
// an unmanaged local item that must survive --force untouched
|
||||
unmanaged := filepath.Join(env.home, ".config/opencode/commands/mine.md")
|
||||
os.MkdirAll(filepath.Dir(unmanaged), 0o755)
|
||||
os.WriteFile(unmanaged, []byte("---\nname: Mine\n---\nprecious\n"), 0o644)
|
||||
|
||||
h.git(t, env.workRepo, "add", "-A")
|
||||
h.git(t, env.workRepo, "commit", "-m", "update deploy command")
|
||||
|
||||
out, err := env.run(t)
|
||||
if err != nil {
|
||||
t.Fatalf("sync failed: %v\n%s", err, out)
|
||||
}
|
||||
if !contains(out, "skipped (local modifications kept): 1") {
|
||||
t.Errorf("default sync must keep the local modification:\n%s", out)
|
||||
}
|
||||
|
||||
out, err = env.run(t, "--force")
|
||||
if err != nil {
|
||||
t.Fatalf("sync --force failed: %v\n%s", err, out)
|
||||
}
|
||||
if !contains(out, "updated: 1") {
|
||||
t.Errorf("force must update the locally modified item:\n%s", out)
|
||||
}
|
||||
if got := readFile(t, deployed); !contains(got, "new body") {
|
||||
t.Error("force must overwrite the local drift with the repository version")
|
||||
}
|
||||
if got := readFile(t, unmanaged); !contains(got, "precious") {
|
||||
t.Error("force must never touch unmanaged local items")
|
||||
}
|
||||
|
||||
// upstream deletion of a locally modified item: force removes it
|
||||
os.WriteFile(deployed, []byte("---\nname: Deploy\n---\nmore drift\n"), 0o644)
|
||||
os.Remove(upstream)
|
||||
h.git(t, env.workRepo, "add", "-A")
|
||||
h.git(t, env.workRepo, "commit", "-m", "delete deploy command")
|
||||
|
||||
out, err = env.run(t)
|
||||
if err != nil {
|
||||
t.Fatalf("sync failed: %v\n%s", err, out)
|
||||
}
|
||||
if !contains(out, "skipped (local modifications kept): 1") {
|
||||
t.Errorf("default sync must keep the modified item after upstream deletion:\n%s", out)
|
||||
}
|
||||
if _, err := os.Stat(deployed); err != nil {
|
||||
t.Fatal("item must still exist before force")
|
||||
}
|
||||
|
||||
out, err = env.run(t, "--force")
|
||||
if err != nil {
|
||||
t.Fatalf("sync --force failed: %v\n%s", err, out)
|
||||
}
|
||||
if !contains(out, "removed: 1") {
|
||||
t.Errorf("force must remove the locally modified item after upstream deletion:\n%s", out)
|
||||
}
|
||||
if _, err := os.Stat(deployed); !os.IsNotExist(err) {
|
||||
t.Error("forced removal must delete the deployed file")
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user