summaryrefslogtreecommitdiff
path: root/internal
diff options
context:
space:
mode:
Diffstat (limited to 'internal')
-rw-r--r--internal/executor/container.go4
-rw-r--r--internal/executor/container_test.go92
-rw-r--r--internal/executor/executor.go12
-rw-r--r--internal/executor/executor_test.go8
-rw-r--r--internal/task/task.go1
5 files changed, 113 insertions, 4 deletions
diff --git a/internal/executor/container.go b/internal/executor/container.go
index 5e1a026..8b244c6 100644
--- a/internal/executor/container.go
+++ b/internal/executor/container.go
@@ -109,6 +109,10 @@ func (r *ContainerRunner) Run(ctx context.Context, t *task.Task, e *storage.Exec
}
}
}
+ // Fall back to task-level BranchName (e.g. set explicitly by executor or tests).
+ if storyBranch == "" {
+ storyBranch = t.BranchName
+ }
// 2. Clone repo into workspace if not resuming.
// git clone requires the target directory to not exist; remove the MkdirTemp-created dir first.
diff --git a/internal/executor/container_test.go b/internal/executor/container_test.go
index b6946ef..15c147f 100644
--- a/internal/executor/container_test.go
+++ b/internal/executor/container_test.go
@@ -514,3 +514,95 @@ func TestContainerRunner_AuthError_SyncsAndRetries(t *testing.T) {
t.Error("expected sync-credentials to be called, but marker file not found")
}
}
+
+func TestContainerRunner_ClonesStoryBranch(t *testing.T) {
+ logger := slog.New(slog.NewTextHandler(io.Discard, nil))
+
+ var checkoutArgs []string
+ runner := &ContainerRunner{
+ Logger: logger,
+ Image: "busybox",
+ Command: func(ctx context.Context, name string, arg ...string) *exec.Cmd {
+ if name == "git" && len(arg) > 0 && arg[0] == "clone" {
+ dir := arg[len(arg)-1]
+ os.MkdirAll(dir, 0755)
+ return exec.Command("true")
+ }
+ // Capture checkout calls: both "git checkout <branch>" and "git -C <dir> checkout <branch>"
+ for i, a := range arg {
+ if a == "checkout" {
+ checkoutArgs = append([]string{}, arg[i:]...)
+ break
+ }
+ }
+ if name == "docker" {
+ return exec.Command("sh", "-c", "exit 1")
+ }
+ return exec.Command("true")
+ },
+ }
+
+ tk := &task.Task{
+ ID: "story-branch-test",
+ RepositoryURL: "https://example.com/repo.git",
+ BranchName: "story/my-feature",
+ Agent: task.AgentConfig{Type: "claude"},
+ }
+ e := &storage.Execution{ID: "exec-1", TaskID: "story-branch-test"}
+
+ runner.Run(context.Background(), tk, e)
+ os.RemoveAll(e.SandboxDir)
+
+ // Assert git checkout was called with the story branch name.
+ if len(checkoutArgs) == 0 {
+ t.Fatal("expected git checkout to be called for story branch, but it was not")
+ }
+ found := false
+ for _, a := range checkoutArgs {
+ if a == "story/my-feature" {
+ found = true
+ break
+ }
+ }
+ if !found {
+ t.Errorf("expected git checkout story/my-feature, got args: %v", checkoutArgs)
+ }
+}
+
+func TestContainerRunner_ClonesDefaultBranchWhenNoBranchName(t *testing.T) {
+ logger := slog.New(slog.NewTextHandler(io.Discard, nil))
+
+ var cloneArgs []string
+ runner := &ContainerRunner{
+ Logger: logger,
+ Image: "busybox",
+ Command: func(ctx context.Context, name string, arg ...string) *exec.Cmd {
+ if name == "git" && len(arg) > 0 && arg[0] == "clone" {
+ cloneArgs = append([]string{}, arg...)
+ dir := arg[len(arg)-1]
+ os.MkdirAll(dir, 0755)
+ return exec.Command("true")
+ }
+ if name == "docker" {
+ return exec.Command("sh", "-c", "exit 1")
+ }
+ return exec.Command("true")
+ },
+ }
+
+ tk := &task.Task{
+ ID: "no-branch-test",
+ RepositoryURL: "https://example.com/repo.git",
+ Agent: task.AgentConfig{Type: "claude"},
+ }
+ e := &storage.Execution{ID: "exec-2", TaskID: "no-branch-test"}
+
+ runner.Run(context.Background(), tk, e)
+ os.RemoveAll(e.SandboxDir)
+
+ for _, a := range cloneArgs {
+ if a == "--branch" {
+ t.Errorf("expected no --branch flag for task without BranchName, got args: %v", cloneArgs)
+ }
+ }
+}
diff --git a/internal/executor/executor.go b/internal/executor/executor.go
index c5a1fce..4183ab0 100644
--- a/internal/executor/executor.go
+++ b/internal/executor/executor.go
@@ -280,6 +280,12 @@ func (p *Pool) executeResume(ctx context.Context, t *task.Task, exec *storage.Ex
t.RepositoryURL = proj.RemoteURL
}
}
+ // Populate BranchName from Story if missing (ADR-007).
+ if t.BranchName == "" && t.StoryID != "" {
+ if story, err := p.store.GetStory(t.StoryID); err == nil && story.BranchName != "" {
+ t.BranchName = story.BranchName
+ }
+ }
err = runner.Run(ctx, t, exec)
exec.EndTime = time.Now().UTC()
@@ -868,6 +874,12 @@ func (p *Pool) execute(ctx context.Context, t *task.Task) {
t.RepositoryURL = proj.RemoteURL
}
}
+ // Populate BranchName from Story if missing (ADR-007).
+ if t.BranchName == "" && t.StoryID != "" {
+ if story, err := p.store.GetStory(t.StoryID); err == nil && story.BranchName != "" {
+ t.BranchName = story.BranchName
+ }
+ }
// Run the task.
err = runner.Run(ctx, t, exec)
diff --git a/internal/executor/executor_test.go b/internal/executor/executor_test.go
index 15ce363..44fa7b5 100644
--- a/internal/executor/executor_test.go
+++ b/internal/executor/executor_test.go
@@ -1056,10 +1056,10 @@ func (m *minimalMockStore) UpdateExecutionChangestats(execID string, stats *task
m.mu.Unlock()
return nil
}
-func (m *minimalMockStore) RecordAgentEvent(_ storage.AgentEvent) error { return nil }
-func (m *minimalMockStore) GetProject(_ string) (*task.Project, error) { return nil, nil }
-func (m *minimalMockStore) GetStory(_ string) (*task.Story, error) { return nil, nil }
-func (m *minimalMockStore) ListTasksByStory(_ string) ([]*task.Task, error) { return nil, nil }
+func (m *minimalMockStore) RecordAgentEvent(_ storage.AgentEvent) error { return nil }
+func (m *minimalMockStore) GetProject(_ string) (*task.Project, error) { return nil, nil }
+func (m *minimalMockStore) GetStory(_ string) (*task.Story, error) { return nil, nil }
+func (m *minimalMockStore) ListTasksByStory(_ string) ([]*task.Task, error) { return nil, nil }
func (m *minimalMockStore) UpdateStoryStatus(_ string, _ task.StoryState) error { return nil }
func (m *minimalMockStore) CreateTask(_ *task.Task) error { return nil }
diff --git a/internal/task/task.go b/internal/task/task.go
index ee79668..ba87360 100644
--- a/internal/task/task.go
+++ b/internal/task/task.go
@@ -82,6 +82,7 @@ type Task struct {
Tags []string `yaml:"tags" json:"tags"`
DependsOn []string `yaml:"depends_on" json:"depends_on"`
StoryID string `yaml:"-" json:"story_id,omitempty"`
+ BranchName string `yaml:"-" json:"branch_name,omitempty"`
State State `yaml:"-" json:"state"`
RejectionComment string `yaml:"-" json:"rejection_comment,omitempty"`
QuestionJSON string `yaml:"-" json:"question,omitempty"`