diff --git a/.changes/unreleased/added-20240911-234212.yaml b/.changes/unreleased/added-20240911-234212.yaml new file mode 100644 index 00000000..5d774d9b --- /dev/null +++ b/.changes/unreleased/added-20240911-234212.yaml @@ -0,0 +1,5 @@ +kind: added +body: Support filepath globs in replacements +time: 2024-09-11T23:42:12.277856663-04:00 +custom: + Issue: "713" diff --git a/core/replacement.go b/core/replacement.go index 8b05fb11..719fef62 100644 --- a/core/replacement.go +++ b/core/replacement.go @@ -2,12 +2,16 @@ package core import ( "bytes" + "errors" "fmt" "os" + "path/filepath" "regexp" "text/template" ) +var ErrNoReplacementFilesFound = errors.New("glob pattern did not match any files") + // Template data used for replacing version values. type ReplaceData struct { // Version of the release, will include "v" prefix if used @@ -39,6 +43,13 @@ type ReplaceData struct { // replace: ' "version": "{{.VersionNoPrefix}}",' type Replacement struct { // Path of the file to find and replace in. + // Also supports Go filepath globs. + // example: yaml + // # Will match any .json file in the current directory + // replacements: + // - path: *.json + // find: ' "version": ".*",' + // replace: ' "version": "{{.VersionNoPrefix}}",' Path string `yaml:"path" required:"true"` // Regular expression to search for in the file. // Capture groups are supported and can be used in the replace value. @@ -67,11 +78,15 @@ func (r Replacement) Execute(data ReplaceData) error { return err } - fileData, err := os.ReadFile(r.Path) + globs, err := filepath.Glob(r.Path) if err != nil { return err } + if len(globs) == 0 { + return fmt.Errorf("%w: %s", ErrNoReplacementFilesFound, r.Path) + } + flags := r.Flags if flags == "" { flags = "m" @@ -82,11 +97,18 @@ func (r Replacement) Execute(data ReplaceData) error { return err } - newData := regex.ReplaceAll(fileData, buf.Bytes()) + for _, path := range globs { + fileData, err := os.ReadFile(path) + if err != nil { + return err + } - err = os.WriteFile(r.Path, newData, CreateFileMode) - if err != nil { - return err + newData := regex.ReplaceAll(fileData, buf.Bytes()) + + err = os.WriteFile(path, newData, CreateFileMode) + if err != nil { + return err + } } return nil diff --git a/core/replacement_test.go b/core/replacement_test.go index 33dc0b45..93da42b9 100644 --- a/core/replacement_test.go +++ b/core/replacement_test.go @@ -126,16 +126,6 @@ level1: then.FileContents(t, endData, filepath) } -func TestErrorBadFileRead(t *testing.T) { - then.WithTempDir(t) - - rep := Replacement{ - Path: "does not exist", - } - err := rep.Execute(ReplaceData{}) - then.NotNil(t, err) -} - func TestErrorBadTemplateParse(t *testing.T) { then.WithTempDir(t) @@ -180,3 +170,59 @@ func TestErrorBadTemplateExec(t *testing.T) { err := rep.Execute(ReplaceData{}) then.NotNil(t, err) } + +func TestErrorBadFileRead(t *testing.T) { + then.WithTempDir(t) + + rep := Replacement{ + Path: "does not exist", + } + err := rep.Execute(ReplaceData{}) + then.Err(t, ErrNoReplacementFilesFound, err) +} + +func TestGlobs(t *testing.T) { + then.WithTempDir(t) + + toReplace := []byte(`{ + "version": "1.0.0" +}`) + then.WriteFile(t, toReplace, "a", "b", "c.json") + then.WriteFile(t, toReplace, "a", "b", "d.xml") + then.WriteFile(t, toReplace, "a", "b", "e.jsonl") + then.WriteFile(t, toReplace, "a", "b", "f.png") + then.WriteFile(t, toReplace, "a", "c", "g.json") + + rep := Replacement{ + Path: "a/*/*.json", + Find: ` "version": ".*"`, + Replace: ` "version": "{{.VersionNoPrefix}}"`, + } + + err := rep.Execute(ReplaceData{ + VersionNoPrefix: "1.1.0", + }) + then.Nil(t, err) + + changedFile := `{ + "version": "1.1.0" +}` + unchangedFile := `{ + "version": "1.0.0" +}` + + then.FileContents(t, changedFile, "a", "b", "c.json") + then.FileContents(t, unchangedFile, "a", "b", "d.xml") + then.FileContents(t, unchangedFile, "a", "b", "e.jsonl") + then.FileContents(t, unchangedFile, "a", "b", "f.png") + then.FileContents(t, changedFile, "a", "c", "g.json") +} + +func TestBadGlob(t *testing.T) { + rep := Replacement{ + Path: `[]`, + } + + err := rep.Execute(ReplaceData{}) + then.NotNil(t, err) +}