Skip to content

Commit c87077e

Browse files
Copilotpelikhan
andauthored
perf: optimize extractWorkflowNameFromFile by eliminating unnecessary YAML parse (#21012)
* Initial plan * perf: optimize extractWorkflowNameFromFile to skip YAML parsing Co-authored-by: pelikhan <[email protected]> * refactor: extract fastParseTitle function and add tests Co-authored-by: pelikhan <[email protected]> --------- Co-authored-by: copilot-swe-agent[bot] <[email protected]> Co-authored-by: pelikhan <[email protected]> Co-authored-by: Peli de Halleux <[email protected]>
1 parent 1a426d0 commit c87077e

File tree

2 files changed

+150
-10
lines changed

2 files changed

+150
-10
lines changed

pkg/cli/commands_utils_test.go

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,113 @@ func TestExtractWorkflowNameFromFile_NonExistentFile(t *testing.T) {
113113
}
114114
}
115115

116+
func TestFastParseTitle(t *testing.T) {
117+
tests := []struct {
118+
name string
119+
content string
120+
expected string
121+
expectError bool
122+
}{
123+
{
124+
name: "H1 after frontmatter",
125+
content: `---
126+
title: Test
127+
---
128+
129+
# My Workflow Title
130+
131+
Some content.`,
132+
expected: "My Workflow Title",
133+
},
134+
{
135+
name: "H1 with trailing spaces",
136+
content: `---
137+
engine: copilot
138+
---
139+
140+
# Weekly Research
141+
142+
Content here.`,
143+
expected: "Weekly Research",
144+
},
145+
{
146+
name: "H1 without frontmatter",
147+
content: `# Simple Title
148+
149+
No frontmatter here.`,
150+
expected: "Simple Title",
151+
},
152+
{
153+
name: "H1 is first line (no frontmatter)",
154+
content: `# Inline Title`,
155+
expected: "Inline Title",
156+
},
157+
{
158+
name: "no H1 header",
159+
content: "Just some text without headers.",
160+
expected: "",
161+
},
162+
{
163+
name: "only H2 headers",
164+
content: `---
165+
engine: copilot
166+
---
167+
168+
## Not an H1`,
169+
expected: "",
170+
},
171+
{
172+
name: "empty content",
173+
content: "",
174+
expected: "",
175+
},
176+
{
177+
name: "unclosed frontmatter returns error",
178+
content: `---
179+
title: Oops
180+
`,
181+
expectError: true,
182+
},
183+
{
184+
name: "dash in middle of content is not frontmatter",
185+
content: `Some text
186+
187+
---
188+
189+
# Not Skipped`,
190+
expected: "Not Skipped",
191+
},
192+
{
193+
name: "H1 inside frontmatter is ignored",
194+
content: `---
195+
# not a header
196+
---
197+
198+
# Real Title`,
199+
expected: "Real Title",
200+
},
201+
}
202+
203+
for _, tt := range tests {
204+
t.Run(tt.name, func(t *testing.T) {
205+
got, err := fastParseTitle(tt.content)
206+
if tt.expectError {
207+
if err == nil {
208+
t.Errorf("fastParseTitle(%q) expected error, got nil", tt.content)
209+
}
210+
return
211+
}
212+
if err != nil {
213+
t.Errorf("fastParseTitle(%q) unexpected error: %v", tt.content, err)
214+
return
215+
}
216+
if got != tt.expected {
217+
t.Errorf("fastParseTitle(%q) = %q, want %q", tt.content, got, tt.expected)
218+
}
219+
})
220+
}
221+
}
222+
116223
func TestIsGitRepo(t *testing.T) {
117224
// Test in current directory (should be a git repo based on project setup)
118225
result := isGitRepo()

pkg/cli/workflows.go

Lines changed: 43 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -282,26 +282,59 @@ func getMarkdownWorkflowFiles(workflowDir string) ([]string, error) {
282282
return mdFiles, nil
283283
}
284284

285+
// fastParseTitle scans markdown content for the first H1 header, skipping an
286+
// optional frontmatter block, without performing a full YAML parse.
287+
//
288+
// Frontmatter is recognised only when "---" appears on the very first line
289+
// (matching the behaviour of ExtractFrontmatterFromContent). Returns the H1
290+
// title text, or ("", nil) when no H1 header is present. Returns an error if
291+
// frontmatter is opened but never closed.
292+
func fastParseTitle(content string) (string, error) {
293+
firstLine := true
294+
inFrontmatter := false
295+
pastFrontmatter := false
296+
for line := range strings.SplitSeq(content, "\n") {
297+
trimmed := strings.TrimSpace(line)
298+
if firstLine {
299+
firstLine = false
300+
if trimmed == "---" {
301+
inFrontmatter = true
302+
continue
303+
}
304+
// No frontmatter on first line; treat the entire file as markdown.
305+
pastFrontmatter = true
306+
} else if inFrontmatter && !pastFrontmatter {
307+
if trimmed == "---" {
308+
pastFrontmatter = true
309+
}
310+
continue
311+
}
312+
if pastFrontmatter && strings.HasPrefix(trimmed, "# ") {
313+
return strings.TrimSpace(trimmed[2:]), nil
314+
}
315+
}
316+
317+
// Unclosed frontmatter is an error (consistent with ExtractFrontmatterFromContent).
318+
if inFrontmatter && !pastFrontmatter {
319+
return "", errors.New("frontmatter not properly closed")
320+
}
321+
322+
return "", nil
323+
}
324+
285325
// extractWorkflowNameFromFile extracts the workflow name from a file's H1 header
286326
func extractWorkflowNameFromFile(filePath string) (string, error) {
287327
content, err := os.ReadFile(filePath)
288328
if err != nil {
289329
return "", err
290330
}
291331

292-
// Extract markdown content (excluding frontmatter)
293-
result, err := parser.ExtractFrontmatterFromContent(string(content))
332+
title, err := fastParseTitle(string(content))
294333
if err != nil {
295334
return "", err
296335
}
297-
298-
// Look for first H1 header
299-
lines := strings.SplitSeq(result.Markdown, "\n")
300-
for line := range lines {
301-
line = strings.TrimSpace(line)
302-
if strings.HasPrefix(line, "# ") {
303-
return strings.TrimSpace(line[2:]), nil
304-
}
336+
if title != "" {
337+
return title, nil
305338
}
306339

307340
// No H1 header found, generate default name from filename

0 commit comments

Comments
 (0)