From 20a24e10cdc5ce854ec9bb5898aeea3dffd34151 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 21 Jan 2026 19:39:21 +0000 Subject: [PATCH 1/2] Initial plan From 504f7546f6a6809d47443e51e1f125259382a802 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 21 Jan 2026 19:49:03 +0000 Subject: [PATCH 2/2] Update documentation to clarify tracker-id is optional for campaign workers Co-authored-by: mnkiefer <8320933+mnkiefer@users.noreply.github.com> --- docs/src/content/docs/examples/campaigns.md | 2 +- .../examples/campaigns/security-scanner.md | 8 +-- pkg/campaign/workflow_fusion_test.go | 61 +++++++++++++++++++ 3 files changed, 66 insertions(+), 5 deletions(-) diff --git a/docs/src/content/docs/examples/campaigns.md b/docs/src/content/docs/examples/campaigns.md index 86f31534a4..55b72dd805 100644 --- a/docs/src/content/docs/examples/campaigns.md +++ b/docs/src/content/docs/examples/campaigns.md @@ -46,10 +46,10 @@ Campaign specs (`.campaign.md` files) define: ### 2. Worker Workflow Pattern Worker workflows should: -- Include tracker-id in created issues/PRs - Support workflow_dispatch for orchestration - Focus on specific, repeatable tasks - Be campaign-agnostic (reusable) +- Optionally include tracker-id in frontmatter to add tracking metadata to created issues/PRs ### 3. Folder Organization diff --git a/docs/src/content/docs/examples/campaigns/security-scanner.md b/docs/src/content/docs/examples/campaigns/security-scanner.md index b4be92a650..6290a8efb1 100644 --- a/docs/src/content/docs/examples/campaigns/security-scanner.md +++ b/docs/src/content/docs/examples/campaigns/security-scanner.md @@ -34,21 +34,21 @@ Scan the repository for security vulnerabilities and create issues for any findi - Recommended fix - References and resources - Labels: security, - - Body should include tracker-id marker for campaign discovery + - Body can optionally include tracker-id marker for campaign discovery 4. For medium and low-severity findings: - Group similar findings into a single issue - Include all details in the issue description 5. Add comments to existing security issues if new information is discovered -## Output Format +## Output Format (Optional) -When creating issues, always include the tracker-id in the issue body: +When creating issues, you can optionally include the tracker-id in the issue body to help campaign orchestrators discover and track work items: ``` tracker-id: security-scanner ``` -This allows campaign orchestrators to discover and track the work items you create. +Note: This is optional. Campaign orchestrators can also discover worker items using labels, so tracker-id is not required. ## Example Issue diff --git a/pkg/campaign/workflow_fusion_test.go b/pkg/campaign/workflow_fusion_test.go index f3245391a7..03aa3181c8 100644 --- a/pkg/campaign/workflow_fusion_test.go +++ b/pkg/campaign/workflow_fusion_test.go @@ -242,3 +242,64 @@ on: pull_request assert.FileExists(t, result.OutputPath) } } + +func TestFuseWorkflowWithoutTrackerID(t *testing.T) { + // This test verifies that campaign worker workflows do NOT require tracker-id + // tracker-id is optional and campaigns can discover workers via labels instead + + // Create temporary directory + tmpDir := t.TempDir() + workflowsDir := filepath.Join(tmpDir, ".github", "workflows") + require.NoError(t, os.MkdirAll(workflowsDir, 0755)) + + // Create workflow WITHOUT tracker-id - this should work fine + workflowContent := `--- +name: Security Scanner +description: Scan for vulnerabilities +on: issues +permissions: + contents: read +safe-outputs: + create-issue: +--- +# Security Scanner +Scan repositories for security issues. +` + + workflowID := "security-scanner" + originalPath := filepath.Join(workflowsDir, workflowID+".md") + require.NoError(t, os.WriteFile(originalPath, []byte(workflowContent), 0644)) + + // Fuse workflow for campaign - should succeed even without tracker-id + campaignID := "security-audit-2025" + result, err := FuseWorkflowForCampaign(tmpDir, workflowID, campaignID) + + // Should succeed - tracker-id is NOT required + require.NoError(t, err, "Campaign worker fusion should succeed without tracker-id") + require.NotNil(t, result) + + // Verify result + assert.Equal(t, workflowID, result.OriginalWorkflowID) + assert.Equal(t, workflowID+"-worker", result.CampaignWorkflowID) + + // Verify file was created + assert.FileExists(t, result.OutputPath) + + // Read fused workflow + fusedContent, err := os.ReadFile(result.OutputPath) + require.NoError(t, err) + + fusedStr := string(fusedContent) + + // Verify campaign metadata was added + assert.Contains(t, fusedStr, "campaign-worker: true", "Expected campaign-worker metadata") + assert.Contains(t, fusedStr, "campaign-id: "+campaignID, "Expected campaign-id metadata") + assert.Contains(t, fusedStr, "source-workflow: "+workflowID, "Expected source-workflow metadata") + + // Verify workflow_dispatch was added + assert.Contains(t, fusedStr, "workflow_dispatch", "Expected workflow_dispatch trigger") + + // Verify that tracker-id is NOT present (it wasn't in the original) + // This is fine - campaigns can discover workers via labels + assert.NotContains(t, fusedStr, "tracker-id:", "tracker-id should not be added if not present in original") +}