This is an automated email from the ASF dual-hosted git repository.
warren pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/incubator-devlake.git
The following commit(s) were added to refs/heads/main by this push:
new 0b4fd423 feat: support more viper data type
0b4fd423 is described below
commit 0b4fd42341f3fb01f3a4470d95b12f8fc51fa626
Author: fatelei <[email protected]>
AuthorDate: Tue May 24 16:46:24 2022 +0800
feat: support more viper data type
---
go.sum | 5 +-
plugins/helper/config_util.go | 83 +++++++++++++++++++++++++++-----
plugins/helper/config_util_test.go | 99 +++++++++++++++++++++++++++++++++++++-
3 files changed, 172 insertions(+), 15 deletions(-)
diff --git a/go.sum b/go.sum
index d4b04279..b9e4de6d 100644
--- a/go.sum
+++ b/go.sum
@@ -118,11 +118,11 @@ github.com/fsnotify/fsnotify v1.5.1/go.mod
h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5
github.com/ghodss/yaml v1.0.0/go.mod
h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/gin-contrib/cors v1.3.1
h1:doAsuITavI4IOcd0Y19U4B+O0dNWihRyX//nn4sEmgA=
github.com/gin-contrib/cors v1.3.1/go.mod
h1:jjEJ4268OPZUcU7k9Pm653S7lXUGcqMADzFA61xsmDk=
+github.com/gin-contrib/gzip v0.0.5
h1:mhnVU32YnnBh2LPH2iqRqsA/eR7SAqRaD388jL2s/j0=
github.com/gin-contrib/gzip v0.0.5/go.mod
h1:OPIK6HR0Um2vNmBUTlayD7qle4yVVRZT0PyhdUigrKk=
github.com/gin-contrib/sse v0.1.0
h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
github.com/gin-contrib/sse v0.1.0/go.mod
h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
github.com/gin-gonic/gin v1.5.0/go.mod
h1:Nd6IXA8m5kNZdNEHMBd93KT+mdY3+bewLgRvmCsR2Do=
-github.com/gin-gonic/gin v1.7.4 h1:QmUZXrvJ9qZ3GfWvQ+2wnW/1ePrTEJqPKMYEU3lD/DM=
github.com/gin-gonic/gin v1.7.4/go.mod
h1:jD2toBW3GZUr5UMcdrwQA10I7RuaFOl/SGeDjXkfUtY=
github.com/gin-gonic/gin v1.7.7 h1:3DoBmSbJbZAWqXJC3SLjAPfutPJJRN1U5pALB7EeTTs=
github.com/gin-gonic/gin v1.7.7/go.mod
h1:axIBovoeJpVj8S3BwE0uPMTeReE4+AfFtqpqaZ1qq1U=
@@ -458,6 +458,7 @@ github.com/onsi/gomega v1.10.1/go.mod
h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1y
github.com/onsi/gomega v1.10.3 h1:gph6h/qe9GSUw1NhH1gp+qb+h8rXD8Cy60Z32Qw3ELA=
github.com/onsi/gomega v1.10.3/go.mod
h1:V9xEwhxec5O8UDM77eCW8vLymOMltsqPVYWrpDsH8xc=
github.com/opentracing/opentracing-go v1.1.0/go.mod
h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
+github.com/otiai10/copy v1.7.0 h1:hVoPiN+t+7d2nzzwMiDHPSOogsWAStewq3TwU05+clE=
github.com/otiai10/copy v1.7.0/go.mod
h1:rmRl6QPdJj6EiUqXQ/4Nn2lLXoNQjFCQbbNrxgc/t3U=
github.com/otiai10/curr v0.0.0-20150429015615-9b4961190c95/go.mod
h1:9qAhocn7zKJG+0mI8eUu6xqkFDYS2kb2saOteoSB3cE=
github.com/otiai10/curr v1.0.0/go.mod
h1:LskTG5wDwr8Rs+nNQ+1LlxRjAtTZZjtJW4rMXl6j4vs=
@@ -647,6 +648,7 @@ golang.org/x/mod v0.2.0/go.mod
h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
+golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod
h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod
h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -691,7 +693,6 @@ golang.org/x/net v0.0.0-20210326060303-6b1517762897/go.mod
h1:uSPa2vr4CLtc/ILN5o
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod
h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/net v0.0.0-20210421230115-4e50805a0758/go.mod
h1:72T/g9IO56b78aLF+1Kcs5dz7/ng1VjMUvfKvpfy+jM=
golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod
h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
-golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd
h1:O7DYs+zxREGLKzKoMQrtrEacpb0ZVXA5rIwylE2Xchk=
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod
h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4
h1:HVyaeDAYux4pnY+D/SiwmLOR36ewZ4iGQIIrtnuCjFA=
golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod
h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
diff --git a/plugins/helper/config_util.go b/plugins/helper/config_util.go
index 49d2abf4..65a51a3c 100644
--- a/plugins/helper/config_util.go
+++ b/plugins/helper/config_util.go
@@ -18,10 +18,12 @@ limitations under the License.
package helper
import (
+ "fmt"
+ "reflect"
+
"github.com/go-playground/validator/v10"
"github.com/mitchellh/mapstructure"
"github.com/spf13/viper"
- "reflect"
)
// DecodeStruct validates `input` struct with `validator` and set it into viper
@@ -46,7 +48,7 @@ func DecodeStruct(output *viper.Viper, input interface{},
data map[string]interf
vf := reflect.ValueOf(input)
if vf.Kind() != reflect.Ptr {
- panic("input is not a pointer")
+ return fmt.Errorf("input %v is not a pointer", input)
}
tf := reflect.Indirect(vf).Type()
fieldTags := make([]string, 0)
@@ -70,13 +72,34 @@ func DecodeStruct(output *viper.Viper, input interface{},
data map[string]interf
continue
}
vfField := vf.Elem().FieldByName(fieldName)
- switch fieldType.String() {
- case "string":
+ switch fieldType.Kind() {
+ case reflect.String:
output.Set(fieldTag, vfField.String())
- case "int", "int64":
+ case reflect.Int, reflect.Int64:
output.Set(fieldTag, vfField.Int())
- case "float64":
+ case reflect.Float64, reflect.Float32:
output.Set(fieldTag, vfField.Float())
+ case reflect.Bool:
+ output.Set(fieldTag, vfField.Bool())
+ case reflect.Slice:
+ elemType := vfField.Type().Elem().Kind()
+ switch elemType {
+ case reflect.String:
+ output.Set(fieldTag,
vfField.Interface().([]string))
+ case reflect.Int:
+ output.Set(fieldTag,
vfField.Interface().([]int))
+ }
+ case reflect.Map:
+ keyType := vfField.Type().Key().Kind()
+ elemType := vfField.Type().Elem().Kind()
+ if keyType == reflect.String {
+ switch elemType {
+ case reflect.String:
+ output.Set(fieldTag,
vfField.Interface().(map[string]string))
+ case reflect.Interface:
+ output.Set(fieldTag,
vfField.Interface().(map[string]interface{}))
+ }
+ }
default:
}
}
@@ -89,7 +112,7 @@ func DecodeStruct(output *viper.Viper, input interface{},
data map[string]interf
func EncodeStruct(input *viper.Viper, output interface{}, tag string) error {
vf := reflect.ValueOf(output)
if vf.Kind() != reflect.Ptr {
- panic("output is not a pointer")
+ return fmt.Errorf("output %v is not a pointer", output)
}
tf := reflect.Indirect(vf).Type()
fieldTags := make([]string, 0)
@@ -113,13 +136,51 @@ func EncodeStruct(input *viper.Viper, output interface{},
tag string) error {
continue
}
vfField := vf.Elem().FieldByName(fieldName)
- switch fieldType.String() {
- case "string":
+ switch fieldType.Kind() {
+ case reflect.String:
vfField.SetString(input.GetString(fieldTag))
- case "int", "int64":
+ case reflect.Int, reflect.Int64:
vfField.SetInt(input.GetInt64(fieldTag))
- case "float64":
+ case reflect.Float64:
vfField.SetFloat(input.GetFloat64(fieldTag))
+ case reflect.Bool:
+ vfField.SetBool(input.GetBool(fieldTag))
+ case reflect.Slice:
+ elem := vfField.Type().Elem()
+ switch elem.Kind() {
+ case reflect.String:
+ value := input.GetStringSlice(fieldTag)
+ stringSlice :=
reflect.MakeSlice(reflect.SliceOf(elem), 0, len(value))
+ for _, item := range value {
+ stringSlice =
reflect.Append(stringSlice, reflect.ValueOf(item))
+ }
+ vfField.Set(stringSlice)
+ case reflect.Int:
+ value := input.GetIntSlice(fieldTag)
+ intSlice :=
reflect.MakeSlice(reflect.SliceOf(elem), 0, len(value))
+ for _, item := range value {
+ intSlice = reflect.Append(intSlice,
reflect.ValueOf(item))
+ }
+ vfField.Set(intSlice)
+ }
+ case reflect.Map:
+ key := vfField.Type().Key()
+ elem := vfField.Type().Elem()
+ if key.Kind() == reflect.String {
+ mapType := reflect.MapOf(key, elem)
+ data := reflect.MakeMap(mapType)
+ switch elem.Kind() {
+ case reflect.String:
+ for k, value := range
input.GetStringMapString(fieldTag) {
+
data.SetMapIndex(reflect.ValueOf(k), reflect.ValueOf(value))
+ }
+ case reflect.Interface:
+ for k, value := range
input.GetStringMap(fieldTag) {
+
data.SetMapIndex(reflect.ValueOf(k), reflect.ValueOf(value))
+ }
+ }
+ vfField.Set(data)
+ }
default:
}
}
diff --git a/plugins/helper/config_util_test.go
b/plugins/helper/config_util_test.go
index 0ddb21f6..1332d940 100644
--- a/plugins/helper/config_util_test.go
+++ b/plugins/helper/config_util_test.go
@@ -20,8 +20,9 @@ package helper
import (
"testing"
- "github.com/apache/incubator-devlake/config"
"github.com/stretchr/testify/assert"
+
+ "github.com/apache/incubator-devlake/config"
)
type TestStruct struct {
@@ -32,6 +33,17 @@ type TestStruct struct {
F5 string `env:"TEST_F5"`
}
+type TestComplexStruct struct {
+ F1 string `env:"TEST_F1"`
+ F2 int `env:"TEST_F2"`
+ F3 float64 `env:"TEST_F3" mapstructure:"TEST_F3"`
+ F4 []int `env:"TEST_F4"`
+ F5 []string `env:"TEST_F5"`
+ F6 bool `env:"TEST_F6"`
+ F7 map[string]string `env:"TEST_F7"`
+ F8 map[string]interface{} `env:"TEST_F8"`
+}
+
func TestSaveToConfig(t *testing.T) {
ts := TestStruct{
F1: "123",
@@ -54,16 +66,99 @@ func TestSaveToConfig(t *testing.T) {
assert.Equal(t, v4, "Test")
}
+func TestSaveToComplexityConfig(t *testing.T) {
+ ts := TestComplexStruct{
+ F1: "123",
+ F2: 76,
+ F3: 1.23,
+ F4: []int{1, 2, 3},
+ F5: []string{"a", "b", "c"},
+ F6: true,
+ F7: map[string]string{
+ "foo": "bar",
+ },
+ F8: map[string]interface{}{
+ "foo1": "bar1",
+ },
+ }
+ data := make(map[string]interface{})
+
+ v := config.GetConfig()
+ assert.Nil(t, DecodeStruct(v, &ts, data, "env"))
+ v1 := v.GetString("TEST_F1")
+ assert.Equal(t, v1, "123")
+ v2 := v.GetInt("TEST_F2")
+ assert.Equal(t, v2, 76)
+ v3 := v.GetFloat64("TEST_F3")
+ assert.Equal(t, v3, 1.23)
+ v4 := v.GetIntSlice("TEST_F4")
+ assert.Equal(t, []int{1, 2, 3}, v4)
+ v5 := v.GetStringSlice("TEST_F5")
+ assert.Equal(t, []string{"a", "b", "c"}, v5)
+ v6 := v.GetBool("TEST_F6")
+ assert.Equal(t, v6, true)
+ v7 := v.GetStringMapString("TEST_F7")
+ assert.Equal(t, map[string]string{"foo": "bar"}, v7)
+ v8 := v.GetStringMap("TEST_F8")
+ assert.Equal(t, map[string]interface{}{"foo1": "bar1"}, v8)
+}
+
func TestLoadFromConfig(t *testing.T) {
v := config.GetConfig()
+ ts := TestStruct{
+ F1: "123",
+ F2: 76,
+ F3: 1.23,
+ F4: "Test",
+ F5: "No Use",
+ }
+ data := make(map[string]interface{})
+ assert.Nil(t, DecodeStruct(v, &ts, data, "env"))
+
vF := TestStruct{}
err := EncodeStruct(v, &vF, "env")
if err != nil {
- panic(err)
+ assert.Error(t, err)
}
//assert.Nil(t, x)
assert.Equal(t, vF.F1, "123")
assert.Equal(t, vF.F2, 76)
assert.Equal(t, vF.F3, 1.23)
assert.Equal(t, vF.F4, "Test")
+ assert.Equal(t, vF.F5, "No Use")
+}
+
+func TestLoadFromComplexityConfig(t *testing.T) {
+ v := config.GetConfig()
+ ts := TestComplexStruct{
+ F1: "123",
+ F2: 76,
+ F3: 1.23,
+ F4: []int{1, 2, 3},
+ F5: []string{"a", "b", "c"},
+ F6: true,
+ F7: map[string]string{
+ "foo": "bar",
+ },
+ F8: map[string]interface{}{
+ "foo1": "bar1",
+ },
+ }
+ data := make(map[string]interface{})
+ assert.Nil(t, DecodeStruct(v, &ts, data, "env"))
+
+ vF := TestComplexStruct{}
+ err := EncodeStruct(v, &vF, "env")
+ if err != nil {
+ assert.Error(t, err)
+ }
+ //assert.Nil(t, x)
+ assert.Equal(t, vF.F1, "123")
+ assert.Equal(t, vF.F2, 76)
+ assert.Equal(t, vF.F3, 1.23)
+ assert.Equal(t, vF.F4, []int{1, 2, 3})
+ assert.Equal(t, vF.F5, []string{"a", "b", "c"})
+ assert.Equal(t, vF.F6, true)
+ assert.Equal(t, vF.F7, map[string]string{"foo": "bar"})
+ assert.Equal(t, vF.F8, map[string]interface{}{"foo1": "bar1"})
}