diff --git a/pkg/pr/apply_test.go b/pkg/pr/apply_test.go index 46c07bc7a..e906e9c3f 100644 --- a/pkg/pr/apply_test.go +++ b/pkg/pr/apply_test.go @@ -213,6 +213,80 @@ func TestApply(t *testing.T) { }, expectedErr: nil, }, + { + name: "should work with multi line regex replacements, example 1", + files: map[string]string{ + filepath.Join(dir, "workload.tf"): `Line 1 +Line 2 +Line 3`, + }, + template: &pr.PrTemplate{ + Context: map[string]interface{}{}, + Spec: pr.PrTemplateSpec{ + Updates: &pr.UpdateSpec{ + RegexReplacements: []pr.RegexReplacement{ + { + Regex: `Line (\d+)`, + Replacement: "Replaced $1", + File: filepath.Join(dir, "workload.tf"), + Templated: false, + }, + }, + }, + }, + }, + expectedFiles: map[string]string{ + filepath.Join(dir, "workload.tf"): `Replaced 1 +Replaced 2 +Replaced 3`, + }, + expectedErr: nil, + }, + { + name: "should work with multi line regex replacements, example 2", + files: map[string]string{ + filepath.Join(dir, "workload.tf"): ` + module "staging" { + source = "./eks" + START + vpc_name = "plural-stage" + kubernetes_version = "1.28" + create_db = false + END + providers = { + helm = helm.staging + } + }`, + }, + template: &pr.PrTemplate{ + Context: map[string]interface{}{ + "version": "1.28", + }, + Spec: pr.PrTemplateSpec{ + Updates: &pr.UpdateSpec{ + RegexReplacements: []pr.RegexReplacement{ + { + Regex: `START.*END`, + Replacement: "kubernetes_version = \"{{ context.version }}\"", + File: filepath.Join(dir, "workload.tf"), + Templated: false, + }, + }, + }, + }, + }, + expectedFiles: map[string]string{ + filepath.Join(dir, "workload.tf"): ` + module "staging" { + source = "./eks" + kubernetes_version = "1.28" + providers = { + helm = helm.staging + } + }`, + }, + expectedErr: nil, + }, { name: "should template and overlay with overwrite yaml file", files: map[string]string{ diff --git a/pkg/pr/updates.go b/pkg/pr/updates.go index c54604dea..1118e9b86 100644 --- a/pkg/pr/updates.go +++ b/pkg/pr/updates.go @@ -5,6 +5,7 @@ import ( "io/fs" "path/filepath" "regexp" + "strings" "dario.cat/mergo" "github.com/samber/lo" @@ -75,13 +76,7 @@ func processRegexReplacements(replacements []RegexReplacement, ctx map[string]in if err != nil { rx = []byte(replacement.Regex) } - - r, err := regexp.Compile(string(rx)) - if err != nil { - return data, err - } - - return r.ReplaceAll(data, replaceWith), nil + return replaceMultiline(rx, replaceWith, data) } dest, err := templateReplacement([]byte(replacement.File), ctx) @@ -97,6 +92,24 @@ func processRegexReplacements(replacements []RegexReplacement, ctx map[string]in return nil } +// replaceMultiline applies regex-based replacements on a multiline string +func replaceMultiline(pattern, replacement, text []byte) ([]byte, error) { + // Replace all newlines with a unique placeholder + placeholder := "__NL__" + flattenedText := strings.ReplaceAll(string(text), "\n", placeholder) + + // Apply the regex replacement on the flattened text + re, err := regexp.Compile(string(pattern)) + if err != nil { + return nil, err + } + flattenedText = re.ReplaceAllString(flattenedText, string(replacement)) + + // Revert the placeholder back to newlines + finalText := strings.ReplaceAll(flattenedText, placeholder, "\n") + return []byte(finalText), nil +} + func processYamlOverlays(overlays []YamlOverlay, ctx map[string]interface{}) error { if len(overlays) == 0 { return nil