From 1e1f0b1e76b89b48542171e2c5ee829a69c2b91f Mon Sep 17 00:00:00 2001 From: thinkerou Date: Wed, 1 Mar 2023 10:03:48 +0800 Subject: [PATCH] chore: support min go version 1.18 (#3511) * chore: min go version 1.18 * fix build tag error * remove build tag * fix word * remove any.go * replace interface{} instead of any --- .github/workflows/gin.yml | 6 +- .github/workflows/goreleaser.yml | 2 +- README.md | 2 +- any.go | 10 --- binding/any.go | 10 --- binding/binding.go | 1 - binding/binding_msgpack_test.go | 1 - binding/binding_nomsgpack.go | 1 - binding/json.go | 2 +- binding/msgpack.go | 1 - binding/msgpack_test.go | 1 - context.go | 6 +- context_1.17_test.go | 94 -------------------- context_1.16_test.go => context_1.18_test.go | 20 +++-- context_1.19_test.go | 1 - context_appengine.go | 1 - context_test.go | 41 ++++++++- debug.go | 4 +- debug_test.go | 4 +- deprecated.go | 2 +- docs/doc.md | 8 +- internal/json/go_json.go | 1 - internal/json/json.go | 3 - internal/json/jsoniter.go | 1 - internal/json/sonic.go | 4 - render/any.go | 10 --- render/msgpack.go | 1 - render/render_msgpack_test.go | 1 - testdata/protoexample/any.go | 10 --- utils.go | 2 +- 30 files changed, 72 insertions(+), 179 deletions(-) delete mode 100644 any.go delete mode 100644 binding/any.go delete mode 100644 context_1.17_test.go rename context_1.16_test.go => context_1.18_test.go (66%) delete mode 100644 render/any.go delete mode 100644 testdata/protoexample/any.go diff --git a/.github/workflows/gin.yml b/.github/workflows/gin.yml index fac97d4..5c1504a 100644 --- a/.github/workflows/gin.yml +++ b/.github/workflows/gin.yml @@ -18,7 +18,7 @@ jobs: - name: Setup go uses: actions/setup-go@v3 with: - go-version: '^1.16' + go-version: '^1.18' - name: Checkout repository uses: actions/checkout@v3 - name: Setup golangci-lint @@ -31,7 +31,7 @@ jobs: strategy: matrix: os: [ubuntu-latest, macos-latest] - go: ['1.16', '1.17', '1.18', '1.19', '1.20'] + go: ['1.18', '1.19', '1.20'] test-tags: ['', '-tags nomsgpack', '-tags "sonic avx"', '-tags go_json'] include: - os: ubuntu-latest @@ -73,7 +73,7 @@ jobs: flags: ${{ matrix.os }},go-${{ matrix.go }},${{ matrix.test-tags }} - name: Format - if: matrix.go-version == '1.19.x' + if: matrix.go-version == '1.20.x' run: diff -u <(echo -n) <(gofmt -d .) notification-gitter: needs: test diff --git a/.github/workflows/goreleaser.yml b/.github/workflows/goreleaser.yml index 3af3a45..baf02af 100644 --- a/.github/workflows/goreleaser.yml +++ b/.github/workflows/goreleaser.yml @@ -21,7 +21,7 @@ jobs: name: Set up Go uses: actions/setup-go@v3 with: - go-version: 1.17 + go-version: 1.20 - name: Run GoReleaser uses: goreleaser/goreleaser-action@v4 diff --git a/README.md b/README.md index 336155a..cba54ab 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,7 @@ Gin is a web framework written in [Go](https://go.dev/). It features a martini-l ### Prerequisites -- **[Go](https://go.dev/)**: ~~any one of the **three latest major** [releases](https://go.dev/doc/devel/release)~~ (now version **1.16+** is required). +- **[Go](https://go.dev/)**: any one of the **three latest major** [releases](https://go.dev/doc/devel/release) (we test it with these). ### Getting Gin diff --git a/any.go b/any.go deleted file mode 100644 index 42b1ea4..0000000 --- a/any.go +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright 2022 Gin Core Team. All rights reserved. -// Use of this source code is governed by a MIT style -// license that can be found in the LICENSE file. - -//go:build !go1.18 -// +build !go1.18 - -package gin - -type any = interface{} diff --git a/binding/any.go b/binding/any.go deleted file mode 100644 index d8251a7..0000000 --- a/binding/any.go +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright 2022 Gin Core Team. All rights reserved. -// Use of this source code is governed by a MIT style -// license that can be found in the LICENSE file. - -//go:build !go1.18 -// +build !go1.18 - -package binding - -type any = interface{} diff --git a/binding/binding.go b/binding/binding.go index a58924e..4094852 100644 --- a/binding/binding.go +++ b/binding/binding.go @@ -3,7 +3,6 @@ // license that can be found in the LICENSE file. //go:build !nomsgpack -// +build !nomsgpack package binding diff --git a/binding/binding_msgpack_test.go b/binding/binding_msgpack_test.go index 04d9407..a6cd6aa 100644 --- a/binding/binding_msgpack_test.go +++ b/binding/binding_msgpack_test.go @@ -3,7 +3,6 @@ // license that can be found in the LICENSE file. //go:build !nomsgpack -// +build !nomsgpack package binding diff --git a/binding/binding_nomsgpack.go b/binding/binding_nomsgpack.go index 7f6a904..93ad8ba 100644 --- a/binding/binding_nomsgpack.go +++ b/binding/binding_nomsgpack.go @@ -3,7 +3,6 @@ // license that can be found in the LICENSE file. //go:build nomsgpack -// +build nomsgpack package binding diff --git a/binding/json.go b/binding/json.go index 36eb27a..e21c2ee 100644 --- a/binding/json.go +++ b/binding/json.go @@ -15,7 +15,7 @@ import ( // EnableDecoderUseNumber is used to call the UseNumber method on the JSON // Decoder instance. UseNumber causes the Decoder to unmarshal a number into an -// interface{} as a Number instead of as a float64. +// any as a Number instead of as a float64. var EnableDecoderUseNumber = false // EnableDecoderDisallowUnknownFields is used to call the DisallowUnknownFields method diff --git a/binding/msgpack.go b/binding/msgpack.go index d1f035e..22de9b5 100644 --- a/binding/msgpack.go +++ b/binding/msgpack.go @@ -3,7 +3,6 @@ // license that can be found in the LICENSE file. //go:build !nomsgpack -// +build !nomsgpack package binding diff --git a/binding/msgpack_test.go b/binding/msgpack_test.go index 11561c8..df386a6 100644 --- a/binding/msgpack_test.go +++ b/binding/msgpack_test.go @@ -3,7 +3,6 @@ // license that can be found in the LICENSE file. //go:build !nomsgpack -// +build !nomsgpack package binding diff --git a/context.go b/context.go index 556f8ac..5716318 100644 --- a/context.go +++ b/context.go @@ -652,7 +652,7 @@ func (c *Context) BindYAML(obj any) error { } // BindTOML is a shortcut for c.MustBindWith(obj, binding.TOML). -func (c *Context) BindTOML(obj interface{}) error { +func (c *Context) BindTOML(obj any) error { return c.MustBindWith(obj, binding.TOML) } @@ -717,7 +717,7 @@ func (c *Context) ShouldBindYAML(obj any) error { } // ShouldBindTOML is a shortcut for c.ShouldBindWith(obj, binding.TOML). -func (c *Context) ShouldBindTOML(obj interface{}) error { +func (c *Context) ShouldBindTOML(obj any) error { return c.ShouldBindWith(obj, binding.TOML) } @@ -995,7 +995,7 @@ func (c *Context) YAML(code int, obj any) { } // TOML serializes the given struct as TOML into the response body. -func (c *Context) TOML(code int, obj interface{}) { +func (c *Context) TOML(code int, obj any) { c.Render(code, render.TOML{Data: obj}) } diff --git a/context_1.17_test.go b/context_1.17_test.go deleted file mode 100644 index 0f8527f..0000000 --- a/context_1.17_test.go +++ /dev/null @@ -1,94 +0,0 @@ -// Copyright 2021 Gin Core Team. All rights reserved. -// Use of this source code is governed by a MIT style -// license that can be found in the LICENSE file. - -//go:build go1.17 -// +build go1.17 - -package gin - -import ( - "bytes" - "mime/multipart" - "net/http" - "net/http/httptest" - "runtime" - "strings" - "testing" - - "github.com/stretchr/testify/assert" -) - -type interceptedWriter struct { - ResponseWriter - b *bytes.Buffer -} - -func (i interceptedWriter) WriteHeader(code int) { - i.Header().Del("X-Test") - i.ResponseWriter.WriteHeader(code) -} - -func TestContextFormFileFailed17(t *testing.T) { - if !isGo117OrGo118() { - return - } - buf := new(bytes.Buffer) - mw := multipart.NewWriter(buf) - defer func(mw *multipart.Writer) { - err := mw.Close() - if err != nil { - assert.Error(t, err) - } - }(mw) - c, _ := CreateTestContext(httptest.NewRecorder()) - c.Request, _ = http.NewRequest("POST", "/", nil) - c.Request.Header.Set("Content-Type", mw.FormDataContentType()) - c.engine.MaxMultipartMemory = 8 << 20 - assert.Panics(t, func() { - f, err := c.FormFile("file") - assert.Error(t, err) - assert.Nil(t, f) - }) -} - -func TestInterceptedHeader(t *testing.T) { - w := httptest.NewRecorder() - c, r := CreateTestContext(w) - - r.Use(func(c *Context) { - i := interceptedWriter{ - ResponseWriter: c.Writer, - b: bytes.NewBuffer(nil), - } - c.Writer = i - c.Next() - c.Header("X-Test", "overridden") - c.Writer = i.ResponseWriter - }) - r.GET("/", func(c *Context) { - c.Header("X-Test", "original") - c.Header("X-Test-2", "present") - c.String(http.StatusOK, "hello world") - }) - c.Request = httptest.NewRequest("GET", "/", nil) - r.HandleContext(c) - // Result() has headers frozen when WriteHeaderNow() has been called - // Compared to this time, this is when the response headers will be flushed - // As response is flushed on c.String, the Header cannot be set by the first - // middleware. Assert this - assert.Equal(t, "", w.Result().Header.Get("X-Test")) - assert.Equal(t, "present", w.Result().Header.Get("X-Test-2")) -} - -func isGo117OrGo118() bool { - version := strings.Split(runtime.Version()[2:], ".") - if len(version) >= 2 { - x := version[0] - y := version[1] - if x == "1" && (y == "17" || y == "18") { - return true - } - } - return false -} diff --git a/context_1.16_test.go b/context_1.18_test.go similarity index 66% rename from context_1.16_test.go rename to context_1.18_test.go index 2676050..6118bea 100644 --- a/context_1.16_test.go +++ b/context_1.18_test.go @@ -2,8 +2,7 @@ // Use of this source code is governed by a MIT style // license that can be found in the LICENSE file. -//go:build !go1.17 -// +build !go1.17 +//go:build !go1.19 package gin @@ -17,15 +16,22 @@ import ( "github.com/stretchr/testify/assert" ) -func TestContextFormFileFailed16(t *testing.T) { +func TestContextFormFileFailed18(t *testing.T) { buf := new(bytes.Buffer) mw := multipart.NewWriter(buf) - mw.Close() + defer func(mw *multipart.Writer) { + err := mw.Close() + if err != nil { + assert.Error(t, err) + } + }(mw) c, _ := CreateTestContext(httptest.NewRecorder()) c.Request, _ = http.NewRequest("POST", "/", nil) c.Request.Header.Set("Content-Type", mw.FormDataContentType()) c.engine.MaxMultipartMemory = 8 << 20 - f, err := c.FormFile("file") - assert.Error(t, err) - assert.Nil(t, f) + assert.Panics(t, func() { + f, err := c.FormFile("file") + assert.Error(t, err) + assert.Nil(t, f) + }) } diff --git a/context_1.19_test.go b/context_1.19_test.go index 4b34ea2..dd75325 100644 --- a/context_1.19_test.go +++ b/context_1.19_test.go @@ -3,7 +3,6 @@ // license that can be found in the LICENSE file. //go:build go1.19 -// +build go1.19 package gin diff --git a/context_appengine.go b/context_appengine.go index 931313f..96b339c 100644 --- a/context_appengine.go +++ b/context_appengine.go @@ -3,7 +3,6 @@ // license that can be found in the LICENSE file. //go:build appengine -// +build appengine package gin diff --git a/context_test.go b/context_test.go index 1ab6b33..1dec902 100644 --- a/context_test.go +++ b/context_test.go @@ -37,7 +37,7 @@ var errTestRender = errors.New("TestRender") // Unit tests TODO // func (c *Context) File(filepath string) { // func (c *Context) Negotiate(code int, config Negotiate) { -// BAD case: func (c *Context) Render(code int, render render.Render, obj ...interface{}) { +// BAD case: func (c *Context) Render(code int, render render.Render, obj ...any) { // test that information is not leaked when reusing Contexts (using the Pool) func createMultipartRequest() *http.Request { @@ -2374,3 +2374,42 @@ func TestCreateTestContextWithRouteParams(t *testing.T) { assert.Equal(t, http.StatusOK, w.Code) assert.Equal(t, "hello gin", w.Body.String()) } + +type interceptedWriter struct { + ResponseWriter + b *bytes.Buffer +} + +func (i interceptedWriter) WriteHeader(code int) { + i.Header().Del("X-Test") + i.ResponseWriter.WriteHeader(code) +} + +func TestInterceptedHeader(t *testing.T) { + w := httptest.NewRecorder() + c, r := CreateTestContext(w) + + r.Use(func(c *Context) { + i := interceptedWriter{ + ResponseWriter: c.Writer, + b: bytes.NewBuffer(nil), + } + c.Writer = i + c.Next() + c.Header("X-Test", "overridden") + c.Writer = i.ResponseWriter + }) + r.GET("/", func(c *Context) { + c.Header("X-Test", "original") + c.Header("X-Test-2", "present") + c.String(http.StatusOK, "hello world") + }) + c.Request = httptest.NewRequest("GET", "/", nil) + r.HandleContext(c) + // Result() has headers frozen when WriteHeaderNow() has been called + // Compared to this time, this is when the response headers will be flushed + // As response is flushed on c.String, the Header cannot be set by the first + // middleware. Assert this + assert.Equal(t, "", w.Result().Header.Get("X-Test")) + assert.Equal(t, "present", w.Result().Header.Get("X-Test-2")) +} diff --git a/debug.go b/debug.go index cbcedbc..1fc0caf 100644 --- a/debug.go +++ b/debug.go @@ -12,7 +12,7 @@ import ( "strings" ) -const ginSupportMinGoVer = 16 +const ginSupportMinGoVer = 18 // IsDebugging returns true if the framework is running in debug mode. // Use SetMode(gin.ReleaseMode) to disable debug mode. @@ -67,7 +67,7 @@ func getMinVer(v string) (uint64, error) { func debugPrintWARNINGDefault() { if v, e := getMinVer(runtime.Version()); e == nil && v < ginSupportMinGoVer { - debugPrint(`[WARNING] Now Gin requires Go 1.16+. + debugPrint(`[WARNING] Now Gin requires Go 1.18+. `) } diff --git a/debug_test.go b/debug_test.go index ce8b19d..2d5e9a5 100644 --- a/debug_test.go +++ b/debug_test.go @@ -21,7 +21,7 @@ import ( // TODO // func debugRoute(httpMethod, absolutePath string, handlers HandlersChain) { -// func debugPrint(format string, values ...interface{}) { +// func debugPrint(format string, values ...any) { func TestIsDebugging(t *testing.T) { SetMode(DebugMode) @@ -104,7 +104,7 @@ func TestDebugPrintWARNINGDefault(t *testing.T) { }) m, e := getMinVer(runtime.Version()) if e == nil && m < ginSupportMinGoVer { - assert.Equal(t, "[GIN-debug] [WARNING] Now Gin requires Go 1.16+.\n\n[GIN-debug] [WARNING] Creating an Engine instance with the Logger and Recovery middleware already attached.\n\n", re) + assert.Equal(t, "[GIN-debug] [WARNING] Now Gin requires Go 1.18+.\n\n[GIN-debug] [WARNING] Creating an Engine instance with the Logger and Recovery middleware already attached.\n\n", re) } else { assert.Equal(t, "[GIN-debug] [WARNING] Creating an Engine instance with the Logger and Recovery middleware already attached.\n\n", re) } diff --git a/deprecated.go b/deprecated.go index fdad855..9521308 100644 --- a/deprecated.go +++ b/deprecated.go @@ -13,7 +13,7 @@ import ( // BindWith binds the passed struct pointer using the specified binding engine. // See the binding package. func (c *Context) BindWith(obj any, b binding.Binding) error { - log.Println(`BindWith(\"interface{}, binding.Binding\") error is going to + log.Println(`BindWith(\"any, binding.Binding\") error is going to be deprecated, please check issue #662 and either use MustBindWith() if you want HTTP 400 to be automatically returned if any error occur, or use ShouldBindWith() if you need to manage the error.`) diff --git a/docs/doc.md b/docs/doc.md index 7cebab5..e48c2ba 100644 --- a/docs/doc.md +++ b/docs/doc.md @@ -425,7 +425,7 @@ func main() { r.Use(gin.Logger()) // Recovery middleware recovers from any panics and writes a 500 if there was one. - r.Use(gin.CustomRecovery(func(c *gin.Context, recovered interface{}) { + r.Use(gin.CustomRecovery(func(c *gin.Context, recovered any) { if err, ok := recovered.(string); ok { c.String(http.StatusInternalServerError, fmt.Sprintf("error: %s", err)) } @@ -996,7 +996,7 @@ curl -X POST -v --form name=user --form "avatar=@./avatar.png" http://localhost: func main() { r := gin.Default() - // gin.H is a shortcut for map[string]interface{} + // gin.H is a shortcut for map[string]any r.GET("/someJSON", func(c *gin.Context) { c.JSON(http.StatusOK, gin.H{"message": "hey", "status": http.StatusOK}) }) @@ -1961,7 +1961,7 @@ func (customerBinding) Name() string { return "form" } -func (customerBinding) Bind(req *http.Request, obj interface{}) error { +func (customerBinding) Bind(req *http.Request, obj any) error { if err := req.ParseForm(); err != nil { return err } @@ -1976,7 +1976,7 @@ func (customerBinding) Bind(req *http.Request, obj interface{}) error { return validate(obj) } -func validate(obj interface{}) error { +func validate(obj any) error { if binding.Validator == nil { return nil } diff --git a/internal/json/go_json.go b/internal/json/go_json.go index 23f7172..47c3559 100644 --- a/internal/json/go_json.go +++ b/internal/json/go_json.go @@ -3,7 +3,6 @@ // license that can be found in the LICENSE file. //go:build go_json -// +build go_json package json diff --git a/internal/json/json.go b/internal/json/json.go index c5f3efc..c7ee83e 100644 --- a/internal/json/json.go +++ b/internal/json/json.go @@ -3,9 +3,6 @@ // license that can be found in the LICENSE file. //go:build !jsoniter && !go_json && !(sonic && avx && (linux || windows || darwin) && amd64) -// +build !jsoniter -// +build !go_json -// +build !sonic !avx !linux,!windows,!darwin !amd64 package json diff --git a/internal/json/jsoniter.go b/internal/json/jsoniter.go index 853b1a9..45ed16b 100644 --- a/internal/json/jsoniter.go +++ b/internal/json/jsoniter.go @@ -3,7 +3,6 @@ // license that can be found in the LICENSE file. //go:build jsoniter -// +build jsoniter package json diff --git a/internal/json/sonic.go b/internal/json/sonic.go index 5a9ca4b..529e16d 100644 --- a/internal/json/sonic.go +++ b/internal/json/sonic.go @@ -3,10 +3,6 @@ // license that can be found in the LICENSE file. //go:build sonic && avx && (linux || windows || darwin) && amd64 -// +build sonic -// +build avx -// +build linux windows darwin -// +build amd64 package json diff --git a/render/any.go b/render/any.go deleted file mode 100644 index b19ad45..0000000 --- a/render/any.go +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright 2021 Gin Core Team. All rights reserved. -// Use of this source code is governed by a MIT style -// license that can be found in the LICENSE file. - -//go:build !go1.18 -// +build !go1.18 - -package render - -type any = interface{} diff --git a/render/msgpack.go b/render/msgpack.go index e0f30f7..d1d8e84 100644 --- a/render/msgpack.go +++ b/render/msgpack.go @@ -3,7 +3,6 @@ // license that can be found in the LICENSE file. //go:build !nomsgpack -// +build !nomsgpack package render diff --git a/render/render_msgpack_test.go b/render/render_msgpack_test.go index 6421236..db4b71e 100644 --- a/render/render_msgpack_test.go +++ b/render/render_msgpack_test.go @@ -3,7 +3,6 @@ // license that can be found in the LICENSE file. //go:build !nomsgpack -// +build !nomsgpack package render diff --git a/testdata/protoexample/any.go b/testdata/protoexample/any.go deleted file mode 100644 index 2203f33..0000000 --- a/testdata/protoexample/any.go +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright 2021 Gin Core Team. All rights reserved. -// Use of this source code is governed by a MIT style -// license that can be found in the LICENSE file. - -//go:build !go1.18 -// +build !go1.18 - -package protoexample - -type any = interface{} diff --git a/utils.go b/utils.go index 4021a2a..47106a7 100644 --- a/utils.go +++ b/utils.go @@ -50,7 +50,7 @@ func WrapH(h http.Handler) HandlerFunc { } } -// H is a shortcut for map[string]interface{} +// H is a shortcut for map[string]any type H map[string]any // MarshalXML allows type H to be used with xml.Marshal.