From 78b27e28d947ffcc903e9cdc0d7b0da5d3d92ee0 Mon Sep 17 00:00:00 2001 From: Gavin Staniforth Date: Wed, 3 Nov 2021 22:08:10 +0000 Subject: [PATCH 1/2] refactor: add version tests to be more defensive --- Makefile | 2 +- .../gitops-commit/slackhttp/handler_test.go | 20 ++--- internal/pkg/gitops/version.go | 2 +- internal/pkg/gitops/version_test.go | 90 +++++++++++++++++++ 4 files changed, 102 insertions(+), 12 deletions(-) create mode 100644 internal/pkg/gitops/version_test.go diff --git a/Makefile b/Makefile index 836a9a1..d9178aa 100644 --- a/Makefile +++ b/Makefile @@ -8,7 +8,7 @@ lint: golangci-lint run tests: - go test ./... + go test -v ./... coverage: go test -coverprofile=coverage.out ./... && go tool cover -html=coverage.out diff --git a/internal/app/gitops-commit/slackhttp/handler_test.go b/internal/app/gitops-commit/slackhttp/handler_test.go index 75edc71..0d51808 100644 --- a/internal/app/gitops-commit/slackhttp/handler_test.go +++ b/internal/app/gitops-commit/slackhttp/handler_test.go @@ -13,25 +13,25 @@ func Test_handleSlackCommand(t *testing.T) { s := &server{} r := &NamedRepositoryRegistry{} - tests := []struct{ - name string + tests := []struct { + name string command string - expect string + expect string }{ { - name: "when using missing bits", + name: "when using missing bits", command: "totally wrong", - expect: "Incorrect usage, expected /gitops-commit [command] [name] [tag]", + expect: "Incorrect usage, expected /gitops-commit [command] [name] [tag]", }, { - name: "when using an invalid command", + name: "when using an invalid command", command: "wrong thing v1.2.3", - expect: "Unknown command 'wrong', expected /gitops-commit [command] [name] [tag]", + expect: "Unknown command 'wrong', expected /gitops-commit [command] [name] [tag]", }, { - name: "when using a valid command ", + name: "when using a valid command ", command: "deploy thing v1.2.3", - expect: "Unknown named repository, cannot handle \"thing\", availabe options ()", + expect: "Unknown named repository, cannot handle \"thing\", availabe options ()", }, } @@ -64,4 +64,4 @@ func Test_handleSlackCommand(t *testing.T) { }) } }) -} \ No newline at end of file +} diff --git a/internal/pkg/gitops/version.go b/internal/pkg/gitops/version.go index b91c72e..fe57e79 100644 --- a/internal/pkg/gitops/version.go +++ b/internal/pkg/gitops/version.go @@ -15,7 +15,7 @@ func ReadCurrentVersion(f []byte, notation string) (string, error) { data := make(map[string]interface{}) err := yaml.Unmarshal(f, &data) - if err != nil { + if err != nil || len(data) <= 0 { return "", fmt.Errorf("unvalid valid: %w", err) } diff --git a/internal/pkg/gitops/version_test.go b/internal/pkg/gitops/version_test.go new file mode 100644 index 0000000..d7f27e1 --- /dev/null +++ b/internal/pkg/gitops/version_test.go @@ -0,0 +1,90 @@ +package gitops + +import ( + "fmt" + "gopkg.in/yaml.v3" + "testing" +) + +func TestReadCurrentVersion(t *testing.T) { + type args struct { + f []byte + notation string + } + + tests := []struct { + name string + args args + want string + wantErr bool + }{ + { + name: "empty file", + args: args{ + f: []byte(""), + notation: "test.test", + }, + want: "", + wantErr: true, + }, + { + name: "invalid yaml", + args: args{ + f: []byte("wibble&&3..\nfff"), + notation: "image.tag", + }, + want: "", + wantErr: true, + }, + { + name: "simple yaml", + args: args{ + f: createSimpleYaml("v1.2.99"), + notation: "image.tag", + }, + want: "v1.2.99", + wantErr: false, + }, + { + name: "invalid notation to yaml", + args: args{ + f: createSimpleYaml("v1.2.99"), + notation: "image.nope", + }, + want: "", + wantErr: true, + }, + } + + fmt.Println(string(createSimpleYaml("v1.2.99"))) + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := ReadCurrentVersion(tt.args.f, tt.args.notation) + if (err != nil) != tt.wantErr { + t.Errorf("ReadCurrentVersion() error = %v, wantErr %v", err, tt.wantErr) + return + } + if got != tt.want { + t.Errorf("ReadCurrentVersion() got = %v, want %v", got, tt.want) + } + }) + } +} + +func createSimpleYaml(t string) []byte { + type tag struct { + Tag string `yaml:"tag"` + } + + marshal, err := yaml.Marshal(&struct { + Image tag `yaml:"image"` + }{ + Image: tag{Tag: t}, + }) + if err != nil { + return nil + } + + return marshal +} From 47607bba7b6eb1acc85f4f02dc7f4c86faaa4948 Mon Sep 17 00:00:00 2001 From: Gavin Staniforth Date: Wed, 3 Nov 2021 23:15:45 +0000 Subject: [PATCH 2/2] feat(yaml): support array notation within yaml --- internal/pkg/gitops/version.go | 25 +++++++++++++++++++++ internal/pkg/gitops/version_test.go | 34 +++++++++++++++++++++++++---- 2 files changed, 55 insertions(+), 4 deletions(-) diff --git a/internal/pkg/gitops/version.go b/internal/pkg/gitops/version.go index fe57e79..c21403f 100644 --- a/internal/pkg/gitops/version.go +++ b/internal/pkg/gitops/version.go @@ -6,6 +6,8 @@ import ( "fmt" "gopkg.in/yaml.v3" "io/ioutil" + "regexp" + "strconv" "strings" ) @@ -41,8 +43,31 @@ func WriteVersion(f []byte, version string, newVersion string, filename string) func unwrapYaml(yaml map[string]interface{}, notion string) (string, error) { d := yaml + r := regexp.MustCompile(`\d+]$`) for _, k := range strings.Split(notion, ".") { + if r.MatchString(k) { + idx := r.FindString(k)[:1] + + if len(idx) > 0 { + i, err := strconv.ParseInt(idx, 10, 8) + + if err != nil { + return "", err + } + + k = k[:len(k)-int(i)] + + if a, ok := d[k].([]interface{}); ok { + if b, ok := a[i].(map[string]interface{}); ok { + d = b + + continue + } + } + } + } + if _, ok := d[k]; !ok { return "", fmt.Errorf("unable to find %s in yaml", notion) } diff --git a/internal/pkg/gitops/version_test.go b/internal/pkg/gitops/version_test.go index d7f27e1..bccf74a 100644 --- a/internal/pkg/gitops/version_test.go +++ b/internal/pkg/gitops/version_test.go @@ -30,7 +30,7 @@ func TestReadCurrentVersion(t *testing.T) { { name: "invalid yaml", args: args{ - f: []byte("wibble&&3..\nfff"), + f: []byte("wibble&&3..\nfff"), notation: "image.tag", }, want: "", @@ -39,7 +39,7 @@ func TestReadCurrentVersion(t *testing.T) { { name: "simple yaml", args: args{ - f: createSimpleYaml("v1.2.99"), + f: createSimpleYaml("v1.2.99"), notation: "image.tag", }, want: "v1.2.99", @@ -48,15 +48,24 @@ func TestReadCurrentVersion(t *testing.T) { { name: "invalid notation to yaml", args: args{ - f: createSimpleYaml("v1.2.99"), + f: createSimpleYaml("v1.2.99"), notation: "image.nope", }, want: "", wantErr: true, }, + { + name: "array notation", + args: args{ + f: createSimpleArrayYaml("v1.9"), + notation: "images[3].tag", + }, + want: "v1.9", + wantErr: false, + }, } - fmt.Println(string(createSimpleYaml("v1.2.99"))) + fmt.Println(string(createSimpleArrayYaml("v1.2.99"))) for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { @@ -88,3 +97,20 @@ func createSimpleYaml(t string) []byte { return marshal } + +func createSimpleArrayYaml(t string) []byte { + type tag struct { + Tag string `yaml:"tag"` + } + + marshal, err := yaml.Marshal(&struct { + Images []tag `yaml:"images"` + }{ + Images: []tag{{Tag: "v1"},{Tag: "v2"},{Tag: "v3"},{Tag: t}}, + }) + if err != nil { + return nil + } + + return marshal +}