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
107 changes: 107 additions & 0 deletions pkg/cli/commands_utils_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,113 @@ func TestExtractWorkflowNameFromFile_NonExistentFile(t *testing.T) {
}
}

func TestFastParseTitle(t *testing.T) {
tests := []struct {
name string
content string
expected string
expectError bool
}{
{
name: "H1 after frontmatter",
content: `---
title: Test
---

# My Workflow Title

Some content.`,
expected: "My Workflow Title",
},
{
name: "H1 with trailing spaces",
content: `---
engine: copilot
---

# Weekly Research

Content here.`,
expected: "Weekly Research",
},
{
name: "H1 without frontmatter",
content: `# Simple Title

No frontmatter here.`,
expected: "Simple Title",
},
{
name: "H1 is first line (no frontmatter)",
content: `# Inline Title`,
expected: "Inline Title",
},
{
name: "no H1 header",
content: "Just some text without headers.",
expected: "",
},
{
name: "only H2 headers",
content: `---
engine: copilot
---

## Not an H1`,
expected: "",
},
{
name: "empty content",
content: "",
expected: "",
},
{
name: "unclosed frontmatter returns error",
content: `---
title: Oops
`,
expectError: true,
},
{
name: "dash in middle of content is not frontmatter",
content: `Some text

---

# Not Skipped`,
expected: "Not Skipped",
},
{
name: "H1 inside frontmatter is ignored",
content: `---
# not a header
---

# Real Title`,
expected: "Real Title",
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := fastParseTitle(tt.content)
if tt.expectError {
if err == nil {
t.Errorf("fastParseTitle(%q) expected error, got nil", tt.content)
}
return
}
if err != nil {
t.Errorf("fastParseTitle(%q) unexpected error: %v", tt.content, err)
return
}
if got != tt.expected {
t.Errorf("fastParseTitle(%q) = %q, want %q", tt.content, got, tt.expected)
}
})
}
}

func TestIsGitRepo(t *testing.T) {
// Test in current directory (should be a git repo based on project setup)
result := isGitRepo()
Expand Down
53 changes: 43 additions & 10 deletions pkg/cli/workflows.go
Original file line number Diff line number Diff line change
Expand Up @@ -282,26 +282,59 @@ func getMarkdownWorkflowFiles(workflowDir string) ([]string, error) {
return mdFiles, nil
}

// fastParseTitle scans markdown content for the first H1 header, skipping an
// optional frontmatter block, without performing a full YAML parse.
//
// Frontmatter is recognised only when "---" appears on the very first line
// (matching the behaviour of ExtractFrontmatterFromContent). Returns the H1
// title text, or ("", nil) when no H1 header is present. Returns an error if
// frontmatter is opened but never closed.
func fastParseTitle(content string) (string, error) {
firstLine := true
inFrontmatter := false
pastFrontmatter := false
for line := range strings.SplitSeq(content, "\n") {
trimmed := strings.TrimSpace(line)
if firstLine {
firstLine = false
if trimmed == "---" {
inFrontmatter = true
continue
}
// No frontmatter on first line; treat the entire file as markdown.
pastFrontmatter = true
} else if inFrontmatter && !pastFrontmatter {
if trimmed == "---" {
pastFrontmatter = true
}
continue
}
if pastFrontmatter && strings.HasPrefix(trimmed, "# ") {
return strings.TrimSpace(trimmed[2:]), nil
}
}

// Unclosed frontmatter is an error (consistent with ExtractFrontmatterFromContent).
if inFrontmatter && !pastFrontmatter {
return "", errors.New("frontmatter not properly closed")
}

return "", nil
}

// extractWorkflowNameFromFile extracts the workflow name from a file's H1 header
func extractWorkflowNameFromFile(filePath string) (string, error) {
content, err := os.ReadFile(filePath)
if err != nil {
return "", err
}

// Extract markdown content (excluding frontmatter)
result, err := parser.ExtractFrontmatterFromContent(string(content))
title, err := fastParseTitle(string(content))
if err != nil {
return "", err
}

// Look for first H1 header
lines := strings.SplitSeq(result.Markdown, "\n")
for line := range lines {
line = strings.TrimSpace(line)
if strings.HasPrefix(line, "# ") {
return strings.TrimSpace(line[2:]), nil
}
if title != "" {
return title, nil
}

// No H1 header found, generate default name from filename
Expand Down
Loading