Skip to content

Commit b4af03f

Browse files
authored
feat: handle local directory arguments in compile command (#30295)
1 parent 31547a1 commit b4af03f

4 files changed

Lines changed: 178 additions & 0 deletions

File tree

cmd/gh-aw/main.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,7 @@ Examples:
253253
` + string(constants.CLIExtensionPrefix) + ` compile ci-doctor # Compile a specific workflow
254254
` + string(constants.CLIExtensionPrefix) + ` compile ci-doctor daily-plan # Compile multiple workflows
255255
` + string(constants.CLIExtensionPrefix) + ` compile workflow.md # Compile by file path
256+
` + string(constants.CLIExtensionPrefix) + ` compile .github/workflows # Compile all workflows in a directory
256257
` + string(constants.CLIExtensionPrefix) + ` compile --dir custom/workflows # Compile from custom directory
257258
` + string(constants.CLIExtensionPrefix) + ` compile --watch ci-doctor # Watch and auto-compile
258259
` + string(constants.CLIExtensionPrefix) + ` compile --trial --logical-repo owner/repo # Compile for trial mode

pkg/cli/compile_args.go

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
// This file provides argument preprocessing for the compile command.
2+
//
3+
// It handles expansion of local directory paths into their constituent
4+
// workflow .md files so that the rest of the compilation pipeline only
5+
// needs to deal with concrete file paths.
6+
//
7+
// # Key Functions
8+
//
9+
// - resolveCompileArgs() - Expand a list of compile arguments
10+
// - expandCompileArg() - Expand a single argument (directory or file)
11+
// - expandDirectoryArg() - Return all .md workflow files inside a directory
12+
13+
package cli
14+
15+
import (
16+
"fmt"
17+
"os"
18+
19+
"github.com/github/gh-aw/pkg/console"
20+
"github.com/github/gh-aw/pkg/logger"
21+
)
22+
23+
var compileArgsLog = logger.New("cli:compile_args")
24+
25+
// resolveCompileArgs preprocesses compile command arguments to handle
26+
// local directory paths. When an argument is a directory it is expanded
27+
// to all .md workflow files in that directory.
28+
func resolveCompileArgs(args []string, verbose bool) ([]string, error) {
29+
if len(args) == 0 {
30+
return args, nil
31+
}
32+
33+
var result []string
34+
for _, arg := range args {
35+
expanded, err := expandCompileArg(arg, verbose)
36+
if err != nil {
37+
return nil, err
38+
}
39+
result = append(result, expanded...)
40+
}
41+
return result, nil
42+
}
43+
44+
// expandCompileArg expands a single compile argument:
45+
// - Local directory paths: expand to all .md files in that directory
46+
// - Everything else: return as-is for the existing resolver to handle
47+
func expandCompileArg(arg string, verbose bool) ([]string, error) {
48+
compileArgsLog.Printf("Processing compile argument: %s", arg)
49+
50+
// Handle local directory paths
51+
info, err := os.Stat(arg)
52+
if err == nil && info.IsDir() {
53+
return expandDirectoryArg(arg, verbose)
54+
}
55+
56+
// Return as-is (regular file path or workflow name)
57+
return []string{arg}, nil
58+
}
59+
60+
// expandDirectoryArg expands a directory path to all .md workflow files in it.
61+
func expandDirectoryArg(dirPath string, verbose bool) ([]string, error) {
62+
compileArgsLog.Printf("Expanding directory argument: %s", dirPath)
63+
64+
if verbose {
65+
fmt.Fprintln(os.Stderr, console.FormatInfoMessage("Compiling all workflows in directory: "+dirPath))
66+
}
67+
68+
mdFiles, err := getMarkdownWorkflowFiles(dirPath)
69+
if err != nil {
70+
return nil, fmt.Errorf("failed to find workflow files in %s: %w", dirPath, err)
71+
}
72+
73+
mdFiles, err = filterMarkdownFilesWithFrontmatter(mdFiles)
74+
if err != nil {
75+
return nil, fmt.Errorf("failed to filter workflow files in %s: %w", dirPath, err)
76+
}
77+
78+
if len(mdFiles) == 0 {
79+
return nil, fmt.Errorf("no workflow markdown files found in %s (workflow files must start with a frontmatter opener on the first line)", dirPath)
80+
}
81+
82+
compileArgsLog.Printf("Found %d workflow files in directory %s", len(mdFiles), dirPath)
83+
return mdFiles, nil
84+
}

pkg/cli/compile_args_test.go

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
//go:build !integration
2+
3+
package cli
4+
5+
import (
6+
"os"
7+
"path/filepath"
8+
"strings"
9+
"testing"
10+
11+
"github.com/stretchr/testify/assert"
12+
"github.com/stretchr/testify/require"
13+
)
14+
15+
func TestExpandCompileArg_RegularFile(t *testing.T) {
16+
// A plain workflow name should be returned as-is
17+
result, err := expandCompileArg("my-workflow", false)
18+
require.NoError(t, err, "plain workflow name should not error")
19+
assert.Equal(t, []string{"my-workflow"}, result, "plain workflow name should be returned unchanged")
20+
}
21+
22+
func TestExpandCompileArg_FilePath(t *testing.T) {
23+
// A non-existent file path should be returned as-is
24+
result, err := expandCompileArg(".github/workflows/my-workflow.md", false)
25+
require.NoError(t, err, "non-existent file path should not error")
26+
assert.Equal(t, []string{".github/workflows/my-workflow.md"}, result, "file path should be returned unchanged")
27+
}
28+
29+
func TestExpandCompileArg_LocalDirectory(t *testing.T) {
30+
// Create a temp directory with workflow files
31+
tmpDir := t.TempDir()
32+
writeWorkflowFile(t, tmpDir, "workflow-a.md")
33+
writeWorkflowFile(t, tmpDir, "workflow-b.md")
34+
35+
result, err := expandCompileArg(tmpDir, false)
36+
require.NoError(t, err, "local directory should expand without error")
37+
assert.Len(t, result, 2, "should return all .md files in the directory")
38+
}
39+
40+
func TestExpandCompileArg_LocalDirectory_Empty(t *testing.T) {
41+
// Directory with no .md files should error
42+
tmpDir := t.TempDir()
43+
_, err := expandCompileArg(tmpDir, false)
44+
assert.Error(t, err, "empty directory should return an error")
45+
assert.Contains(t, err.Error(), "no workflow markdown files found", "error should mention no workflow files")
46+
}
47+
48+
func TestExpandCompileArg_URLPassthrough(t *testing.T) {
49+
// URLs should be returned as-is (not processed)
50+
url := "https://github.com/org/repo/tree/main/.github/workflows"
51+
result, err := expandCompileArg(url, false)
52+
require.NoError(t, err, "URL should not error")
53+
assert.Equal(t, []string{url}, result, "URL should be returned unchanged")
54+
}
55+
56+
func TestResolveCompileArgs_Empty(t *testing.T) {
57+
result, err := resolveCompileArgs(nil, false)
58+
require.NoError(t, err)
59+
assert.Empty(t, result)
60+
}
61+
62+
func TestResolveCompileArgs_Mixed(t *testing.T) {
63+
// Create a temp directory with a workflow file
64+
tmpDir := t.TempDir()
65+
writeWorkflowFile(t, tmpDir, "workflow-a.md")
66+
67+
// Mix: a plain workflow name + a directory
68+
result, err := resolveCompileArgs([]string{"plain-workflow", tmpDir}, false)
69+
require.NoError(t, err, "mixed args should expand without error")
70+
require.Len(t, result, 2, "should have one plain name + one expanded file")
71+
72+
// The plain workflow name should be unchanged
73+
assert.Equal(t, "plain-workflow", result[0], "first arg should be unchanged")
74+
// The directory arg should be the single .md file in tmpDir
75+
assert.True(t, strings.HasSuffix(result[1], "workflow-a.md"), "second arg should be the expanded .md file")
76+
}
77+
78+
// writeWorkflowFile creates a minimal workflow .md file in dir with the given name.
79+
func writeWorkflowFile(t *testing.T, dir, name string) {
80+
t.Helper()
81+
content := "---\non: push\n---\n\n# Test Workflow\n"
82+
require.NoError(t, os.WriteFile(filepath.Join(dir, name), []byte(content), 0644),
83+
"write workflow file %s", name)
84+
}

pkg/cli/compile_orchestrator.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,15 @@ func CompileWorkflows(ctx context.Context, config CompileConfig) ([]*workflow.Wo
5757
compileOrchestratorLog.Printf("Using custom workflow directory: %s", workflowDir)
5858
}
5959

60+
// Preprocess args: expand directory paths and GitHub URLs to constituent workflow files
61+
if len(config.MarkdownFiles) > 0 {
62+
expandedFiles, err := resolveCompileArgs(config.MarkdownFiles, config.Verbose)
63+
if err != nil {
64+
return nil, err
65+
}
66+
config.MarkdownFiles = expandedFiles
67+
}
68+
6069
// Create and configure compiler
6170
compiler := createAndConfigureCompiler(config)
6271

0 commit comments

Comments
 (0)