diff --git a/pkg/workflow/yaml.go b/pkg/workflow/yaml.go index 05164eeed84..d7644742c6f 100644 --- a/pkg/workflow/yaml.go +++ b/pkg/workflow/yaml.go @@ -146,17 +146,9 @@ func UnquoteYAMLKey(yamlStr string, key string) string { re = regexp.MustCompile(pattern) unquoteYAMLKeyCache.Store(key, re) } - return re.ReplaceAllStringFunc(yamlStr, func(match string) string { - // Find the submatch groups - submatches := re.FindStringSubmatch(match) - if len(submatches) >= 3 { - // submatches[0] is the full match - // submatches[1] is the line start (^ or \n) - // submatches[2] is the whitespace - return submatches[1] + submatches[2] + key + ":" - } - return match - }) + // Use ReplaceAllString with capture group references for a single-pass replacement. + // ${1} = line start (^ or \n), ${2} = optional whitespace + return re.ReplaceAllString(yamlStr, "${1}${2}"+key+":") } // MarshalWithFieldOrder marshals a map to YAML with fields in a specific order. diff --git a/pkg/workflow/yaml_test.go b/pkg/workflow/yaml_test.go index 622f404bf3c..68cd73bf31b 100644 --- a/pkg/workflow/yaml_test.go +++ b/pkg/workflow/yaml_test.go @@ -407,6 +407,36 @@ func TestExtractTopLevelYAMLSectionWithOrdering(t *testing.T) { } } +// BenchmarkUnquoteYAMLKey measures single-pass regex replacement performance. +// This benchmark guards against regressions where the implementation calls +// FindStringSubmatch inside a ReplaceAllStringFunc callback (double regex pass). +func BenchmarkUnquoteYAMLKey(b *testing.B) { + // A realistic workflow YAML with the "on" key quoted by the marshaler + yamlStr := `"on": + push: + branches: + - main + pull_request: + types: + - opened + - synchronize + issues: + types: + - opened + workflow_dispatch: +jobs: + agent: + runs-on: ubuntu-latest + steps: + - name: Run + run: echo hello +` + b.ReportAllocs() + for b.Loop() { + _ = UnquoteYAMLKey(yamlStr, "on") + } +} + func TestFormatYAMLValue(t *testing.T) { tests := []struct { name string