From 615df880d3f7d93b713a53d0f68f361795b9c06c Mon Sep 17 00:00:00 2001 From: Gabriele Fontana <gafreax@gmail.com> Date: Sun, 24 Nov 2024 21:52:57 +0100 Subject: [PATCH] Feat/add contain value rule (#103) * feat(add-contain-value-rule): add contain_value expression * refactor(add-contain-value-rule): renaming * test(add-contain-value-rule): add test for contain_value expression * feat(add-contain-value-rule): add fileThatContainValue schema definition * feat(add-contain-value-rule): add Value field in That type * test(add-contain-value-rule): add taht contain rule example --- api/config_schema.json | 17 ++++++ examples/.goarkitect.yaml | 12 +++++ internal/arch/file/that/contain_value.go | 43 +++++++++++++++ internal/arch/file/that/contain_value_test.go | 52 +++++++++++++++++++ internal/config/executor.go | 4 ++ 5 files changed, 128 insertions(+) create mode 100644 internal/arch/file/that/contain_value.go create mode 100644 internal/arch/file/that/contain_value_test.go diff --git a/api/config_schema.json b/api/config_schema.json index 3edb181..72b84c2 100644 --- a/api/config_schema.json +++ b/api/config_schema.json @@ -96,6 +96,23 @@ "folder" ] }, + "fileThatContainValue": { + "type": "object", + "additionalProperties": false, + "properties": { + "kind": { + "type": "string", + "pattern": "^contain_value$" + }, + "value": { + "type": "string" + } + }, + "required": [ + "kind", + "value" + ] + }, "fileThatEndWith": { "type": "object", "additionalProperties": false, diff --git a/examples/.goarkitect.yaml b/examples/.goarkitect.yaml index 7413639..0767edb 100644 --- a/examples/.goarkitect.yaml +++ b/examples/.goarkitect.yaml @@ -69,3 +69,15 @@ rules: - kind: end_with suffix: file because: "it is an example" + - name: a set of file that contains .go must be go file (end with .go) + kind: file + matcher: + kind: all + thats: + - kind: contain_value + value: .go + excepts: [] + shoulds: + - kind: end_with + suffix: .go + because: "it is an example " diff --git a/internal/arch/file/that/contain_value.go b/internal/arch/file/that/contain_value.go new file mode 100644 index 0000000..c2f0b2e --- /dev/null +++ b/internal/arch/file/that/contain_value.go @@ -0,0 +1,43 @@ +package that + +import ( + "strings" + + "github.com/omissis/goarkitect/internal/arch/file" + "github.com/omissis/goarkitect/internal/arch/rule" +) + +func ContainValue(s string) *ContainValueExpression { + return &ContainValueExpression{ + value: s, + } +} + +type ContainValueExpression struct { + value string + + errors []error +} + +func (e *ContainValueExpression) GetErrors() []error { + return e.errors +} + +func (e *ContainValueExpression) Evaluate(rb rule.Builder) { + frb, ok := rb.(*file.RuleBuilder) + if !ok { + e.errors = append(e.errors, file.ErrInvalidRuleBuilder) + + return + } + + files := make([]string, 0) + + for _, f := range frb.GetFiles() { + if strings.Contains(f, e.value) { + files = append(files, f) + } + } + + frb.SetFiles(files) +} diff --git a/internal/arch/file/that/contain_value_test.go b/internal/arch/file/that/contain_value_test.go new file mode 100644 index 0000000..2ea34e2 --- /dev/null +++ b/internal/arch/file/that/contain_value_test.go @@ -0,0 +1,52 @@ +package that_test + +import ( + "testing" + + "github.com/google/go-cmp/cmp" + "github.com/google/go-cmp/cmp/cmpopts" + + "github.com/omissis/goarkitect/internal/arch/file" + "github.com/omissis/goarkitect/internal/arch/file/that" + "github.com/omissis/goarkitect/internal/arch/rule" +) + +func Test_ContainValue(t *testing.T) { + t.Parallel() + + rb := func() *file.RuleBuilder { + rb := file.All() + rb.SetFiles([]string{"Dockerfile", "Makefile", "foo/bar.go"}) + + return rb + } + + testCases := []struct { + desc string + ruleBuilder *file.RuleBuilder + value string + want []string + }{ + { + desc: "files contains value 'foo'", + ruleBuilder: rb(), + value: "foo", + want: []string{"foo/bar.go"}, + }, + } + for _, tC := range testCases { + tC := tC + + t.Run(tC.desc, func(t *testing.T) { + t.Parallel() + + ew := that.ContainValue(tC.value) + ew.Evaluate(tC.ruleBuilder) + + got := tC.ruleBuilder.GetFiles() + if !cmp.Equal(got, tC.want, cmp.AllowUnexported(rule.Violation{}), cmpopts.EquateEmpty()) { + t.Errorf("want = %+v, got = %+v", tC.want, got) + } + }) + } +} diff --git a/internal/config/executor.go b/internal/config/executor.go index 00b64fe..99c14d3 100644 --- a/internal/config/executor.go +++ b/internal/config/executor.go @@ -44,6 +44,7 @@ type That struct { Folder string `json:"folder" yaml:"folder"` Recursive bool `json:"recursive" yaml:"recursive"` Suffix string `json:"suffix" yaml:"suffix"` + Value string `json:"value" yaml:"value"` } type Except struct { Kind string `json:"kind" yaml:"kind"` @@ -158,6 +159,9 @@ func applyThats(rb *file.RuleBuilder, ts []That) error { case "end_with": rb.That(ft.EndWith(t.Suffix)) + case "contain_value": + rb.That(ft.ContainValue(t.Value)) + default: return fmt.Errorf("'%s': %w", t.Kind, ErrUnknonwnThat) }