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

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion .github/workflows/security-alert-burndown.campaign.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ allowed-repos:
- githubnext/gh-aw
discovery-repos:
- githubnext/gh-aw
tracker-label: campaign:security-alert-burndown
tracker-label: z_campaign_security-alert-burndown
memory-paths:
- memory/campaigns/security-alert-burndown/**
metrics-glob: memory/campaigns/security-alert-burndown/metrics/*.json
Expand Down
7 changes: 4 additions & 3 deletions pkg/campaign/validation.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,9 +69,10 @@ func ValidateSpec(spec *CampaignSpec) []string {
// Validate tracker-label format if provided
if strings.TrimSpace(spec.TrackerLabel) != "" {
trimmedLabel := strings.TrimSpace(spec.TrackerLabel)
// Tracker labels should follow the pattern "campaign:campaign-id"
if !strings.HasPrefix(trimmedLabel, "campaign:") {
problems = append(problems, fmt.Sprintf("tracker-label should start with 'campaign:' prefix - got '%s', recommended: 'campaign:%s'", trimmedLabel, spec.ID))
// Tracker labels should follow the pattern "z_campaign_<campaign-id>"
expectedLabel := fmt.Sprintf("z_campaign_%s", strings.ToLower(strings.ReplaceAll(spec.ID, "_", "-")))
if !strings.HasPrefix(trimmedLabel, "z_campaign_") {
problems = append(problems, fmt.Sprintf("tracker-label should start with 'z_campaign_' prefix - got '%s', recommended: '%s'", trimmedLabel, expectedLabel))
}
// Check for invalid characters in labels (GitHub label restrictions)
if strings.Contains(trimmedLabel, " ") {
Expand Down
76 changes: 76 additions & 0 deletions pkg/campaign/validation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -754,3 +754,79 @@ func TestValidateSpec_AllowedOrgsWildcard(t *testing.T) {
t.Errorf("Expected wildcard validation problem for orgs, got: %v", problems)
}
}

func TestValidateSpec_TrackerLabelFormat(t *testing.T) {
tests := []struct {
name string
campaignID string
trackerLabel string
expectError bool
errorContains string
}{
{
name: "valid tracker label with z_campaign_ prefix",
campaignID: "security-alert-burndown",
trackerLabel: "z_campaign_security-alert-burndown",
expectError: false,
},
{
name: "invalid tracker label with old campaign: prefix",
campaignID: "security-alert-burndown",
trackerLabel: "campaign:security-alert-burndown",
expectError: true,
errorContains: "tracker-label should start with 'z_campaign_' prefix",
},
{
name: "invalid tracker label with wrong format",
campaignID: "test-campaign",
trackerLabel: "wrong-label-format",
expectError: true,
errorContains: "tracker-label should start with 'z_campaign_' prefix",
},
{
name: "empty tracker label is valid (optional field)",
campaignID: "test-campaign",
trackerLabel: "",
expectError: false,
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
spec := &CampaignSpec{
ID: tt.campaignID,
Name: "Test Campaign",
ProjectURL: "https://github.com/orgs/org/projects/1",
DiscoveryRepos: []string{"test/repo"},
Workflows: []string{"workflow1"},
TrackerLabel: tt.trackerLabel,
}

problems := ValidateSpec(spec)

if tt.expectError {
if len(problems) == 0 {
t.Errorf("Expected validation error but got none")
return
}
found := false
for _, p := range problems {
if strings.Contains(p, tt.errorContains) {
found = true
break
}
}
if !found {
t.Errorf("Expected error containing %q, got: %v", tt.errorContains, problems)
}
} else {
// Filter out problems that are not related to tracker-label
for _, p := range problems {
if strings.Contains(p, "tracker-label") {
t.Errorf("Unexpected tracker-label validation error: %s", p)
}
}
}
})
}
}
Loading