diff --git a/.golangci.yaml b/.golangci.yaml index 40ca9a6..8c3d50f 100644 --- a/.golangci.yaml +++ b/.golangci.yaml @@ -1,37 +1,19 @@ # Options for analysis running. -run: - # The default concurrency value is the number of available CPU. - concurrency: 4 - # Timeout for analysis, e.g. 30s, 5m. - # Default: 1m - timeout: 30s - # Exit code when at least one issue was found. - # Default: 1 - issues-exit-code: 2 - # Include test files or not. - # Default: true - tests: false - # Which dirs to skip: issues from them won't be reported. - # Can use regexp here: `generated.*`, regexp is applied on full path, - # including the path prefix if one is set. - # Default value is empty list, - # but default dirs are skipped independently of this option's value (see skip-dirs-use-default). - # "/" will be replaced by current OS file path separator to properly work on Windows. - skip-dirs: - - example - # Enables skipping of directories: - # - vendor$, third_party$, testdata$, examples$, Godeps$, builtin$ - # Default: true - skip-dirs-use-default: false - # If set we pass it to "go list -mod={option}". From "go help modules": - # If invoked with -mod=readonly, the go command is disallowed from the implicit - # automatic updating of go.mod described above. Instead, it fails when any changes - # to go.mod are needed. This setting is most useful to check that go.mod does - # not need updates, such as in a continuous integration and testing system. - # If invoked with -mod=vendor, the go command assumes that the vendor - # directory holds the correct copies of dependencies and ignores - # the dependency descriptions in go.mod. - # - # Allowed values: readonly|vendor|mod - # By default, it isn't set. - modules-download-mode: readonly \ No newline at end of file +version: "2" +linters: + enable: + - cyclop + - nestif + - bodyclose + - iface + - gosec + + exclusions: + paths: "example/*" + rules: + - path: '(.+)_test\.go' + linters: + - gosec + + + diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..13566b8 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/.idea/golinter.xml b/.idea/golinter.xml new file mode 100644 index 0000000..00b449d --- /dev/null +++ b/.idea/golinter.xml @@ -0,0 +1,7 @@ + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..8f6abd5 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/pyrotic.iml b/.idea/pyrotic.iml new file mode 100644 index 0000000..5e764c4 --- /dev/null +++ b/.idea/pyrotic.iml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..35eb1dd --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/go.mod b/go.mod index caf9679..1933540 100644 --- a/go.mod +++ b/go.mod @@ -1,13 +1,13 @@ module github.com/code-gorilla-au/pyrotic -go 1.24.1 +go 1.24.4 require ( github.com/code-gorilla-au/odize v1.3.4 github.com/gobuffalo/flect v1.0.3 github.com/mattn/go-isatty v0.0.20 github.com/spf13/cobra v1.9.1 - golang.org/x/text v0.25.0 + golang.org/x/text v0.26.0 ) require ( diff --git a/go.sum b/go.sum index fc489c1..2000b32 100644 --- a/go.sum +++ b/go.sum @@ -32,8 +32,8 @@ github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXl golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20= golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= -golang.org/x/text v0.25.0 h1:qVyWApTSYLk/drJRO5mDlNYskwQznZmkpV2c8q9zls4= -golang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA= +golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M= +golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= diff --git a/internal/engine/engine.go b/internal/engine/engine.go index 693c3ea..4cb2aa4 100644 --- a/internal/engine/engine.go +++ b/internal/engine/engine.go @@ -45,7 +45,7 @@ func (c *Core) Generate(data Data) error { } for _, item := range parsedOutput { - switch item.ParseData.Action { + switch item.Action { case parser.ActionAppend: if err := c.fwr.AppendFile(item.To, item.Output); err != nil { log.Println("error appending file ", err) diff --git a/internal/parser/errors.go b/internal/parser/errors.go index 679ebbd..e78709f 100644 --- a/internal/parser/errors.go +++ b/internal/parser/errors.go @@ -5,4 +5,5 @@ import "errors" var ( ErrParsingBool = errors.New("unable to parse bool") ErrMalformedTemplate = errors.New("malformed template data") + ErrNoMatchingField = errors.New("no matching field") ) diff --git a/internal/parser/lexer.go b/internal/parser/lexer.go index 86820b2..0c3109c 100644 --- a/internal/parser/lexer.go +++ b/internal/parser/lexer.go @@ -70,7 +70,7 @@ func generateParseData(tmplName string, meta []string, data TemplateData, funcs parsedMeta = append(parsedMeta, buf.String()) } - return hydrateData(parsedMeta, data) + return hydrateTemplateData(parsedMeta, data) } @@ -98,49 +98,45 @@ func generateTemplate(tmplName, tmplOutput string, data TemplateData, funcs temp return buf.Bytes(), nil } -func hydrateData(meta []string, data TemplateData) (TemplateData, error) { +func hydrateTemplateData(meta []string, data TemplateData) (TemplateData, error) { result := TemplateData{ Name: data.Name, ParseData: data.ParseData, } - result.ParseData.Action = ActionCreate + result.Action = ActionCreate tmp := map[string]string{} for _, item := range meta { + tokens := strings.Split(strings.TrimSpace(item), tokenColon) if len(tokens) != 2 { return result, fmt.Errorf("%w : %s", ErrMalformedTemplate, item) } - switch strings.TrimSpace(tokens[0]) { - case fieldTo: - result.To = strings.TrimSpace(tokens[1]) - case fieldAfter: - result.ParseData.InjectClause = InjectAfter - result.ParseData.InjectMatcher = strings.TrimSpace(tokens[1]) - case fieldBefore: - result.ParseData.InjectClause = InjectBefore - result.ParseData.InjectMatcher = strings.TrimSpace(tokens[1]) - case fieldAppend: - result.ParseData.Action = ActionAppend - stringAppend := strings.TrimSpace(tokens[1]) - if _, err := strconv.ParseBool(stringAppend); err != nil { - return result, ErrParsingBool - } - case fieldInject: - result.ParseData.Action = ActionInject - stringAppend := strings.TrimSpace(tokens[1]) - if _, err := strconv.ParseBool(stringAppend); err != nil { - return result, ErrParsingBool - } - default: - key := strings.TrimSpace(tokens[0]) - tmp[key] = strings.TrimSpace(tokens[1]) + field := strings.ToLower(strings.TrimSpace(tokens[0])) + value := strings.TrimSpace(tokens[1]) + + if !hasMatchingField(field) { + key := field + tmp[key] = value + continue + } + + if field == fieldTo { + result.To = value + continue } + + var err error + result.ParseData, err = extractParsedData(field, value, result.ParseData) + if err != nil { + return result, err + } + } // this will override any values pre-defined in the template, - // this is intended so you are able to have "sane defaults" as well as override via cmd + // this is intended, so you are able to have "sane defaults" as well as override via cmd for key, value := range data.Meta { tmp[key] = value } @@ -149,10 +145,36 @@ func hydrateData(meta []string, data TemplateData) (TemplateData, error) { return result, nil } +func extractParsedData(field, value string, result ParseData) (ParseData, error) { + + switch field { + case fieldAfter: + result.InjectClause = InjectAfter + result.InjectMatcher = value + case fieldBefore: + result.InjectClause = InjectBefore + result.InjectMatcher = value + case fieldAppend: + result.Action = ActionAppend + stringAppend := value + if _, err := strconv.ParseBool(stringAppend); err != nil { + return result, ErrParsingBool + } + case fieldInject: + result.Action = ActionInject + stringAppend := value + if _, err := strconv.ParseBool(stringAppend); err != nil { + return result, ErrParsingBool + } + } + + return result, nil +} + func extractMetaDataFromTemplate(template string) ([]string, string) { rawOut := strings.Split(template, tokenNewLine) - meta := []string{} - output := []string{} + var meta []string + var output []string count := 0 for index, s := range rawOut { trimmed := strings.TrimSpace(s) @@ -171,3 +193,16 @@ func extractMetaDataFromTemplate(template string) ([]string, string) { } return meta, strings.Join(output, tokenNewLine) } + +func hasMatchingField(maybeField string) bool { + repo := map[string]struct{}{ + fieldTo: {}, + fieldAppend: {}, + fieldInject: {}, + fieldAfter: {}, + fieldBefore: {}, + } + + _, ok := repo[maybeField] + return ok +} diff --git a/internal/parser/lexer_test.go b/internal/parser/lexer_test.go index b62658b..5cfc285 100644 --- a/internal/parser/lexer_test.go +++ b/internal/parser/lexer_test.go @@ -224,7 +224,7 @@ func Test_hydrateData(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - got, err := hydrateData(tt.args.meta, tt.args.data) + got, err := hydrateTemplateData(tt.args.meta, tt.args.data) if tt.wantErr { odize.AssertTrue(t, errors.Is(err, tt.err)) } @@ -265,7 +265,7 @@ func Test_extractMeta(t *testing.T) { to: foo `, }, - meta: []string{}, + meta: nil, output: "", }, { @@ -285,10 +285,10 @@ func Test_extractMeta(t *testing.T) { t.Run(tt.name, func(t *testing.T) { got, got1 := extractMetaDataFromTemplate(tt.args.output) if !reflect.DeepEqual(got, tt.meta) { - t.Errorf("extractMeta() got = %v, want %v", got, tt.meta) + t.Errorf("extractMetaDataFromTemplate() got = %v, want %v", got, tt.meta) } if strings.TrimSpace(got1) != tt.output { - t.Errorf("extractMeta() got1 = %v, want %v", got1, tt.output) + t.Errorf("extractMetaDataFromTemplate() got1 = %v, want %v", got1, tt.output) } }) } diff --git a/scripts/lints.mk b/scripts/lints.mk index 9ac9539..b87e11d 100644 --- a/scripts/lints.mk +++ b/scripts/lints.mk @@ -7,7 +7,6 @@ lint: ## Lint tools golangci-lint run ./... scan: ## Security scanning - gosec ./... govulncheck ./... trivy: ## Trivy secrets scanning diff --git a/scripts/tools.mk b/scripts/tools.mk index f780fb9..77eb5df 100644 --- a/scripts/tools.mk +++ b/scripts/tools.mk @@ -1,5 +1,4 @@ get-tools: ## Get tools used go install golang.org/x/vuln/cmd/govulncheck@latest - go install github.com/securego/gosec/v2/cmd/gosec@latest - go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest \ No newline at end of file + go install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@v2.2.2 \ No newline at end of file