Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/src/content/docs/examples/campaigns.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
8 changes: 4 additions & 4 deletions docs/src/content/docs/examples/campaigns/security-scanner.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,21 +34,21 @@ Scan the repository for security vulnerabilities and create issues for any findi
- Recommended fix
- References and resources
- Labels: security, <severity-level>
- 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

Expand Down
61 changes: 61 additions & 0 deletions pkg/campaign/workflow_fusion_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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")
}
Loading