summaryrefslogtreecommitdiff
path: root/internal/executor/claude_test.go
diff options
context:
space:
mode:
authorPeter Stone <thepeterstone@gmail.com>2026-03-15 06:29:43 +0000
committerPeter Stone <thepeterstone@gmail.com>2026-03-15 09:19:43 +0000
commit5fccaa636cd400cd7809a1d2e4f254c3fff58218 (patch)
tree003126cbc82fbd0072e8fc9f61bb0c88d88b7d94 /internal/executor/claude_test.go
parentd0ed3694246ab8d352166f098be5d642e0dbe44d (diff)
feat: run build (Makefile, gradlew, or go build) before sandbox autocommit
Diffstat (limited to 'internal/executor/claude_test.go')
-rw-r--r--internal/executor/claude_test.go106
1 files changed, 106 insertions, 0 deletions
diff --git a/internal/executor/claude_test.go b/internal/executor/claude_test.go
index 02d1b2e..04ea6b7 100644
--- a/internal/executor/claude_test.go
+++ b/internal/executor/claude_test.go
@@ -512,6 +512,112 @@ func TestTeardownSandbox_AutocommitsChanges(t *testing.T) {
}
}
+func TestTeardownSandbox_BuildFailure_BlocksAutocommit(t *testing.T) {
+ bare := t.TempDir()
+ if out, err := exec.Command("git", "init", "--bare", bare).CombinedOutput(); err != nil {
+ t.Fatalf("git init bare: %v\n%s", err, out)
+ }
+
+ sandbox := t.TempDir()
+ initGitRepo(t, sandbox)
+ if out, err := exec.Command("git", "-c", "safe.directory=*", "-C", sandbox, "remote", "add", "origin", bare).CombinedOutput(); err != nil {
+ t.Fatalf("git remote add: %v\n%s", err, out)
+ }
+
+ // Capture startHEAD
+ headOut, err := exec.Command("git", "-c", "safe.directory=*", "-C", sandbox, "rev-parse", "HEAD").Output()
+ if err != nil {
+ t.Fatalf("rev-parse HEAD: %v", err)
+ }
+ startHEAD := strings.TrimSpace(string(headOut))
+
+ // Leave an uncommitted file.
+ if err := os.WriteFile(filepath.Join(sandbox, "dirty.txt"), []byte("dirty"), 0644); err != nil {
+ t.Fatal(err)
+ }
+
+ // Add a failing Makefile.
+ makefile := "build:\n\t@echo 'build failed'\n\texit 1\n"
+ if err := os.WriteFile(filepath.Join(sandbox, "Makefile"), []byte(makefile), 0644); err != nil {
+ t.Fatal(err)
+ }
+
+ logger := slog.New(slog.NewTextHandler(io.Discard, nil))
+ execRecord := &storage.Execution{}
+
+ err = teardownSandbox("", sandbox, startHEAD, logger, execRecord)
+ if err == nil {
+ t.Error("expected teardown to fail due to build failure, but it succeeded")
+ } else if !strings.Contains(err.Error(), "build failed before autocommit") {
+ t.Errorf("expected build failure error message, got: %v", err)
+ }
+
+ // Sandbox should NOT be removed if teardown failed.
+ if _, statErr := os.Stat(sandbox); os.IsNotExist(statErr) {
+ t.Error("sandbox should have been preserved after build failure")
+ }
+
+ // Verify no new commit in bare repo.
+ out, err := exec.Command("git", "-C", bare, "log", "HEAD").CombinedOutput()
+ if strings.Contains(string(out), "chore: autocommit uncommitted changes") {
+ t.Error("autocommit should not have been pushed after build failure")
+ }
+}
+
+func TestTeardownSandbox_BuildSuccess_ProceedsToAutocommit(t *testing.T) {
+ bare := t.TempDir()
+ if out, err := exec.Command("git", "init", "--bare", bare).CombinedOutput(); err != nil {
+ t.Fatalf("git init bare: %v\n%s", err, out)
+ }
+
+ sandbox := t.TempDir()
+ initGitRepo(t, sandbox)
+ if out, err := exec.Command("git", "-c", "safe.directory=*", "-C", sandbox, "remote", "add", "origin", bare).CombinedOutput(); err != nil {
+ t.Fatalf("git remote add: %v\n%s", err, out)
+ }
+
+ // Capture startHEAD
+ headOut, err := exec.Command("git", "-c", "safe.directory=*", "-C", sandbox, "rev-parse", "HEAD").Output()
+ if err != nil {
+ t.Fatalf("rev-parse HEAD: %v", err)
+ }
+ startHEAD := strings.TrimSpace(string(headOut))
+
+ // Leave an uncommitted file.
+ if err := os.WriteFile(filepath.Join(sandbox, "dirty.txt"), []byte("dirty"), 0644); err != nil {
+ t.Fatal(err)
+ }
+
+ // Add a successful Makefile.
+ makefile := "build:\n\t@echo 'build succeeded'\n"
+ if err := os.WriteFile(filepath.Join(sandbox, "Makefile"), []byte(makefile), 0644); err != nil {
+ t.Fatal(err)
+ }
+
+ logger := slog.New(slog.NewTextHandler(io.Discard, nil))
+ execRecord := &storage.Execution{}
+
+ err = teardownSandbox("", sandbox, startHEAD, logger, execRecord)
+ if err != nil {
+ t.Fatalf("expected teardown to succeed after build success, got error: %v", err)
+ }
+
+ // Sandbox should be removed after success.
+ if _, statErr := os.Stat(sandbox); !os.IsNotExist(statErr) {
+ t.Error("sandbox should have been removed after successful build and autocommit")
+ }
+
+ // Verify new commit in bare repo.
+ out, err := exec.Command("git", "-C", bare, "log", "-1", "--pretty=%B").Output()
+ if err != nil {
+ t.Fatalf("git log in bare repo: %v", err)
+ }
+ if !strings.Contains(string(out), "chore: autocommit uncommitted changes") {
+ t.Errorf("expected autocommit message in log, got: %q", string(out))
+ }
+}
+
+
func TestTeardownSandbox_CleanSandboxWithNoNewCommits_RemovesSandbox(t *testing.T) {
src := t.TempDir()
initGitRepo(t, src)