Skip to content

Commit b8a68ce

Browse files
committed
Merge branch 'master' into support-request-custom-field-not-set-err
2 parents b1fe325 + b24fb3e commit b8a68ce

File tree

135 files changed

+3154
-944
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

135 files changed

+3154
-944
lines changed

.github/workflows/release.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ jobs:
2222
github_token: ${{ secrets.GITHUB_TOKEN }}
2323
goos: ${{ matrix.goos }}
2424
goarch: ${{ matrix.goarch }}
25-
goversion: "https://dl.google.com/go/go1.20.14.linux-amd64.tar.gz"
25+
goversion: "https://dl.google.com/go/go1.21.13.linux-amd64.tar.gz"
2626
project_path: "tools/goctl"
2727
binary_name: "goctl"
28-
extra_files: tools/goctl/readme.md tools/goctl/readme-cn.md
28+
extra_files: tools/goctl/readme.md tools/goctl/readme-cn.md

.github/workflows/reviewdog.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,6 @@ jobs:
1414
# Report all results.
1515
filter_mode: nofilter
1616
# Exit with 1 when it find at least one finding.
17-
fail_on_error: true
17+
fail_level: any
1818
# Set staticcheck flags
1919
staticcheck_flags: -checks=inherit,-SA1019,-SA1029,-SA5008
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
name: Release Version Check
2+
3+
on:
4+
push:
5+
tags:
6+
- 'tools/goctl/v*'
7+
workflow_dispatch:
8+
9+
jobs:
10+
version-check:
11+
runs-on: ubuntu-latest
12+
steps:
13+
- uses: actions/checkout@v4
14+
15+
- name: Set up Go
16+
uses: actions/setup-go@v5
17+
with:
18+
go-version: '1.21'
19+
20+
- name: Extract tag version
21+
id: get_version
22+
run: |
23+
# Extract version from tools/goctl/v* format
24+
VERSION="${GITHUB_REF#refs/tags/tools/goctl/v}"
25+
echo "VERSION=$VERSION" >> $GITHUB_ENV
26+
echo "Extracted version: $VERSION"
27+
28+
- name: Check version in goctl source code
29+
run: |
30+
# Change to goctl directory
31+
cd tools/goctl
32+
33+
# Check version in BuildVersion constant
34+
VERSION_IN_CODE=$(grep -r "const BuildVersion =" . | grep -o '".*"' | tr -d '"')
35+
echo "Version in code: $VERSION_IN_CODE"
36+
echo "Expected version: $VERSION"
37+
38+
if [ "$VERSION_IN_CODE" != "$VERSION" ]; then
39+
echo "Version mismatch: Version in code ($VERSION_IN_CODE) doesn't match tag version ($VERSION)"
40+
exit 1
41+
fi
42+
echo "✅ Version check passed!"

core/breaker/nopbreaker_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,9 @@ import (
1111
func TestNopBreaker(t *testing.T) {
1212
b := NopBreaker()
1313
assert.Equal(t, nopBreakerName, b.Name())
14-
p, err := b.Allow()
14+
_, err := b.Allow()
1515
assert.Nil(t, err)
16-
p, err = b.AllowCtx(context.Background())
16+
p, err := b.AllowCtx(context.Background())
1717
assert.Nil(t, err)
1818
p.Accept()
1919
for i := 0; i < 1000; i++ {

core/conf/config.go

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,11 @@ func Load(file string, v any, opts ...Option) error {
6262
return loader([]byte(os.ExpandEnv(string(content))), v)
6363
}
6464

65-
return loader(content, v)
65+
if err = loader(content, v); err != nil {
66+
return err
67+
}
68+
69+
return validate(v)
6670
}
6771

6872
// LoadConfig loads config into v from file, .json, .yaml and .yml are acceptable.
@@ -85,7 +89,12 @@ func LoadFromJsonBytes(content []byte, v any) error {
8589

8690
lowerCaseKeyMap := toLowerCaseKeyMap(m, info)
8791

88-
return mapping.UnmarshalJsonMap(lowerCaseKeyMap, v, mapping.WithCanonicalKeyFunc(toLowerCase))
92+
if err = mapping.UnmarshalJsonMap(lowerCaseKeyMap, v,
93+
mapping.WithCanonicalKeyFunc(toLowerCase)); err != nil {
94+
return err
95+
}
96+
97+
return validate(v)
8998
}
9099

91100
// LoadConfigFromJsonBytes loads config into v from content json bytes.
@@ -192,7 +201,7 @@ func buildFieldsInfo(tp reflect.Type, fullName string) (*fieldInfo, error) {
192201
case reflect.Array, reflect.Slice, reflect.Map:
193202
return buildFieldsInfo(mapping.Deref(tp.Elem()), fullName)
194203
case reflect.Chan, reflect.Func:
195-
return nil, fmt.Errorf("unsupported type: %s", tp.Kind())
204+
return nil, fmt.Errorf("unsupported type: %s, fullName: %s", tp.Kind(), fullName)
196205
default:
197206
return &fieldInfo{
198207
children: make(map[string]*fieldInfo),

core/conf/config_test.go

Lines changed: 63 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package conf
22

33
import (
4+
"errors"
45
"os"
56
"reflect"
67
"testing"
@@ -40,9 +41,8 @@ func TestConfigJson(t *testing.T) {
4041
for _, test := range tests {
4142
test := test
4243
t.Run(test, func(t *testing.T) {
43-
tmpfile, err := createTempFile(test, text)
44+
tmpfile, err := createTempFile(t, test, text)
4445
assert.Nil(t, err)
45-
defer os.Remove(tmpfile)
4646

4747
var val struct {
4848
A string `json:"a"`
@@ -82,9 +82,8 @@ c = "${FOO}"
8282
d = "abcd!@#$112"
8383
`
8484
t.Setenv("FOO", "2")
85-
tmpfile, err := createTempFile(".toml", text)
85+
tmpfile, err := createTempFile(t, ".toml", text)
8686
assert.Nil(t, err)
87-
defer os.Remove(tmpfile)
8887

8988
var val struct {
9089
A string `json:"a"`
@@ -105,9 +104,8 @@ b = 1
105104
c = "FOO"
106105
d = "abcd"
107106
`
108-
tmpfile, err := createTempFile(".toml", text)
107+
tmpfile, err := createTempFile(t, ".toml", text)
109108
assert.Nil(t, err)
110-
defer os.Remove(tmpfile)
111109

112110
var val struct {
113111
A string `json:"a"`
@@ -127,9 +125,8 @@ func TestConfigWithLower(t *testing.T) {
127125
text := `a = "foo"
128126
b = 1
129127
`
130-
tmpfile, err := createTempFile(".toml", text)
128+
tmpfile, err := createTempFile(t, ".toml", text)
131129
assert.Nil(t, err)
132-
defer os.Remove(tmpfile)
133130

134131
var val struct {
135132
A string `json:"a"`
@@ -207,9 +204,8 @@ c = "${FOO}"
207204
d = "abcd!@#112"
208205
`
209206
t.Setenv("FOO", "2")
210-
tmpfile, err := createTempFile(".toml", text)
207+
tmpfile, err := createTempFile(t, ".toml", text)
211208
assert.Nil(t, err)
212-
defer os.Remove(tmpfile)
213209

214210
var val struct {
215211
A string `json:"a"`
@@ -241,9 +237,8 @@ func TestConfigJsonEnv(t *testing.T) {
241237
for _, test := range tests {
242238
test := test
243239
t.Run(test, func(t *testing.T) {
244-
tmpfile, err := createTempFile(test, text)
240+
tmpfile, err := createTempFile(t, test, text)
245241
assert.Nil(t, err)
246-
defer os.Remove(tmpfile)
247242

248243
var val struct {
249244
A string `json:"a"`
@@ -1217,11 +1212,44 @@ Name = "bar"
12171212
})
12181213
}
12191214

1215+
func Test_LoadBadConfig(t *testing.T) {
1216+
type Config struct {
1217+
Name string `json:"name,options=foo|bar"`
1218+
}
1219+
1220+
file, err := createTempFile(t, ".json", `{"name": "baz"}`)
1221+
assert.NoError(t, err)
1222+
1223+
var c Config
1224+
err = Load(file, &c)
1225+
assert.Error(t, err)
1226+
}
1227+
12201228
func Test_getFullName(t *testing.T) {
12211229
assert.Equal(t, "a.b", getFullName("a", "b"))
12221230
assert.Equal(t, "a", getFullName("", "a"))
12231231
}
12241232

1233+
func TestValidate(t *testing.T) {
1234+
t.Run("normal config", func(t *testing.T) {
1235+
var c mockConfig
1236+
err := LoadFromJsonBytes([]byte(`{"val": "hello", "number": 8}`), &c)
1237+
assert.NoError(t, err)
1238+
})
1239+
1240+
t.Run("error no int", func(t *testing.T) {
1241+
var c mockConfig
1242+
err := LoadFromJsonBytes([]byte(`{"val": "hello"}`), &c)
1243+
assert.Error(t, err)
1244+
})
1245+
1246+
t.Run("error no string", func(t *testing.T) {
1247+
var c mockConfig
1248+
err := LoadFromJsonBytes([]byte(`{"number": 8}`), &c)
1249+
assert.Error(t, err)
1250+
})
1251+
}
1252+
12251253
func Test_buildFieldsInfo(t *testing.T) {
12261254
type ParentSt struct {
12271255
Name string
@@ -1311,13 +1339,13 @@ func Test_buildFieldsInfo(t *testing.T) {
13111339
}
13121340
}
13131341

1314-
func createTempFile(ext, text string) (string, error) {
1342+
func createTempFile(t *testing.T, ext, text string) (string, error) {
13151343
tmpFile, err := os.CreateTemp(os.TempDir(), hash.Md5Hex([]byte(text))+"*"+ext)
13161344
if err != nil {
13171345
return "", err
13181346
}
13191347

1320-
if err := os.WriteFile(tmpFile.Name(), []byte(text), os.ModeTemporary); err != nil {
1348+
if err = os.WriteFile(tmpFile.Name(), []byte(text), os.ModeTemporary); err != nil {
13211349
return "", err
13221350
}
13231351

@@ -1326,5 +1354,26 @@ func createTempFile(ext, text string) (string, error) {
13261354
return "", err
13271355
}
13281356

1357+
t.Cleanup(func() {
1358+
_ = os.Remove(filename)
1359+
})
1360+
13291361
return filename, nil
13301362
}
1363+
1364+
type mockConfig struct {
1365+
Val string
1366+
Number int
1367+
}
1368+
1369+
func (m mockConfig) Validate() error {
1370+
if len(m.Val) == 0 {
1371+
return errors.New("val is empty")
1372+
}
1373+
1374+
if m.Number == 0 {
1375+
return errors.New("number is zero")
1376+
}
1377+
1378+
return nil
1379+
}

core/conf/validate.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package conf
2+
3+
import "github.com/zeromicro/go-zero/core/validation"
4+
5+
// validate validates the value if it implements the Validator interface.
6+
func validate(v any) error {
7+
if val, ok := v.(validation.Validator); ok {
8+
return val.Validate()
9+
}
10+
11+
return nil
12+
}

core/conf/validate_test.go

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
package conf
2+
3+
import (
4+
"errors"
5+
"testing"
6+
7+
"github.com/stretchr/testify/assert"
8+
)
9+
10+
type mockType int
11+
12+
func (m mockType) Validate() error {
13+
if m < 10 {
14+
return errors.New("invalid value")
15+
}
16+
17+
return nil
18+
}
19+
20+
type anotherMockType int
21+
22+
func Test_validate(t *testing.T) {
23+
tests := []struct {
24+
name string
25+
v any
26+
wantErr bool
27+
}{
28+
{
29+
name: "invalid",
30+
v: mockType(5),
31+
wantErr: true,
32+
},
33+
{
34+
name: "valid",
35+
v: mockType(10),
36+
wantErr: false,
37+
},
38+
{
39+
name: "not validator",
40+
v: anotherMockType(5),
41+
wantErr: false,
42+
},
43+
}
44+
45+
for _, tt := range tests {
46+
t.Run(tt.name, func(t *testing.T) {
47+
err := validate(tt.v)
48+
assert.Equal(t, tt.wantErr, err != nil)
49+
})
50+
}
51+
}
52+
53+
type mockVal struct {
54+
}
55+
56+
func (m mockVal) Validate() error {
57+
return errors.New("invalid value")
58+
}
59+
60+
func Test_validateValPtr(t *testing.T) {
61+
tests := []struct {
62+
name string
63+
v any
64+
wantErr bool
65+
}{
66+
{
67+
name: "invalid",
68+
v: mockVal{},
69+
},
70+
{
71+
name: "invalid value",
72+
v: &mockVal{},
73+
},
74+
}
75+
76+
for _, tt := range tests {
77+
t.Run(tt.name, func(t *testing.T) {
78+
assert.Error(t, validate(tt.v))
79+
})
80+
}
81+
}

0 commit comments

Comments
 (0)