From 2b9796e07e2d4367e18a44eb6794f28f9aa96c79 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 12 Sep 2025 16:12:15 +0000 Subject: [PATCH 1/3] Initial plan From c5d1c4cbaa654c029d9921280057fa51a0f4b7bc Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 12 Sep 2025 16:20:02 +0000 Subject: [PATCH 2/3] Add staged environment variable support to create-pull-request job Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- ...t-safe-output-create-pull-request.lock.yml | 1 + pkg/workflow/compiler.go | 5 + pkg/workflow/staged_pull_request_test.go | 101 ++++++++++++++++++ 3 files changed, 107 insertions(+) create mode 100644 pkg/workflow/staged_pull_request_test.go diff --git a/.github/workflows/test-safe-output-create-pull-request.lock.yml b/.github/workflows/test-safe-output-create-pull-request.lock.yml index c1f83311956..6fe23421ac2 100644 --- a/.github/workflows/test-safe-output-create-pull-request.lock.yml +++ b/.github/workflows/test-safe-output-create-pull-request.lock.yml @@ -1295,6 +1295,7 @@ jobs: GITHUB_AW_PR_LABELS: "test-safe-output,automation" GITHUB_AW_PR_DRAFT: "true" GITHUB_AW_PR_IF_NO_CHANGES: "warn" + GITHUB_AW_SAFE_OUTPUTS_STAGED: "true" with: script: | /** @type {typeof import("fs")} */ diff --git a/pkg/workflow/compiler.go b/pkg/workflow/compiler.go index ce7092e5cd7..454bc174d13 100644 --- a/pkg/workflow/compiler.go +++ b/pkg/workflow/compiler.go @@ -2547,6 +2547,11 @@ func (c *Compiler) buildCreateOutputPullRequestJob(data *WorkflowData, mainJobNa } steps = append(steps, fmt.Sprintf(" GITHUB_AW_PR_IF_NO_CHANGES: %q\n", ifNoChanges)) + // Pass the staged flag if it's set to true + if data.SafeOutputs.Staged != nil && *data.SafeOutputs.Staged { + steps = append(steps, " GITHUB_AW_SAFE_OUTPUTS_STAGED: \"true\"\n") + } + steps = append(steps, " with:\n") steps = append(steps, " script: |\n") diff --git a/pkg/workflow/staged_pull_request_test.go b/pkg/workflow/staged_pull_request_test.go new file mode 100644 index 00000000000..4088203b9f5 --- /dev/null +++ b/pkg/workflow/staged_pull_request_test.go @@ -0,0 +1,101 @@ +package workflow + +import ( + "strings" + "testing" +) + +func TestCreatePullRequestJobWithStagedFlag(t *testing.T) { + // Create a compiler instance + c := NewCompiler(false, "", "test") + + // Test with staged: true + workflowData := &WorkflowData{ + Name: "test-workflow", + SafeOutputs: &SafeOutputsConfig{ + CreatePullRequests: &CreatePullRequestsConfig{}, + Staged: &[]bool{true}[0], // pointer to true + }, + } + + job, err := c.buildCreateOutputPullRequestJob(workflowData, "main_job") + if err != nil { + t.Fatalf("Unexpected error building create pull request job: %v", err) + } + + // Convert steps to a single string for testing + stepsContent := strings.Join(job.Steps, "") + + // Check that GITHUB_AW_SAFE_OUTPUTS_STAGED is included in the env section + if !strings.Contains(stepsContent, " GITHUB_AW_SAFE_OUTPUTS_STAGED: \"true\"\n") { + t.Error("Expected GITHUB_AW_SAFE_OUTPUTS_STAGED environment variable to be set to true in create-pull-request job") + } + + // Test with staged: false + workflowData.SafeOutputs.Staged = &[]bool{false}[0] // pointer to false + + job, err = c.buildCreateOutputPullRequestJob(workflowData, "main_job") + if err != nil { + t.Fatalf("Unexpected error building create pull request job: %v", err) + } + + stepsContent = strings.Join(job.Steps, "") + + // Check that GITHUB_AW_SAFE_OUTPUTS_STAGED is not included in the env section when false + // We need to be specific to avoid matching the JavaScript code that references the variable + if strings.Contains(stepsContent, " GITHUB_AW_SAFE_OUTPUTS_STAGED:") { + t.Error("Expected GITHUB_AW_SAFE_OUTPUTS_STAGED environment variable not to be set when staged is false") + } + + // Test with staged: nil (not specified) + workflowData.SafeOutputs.Staged = nil + + job, err = c.buildCreateOutputPullRequestJob(workflowData, "main_job") + if err != nil { + t.Fatalf("Unexpected error building create pull request job: %v", err) + } + + stepsContent = strings.Join(job.Steps, "") + + // Check that GITHUB_AW_SAFE_OUTPUTS_STAGED is not included in the env section when nil + // We need to be specific to avoid matching the JavaScript code that references the variable + if strings.Contains(stepsContent, " GITHUB_AW_SAFE_OUTPUTS_STAGED:") { + t.Error("Expected GITHUB_AW_SAFE_OUTPUTS_STAGED environment variable not to be set when staged is nil") + } +} + +func TestCreatePullRequestJobWithoutSafeOutputs(t *testing.T) { + // Create a compiler instance + c := NewCompiler(false, "", "test") + + // Test with no SafeOutputs config - this should fail + workflowData := &WorkflowData{ + Name: "test-workflow", + SafeOutputs: nil, + } + + _, err := c.buildCreateOutputPullRequestJob(workflowData, "main_job") + if err == nil { + t.Error("Expected error when SafeOutputs is nil") + } + + expectedError := "safe-outputs.create-pull-request configuration is required" + if !strings.Contains(err.Error(), expectedError) { + t.Errorf("Expected error message to contain '%s', got: %v", expectedError, err) + } + + // Test with SafeOutputs but no CreatePullRequests config - this should also fail + workflowData.SafeOutputs = &SafeOutputsConfig{ + CreateIssues: &CreateIssuesConfig{}, + Staged: &[]bool{true}[0], + } + + _, err = c.buildCreateOutputPullRequestJob(workflowData, "main_job") + if err == nil { + t.Error("Expected error when CreatePullRequests is nil") + } + + if !strings.Contains(err.Error(), expectedError) { + t.Errorf("Expected error message to contain '%s', got: %v", expectedError, err) + } +} From 144eaa06df4c0841fcec437b9e16f4ed63e81369 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 12 Sep 2025 16:34:40 +0000 Subject: [PATCH 3/3] Add staged environment variable support to create-issue and add-issue-label jobs Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- .../test-safe-output-add-issue-label.lock.yml | 1 + .../test-safe-output-create-issue.lock.yml | 1 + pkg/workflow/compiler.go | 5 + pkg/workflow/output_labels.go | 5 + pkg/workflow/staged_add_issue_labels_test.go | 118 ++++++++++++++++++ pkg/workflow/staged_create_issue_test.go | 101 +++++++++++++++ 6 files changed, 231 insertions(+) create mode 100644 pkg/workflow/staged_add_issue_labels_test.go create mode 100644 pkg/workflow/staged_create_issue_test.go diff --git a/.github/workflows/test-safe-output-add-issue-label.lock.yml b/.github/workflows/test-safe-output-add-issue-label.lock.yml index 9b5f44ff451..3afa20cd57b 100644 --- a/.github/workflows/test-safe-output-add-issue-label.lock.yml +++ b/.github/workflows/test-safe-output-add-issue-label.lock.yml @@ -1140,6 +1140,7 @@ jobs: GITHUB_AW_AGENT_OUTPUT: ${{ needs.test-safe-output-add-issue-label.outputs.output }} GITHUB_AW_LABELS_ALLOWED: "test-safe-output,automation,bug,enhancement,documentation,question" GITHUB_AW_LABELS_MAX_COUNT: 3 + GITHUB_AW_SAFE_OUTPUTS_STAGED: "true" with: script: | async function main() { diff --git a/.github/workflows/test-safe-output-create-issue.lock.yml b/.github/workflows/test-safe-output-create-issue.lock.yml index 64b5e310426..bc47e45b451 100644 --- a/.github/workflows/test-safe-output-create-issue.lock.yml +++ b/.github/workflows/test-safe-output-create-issue.lock.yml @@ -1201,6 +1201,7 @@ jobs: GITHUB_AW_AGENT_OUTPUT: ${{ needs.test-safe-output-create-issue.outputs.output }} GITHUB_AW_ISSUE_TITLE_PREFIX: "[Test] " GITHUB_AW_ISSUE_LABELS: "test-safe-output,automation" + GITHUB_AW_SAFE_OUTPUTS_STAGED: "true" with: script: | async function main() { diff --git a/pkg/workflow/compiler.go b/pkg/workflow/compiler.go index 454bc174d13..a0b49eeabd6 100644 --- a/pkg/workflow/compiler.go +++ b/pkg/workflow/compiler.go @@ -2162,6 +2162,11 @@ func (c *Compiler) buildCreateOutputIssueJob(data *WorkflowData, mainJobName str steps = append(steps, fmt.Sprintf(" GITHUB_AW_ISSUE_LABELS: %q\n", labelsStr)) } + // Pass the staged flag if it's set to true + if data.SafeOutputs.Staged != nil && *data.SafeOutputs.Staged { + steps = append(steps, " GITHUB_AW_SAFE_OUTPUTS_STAGED: \"true\"\n") + } + steps = append(steps, " with:\n") steps = append(steps, " script: |\n") diff --git a/pkg/workflow/output_labels.go b/pkg/workflow/output_labels.go index d31b0c42a44..819dad2fee5 100644 --- a/pkg/workflow/output_labels.go +++ b/pkg/workflow/output_labels.go @@ -37,6 +37,11 @@ func (c *Compiler) buildCreateOutputLabelJob(data *WorkflowData, mainJobName str // Pass the max limit steps = append(steps, fmt.Sprintf(" GITHUB_AW_LABELS_MAX_COUNT: %d\n", maxCount)) + // Pass the staged flag if it's set to true + if data.SafeOutputs.Staged != nil && *data.SafeOutputs.Staged { + steps = append(steps, " GITHUB_AW_SAFE_OUTPUTS_STAGED: \"true\"\n") + } + steps = append(steps, " with:\n") steps = append(steps, " script: |\n") diff --git a/pkg/workflow/staged_add_issue_labels_test.go b/pkg/workflow/staged_add_issue_labels_test.go new file mode 100644 index 00000000000..a7e7a76c1e3 --- /dev/null +++ b/pkg/workflow/staged_add_issue_labels_test.go @@ -0,0 +1,118 @@ +package workflow + +import ( + "strings" + "testing" +) + +func TestAddIssueLabelsJobWithStagedFlag(t *testing.T) { + // Create a compiler instance + c := NewCompiler(false, "", "test") + + // Test with staged: true + workflowData := &WorkflowData{ + Name: "test-workflow", + SafeOutputs: &SafeOutputsConfig{ + AddIssueLabels: &AddIssueLabelsConfig{}, + Staged: &[]bool{true}[0], // pointer to true + }, + } + + job, err := c.buildCreateOutputLabelJob(workflowData, "main_job") + if err != nil { + t.Fatalf("Unexpected error building add labels job: %v", err) + } + + // Convert steps to a single string for testing + stepsContent := strings.Join(job.Steps, "") + + // Check that GITHUB_AW_SAFE_OUTPUTS_STAGED is included in the env section + if !strings.Contains(stepsContent, " GITHUB_AW_SAFE_OUTPUTS_STAGED: \"true\"\n") { + t.Error("Expected GITHUB_AW_SAFE_OUTPUTS_STAGED environment variable to be set to true in add-issue-label job") + } + + // Test with staged: false + workflowData.SafeOutputs.Staged = &[]bool{false}[0] // pointer to false + + job, err = c.buildCreateOutputLabelJob(workflowData, "main_job") + if err != nil { + t.Fatalf("Unexpected error building add labels job: %v", err) + } + + stepsContent = strings.Join(job.Steps, "") + + // Check that GITHUB_AW_SAFE_OUTPUTS_STAGED is not included in the env section when false + // We need to be specific to avoid matching the JavaScript code that references the variable + if strings.Contains(stepsContent, " GITHUB_AW_SAFE_OUTPUTS_STAGED:") { + t.Error("Expected GITHUB_AW_SAFE_OUTPUTS_STAGED environment variable not to be set when staged is false") + } + + // Test with staged: nil (not specified) + workflowData.SafeOutputs.Staged = nil + + job, err = c.buildCreateOutputLabelJob(workflowData, "main_job") + if err != nil { + t.Fatalf("Unexpected error building add labels job: %v", err) + } + + stepsContent = strings.Join(job.Steps, "") + + // Check that GITHUB_AW_SAFE_OUTPUTS_STAGED is not included in the env section when nil + // We need to be specific to avoid matching the JavaScript code that references the variable + if strings.Contains(stepsContent, " GITHUB_AW_SAFE_OUTPUTS_STAGED:") { + t.Error("Expected GITHUB_AW_SAFE_OUTPUTS_STAGED environment variable not to be set when staged is nil") + } +} + +func TestAddIssueLabelsJobWithNilSafeOutputs(t *testing.T) { + // Create a compiler instance + c := NewCompiler(false, "", "test") + + // Test with no SafeOutputs config - this should fail + workflowData := &WorkflowData{ + Name: "test-workflow", + SafeOutputs: nil, + } + + _, err := c.buildCreateOutputLabelJob(workflowData, "main_job") + if err == nil { + t.Error("Expected error when SafeOutputs is nil") + } + + expectedError := "safe-outputs configuration is required" + if !strings.Contains(err.Error(), expectedError) { + t.Errorf("Expected error message to contain '%s', got: %v", expectedError, err) + } +} + +func TestAddIssueLabelsJobWithNilAddIssueLabelsConfig(t *testing.T) { + // Create a compiler instance + c := NewCompiler(false, "", "test") + + // Test with SafeOutputs but nil AddIssueLabels config - this should work as it's a valid case + workflowData := &WorkflowData{ + Name: "test-workflow", + SafeOutputs: &SafeOutputsConfig{ + AddIssueLabels: nil, // This is valid - means empty configuration + Staged: &[]bool{true}[0], + }, + } + + job, err := c.buildCreateOutputLabelJob(workflowData, "main_job") + if err != nil { + t.Fatalf("Expected no error when AddIssueLabels is nil (should use defaults): %v", err) + } + + // Convert steps to a single string for testing + stepsContent := strings.Join(job.Steps, "") + + // Check that GITHUB_AW_SAFE_OUTPUTS_STAGED is included in the env section + if !strings.Contains(stepsContent, " GITHUB_AW_SAFE_OUTPUTS_STAGED: \"true\"\n") { + t.Error("Expected GITHUB_AW_SAFE_OUTPUTS_STAGED environment variable to be set to true even with nil AddIssueLabels config") + } + + // Check that default max count is used + if !strings.Contains(stepsContent, " GITHUB_AW_LABELS_MAX_COUNT: 3\n") { + t.Error("Expected default max count of 3 when AddIssueLabels is nil") + } +} diff --git a/pkg/workflow/staged_create_issue_test.go b/pkg/workflow/staged_create_issue_test.go new file mode 100644 index 00000000000..4b914f3c50d --- /dev/null +++ b/pkg/workflow/staged_create_issue_test.go @@ -0,0 +1,101 @@ +package workflow + +import ( + "strings" + "testing" +) + +func TestCreateIssueJobWithStagedFlag(t *testing.T) { + // Create a compiler instance + c := NewCompiler(false, "", "test") + + // Test with staged: true + workflowData := &WorkflowData{ + Name: "test-workflow", + SafeOutputs: &SafeOutputsConfig{ + CreateIssues: &CreateIssuesConfig{}, + Staged: &[]bool{true}[0], // pointer to true + }, + } + + job, err := c.buildCreateOutputIssueJob(workflowData, "main_job", false) + if err != nil { + t.Fatalf("Unexpected error building create issue job: %v", err) + } + + // Convert steps to a single string for testing + stepsContent := strings.Join(job.Steps, "") + + // Check that GITHUB_AW_SAFE_OUTPUTS_STAGED is included in the env section + if !strings.Contains(stepsContent, " GITHUB_AW_SAFE_OUTPUTS_STAGED: \"true\"\n") { + t.Error("Expected GITHUB_AW_SAFE_OUTPUTS_STAGED environment variable to be set to true in create-issue job") + } + + // Test with staged: false + workflowData.SafeOutputs.Staged = &[]bool{false}[0] // pointer to false + + job, err = c.buildCreateOutputIssueJob(workflowData, "main_job", false) + if err != nil { + t.Fatalf("Unexpected error building create issue job: %v", err) + } + + stepsContent = strings.Join(job.Steps, "") + + // Check that GITHUB_AW_SAFE_OUTPUTS_STAGED is not included in the env section when false + // We need to be specific to avoid matching the JavaScript code that references the variable + if strings.Contains(stepsContent, " GITHUB_AW_SAFE_OUTPUTS_STAGED:") { + t.Error("Expected GITHUB_AW_SAFE_OUTPUTS_STAGED environment variable not to be set when staged is false") + } + + // Test with staged: nil (not specified) + workflowData.SafeOutputs.Staged = nil + + job, err = c.buildCreateOutputIssueJob(workflowData, "main_job", false) + if err != nil { + t.Fatalf("Unexpected error building create issue job: %v", err) + } + + stepsContent = strings.Join(job.Steps, "") + + // Check that GITHUB_AW_SAFE_OUTPUTS_STAGED is not included in the env section when nil + // We need to be specific to avoid matching the JavaScript code that references the variable + if strings.Contains(stepsContent, " GITHUB_AW_SAFE_OUTPUTS_STAGED:") { + t.Error("Expected GITHUB_AW_SAFE_OUTPUTS_STAGED environment variable not to be set when staged is nil") + } +} + +func TestCreateIssueJobWithoutSafeOutputs(t *testing.T) { + // Create a compiler instance + c := NewCompiler(false, "", "test") + + // Test with no SafeOutputs config - this should fail + workflowData := &WorkflowData{ + Name: "test-workflow", + SafeOutputs: nil, + } + + _, err := c.buildCreateOutputIssueJob(workflowData, "main_job", false) + if err == nil { + t.Error("Expected error when SafeOutputs is nil") + } + + expectedError := "safe-outputs.create-issue configuration is required" + if !strings.Contains(err.Error(), expectedError) { + t.Errorf("Expected error message to contain '%s', got: %v", expectedError, err) + } + + // Test with SafeOutputs but no CreateIssues config - this should also fail + workflowData.SafeOutputs = &SafeOutputsConfig{ + CreatePullRequests: &CreatePullRequestsConfig{}, + Staged: &[]bool{true}[0], + } + + _, err = c.buildCreateOutputIssueJob(workflowData, "main_job", false) + if err == nil { + t.Error("Expected error when CreateIssues is nil") + } + + if !strings.Contains(err.Error(), expectedError) { + t.Errorf("Expected error message to contain '%s', got: %v", expectedError, err) + } +}