83 lines
2.9 KiB
Go
83 lines
2.9 KiB
Go
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")
|
||
|
|
}
|
||
|
|
}
|