Skip to content
Merged
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
10 changes: 9 additions & 1 deletion pkg/app/piped/eventwatcher/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library")
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")

go_library(
name = "go_default_library",
Expand All @@ -13,3 +13,11 @@ go_library(
"@org_uber_go_zap//:go_default_library",
],
)

go_test(
name = "go_default_test",
size = "small",
srcs = ["eventwatcher_test.go"],
embed = [":go_default_library"],
deps = ["@com_github_stretchr_testify//assert:go_default_library"],
)
34 changes: 24 additions & 10 deletions pkg/app/piped/eventwatcher/eventwatcher.go
Original file line number Diff line number Diff line change
Expand Up @@ -222,16 +222,9 @@ func (w *watcher) modifyFiles(ctx context.Context, event *config.EventWatcherEve
if err != nil {
return nil, fmt.Errorf("failed to get value at %s in %s: %w", r.YAMLField, r.File, err)
}
var value string
switch vv := v.(type) {
case string:
value = vv
case int:
value = strconv.Itoa(vv)
case float64:
value = strconv.FormatFloat(vv, 'f', -1, 64)
default:
return nil, fmt.Errorf("unknown type of value is defined at %s in %s", r.YAMLField, r.File)
value, err := convertStr(v)
if err != nil {
return nil, fmt.Errorf("a value of unknown type is defined at %s in %s: %w", err, r.YAMLField, r.File)
}
if latestEvent.Data == value {
// Already up-to-date.
Expand Down Expand Up @@ -260,3 +253,24 @@ func (w *watcher) modifyFiles(ctx context.Context, event *config.EventWatcherEve
message: commitMsg,
}, nil
}

// convertStr converts a given value into a string.
func convertStr(value interface{}) (out string, err error) {
switch v := value.(type) {
case string:
out = v
case int:
out = strconv.Itoa(v)
case int64:
out = strconv.FormatInt(v, 10)
case uint64:
out = strconv.FormatUint(v, 10)
case float64:
out = strconv.FormatFloat(v, 'f', -1, 64)
case bool:
out = strconv.FormatBool(v)
default:
err = fmt.Errorf("failed to convert %T into string", v)
}
return
}
80 changes: 80 additions & 0 deletions pkg/app/piped/eventwatcher/eventwatcher_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
// Copyright 2021 The PipeCD Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package eventwatcher

import (
"testing"

"github.com/stretchr/testify/assert"
)

func TestGetValue(t *testing.T) {
testcases := []struct {
name string
value interface{}
want string
wantErr bool
}{
{
name: "string",
value: "value",
want: "value",
wantErr: false,
},
{
name: "int",
value: 1,
want: "1",
wantErr: false,
},
{
name: "int64",
value: int64(1),
want: "1",
wantErr: false,
},
{
name: "uint64",
value: uint64(1),
want: "1",
wantErr: false,
},
{
name: "float64",
value: 1.1,
want: "1.1",
wantErr: false,
},
{
name: "bool",
value: true,
want: "true",
wantErr: false,
},
{
name: "map",
value: make(map[string]interface{}),
want: "",
wantErr: true,
},
}
for _, tc := range testcases {
t.Run(tc.name, func(t *testing.T) {
got, err := convertStr(tc.value)
assert.Equal(t, tc.wantErr, err != nil)
assert.Equal(t, tc.want, got)
})
}
}
7 changes: 6 additions & 1 deletion pkg/yamlprocessor/yamlprocessor.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ import (
"github.com/goccy/go-yaml/parser"
)

// GetValue gives back the value placed at a given path.
// GetValue gives back the value placed at a given path. The type of
// returned value can be string, int64, uint64, float64, bool, and []interface{}.
//
// The path requires to start with "$" which represents the root element.
// Available operators are:
Expand All @@ -48,6 +49,10 @@ func GetValue(yml []byte, path string) (interface{}, error) {
return nil, err
}

// TODO: Validate value in YAML before actual reading
// because it panics if:
// - the value is -0.
// - unexistence path given.
var value interface{}
if err := p.Read(bytes.NewReader(yml), &value); err != nil {
return nil, err
Expand Down
21 changes: 19 additions & 2 deletions pkg/yamlprocessor/yamlprocessor_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,13 @@ func TestGetValue(t *testing.T) {
want: uint64(1),
wantErr: false,
},
{
name: "given a int64 path",
yml: "foo: -1",
path: "$.foo",
want: int64(-1),
wantErr: false,
},
{
name: "given a float64 path",
yml: "foo: 1.5",
Expand All @@ -87,7 +94,7 @@ func TestGetValue(t *testing.T) {
wantErr: false,
},
{
name: "given a array path",
name: "given an array path",
yml: `
foo:
- bar: 1`,
Expand All @@ -96,7 +103,17 @@ foo:
wantErr: false,
},
{
name: "given a array path with wildcard",
name: "given an entire array path",
yml: `
foo:
- bar: 1
- baz: 2`,
path: "$.foo",
want: []interface{}{map[string]interface{}{"bar": uint64(1)}, map[string]interface{}{"baz": uint64(2)}},
wantErr: false,
},
{
name: "given an entire array path with wildcard",
yml: `
foo:
- bar: 1
Expand Down