-
Notifications
You must be signed in to change notification settings - Fork 11
Adding in the ability to add a git worktree into the created workspace for a test #154
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
99ec1b5
f1f6c66
83df3ed
f75e5f6
4ec9554
d1da0c9
8729617
f7b0fab
42bc291
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -897,6 +897,57 @@ config: | |
| max_attempts: 3 # Retry failed graders up to 3 times (default: 1, no retries) | ||
| ``` | ||
|
|
||
| ### Git Resources | ||
|
|
||
| Task inputs can reference git repositories as resources, checked out at a specific commit. This is useful for testing against real codebases without manually preparing fixture directories. | ||
|
|
||
| ```yaml | ||
| # Task YAML | ||
| inputs: | ||
| prompt: "Fix the bug in server.go" | ||
| workdir: my-repo # agent starts inside this subdirectory | ||
| files: | ||
| # Existing resource types still work: | ||
| - path: helpers/utils.js # file from context_dir | ||
| - content: "package main\n..." # inline content | ||
|
|
||
| repos: | ||
| # Git resource — checkout a commit from a local repo | ||
| - type: worktree # required (currently only worktree is supported) | ||
| source: /path/to/local/repo # required for worktree strategy | ||
| commit: abc123def | ||
| dest: my-repo # optional: subdirectory in workspace | ||
| ``` | ||
|
|
||
| **`workdir`** (optional): A relative path within the workspace to use as the agent's working directory. When a git resource is checked out into a subdirectory via `dest`, set `workdir` to that subdirectory so the agent starts inside the repo. Must not escape the workspace root. | ||
|
|
||
|
Comment on lines
+906
to
+923
|
||
| **Strategy support:** | ||
|
|
||
| | Strategy | Use Case | Mechanism | | ||
| |---|---|---| | ||
| | `worktree` | Already inside the target repo; very cheap, no network | `git worktree add` | | ||
|
|
||
| **Fields:** | ||
|
|
||
| | Field | Required | Description | | ||
| |---|---|---| | ||
| | `type` | Yes | Currently only `worktree` | | ||
| | `source` | Yes | Local folder where the git repository resides | | ||
| | `commit` | No | Commit SHA, branch, or tag. Defaults to HEAD | | ||
| | `dest` | No | Subdirectory name in workspace. Omit to use workspace root | | ||
|
|
||
| **Examples:** | ||
|
|
||
| ```yaml | ||
| # Worktree strategy — cheap checkout from local repo | ||
| - type: worktree | ||
| source: /path/to/local/repo | ||
| commit: feature-branch | ||
| dest: feature | ||
| ``` | ||
|
|
||
| Worktrees are automatically cleaned up after each task via `git worktree remove`. | ||
richardpark-msft marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| When a grader fails, waza will retry the task execution up to `max_attempts` times. The evaluation outcome includes an `attempts` field showing how many executions were needed to pass. This is useful for handling transient failures in external services or non-deterministic grader behavior. | ||
|
|
||
| **Output:** JSON results include `attempts` per task showing the number of executions performed. | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -25,8 +25,14 @@ type CopilotEngine struct { | |
|
|
||
| startOnce sync.Once | ||
|
|
||
| workspacesMu sync.Mutex | ||
| workspaces []string // workspaces to clean up at Shutdown | ||
| // resourcesMu protects workspaces and worktrees | ||
| resourcesMu sync.Mutex | ||
| // workspaces are temp folders - each test run gets a unique one, and it's removed at Shutdown. | ||
| workspaces []string | ||
| // gitResources that will be cleaned up at Shutdown. | ||
| // NOTE: in some cases there is some bookkeeping information (like with git workspaces) so cleanup | ||
| // must be called before the workspace is deleted. | ||
| gitResources []GitResource | ||
|
|
||
| // sessions maps session IDs to copilotSessions | ||
| sessions map[string]CopilotSession | ||
|
|
@@ -137,7 +143,7 @@ func (e *CopilotEngine) Execute(ctx context.Context, req *ExecutionRequest) (*Ex | |
|
|
||
| start := time.Now() | ||
|
|
||
| workspaceDir, err := e.setupWorkspace(req.Resources) | ||
| workspaceDir, err := e.setupWorkspace(ctx, req.Resources, req.GitResources) | ||
|
|
||
| if err != nil { | ||
| return nil, err | ||
richardpark-msft marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
@@ -289,23 +295,32 @@ func (e *CopilotEngine) doShutdown(ctx context.Context) error { | |
| return fmt.Errorf("failed to stop client: %w", err) | ||
| } | ||
|
|
||
| // remove the workspace folders - should be safe now that all the copilot sessions are shut down | ||
| // and the tests are complete. | ||
| workspaces := func() []string { | ||
| e.workspacesMu.Lock() | ||
| defer e.workspacesMu.Unlock() | ||
| workspaces, gitResources := func() ([]string, []GitResource) { | ||
| e.resourcesMu.Lock() | ||
| defer e.resourcesMu.Unlock() | ||
| worktrees := e.gitResources | ||
| e.gitResources = nil | ||
|
|
||
| workspaces := e.workspaces | ||
| e.workspaces = nil | ||
| return workspaces | ||
|
|
||
| return workspaces, worktrees | ||
| }() | ||
|
|
||
| // Clean up worktrees before removing workspaces (worktrees may be inside workspace dirs) | ||
| for _, wt := range gitResources { | ||
| if err := wt.Cleanup(ctx); err != nil { | ||
| slog.Warn("failed to cleanup git resource", "error", err) | ||
| } | ||
| } | ||
|
Comment on lines
+310
to
+315
|
||
|
|
||
| // remove the workspace folders - should be safe now that all the copilot sessions are shut down | ||
| // and the tests are complete. | ||
| for _, ws := range workspaces { | ||
| if ws != "" { | ||
| if err := os.RemoveAll(ws); err != nil { | ||
| // errors here probably indicate some issue with our code continuing to lock files | ||
| // even after tests have completed... | ||
| slog.Warn("failed to cleanup stale workspace", "path", ws, "error", err) | ||
| } | ||
| if err := os.RemoveAll(ws); err != nil { | ||
| // errors here probably indicate some issue with our code continuing to lock files | ||
| // even after tests have completed... | ||
| slog.Warn("failed to cleanup stale workspace", "path", ws, "error", err) | ||
| } | ||
| } | ||
|
|
||
|
|
@@ -376,22 +391,32 @@ func (*CopilotEngine) getSkillDirs(cwd string, req *ExecutionRequest) []string { | |
| return skillDirs | ||
| } | ||
|
|
||
| func (e *CopilotEngine) setupWorkspace(resources []ResourceFile) (string, error) { | ||
| func (e *CopilotEngine) setupWorkspace(ctx context.Context, resources []ResourceFile, gitResources []models.GitResource) (string, error) { | ||
| workspaceDir, err := os.MkdirTemp("", "waza-*") | ||
|
|
||
| if err != nil { | ||
| return "", fmt.Errorf("failed to create temp workspace: %w", err) | ||
| } | ||
|
|
||
| e.workspacesMu.Lock() | ||
| e.resourcesMu.Lock() | ||
| e.workspaces = append(e.workspaces, workspaceDir) | ||
| e.workspacesMu.Unlock() | ||
| e.resourcesMu.Unlock() | ||
|
|
||
| // Write resource files to workspace | ||
| if err := setupWorkspaceResources(workspaceDir, resources); err != nil { | ||
| return "", fmt.Errorf("failed to setup resources at workspace %s: %w", workspaceDir, err) | ||
| } | ||
|
|
||
| wts, err := CloneGitResources(ctx, gitResources, workspaceDir) | ||
| if err != nil { | ||
| return "", err | ||
| } | ||
|
Comment on lines
405
to
+413
|
||
| if len(wts) > 0 { | ||
| e.resourcesMu.Lock() | ||
| e.gitResources = append(e.gitResources, wts...) | ||
| e.resourcesMu.Unlock() | ||
| } | ||
|
Comment on lines
+410
to
+418
|
||
|
|
||
| return workspaceDir, nil | ||
| } | ||
|
|
||
|
|
||
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,3 +1,4 @@ | ||
| package execution | ||
|
|
||
| //go:generate go tool mockgen -package execution -destination copilot_client_wrapper_mocks_test.go . CopilotSession,CopilotClient | ||
| //go:generate go tool mockgen -package execution -destination execution_mocks.go . GitResource | ||
richardpark-msft marked this conversation as resolved.
Show resolved
Hide resolved
|
||
Uh oh!
There was an error while loading. Please reload this page.