summaryrefslogtreecommitdiff
path: root/internal/executor
diff options
context:
space:
mode:
Diffstat (limited to 'internal/executor')
-rw-r--r--internal/executor/container.go20
-rw-r--r--internal/executor/container_test.go67
2 files changed, 82 insertions, 5 deletions
diff --git a/internal/executor/container.go b/internal/executor/container.go
index 61ac29c..23e35b3 100644
--- a/internal/executor/container.go
+++ b/internal/executor/container.go
@@ -151,6 +151,14 @@ func (r *ContainerRunner) Run(ctx context.Context, t *task.Task, e *storage.Exec
}
}
}
+ // For non-story tasks (e.g. CI webhook tasks), also resolve local path from the task's
+ // project field. This lets the runner clone from the local mirror instead of an HTTPS
+ // remote that may require credentials not available on the host.
+ if storyLocalPath == "" && t.Project != "" && r.Store != nil {
+ if proj, err := r.Store.GetProject(t.Project); err == nil && proj != nil && proj.LocalPath != "" {
+ storyLocalPath = proj.LocalPath
+ }
+ }
// Fall back to task-level BranchName (e.g. set explicitly by executor or tests).
if storyBranch == "" {
storyBranch = t.BranchName
@@ -171,13 +179,15 @@ func (r *ContainerRunner) Run(ctx context.Context, t *task.Task, e *storage.Exec
if err := os.Remove(workspace); err != nil {
return fmt.Errorf("removing workspace before clone: %w", err)
}
- r.Logger.Info("cloning repository", "url", repoURL, "workspace", workspace)
- var cloneArgs []string
+ // Prefer the local path as the clone source to avoid HTTPS auth requirements.
+ // For story tasks the storyLocalPath is also available as a speed reference,
+ // but we clone from the local path directly since it is already authoritative.
+ cloneSrc := repoURL
if storyLocalPath != "" {
- cloneArgs = []string{"clone", "--reference", storyLocalPath, repoURL, workspace}
- } else {
- cloneArgs = []string{"clone", repoURL, workspace}
+ cloneSrc = storyLocalPath
}
+ r.Logger.Info("cloning repository", "src", cloneSrc, "workspace", workspace)
+ cloneArgs := []string{"clone", cloneSrc, workspace}
if out, err := r.command(ctx, "git", cloneArgs...).CombinedOutput(); err != nil {
return fmt.Errorf("git clone failed: %w\n%s", err, string(out))
}
diff --git a/internal/executor/container_test.go b/internal/executor/container_test.go
index f0b2a3a..54b4689 100644
--- a/internal/executor/container_test.go
+++ b/internal/executor/container_test.go
@@ -607,6 +607,73 @@ func TestContainerRunner_ClonesDefaultBranchWhenNoBranchName(t *testing.T) {
}
}
+// TestContainerRunner_ClonesFromLocalPathForCITask verifies that when a task has
+// an HTTPS repository_url but the project has a known local path, the runner
+// clones from the local path to avoid HTTPS auth failures.
+func TestContainerRunner_ClonesFromLocalPathForCITask(t *testing.T) {
+ dir := t.TempDir()
+ localRepo := filepath.Join(dir, "local-repo.git")
+ if out, err := exec.Command("git", "init", "--bare", localRepo).CombinedOutput(); err != nil {
+ t.Fatalf("git init bare: %v\n%s", err, out)
+ }
+
+ store := testStore(t)
+ proj := &task.Project{
+ ID: "nav",
+ Name: "nav",
+ RemoteURL: localRepo,
+ LocalPath: localRepo,
+ }
+ if err := store.CreateProject(proj); err != nil {
+ t.Fatalf("CreateProject: %v", err)
+ }
+
+ var cloneSrc string
+ logger := slog.New(slog.NewTextHandler(io.Discard, nil))
+ runner := &ContainerRunner{
+ Logger: logger,
+ Image: "busybox",
+ Store: store,
+ Command: func(ctx context.Context, name string, arg ...string) *exec.Cmd {
+ if name == "git" && len(arg) > 0 && arg[0] == "clone" {
+ // Record what source was cloned from.
+ for i, a := range arg {
+ if a != "clone" && a != "--reference" && i > 0 && arg[i-1] != "--reference" {
+ // last non-dest arg before workspace is the source
+ }
+ _ = a
+ }
+ // source is second-to-last arg (before workspace dir)
+ cloneSrc = arg[len(arg)-2]
+ 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: "ci-task-1",
+ RepositoryURL: "https://github.com/thepeterstone/nav.git",
+ Project: "nav",
+ Agent: task.AgentConfig{Type: "claude"},
+ }
+ e := &storage.Execution{ID: "exec-ci-1", TaskID: "ci-task-1"}
+ runner.Run(context.Background(), tk, e)
+ os.RemoveAll(e.SandboxDir)
+
+ if cloneSrc == "https://github.com/thepeterstone/nav.git" {
+ t.Error("runner cloned from GitHub HTTPS URL; expected local path to avoid auth failure")
+ }
+ if cloneSrc != localRepo {
+ t.Errorf("expected clone source %q, got %q", localRepo, cloneSrc)
+ }
+}
+
func TestEnsureStoryBranch_CreatesMissingBranch(t *testing.T) {
// Set up a bare repo and a local clone to test branch creation.
dir := t.TempDir()