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
3 changes: 2 additions & 1 deletion .github/aw/schemas/agentic-workflow.json
Original file line number Diff line number Diff line change
Expand Up @@ -3890,7 +3890,8 @@
"description": "Relative time (e.g., '2h', '7d', '2w', '1m', '1y'); minimum 2h for hour values"
}
],
"description": "Time until the discussion expires and should be automatically closed. Supports integer (days) or relative time format like '2h' (2 hours), '7d' (7 days), '2w' (2 weeks), '1m' (1 month), '1y' (1 year). Minimum duration: 2 hours. When set, a maintenance workflow will be generated."
"default": 7,
"description": "Time until the discussion expires and should be automatically closed. Supports integer (days) or relative time format like '2h' (2 hours), '7d' (7 days), '2w' (2 weeks), '1m' (1 month), '1y' (1 year). Minimum duration: 2 hours. When set, a maintenance workflow will be generated. Defaults to 7 days if not specified."
}
},
"additionalProperties": false,
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/github-remote-mcp-auth-test.lock.yml

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

9 changes: 7 additions & 2 deletions pkg/cli/compile_campaign.go
Original file line number Diff line number Diff line change
Expand Up @@ -130,8 +130,13 @@ func validateCampaigns(workflowDir string, verbose bool, campaignFiles []string)
// Validate the spec itself
problems := campaign.ValidateSpec(&spec)

// Validate that referenced workflows exist
workflowProblems := campaign.ValidateWorkflowsExist(&spec, absWorkflowDir)
// Validate that referenced workflows exist in the same directory as the campaign spec
// Use the directory of the campaign spec file, not a global workflow directory
campaignDir := filepath.Dir(spec.ConfigPath)
if !filepath.IsAbs(campaignDir) {
campaignDir = filepath.Join(gitRoot, campaignDir)
}
workflowProblems := campaign.ValidateWorkflowsExist(&spec, campaignDir)
problems = append(problems, workflowProblems...)

if len(problems) > 0 {
Expand Down
88 changes: 88 additions & 0 deletions pkg/cli/compile_campaign_validation_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
package cli

import (
"os"
"path/filepath"
"testing"

"github.com/githubnext/gh-aw/pkg/campaign"
)

// TestValidateCampaignsUsesCorrectDirectory tests that validateCampaigns uses
// the campaign spec file's directory to validate referenced workflows, not
// a global workflow directory parameter.
func TestValidateCampaignsUsesCorrectDirectory(t *testing.T) {
tmpDir := t.TempDir()

// Create a campaign spec file
workflowsDir := filepath.Join(tmpDir, ".github", "workflows")
if err := os.MkdirAll(workflowsDir, 0755); err != nil {
t.Fatal(err)
}

// Create referenced workflow files
workflowFile := filepath.Join(workflowsDir, "example-workflow.md")
workflowContent := `---
engine: copilot
---

# Test workflow
Test workflow content
`
if err := os.WriteFile(workflowFile, []byte(workflowContent), 0644); err != nil {
t.Fatal(err)
}

// Create campaign spec file
campaignFile := filepath.Join(workflowsDir, "test-campaign.campaign.md")
campaignContent := `---
id: test-campaign
name: Test Campaign
description: A test campaign
version: v1
project-url: https://github.com/orgs/test/projects/1
workflows:
- example-workflow
state: active
---

# Campaign Test
Test campaign
`
if err := os.WriteFile(campaignFile, []byte(campaignContent), 0644); err != nil {
t.Fatal(err)
}

// Change to tmpDir so it becomes the git root for the test
origDir, err := os.Getwd()
if err != nil {
t.Fatal(err)
}
defer os.Chdir(origDir)

if err := os.Chdir(tmpDir); err != nil {
t.Fatal(err)
}

// Initialize a git repo
if err := os.WriteFile(".git", []byte("fake git"), 0644); err != nil {
t.Fatal(err)
}

// Load the campaign spec
specs, err := campaign.LoadSpecs(tmpDir)
if err != nil {
t.Fatalf("LoadSpecs failed: %v", err)
}

if len(specs) == 0 {
t.Fatal("Expected to load 1 campaign spec, got 0")
}

// Validate campaigns with an incorrect workflow directory
// This should still work because validateCampaigns should use each spec's directory
err = validateCampaigns(".github/workflows", false, []string{campaignFile})
if err != nil {
t.Fatalf("validateCampaigns failed: %v", err)
}
}
Loading