Skip to content

Commit

Permalink
Add pr template command
Browse files Browse the repository at this point in the history
Will be used for on-demand pr gen
  • Loading branch information
michaeljguarino committed Jan 21, 2024
1 parent 1685bfc commit bf892f5
Show file tree
Hide file tree
Showing 7 changed files with 251 additions and 0 deletions.
7 changes: 7 additions & 0 deletions cmd/plural/plural.go
Original file line number Diff line number Diff line change
Expand Up @@ -504,6 +504,13 @@ func (p *Plural) getCommands() []cli.Command {
},
Category: "CD",
},
{
Name: "pull-requests",
Aliases: []string{"pr"},
Usage: "Generate and manage pull requests",
Subcommands: prCommands(),
Category: "CD",
},
{
Name: "template",
Aliases: []string{"tpl"},
Expand Down
32 changes: 32 additions & 0 deletions cmd/plural/pr.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package plural

import (
"github.com/pluralsh/plural-cli/pkg/pr"
"github.com/urfave/cli"
)

func prCommands() []cli.Command {
return []cli.Command{
{
Name: "template",
Usage: "applies a pr template resource in the local source tree",
Action: handlePrTemplate,
Flags: []cli.Flag{
cli.StringFlag{
Name: "file",
Usage: "the file the template was placed in",
Required: true,
},
},
},
}
}

func handlePrTemplate(c *cli.Context) error {
template, err := pr.Build(c.String("file"))
if err != nil {
return err
}

return pr.Apply(template)
}
9 changes: 9 additions & 0 deletions pkg/pr/apply.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package pr

func Apply(template *PrTemplate) error {
if err := applyUpdates(template.Spec.Updates, template.Context); err != nil {
return err
}

return applyCreates(template.Spec.Creates, template.Context)
}
5 changes: 5 additions & 0 deletions pkg/pr/creates.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package pr

func applyCreates(creates *CreateSpec, ctx map[string]interface{}) error {
return nil
}
45 changes: 45 additions & 0 deletions pkg/pr/types.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package pr

import (
"os"

"sigs.k8s.io/yaml"
)

type PrTemplate struct {
ApiVersion string `json:"apiVersion"`
Kind string `json:"kind"`
Metadata map[string]interface{} `json:"metadata"`
Context map[string]interface{} `json:"context"`
Spec PrTemplateSpec `json:"spec"`
}

type PrTemplateSpec struct {
Updates *UpdateSpec `json:"updates"`
Creates *CreateSpec `json:"creates"`
}

type UpdateSpec struct {
Regexes []string `json:"regexes"`
Files []string `json:"files"`
ReplaceTemplate string `json:"replace_template"`
Yq string `json:"yq"`
MatchStrategy string `json:"match_strategy"`
}

type CreateSpec struct {
}

func Build(path string) (*PrTemplate, error) {
pr := &PrTemplate{}
data, err := os.ReadFile(path)
if err != nil {
return pr, err
}

if err := yaml.Unmarshal(data, pr); err != nil {
return pr, err
}

return pr, nil
}
114 changes: 114 additions & 0 deletions pkg/pr/updates.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
package pr

import (
"io/fs"
"path/filepath"
"regexp"
)

func applyUpdates(updates *UpdateSpec, ctx map[string]interface{}) error {
replacement, err := templateReplacement(updates.ReplaceTemplate, ctx)
if err != nil {
return err
}

return filepath.Walk(".", func(path string, info fs.FileInfo, err error) error {
if err != nil {
return err
}

if info.IsDir() {
return nil
}

ok, err := filenameMatches(path, updates.Files)
if err != nil {
return err
}

if ok {
return updateFile(path, updates, replacement)
}

return nil
})
}

func updateFile(path string, updates *UpdateSpec, replacement string) error {
switch updates.MatchStrategy {
case "any":
return anyUpdateFile(path, updates, replacement)
case "all":
return allUpdateFile(path, updates)
case "recursive":
return recursiveUpdateFile(path, updates, replacement)
default:
return nil
}
}

func anyUpdateFile(path string, updates *UpdateSpec, replacement string) error {
return replaceInPlace(path, func(data []byte) ([]byte, error) {
for _, reg := range updates.Regexes {
r, err := regexp.Compile(reg)
if err != nil {
return data, err
}
data = r.ReplaceAll(data, []byte(replacement))
}
return data, nil
})
}

func allUpdateFile(path string, updates *UpdateSpec) error {
return nil
}

func recursiveUpdateFile(path string, updates *UpdateSpec, replacement string) error {
return replaceInPlace(path, func(data []byte) ([]byte, error) {
for _, reg := range updates.Regexes {
r, err := regexp.Compile(reg)
if err != nil {
return data, err
}
data = r.ReplaceAll(data, []byte(replacement))
}
return data, nil
})
}

func recursiveReplace(data []byte, regexes []string, replacement string) ([]byte, error) {
if len(regexes) == 0 {
return []byte(replacement), nil
}

r, err := regexp.Compile(regexes[0])
if err != nil {
return data, err
}

res := r.ReplaceAllFunc(data, func(d []byte) []byte {
res, err := recursiveReplace(d, regexes[1:], replacement)
if err != nil {
panic(err)
}
return res
})

return res, nil
}

func filenameMatches(path string, files []string) (bool, error) {
for _, f := range files {
r, err := regexp.Compile(f)
if err != nil {
return false, err
}

if r.MatchString(path) {
return true, nil
}
}

return false, nil
}
39 changes: 39 additions & 0 deletions pkg/pr/utils.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package pr

import (
"bytes"
"os"
"text/template"

"github.com/Masterminds/sprig/v3"
)

func templateReplacement(data string, ctx map[string]interface{}) (string, error) {
tpl, err := template.New("gotpl").Funcs(sprig.TxtFuncMap()).Parse(data)
if err != nil {
return "", err
}
var buf bytes.Buffer
if err := tpl.Execute(&buf, map[string]interface{}{"context": ctx}); err != nil {
return "", err
}
return buf.String(), nil
}

func replaceInPlace(path string, rep func(data []byte) ([]byte, error)) error {
info, err := os.Stat(path)
if err != nil {
return err
}

data, err := os.ReadFile(path)
if err != nil {
return err
}

resData, err := rep(data)
if err != nil {
return err
}
return os.WriteFile(path, resData, info.Mode())
}

0 comments on commit bf892f5

Please sign in to comment.