diff --git a/.github/workflows/dev.lock.yml b/.github/workflows/dev.lock.yml index c5f54e89f6d..736492baf2f 100644 --- a/.github/workflows/dev.lock.yml +++ b/.github/workflows/dev.lock.yml @@ -954,6 +954,13 @@ jobs: name: aw_info.json path: /tmp/aw_info.json if-no-files-found: warn + - name: Upload config + if: always() + uses: actions/upload-artifact@v4 + with: + name: config + path: /tmp/.copilot/ + if-no-files-found: ignore - name: Execute GitHub Copilot CLI id: agentic_execution # Copilot CLI tool arguments (sorted): diff --git a/pkg/cli/workflows/test-copilot-add-issue-comment.lock.yml b/pkg/cli/workflows/test-copilot-add-issue-comment.lock.yml index 38d28435c93..b1b2dcb57a6 100644 --- a/pkg/cli/workflows/test-copilot-add-issue-comment.lock.yml +++ b/pkg/cli/workflows/test-copilot-add-issue-comment.lock.yml @@ -106,6 +106,13 @@ jobs: name: aw_info.json path: /tmp/aw_info.json if-no-files-found: warn + - name: Upload config + if: always() + uses: actions/upload-artifact@v4 + with: + name: config + path: /tmp/.copilot/ + if-no-files-found: ignore - name: Execute GitHub Copilot CLI id: agentic_execution timeout-minutes: 5 diff --git a/pkg/cli/workflows/test-copilot-add-issue-labels.lock.yml b/pkg/cli/workflows/test-copilot-add-issue-labels.lock.yml index fe63c358aac..0f8b00554cb 100644 --- a/pkg/cli/workflows/test-copilot-add-issue-labels.lock.yml +++ b/pkg/cli/workflows/test-copilot-add-issue-labels.lock.yml @@ -106,6 +106,13 @@ jobs: name: aw_info.json path: /tmp/aw_info.json if-no-files-found: warn + - name: Upload config + if: always() + uses: actions/upload-artifact@v4 + with: + name: config + path: /tmp/.copilot/ + if-no-files-found: ignore - name: Execute GitHub Copilot CLI id: agentic_execution timeout-minutes: 5 diff --git a/pkg/cli/workflows/test-copilot-cache-memory.lock.yml b/pkg/cli/workflows/test-copilot-cache-memory.lock.yml index 7ff00967097..324d94e61b2 100644 --- a/pkg/cli/workflows/test-copilot-cache-memory.lock.yml +++ b/pkg/cli/workflows/test-copilot-cache-memory.lock.yml @@ -191,6 +191,13 @@ jobs: name: aw_info.json path: /tmp/aw_info.json if-no-files-found: warn + - name: Upload config + if: always() + uses: actions/upload-artifact@v4 + with: + name: config + path: /tmp/.copilot/ + if-no-files-found: ignore - name: Execute GitHub Copilot CLI id: agentic_execution timeout-minutes: 5 diff --git a/pkg/cli/workflows/test-copilot-command.lock.yml b/pkg/cli/workflows/test-copilot-command.lock.yml index 9ade45bdc27..44ee0449678 100644 --- a/pkg/cli/workflows/test-copilot-command.lock.yml +++ b/pkg/cli/workflows/test-copilot-command.lock.yml @@ -108,6 +108,13 @@ jobs: name: aw_info.json path: /tmp/aw_info.json if-no-files-found: warn + - name: Upload config + if: always() + uses: actions/upload-artifact@v4 + with: + name: config + path: /tmp/.copilot/ + if-no-files-found: ignore - name: Execute GitHub Copilot CLI id: agentic_execution timeout-minutes: 5 diff --git a/pkg/cli/workflows/test-copilot-create-issue.lock.yml b/pkg/cli/workflows/test-copilot-create-issue.lock.yml index ffe91e3d465..36046b9df05 100644 --- a/pkg/cli/workflows/test-copilot-create-issue.lock.yml +++ b/pkg/cli/workflows/test-copilot-create-issue.lock.yml @@ -106,6 +106,13 @@ jobs: name: aw_info.json path: /tmp/aw_info.json if-no-files-found: warn + - name: Upload config + if: always() + uses: actions/upload-artifact@v4 + with: + name: config + path: /tmp/.copilot/ + if-no-files-found: ignore - name: Execute GitHub Copilot CLI id: agentic_execution timeout-minutes: 5 diff --git a/pkg/cli/workflows/test-copilot-create-pull-request-review-comment.lock.yml b/pkg/cli/workflows/test-copilot-create-pull-request-review-comment.lock.yml index 1c8353c6236..28a529e427e 100644 --- a/pkg/cli/workflows/test-copilot-create-pull-request-review-comment.lock.yml +++ b/pkg/cli/workflows/test-copilot-create-pull-request-review-comment.lock.yml @@ -106,6 +106,13 @@ jobs: name: aw_info.json path: /tmp/aw_info.json if-no-files-found: warn + - name: Upload config + if: always() + uses: actions/upload-artifact@v4 + with: + name: config + path: /tmp/.copilot/ + if-no-files-found: ignore - name: Execute GitHub Copilot CLI id: agentic_execution timeout-minutes: 5 diff --git a/pkg/cli/workflows/test-copilot-create-pull-request.lock.yml b/pkg/cli/workflows/test-copilot-create-pull-request.lock.yml index 1cae8d5834c..9e5a370ec60 100644 --- a/pkg/cli/workflows/test-copilot-create-pull-request.lock.yml +++ b/pkg/cli/workflows/test-copilot-create-pull-request.lock.yml @@ -113,6 +113,13 @@ jobs: name: aw_info.json path: /tmp/aw_info.json if-no-files-found: warn + - name: Upload config + if: always() + uses: actions/upload-artifact@v4 + with: + name: config + path: /tmp/.copilot/ + if-no-files-found: ignore - name: Execute GitHub Copilot CLI id: agentic_execution timeout-minutes: 5 diff --git a/pkg/cli/workflows/test-copilot-create-repository-security-advisory.lock.yml b/pkg/cli/workflows/test-copilot-create-repository-security-advisory.lock.yml index a6e75d6113d..61b31832fee 100644 --- a/pkg/cli/workflows/test-copilot-create-repository-security-advisory.lock.yml +++ b/pkg/cli/workflows/test-copilot-create-repository-security-advisory.lock.yml @@ -109,6 +109,13 @@ jobs: name: aw_info.json path: /tmp/aw_info.json if-no-files-found: warn + - name: Upload config + if: always() + uses: actions/upload-artifact@v4 + with: + name: config + path: /tmp/.copilot/ + if-no-files-found: ignore - name: Execute GitHub Copilot CLI id: agentic_execution timeout-minutes: 5 diff --git a/pkg/cli/workflows/test-copilot-markitdown-mcp.lock.yml b/pkg/cli/workflows/test-copilot-markitdown-mcp.lock.yml index 2811b348d4b..82b053dfaa9 100644 --- a/pkg/cli/workflows/test-copilot-markitdown-mcp.lock.yml +++ b/pkg/cli/workflows/test-copilot-markitdown-mcp.lock.yml @@ -120,6 +120,13 @@ jobs: name: aw_info.json path: /tmp/aw_info.json if-no-files-found: warn + - name: Upload config + if: always() + uses: actions/upload-artifact@v4 + with: + name: config + path: /tmp/.copilot/ + if-no-files-found: ignore - name: Execute GitHub Copilot CLI id: agentic_execution # Copilot CLI tool arguments (sorted): diff --git a/pkg/cli/workflows/test-copilot-max-patch-size.lock.yml b/pkg/cli/workflows/test-copilot-max-patch-size.lock.yml index 647291e8a37..4a9a5a999ce 100644 --- a/pkg/cli/workflows/test-copilot-max-patch-size.lock.yml +++ b/pkg/cli/workflows/test-copilot-max-patch-size.lock.yml @@ -740,6 +740,13 @@ jobs: name: aw_info.json path: /tmp/aw_info.json if-no-files-found: warn + - name: Upload config + if: always() + uses: actions/upload-artifact@v4 + with: + name: config + path: /tmp/.copilot/ + if-no-files-found: ignore - name: Execute GitHub Copilot CLI id: agentic_execution # Copilot CLI tool arguments (sorted): diff --git a/pkg/cli/workflows/test-copilot-mcp.lock.yml b/pkg/cli/workflows/test-copilot-mcp.lock.yml index feeca77cc5c..8fb1ae39d63 100644 --- a/pkg/cli/workflows/test-copilot-mcp.lock.yml +++ b/pkg/cli/workflows/test-copilot-mcp.lock.yml @@ -111,6 +111,13 @@ jobs: name: aw_info.json path: /tmp/aw_info.json if-no-files-found: warn + - name: Upload config + if: always() + uses: actions/upload-artifact@v4 + with: + name: config + path: /tmp/.copilot/ + if-no-files-found: ignore - name: Execute GitHub Copilot CLI id: agentic_execution timeout-minutes: 5 diff --git a/pkg/cli/workflows/test-copilot-missing-tool.lock.yml b/pkg/cli/workflows/test-copilot-missing-tool.lock.yml index 40437414f23..af9a20d6068 100644 --- a/pkg/cli/workflows/test-copilot-missing-tool.lock.yml +++ b/pkg/cli/workflows/test-copilot-missing-tool.lock.yml @@ -805,6 +805,13 @@ jobs: name: aw_info.json path: /tmp/aw_info.json if-no-files-found: warn + - name: Upload config + if: always() + uses: actions/upload-artifact@v4 + with: + name: config + path: /tmp/.copilot/ + if-no-files-found: ignore - name: Execute GitHub Copilot CLI id: agentic_execution # Copilot CLI tool arguments (sorted): diff --git a/pkg/cli/workflows/test-copilot-patch-size-exceeded.lock.yml b/pkg/cli/workflows/test-copilot-patch-size-exceeded.lock.yml index e256fb754bd..909a8ce459a 100644 --- a/pkg/cli/workflows/test-copilot-patch-size-exceeded.lock.yml +++ b/pkg/cli/workflows/test-copilot-patch-size-exceeded.lock.yml @@ -742,6 +742,13 @@ jobs: name: aw_info.json path: /tmp/aw_info.json if-no-files-found: warn + - name: Upload config + if: always() + uses: actions/upload-artifact@v4 + with: + name: config + path: /tmp/.copilot/ + if-no-files-found: ignore - name: Execute GitHub Copilot CLI id: agentic_execution # Copilot CLI tool arguments (sorted): diff --git a/pkg/cli/workflows/test-copilot-push-to-pull-request-branch.lock.yml b/pkg/cli/workflows/test-copilot-push-to-pull-request-branch.lock.yml index d2962235708..25bb429e6d0 100644 --- a/pkg/cli/workflows/test-copilot-push-to-pull-request-branch.lock.yml +++ b/pkg/cli/workflows/test-copilot-push-to-pull-request-branch.lock.yml @@ -113,6 +113,13 @@ jobs: name: aw_info.json path: /tmp/aw_info.json if-no-files-found: warn + - name: Upload config + if: always() + uses: actions/upload-artifact@v4 + with: + name: config + path: /tmp/.copilot/ + if-no-files-found: ignore - name: Execute GitHub Copilot CLI id: agentic_execution timeout-minutes: 5 diff --git a/pkg/cli/workflows/test-copilot-update-issue.lock.yml b/pkg/cli/workflows/test-copilot-update-issue.lock.yml index d3b923b03c1..ec2b3204061 100644 --- a/pkg/cli/workflows/test-copilot-update-issue.lock.yml +++ b/pkg/cli/workflows/test-copilot-update-issue.lock.yml @@ -109,6 +109,13 @@ jobs: name: aw_info.json path: /tmp/aw_info.json if-no-files-found: warn + - name: Upload config + if: always() + uses: actions/upload-artifact@v4 + with: + name: config + path: /tmp/.copilot/ + if-no-files-found: ignore - name: Execute GitHub Copilot CLI id: agentic_execution timeout-minutes: 5 diff --git a/pkg/workflow/copilot_engine.go b/pkg/workflow/copilot_engine.go index 3bca0844f89..fa8623f6267 100644 --- a/pkg/workflow/copilot_engine.go +++ b/pkg/workflow/copilot_engine.go @@ -141,6 +141,10 @@ copilot %s 2>&1 | tee %s`, strings.Join(copilotArgs, " "), logFile) } } + // Add upload config step before running copilot CLI + uploadConfigStep := e.generateUploadConfigStep() + steps = append(steps, uploadConfigStep) + // Generate the step for Copilot CLI execution stepName := "Execute GitHub Copilot CLI" var stepLines []string @@ -200,6 +204,21 @@ func (e *CopilotEngine) convertStepToYAML(stepMap map[string]any) (string, error return ConvertStepToYAML(stepMap) } +// generateUploadConfigStep generates a step to upload the XDG_CONFIG_HOME folder content +func (e *CopilotEngine) generateUploadConfigStep() GitHubActionStep { + var stepLines []string + + stepLines = append(stepLines, " - name: Upload config") + stepLines = append(stepLines, " if: always()") + stepLines = append(stepLines, " uses: actions/upload-artifact@v4") + stepLines = append(stepLines, " with:") + stepLines = append(stepLines, " name: config") + stepLines = append(stepLines, " path: /tmp/.copilot/") + stepLines = append(stepLines, " if-no-files-found: ignore") + + return GitHubActionStep(stepLines) +} + func (e *CopilotEngine) RenderMCPConfig(yaml *strings.Builder, tools map[string]any, mcpTools []string, workflowData *WorkflowData) { // Build the MCP configuration structure config := CopilotMCPConfig{ diff --git a/pkg/workflow/copilot_engine_test.go b/pkg/workflow/copilot_engine_test.go index 4274bcb48d8..4080499c251 100644 --- a/pkg/workflow/copilot_engine_test.go +++ b/pkg/workflow/copilot_engine_test.go @@ -61,12 +61,12 @@ func TestCopilotEngineExecutionSteps(t *testing.T) { } steps := engine.GetExecutionSteps(workflowData, "/tmp/test.log") - if len(steps) != 2 { - t.Fatalf("Expected 2 steps for Copilot CLI execution (execution + log capture), got %d", len(steps)) + if len(steps) != 3 { + t.Fatalf("Expected 3 steps (upload config + copilot execution + log capture), got %d", len(steps)) } - // Check the execution step - stepContent := strings.Join([]string(steps[0]), "\n") + // Check the execution step (second step) + stepContent := strings.Join([]string(steps[1]), "\n") if !strings.Contains(stepContent, "name: Execute GitHub Copilot CLI") { t.Errorf("Expected step name 'Execute GitHub Copilot CLI' in step content:\n%s", stepContent) @@ -98,12 +98,12 @@ func TestCopilotEngineExecutionStepsWithOutput(t *testing.T) { } steps := engine.GetExecutionSteps(workflowData, "/tmp/test.log") - if len(steps) != 2 { - t.Fatalf("Expected 2 steps for Copilot CLI execution with output (execution + log capture), got %d", len(steps)) + if len(steps) != 3 { + t.Fatalf("Expected 3 steps (upload config + copilot execution + log capture) with output, got %d", len(steps)) } - // Check the execution step - stepContent := strings.Join([]string(steps[0]), "\n") + // Check the execution step (second step) + stepContent := strings.Join([]string(steps[1]), "\n") // Test that GITHUB_AW_SAFE_OUTPUTS is present when SafeOutputs is not nil if !strings.Contains(stepContent, "GITHUB_AW_SAFE_OUTPUTS: ${{ env.GITHUB_AW_SAFE_OUTPUTS }}") { @@ -301,12 +301,30 @@ func TestCopilotEngineExecutionStepsWithToolArguments(t *testing.T) { } steps := engine.GetExecutionSteps(workflowData, "/tmp/test.log") - if len(steps) != 2 { - t.Fatalf("Expected 2 steps for Copilot CLI execution with tools (execution + log capture), got %d", len(steps)) + if len(steps) != 3 { + t.Fatalf("Expected 3 steps (upload config + copilot execution + log capture), got %d", len(steps)) } - // Check the execution step contains tool arguments - stepContent := strings.Join([]string(steps[0]), "\n") + // Check the upload config step (first step) + uploadStepContent := strings.Join([]string(steps[0]), "\n") + if !strings.Contains(uploadStepContent, "name: Upload config") { + t.Errorf("Expected first step to be upload config step:\n%s", uploadStepContent) + } + + if !strings.Contains(uploadStepContent, "uses: actions/upload-artifact@v4") { + t.Errorf("Expected upload step to use actions/upload-artifact@v4:\n%s", uploadStepContent) + } + + if !strings.Contains(uploadStepContent, "name: config") { + t.Errorf("Expected artifact name to be 'config':\n%s", uploadStepContent) + } + + if !strings.Contains(uploadStepContent, "path: /tmp/.copilot/") { + t.Errorf("Expected artifact path to be '/tmp/.copilot/':\n%s", uploadStepContent) + } + + // Check the execution step contains tool arguments (second step) + stepContent := strings.Join([]string(steps[1]), "\n") // Should contain the tool arguments in the command line if !strings.Contains(stepContent, "--allow-tool shell(echo)") { @@ -334,3 +352,42 @@ func TestCopilotEngineExecutionStepsWithToolArguments(t *testing.T) { t.Errorf("Expected step to contain comment for write:\n%s", stepContent) } } + +func TestCopilotEngineUploadConfigStep(t *testing.T) { + engine := NewCopilotEngine() + workflowData := &WorkflowData{ + Name: "test-workflow", + } + steps := engine.GetExecutionSteps(workflowData, "/tmp/test.log") + + if len(steps) != 3 { + t.Fatalf("Expected 3 steps (upload config + copilot execution + log capture), got %d", len(steps)) + } + + // Check the upload config step is present and correct + uploadStepContent := strings.Join([]string(steps[0]), "\n") + + if !strings.Contains(uploadStepContent, "name: Upload config") { + t.Errorf("Expected upload config step name in:\n%s", uploadStepContent) + } + + if !strings.Contains(uploadStepContent, "if: always()") { + t.Errorf("Expected upload config step to have 'if: always()' condition in:\n%s", uploadStepContent) + } + + if !strings.Contains(uploadStepContent, "uses: actions/upload-artifact@v4") { + t.Errorf("Expected upload config step to use 'actions/upload-artifact@v4' in:\n%s", uploadStepContent) + } + + if !strings.Contains(uploadStepContent, "name: config") { + t.Errorf("Expected artifact name 'config' in:\n%s", uploadStepContent) + } + + if !strings.Contains(uploadStepContent, "path: /tmp/.copilot/") { + t.Errorf("Expected artifact path '/tmp/.copilot/' in:\n%s", uploadStepContent) + } + + if !strings.Contains(uploadStepContent, "if-no-files-found: ignore") { + t.Errorf("Expected 'if-no-files-found: ignore' in:\n%s", uploadStepContent) + } +}