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
This commit is contained in:
thinkerou 2023-03-01 10:03:48 +08:00 committed by GitHub
parent 943e93cba0
commit 1e1f0b1e76
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
30 changed files with 72 additions and 179 deletions

View File

@ -18,7 +18,7 @@ jobs:
- name: Setup go - name: Setup go
uses: actions/setup-go@v3 uses: actions/setup-go@v3
with: with:
go-version: '^1.16' go-version: '^1.18'
- name: Checkout repository - name: Checkout repository
uses: actions/checkout@v3 uses: actions/checkout@v3
- name: Setup golangci-lint - name: Setup golangci-lint
@ -31,7 +31,7 @@ jobs:
strategy: strategy:
matrix: matrix:
os: [ubuntu-latest, macos-latest] 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'] test-tags: ['', '-tags nomsgpack', '-tags "sonic avx"', '-tags go_json']
include: include:
- os: ubuntu-latest - os: ubuntu-latest
@ -73,7 +73,7 @@ jobs:
flags: ${{ matrix.os }},go-${{ matrix.go }},${{ matrix.test-tags }} flags: ${{ matrix.os }},go-${{ matrix.go }},${{ matrix.test-tags }}
- name: Format - name: Format
if: matrix.go-version == '1.19.x' if: matrix.go-version == '1.20.x'
run: diff -u <(echo -n) <(gofmt -d .) run: diff -u <(echo -n) <(gofmt -d .)
notification-gitter: notification-gitter:
needs: test needs: test

View File

@ -21,7 +21,7 @@ jobs:
name: Set up Go name: Set up Go
uses: actions/setup-go@v3 uses: actions/setup-go@v3
with: with:
go-version: 1.17 go-version: 1.20
- -
name: Run GoReleaser name: Run GoReleaser
uses: goreleaser/goreleaser-action@v4 uses: goreleaser/goreleaser-action@v4

View File

@ -31,7 +31,7 @@ Gin is a web framework written in [Go](https://go.dev/). It features a martini-l
### Prerequisites ### 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 ### Getting Gin

10
any.go
View File

@ -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{}

View File

@ -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{}

View File

@ -3,7 +3,6 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build !nomsgpack //go:build !nomsgpack
// +build !nomsgpack
package binding package binding

View File

@ -3,7 +3,6 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build !nomsgpack //go:build !nomsgpack
// +build !nomsgpack
package binding package binding

View File

@ -3,7 +3,6 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build nomsgpack //go:build nomsgpack
// +build nomsgpack
package binding package binding

View File

@ -15,7 +15,7 @@ import (
// EnableDecoderUseNumber is used to call the UseNumber method on the JSON // EnableDecoderUseNumber is used to call the UseNumber method on the JSON
// Decoder instance. UseNumber causes the Decoder to unmarshal a number into an // 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 var EnableDecoderUseNumber = false
// EnableDecoderDisallowUnknownFields is used to call the DisallowUnknownFields method // EnableDecoderDisallowUnknownFields is used to call the DisallowUnknownFields method

View File

@ -3,7 +3,6 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build !nomsgpack //go:build !nomsgpack
// +build !nomsgpack
package binding package binding

View File

@ -3,7 +3,6 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build !nomsgpack //go:build !nomsgpack
// +build !nomsgpack
package binding package binding

View File

@ -652,7 +652,7 @@ func (c *Context) BindYAML(obj any) error {
} }
// BindTOML is a shortcut for c.MustBindWith(obj, binding.TOML). // 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) 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). // 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) 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. // 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}) c.Render(code, render.TOML{Data: obj})
} }

View File

@ -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
}

View File

@ -2,8 +2,7 @@
// Use of this source code is governed by a MIT style // Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build !go1.17 //go:build !go1.19
// +build !go1.17
package gin package gin
@ -17,15 +16,22 @@ import (
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
func TestContextFormFileFailed16(t *testing.T) { func TestContextFormFileFailed18(t *testing.T) {
buf := new(bytes.Buffer) buf := new(bytes.Buffer)
mw := multipart.NewWriter(buf) 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, _ := CreateTestContext(httptest.NewRecorder())
c.Request, _ = http.NewRequest("POST", "/", nil) c.Request, _ = http.NewRequest("POST", "/", nil)
c.Request.Header.Set("Content-Type", mw.FormDataContentType()) c.Request.Header.Set("Content-Type", mw.FormDataContentType())
c.engine.MaxMultipartMemory = 8 << 20 c.engine.MaxMultipartMemory = 8 << 20
assert.Panics(t, func() {
f, err := c.FormFile("file") f, err := c.FormFile("file")
assert.Error(t, err) assert.Error(t, err)
assert.Nil(t, f) assert.Nil(t, f)
})
} }

View File

@ -3,7 +3,6 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build go1.19 //go:build go1.19
// +build go1.19
package gin package gin

View File

@ -3,7 +3,6 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build appengine //go:build appengine
// +build appengine
package gin package gin

View File

@ -37,7 +37,7 @@ var errTestRender = errors.New("TestRender")
// Unit tests TODO // Unit tests TODO
// func (c *Context) File(filepath string) { // func (c *Context) File(filepath string) {
// func (c *Context) Negotiate(code int, config Negotiate) { // 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) // test that information is not leaked when reusing Contexts (using the Pool)
func createMultipartRequest() *http.Request { func createMultipartRequest() *http.Request {
@ -2374,3 +2374,42 @@ func TestCreateTestContextWithRouteParams(t *testing.T) {
assert.Equal(t, http.StatusOK, w.Code) assert.Equal(t, http.StatusOK, w.Code)
assert.Equal(t, "hello gin", w.Body.String()) 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"))
}

View File

@ -12,7 +12,7 @@ import (
"strings" "strings"
) )
const ginSupportMinGoVer = 16 const ginSupportMinGoVer = 18
// IsDebugging returns true if the framework is running in debug mode. // IsDebugging returns true if the framework is running in debug mode.
// Use SetMode(gin.ReleaseMode) to disable debug mode. // Use SetMode(gin.ReleaseMode) to disable debug mode.
@ -67,7 +67,7 @@ func getMinVer(v string) (uint64, error) {
func debugPrintWARNINGDefault() { func debugPrintWARNINGDefault() {
if v, e := getMinVer(runtime.Version()); e == nil && v < ginSupportMinGoVer { 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+.
`) `)
} }

View File

@ -21,7 +21,7 @@ import (
// TODO // TODO
// func debugRoute(httpMethod, absolutePath string, handlers HandlersChain) { // func debugRoute(httpMethod, absolutePath string, handlers HandlersChain) {
// func debugPrint(format string, values ...interface{}) { // func debugPrint(format string, values ...any) {
func TestIsDebugging(t *testing.T) { func TestIsDebugging(t *testing.T) {
SetMode(DebugMode) SetMode(DebugMode)
@ -104,7 +104,7 @@ func TestDebugPrintWARNINGDefault(t *testing.T) {
}) })
m, e := getMinVer(runtime.Version()) m, e := getMinVer(runtime.Version())
if e == nil && m < ginSupportMinGoVer { 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 { } else {
assert.Equal(t, "[GIN-debug] [WARNING] Creating an Engine instance with the Logger and Recovery middleware already attached.\n\n", re) assert.Equal(t, "[GIN-debug] [WARNING] Creating an Engine instance with the Logger and Recovery middleware already attached.\n\n", re)
} }

View File

@ -13,7 +13,7 @@ import (
// BindWith binds the passed struct pointer using the specified binding engine. // BindWith binds the passed struct pointer using the specified binding engine.
// See the binding package. // See the binding package.
func (c *Context) BindWith(obj any, b binding.Binding) error { 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 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 want HTTP 400 to be automatically returned if any error occur, or use
ShouldBindWith() if you need to manage the error.`) ShouldBindWith() if you need to manage the error.`)

View File

@ -425,7 +425,7 @@ func main() {
r.Use(gin.Logger()) r.Use(gin.Logger())
// Recovery middleware recovers from any panics and writes a 500 if there was one. // 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 { if err, ok := recovered.(string); ok {
c.String(http.StatusInternalServerError, fmt.Sprintf("error: %s", err)) 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() { func main() {
r := gin.Default() 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) { r.GET("/someJSON", func(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"message": "hey", "status": http.StatusOK}) c.JSON(http.StatusOK, gin.H{"message": "hey", "status": http.StatusOK})
}) })
@ -1961,7 +1961,7 @@ func (customerBinding) Name() string {
return "form" 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 { if err := req.ParseForm(); err != nil {
return err return err
} }
@ -1976,7 +1976,7 @@ func (customerBinding) Bind(req *http.Request, obj interface{}) error {
return validate(obj) return validate(obj)
} }
func validate(obj interface{}) error { func validate(obj any) error {
if binding.Validator == nil { if binding.Validator == nil {
return nil return nil
} }

View File

@ -3,7 +3,6 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build go_json //go:build go_json
// +build go_json
package json package json

View File

@ -3,9 +3,6 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build !jsoniter && !go_json && !(sonic && avx && (linux || windows || darwin) && amd64) //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 package json

View File

@ -3,7 +3,6 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build jsoniter //go:build jsoniter
// +build jsoniter
package json package json

View File

@ -3,10 +3,6 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build sonic && avx && (linux || windows || darwin) && amd64 //go:build sonic && avx && (linux || windows || darwin) && amd64
// +build sonic
// +build avx
// +build linux windows darwin
// +build amd64
package json package json

View File

@ -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{}

View File

@ -3,7 +3,6 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build !nomsgpack //go:build !nomsgpack
// +build !nomsgpack
package render package render

View File

@ -3,7 +3,6 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build !nomsgpack //go:build !nomsgpack
// +build !nomsgpack
package render package render

View File

@ -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{}

View File

@ -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 type H map[string]any
// MarshalXML allows type H to be used with xml.Marshal. // MarshalXML allows type H to be used with xml.Marshal.