66 "path/filepath"
77 "strings"
88
9+ "github.com/githubnext/gh-aw/pkg/campaign"
910 "github.com/githubnext/gh-aw/pkg/console"
1011 "github.com/githubnext/gh-aw/pkg/logger"
1112 "github.com/githubnext/gh-aw/pkg/workflow"
@@ -27,6 +28,65 @@ func compileSingleFile(compiler *workflow.Compiler, file string, stats *Compilat
2728
2829 stats .Total ++
2930
31+ // Handle campaign spec files separately from regular workflows
32+ if strings .HasSuffix (file , ".campaign.md" ) {
33+ compileHelpersLog .Printf ("Processing campaign spec file: %s" , file )
34+ if verbose {
35+ fmt .Fprintln (os .Stderr , console .FormatProgressMessage (fmt .Sprintf ("Validating campaign spec: %s" , file )))
36+ }
37+
38+ // Validate the campaign spec file and referenced workflows
39+ spec , problems , vErr := campaign .ValidateSpecFromFile (file )
40+ if vErr != nil {
41+ fmt .Fprintln (os .Stderr , console .FormatErrorMessage (fmt .Sprintf ("failed to validate campaign spec %s: %v" , file , vErr )))
42+ stats .Errors ++
43+ stats .FailedWorkflows = append (stats .FailedWorkflows , filepath .Base (file ))
44+ return true
45+ }
46+
47+ // Also ensure that workflows referenced by the campaign spec exist
48+ workflowsDir := filepath .Dir (file )
49+ workflowProblems := campaign .ValidateWorkflowsExist (spec , workflowsDir )
50+ problems = append (problems , workflowProblems ... )
51+
52+ if len (problems ) > 0 {
53+ for _ , p := range problems {
54+ fmt .Fprintln (os .Stderr , console .FormatErrorMessage (p ))
55+ }
56+ stats .Errors ++
57+ stats .FailedWorkflows = append (stats .FailedWorkflows , filepath .Base (file ))
58+ return true
59+ }
60+
61+ // Generate and compile the campaign orchestrator workflow
62+ if verbose {
63+ fmt .Fprintln (os .Stderr , console .FormatSuccessMessage (fmt .Sprintf ("Validated campaign spec %s" , filepath .Base (file ))))
64+ }
65+
66+ _ , genErr := generateAndCompileCampaignOrchestrator (
67+ compiler ,
68+ spec ,
69+ file ,
70+ verbose ,
71+ false , // noEmit
72+ false , // zizmor
73+ false , // poutine
74+ false , // actionlint
75+ false , // strict
76+ false , // validateActionSHAs
77+ )
78+ if genErr != nil {
79+ fmt .Fprintln (os .Stderr , console .FormatErrorMessage (fmt .Sprintf ("failed to compile campaign orchestrator for %s: %v" , filepath .Base (file ), genErr )))
80+ stats .Errors ++
81+ stats .FailedWorkflows = append (stats .FailedWorkflows , filepath .Base (file ))
82+ } else {
83+ compileHelpersLog .Printf ("Successfully compiled campaign orchestrator for: %s" , file )
84+ }
85+
86+ return true
87+ }
88+
89+ // Regular workflow file - compile normally
3090 compileHelpersLog .Printf ("Compiling: %s" , file )
3191 if verbose {
3292 fmt .Fprintln (os .Stderr , console .FormatProgressMessage (fmt .Sprintf ("Compiling: %s" , file )))
@@ -256,7 +316,39 @@ func compileModifiedFilesWithDependencies(compiler *workflow.Compiler, depGraph
256316
257317// handleFileDeleted handles the deletion of a markdown file by removing its corresponding lock file
258318func handleFileDeleted (mdFile string , verbose bool ) {
259- // Generate the corresponding lock file path
319+ // For campaign spec files, remove both the generated orchestrator and its lock file
320+ if strings .HasSuffix (mdFile , ".campaign.md" ) {
321+ // Remove the generated .campaign.g.md file
322+ orchestratorFile := strings .TrimSuffix (mdFile , ".campaign.md" ) + ".campaign.g.md"
323+ if _ , err := os .Stat (orchestratorFile ); err == nil {
324+ if err := os .Remove (orchestratorFile ); err != nil {
325+ if verbose {
326+ fmt .Printf ("⚠️ Failed to remove orchestrator file %s: %v\n " , orchestratorFile , err )
327+ }
328+ } else {
329+ if verbose {
330+ fmt .Printf ("🗑️ Removed generated orchestrator: %s\n " , orchestratorFile )
331+ }
332+ }
333+ }
334+
335+ // Remove the orchestrator's lock file
336+ orchestratorLockFile := strings .TrimSuffix (mdFile , ".campaign.md" ) + ".campaign.g.lock.yml"
337+ if _ , err := os .Stat (orchestratorLockFile ); err == nil {
338+ if err := os .Remove (orchestratorLockFile ); err != nil {
339+ if verbose {
340+ fmt .Printf ("⚠️ Failed to remove orchestrator lock file %s: %v\n " , orchestratorLockFile , err )
341+ }
342+ } else {
343+ if verbose {
344+ fmt .Printf ("🗑️ Removed orchestrator lock file: %s\n " , orchestratorLockFile )
345+ }
346+ }
347+ }
348+ return
349+ }
350+
351+ // Regular workflow file - generate the corresponding lock file path
260352 lockFile := strings .TrimSuffix (mdFile , ".md" ) + ".lock.yml"
261353
262354 // Check if the lock file exists and remove it
0 commit comments