Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 7 additions & 4 deletions internal/boilersuite/regexes.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,14 @@ import (
)

var (
// YearMarkerRegex matches the marker which should appear in boilerplate sample files but not in actual files
YearMarkerRegex = regexp.MustCompile(`<<YEAR>>`)
// CopyrightMarker should appear in boilerplate sample files but not in actual files
CopyrightMarker = "Copyright <<YEAR>>"

// AuthorMarkerRegex matches the marker which should appear in boilerplate sample files but not in actual files
AuthorMarkerRegex = regexp.MustCompile(`<<AUTHOR>>`)
// YearMarker should appear in boilerplate sample files but not in actual files
YearMarker = "<<YEAR>>"

// AuthorMarker should appear in boilerplate sample files but not in actual files
AuthorMarker = "<<AUTHOR>>"

// DateRegex matches the actual date found inside a file
DateRegex = regexp.MustCompile(`Copyright 20\d\d`)
Expand Down
26 changes: 16 additions & 10 deletions internal/boilersuite/template.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ package boilersuite

import (
"fmt"
"os"
"strings"
)

Expand Down Expand Up @@ -46,15 +47,15 @@ type BoilerplateTemplateConfiguration struct {

// NewBoilerplateTemplate creates a new boilerplate template using the given raw template and configuration
func NewBoilerplateTemplate(raw string, config BoilerplateTemplateConfiguration) (BoilerplateTemplate, error) {
if !YearMarkerRegex.MatchString(raw) {
return BoilerplateTemplate{}, fmt.Errorf("invalid template: couldn't find year replacement marker %s", YearMarkerRegex.String())
if !strings.Contains(raw, YearMarker) {
return BoilerplateTemplate{}, fmt.Errorf("couldn't find replacement marker %q", YearMarker)
}

if !AuthorMarkerRegex.MatchString(raw) {
return BoilerplateTemplate{}, fmt.Errorf("invalid template: couldn't find author replacement marker %s", AuthorMarkerRegex.String())
if !strings.Contains(raw, AuthorMarker) {
return BoilerplateTemplate{}, fmt.Errorf("couldn't find replacement marker %q", AuthorMarker)
}

replaced := AuthorMarkerRegex.ReplaceAllString(raw, config.ExpectedAuthor)
replaced := strings.ReplaceAll(raw, AuthorMarker, config.ExpectedAuthor)

lineCount := strings.Count(replaced, "\n") + 1

Expand All @@ -66,13 +67,18 @@ func NewBoilerplateTemplate(raw string, config BoilerplateTemplateConfiguration)
}, nil
}

// Validate checks the given raw input file against the template
func (t BoilerplateTemplate) Validate(raw string) error {
if SkipFileRegex.MatchString(raw) || GeneratedRegex.MatchString(raw) {
// Validate checks the given file path against the template
func (t BoilerplateTemplate) Validate(path string) error {
contents, err := os.ReadFile(path)
if err != nil {
return fmt.Errorf("failed to read: %w", err)
}

if SkipFileRegex.Match(contents) || GeneratedRegex.Match(contents) {
return nil
}

normalizedContents, err := t.normalizeAndTrimFile(raw)
normalizedContents, err := t.normalizeAndTrimFile(string(contents))
if err != nil {
return err
}
Expand All @@ -96,7 +102,7 @@ func (t BoilerplateTemplate) normalizeAndTrimFile(raw string) (string, error) {
}

// replace anything which looks like a date with the year marker
raw = DateRegex.ReplaceAllString(raw, "Copyright "+YearMarkerRegex.String())
raw = DateRegex.ReplaceAllString(raw, CopyrightMarker)

// Remove any windows-style line feeds in the raw input

Expand Down
83 changes: 23 additions & 60 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,6 @@ const (
defaultAuthor = "cert-manager"
)

var (
alwaysSkippedDirs = []string{".git", "_bin", "bin", "node_modules", "vendor", "third_party", "staging"}
)

//go:embed boilerplate-templates/*.boilertmpl
var boilerplateTemplateDir embed.FS

Expand All @@ -49,7 +45,7 @@ func main() {
verboseLogger := log.New(io.Discard, "", 0)

skipFlag := flag.String("skip", "", "Space-separated list of prefixes for paths which shouldn't be checked. Spaces in prefixes not supported.")
authorFlag := flag.String("author", defaultAuthor, fmt.Sprintf("The expected author for files, which will be substituted for the %q marker in templates", boilersuite.AuthorMarkerRegex))
authorFlag := flag.String("author", defaultAuthor, fmt.Sprintf("The expected author for files, which will be substituted for the %q marker in templates", boilersuite.AuthorMarker))
verboseFlag := flag.Bool("verbose", false, "If set, prints verbose output")
cpuProfile := flag.String("cpuprofile", "", "If set, writes CPU profiling information to the given filename")
printVersion := flag.Bool("version", false, "If set, prints the version and exits")
Expand All @@ -66,14 +62,13 @@ func main() {
logger.Fatalf("usage: %s [--version] [--skip \"paths to skip\"] [--author \"example\"] [--verbose] <path-to-dir>", os.Args[0])
}

var skippedDirs []string

skippedDirs := []string{".git", "_bin", "bin", "node_modules", "vendor", "third_party", "staging"}
if skipFlag != nil && len(*skipFlag) > 0 {
skippedDirs = strings.Fields(*skipFlag)
skippedDirs = append(skippedDirs, strings.Fields(*skipFlag)...)
Comment thread
vincentdephily marked this conversation as resolved.
}

if *verboseFlag {
verboseLogger = log.New(os.Stdout, "[VERBOSE] ", log.LstdFlags)
verboseLogger = log.New(os.Stdout, "[VERBOSE] ", log.LstdFlags|log.Lmsgprefix)
}

if *cpuProfile != "" {
Expand All @@ -97,29 +92,9 @@ func main() {

targetBase := flag.Arg(0)

dir, err := isDir(targetBase)
targets, err := getTargets(targetBase, templates, skippedDirs, verboseLogger)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

does this still work with single file targets?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm pretty sure I had tested single-file at the time, but now I'm getting an error from the "git repository matcher" merged recently. I'll look for a fix.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My bad, good catch.

I've restored the ability to scan single target, using a check at the start of getTargets() rather than a revert because it should simplify the later changes and because I'd like to keep main() simple.

if err != nil {
// couldn't check if the base was a dir or not
logger.Fatalf("target invalid: %s", err)
}

var targets []target

if dir {
targets, err = getTargets(targetBase, templates, skippedDirs, verboseLogger)
if err != nil {
logger.Fatalf("failed to list targets in dir %q: %s", targetBase, err.Error())
}
} else {
contents, err := os.ReadFile(targetBase)
if err != nil {
logger.Fatalf("failed to read %q: %s", targetBase, err.Error())
}

targets = []target{target{
path: targetBase,
contents: string(contents),
}}
logger.Fatalf("failed to list targets in dir %q: %s", targetBase, err.Error())
}

if len(targets) == 0 {
Expand All @@ -128,19 +103,19 @@ func main() {

validationErrors := make([]error, 0)

for _, t := range targets {
tmpl, ok := templates.TemplateFor(t.path)
for _, path := range targets {
tmpl, ok := templates.TemplateFor(path)
if !ok {
panic("failed to get a template for a target which was already processed")
}

err := tmpl.Validate(t.contents)
err := tmpl.Validate(path)
if err != nil {
validationErrors = append(validationErrors, fmt.Errorf("invalid boilerplate in %q: %w", t.path, err))
validationErrors = append(validationErrors, fmt.Errorf("invalid boilerplate in %q: %w", path, err))
continue
}

verboseLogger.Printf("validated %q successfully", t.path)
verboseLogger.Printf("validated %q successfully", path)
}

if len(validationErrors) == 0 {
Expand All @@ -155,26 +130,22 @@ func main() {
logger.Fatalln("at least one file had errors")
}

type target struct {
path string
contents string
}
func getTargets(targetBase string, templates boilersuite.TemplateMap, skipList []string, verboseLogger *log.Logger) ([]string, error) {
var targets []string

func isDir(path string) (bool, error) {
stat, err := os.Stat(path)
fileInfo, err := os.Stat(targetBase)
if err != nil {
return false, err
return nil, err
}
if fileInfo.Mode().IsRegular() {
if _, ok := templates.TemplateFor(targetBase); ok {
targets = append(targets, targetBase)
}
return targets, nil
}

return stat.IsDir(), nil
}

func getTargets(targetBase string, templates boilersuite.TemplateMap, skippedPrefixes []string, verboseLogger *log.Logger) ([]target, error) {
var targets []target

skipMap := make(map[string]struct{})

for _, skip := range append(skippedPrefixes, alwaysSkippedDirs...) {
for _, skip := range skipList {
skipMap[skip] = struct{}{}
}

Expand Down Expand Up @@ -221,15 +192,7 @@ func getTargets(targetBase string, templates boilersuite.TemplateMap, skippedPre
return nil
}

contents, err := os.ReadFile(path)
if err != nil {
return fmt.Errorf("failed to read %q: %w", path, err)
}

targets = append(targets, target{
path: path,
contents: string(contents),
})
targets = append(targets, path)

return nil
})
Expand Down
8 changes: 4 additions & 4 deletions templates_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,13 +51,13 @@ func Test_Templates(t *testing.T) {
continue
}

if !boilersuite.YearMarkerRegex.Match(contents) {
t.Errorf("couldn't find marker %s in %q", boilersuite.YearMarkerRegex.String(), path)
if !strings.Contains(string(contents), boilersuite.YearMarker) {
t.Errorf("couldn't find marker %s in %q", boilersuite.YearMarker, path)
continue
}

if !boilersuite.AuthorMarkerRegex.Match(contents) {
t.Errorf("couldn't find marker %s in %q", boilersuite.AuthorMarkerRegex.String(), path)
if !strings.Contains(string(contents), boilersuite.AuthorMarker) {
t.Errorf("couldn't find marker %s in %q", boilersuite.AuthorMarker, path)
continue
}

Expand Down