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
18 changes: 12 additions & 6 deletions cmd/gh-aw/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -195,13 +195,19 @@ var disableCmd = &cobra.Command{
}

var compileCmd = &cobra.Command{
Use: "compile [markdown-file]",
Use: "compile [markdown-file]...",
Short: "Compile markdown to YAML workflows",
Long: `Compile one or more markdown workflow files to YAML workflows.

If no files are specified, all markdown files in .github/workflows will be compiled.

Examples:
` + constants.CLIExtensionPrefix + ` compile # Compile all markdown files
` + constants.CLIExtensionPrefix + ` compile weekly-research # Compile a specific workflow
` + constants.CLIExtensionPrefix + ` compile weekly-research daily-plan # Compile multiple workflows
` + constants.CLIExtensionPrefix + ` compile workflow.md # Compile by file path
` + constants.CLIExtensionPrefix + ` compile --watch weekly-research # Watch and auto-compile`,
Run: func(cmd *cobra.Command, args []string) {
var file string
if len(args) > 0 {
file = args[0]
}
engineOverride, _ := cmd.Flags().GetString("engine")
validate, _ := cmd.Flags().GetBool("validate")
watch, _ := cmd.Flags().GetBool("watch")
Expand All @@ -210,7 +216,7 @@ var compileCmd = &cobra.Command{
fmt.Fprintln(os.Stderr, console.FormatErrorMessage(err.Error()))
os.Exit(1)
}
if err := cli.CompileWorkflows(file, verbose, engineOverride, validate, watch, instructions); err != nil {
if err := cli.CompileWorkflows(args, verbose, engineOverride, validate, watch, instructions); err != nil {
fmt.Fprintln(os.Stderr, console.FormatErrorMessage(err.Error()))
os.Exit(1)
}
Expand Down
57 changes: 44 additions & 13 deletions pkg/cli/commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -568,7 +568,7 @@ func AddWorkflowWithTracking(workflow string, number int, verbose bool, engineOv
}

// CompileWorkflows compiles markdown files into GitHub Actions workflow files
func CompileWorkflows(markdownFile string, verbose bool, engineOverride string, validate bool, watch bool, writeInstructions bool) error {
func CompileWorkflows(markdownFiles []string, verbose bool, engineOverride string, validate bool, watch bool, writeInstructions bool) error {
// Create compiler with verbose flag and AI engine override
compiler := workflow.NewCompiler(verbose, engineOverride, GetVersion())

Expand All @@ -577,21 +577,43 @@ func CompileWorkflows(markdownFile string, verbose bool, engineOverride string,

if watch {
// Watch mode: watch for file changes and recompile automatically
// For watch mode, we only support a single file for now
var markdownFile string
if len(markdownFiles) > 0 {
if len(markdownFiles) > 1 {
fmt.Println(console.FormatWarningMessage("Watch mode only supports a single file, using the first one"))
}
// Resolve the workflow file to get the full path
resolvedFile, err := resolveWorkflowFile(markdownFiles[0], verbose)
if err != nil {
return fmt.Errorf("failed to resolve workflow '%s': %w", markdownFiles[0], err)
}
markdownFile = resolvedFile
}
return watchAndCompileWorkflows(markdownFile, compiler, verbose)
}

if markdownFile != "" {
// Resolve workflow ID or file path to actual file path
resolvedFile, err := resolveWorkflowFile(markdownFile, verbose)
if err != nil {
return fmt.Errorf("failed to resolve workflow: %w", err)
if len(markdownFiles) > 0 {
// Compile specific workflow files
var compiledCount int
for _, markdownFile := range markdownFiles {
// Resolve workflow ID or file path to actual file path
resolvedFile, err := resolveWorkflowFile(markdownFile, verbose)
if err != nil {
return fmt.Errorf("failed to resolve workflow '%s': %w", markdownFile, err)
}

if verbose {
fmt.Println(console.FormatInfoMessage(fmt.Sprintf("Compiling %s", resolvedFile)))
}
if err := compiler.CompileWorkflow(resolvedFile); err != nil {
return fmt.Errorf("failed to compile workflow '%s': %w", markdownFile, err)
}
compiledCount++
}

if verbose {
fmt.Printf("Compiling %s\n", resolvedFile)
}
if err := compiler.CompileWorkflow(resolvedFile); err != nil {
return err
fmt.Println(console.FormatSuccessMessage(fmt.Sprintf("Successfully compiled %d workflow file(s)", compiledCount)))
}

// Ensure .gitattributes marks .lock.yml files as generated
Expand Down Expand Up @@ -3028,7 +3050,12 @@ func resolveWorkflowFile(fileOrWorkflowName string, verbose bool) (string, error
if verbose {
fmt.Printf("Found workflow file at path: %s\n", fileOrWorkflowName)
}
return fileOrWorkflowName, nil
// Return absolute path
absPath, err := filepath.Abs(fileOrWorkflowName)
if err != nil {
return fileOrWorkflowName, nil // fallback to original path
}
return absPath, nil
}

// If it's not a direct file path, try to resolve it as a workflow name
Expand Down Expand Up @@ -3081,8 +3108,12 @@ func resolveWorkflowFile(fileOrWorkflowName string, verbose bool) (string, error

return tmpFile.Name(), nil
} else {
// It's a local file, return the source path
return sourceInfo.SourcePath, nil
// It's a local file, make sure we return an absolute path
absPath, err := filepath.Abs(sourceInfo.SourcePath)
if err != nil {
return sourceInfo.SourcePath, nil // fallback to original path
}
return absPath, nil
}
}

Expand Down
6 changes: 5 additions & 1 deletion pkg/cli/commands_compile_workflow_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -508,7 +508,11 @@ This is a test workflow for backward compatibility.
}

// Test CompileWorkflows function with workflow ID
err = CompileWorkflows(tt.workflowID, false, "", false, false, false)
var args []string
if tt.workflowID != "" {
args = []string{tt.workflowID}
}
err = CompileWorkflows(args, false, "", false, false, false)

if tt.expectError {
if err == nil {
Expand Down
8 changes: 6 additions & 2 deletions pkg/cli/commands_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,11 @@ func TestCompileWorkflows(t *testing.T) {

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
err := CompileWorkflows(tt.markdownFile, false, "", false, false, false)
var args []string
if tt.markdownFile != "" {
args = []string{tt.markdownFile}
}
err := CompileWorkflows(args, false, "", false, false, false)

if tt.expectError && err == nil {
t.Errorf("Expected error for test '%s', got nil", tt.name)
Expand Down Expand Up @@ -235,7 +239,7 @@ func TestAllCommandsExist(t *testing.T) {
}{
{func() error { return ListWorkflows(false) }, false, "ListWorkflows"},
{func() error { return AddWorkflowWithTracking("", 1, false, "", "", false, nil) }, false, "AddWorkflowWithTracking (empty name)"}, // Shows help when empty, doesn't error
{func() error { return CompileWorkflows("", false, "", false, false, false) }, false, "CompileWorkflows"}, // Should compile existing markdown files successfully
{func() error { return CompileWorkflows([]string{}, false, "", false, false, false) }, false, "CompileWorkflows"}, // Should compile existing markdown files successfully
{func() error { return RemoveWorkflows("test", false) }, false, "RemoveWorkflows"}, // Should handle missing directory gracefully
{func() error { return StatusWorkflows("test", false) }, false, "StatusWorkflows"}, // Should handle missing directory gracefully
{func() error { return EnableWorkflows("test") }, false, "EnableWorkflows"}, // Should handle missing directory gracefully
Expand Down