mirror of
https://github.com/gin-gonic/gin.git
synced 2026-09-04 14:49:27 +08:00
Compare commits
5 Commits
ea31e7657e
...
d9e3a8da27
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d9e3a8da27 | ||
|
|
dcaa4296d1 | ||
|
|
8dd20118ba | ||
|
|
00cfe5aac2 | ||
|
|
eb225210b8 |
2
.github/workflows/codeql.yml
vendored
2
.github/workflows/codeql.yml
vendored
@ -33,7 +33,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v6
|
||||
uses: actions/checkout@v7
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
|
||||
12
.github/workflows/gin.yml
vendored
12
.github/workflows/gin.yml
vendored
@ -16,11 +16,11 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
uses: actions/checkout@v7
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v6
|
||||
uses: actions/setup-go@v7
|
||||
with:
|
||||
go-version: "^1"
|
||||
- name: Setup golangci-lint
|
||||
@ -55,17 +55,17 @@ jobs:
|
||||
GOPROXY: https://proxy.golang.org
|
||||
steps:
|
||||
- name: Set up Go ${{ matrix.go }}
|
||||
uses: actions/setup-go@v6
|
||||
uses: actions/setup-go@v7
|
||||
with:
|
||||
go-version: ${{ matrix.go }}
|
||||
cache: false
|
||||
|
||||
- name: Checkout Code
|
||||
uses: actions/checkout@v6
|
||||
uses: actions/checkout@v7
|
||||
with:
|
||||
ref: ${{ github.ref }}
|
||||
|
||||
- uses: actions/cache@v5
|
||||
- uses: actions/cache@v6
|
||||
with:
|
||||
path: |
|
||||
${{ matrix.go-build }}
|
||||
@ -78,6 +78,6 @@ jobs:
|
||||
run: make test
|
||||
|
||||
- name: Upload coverage to Codecov
|
||||
uses: codecov/codecov-action@v6
|
||||
uses: codecov/codecov-action@v7
|
||||
with:
|
||||
flags: ${{ matrix.os }},go-${{ matrix.go }},${{ matrix.test-tags }}
|
||||
|
||||
4
.github/workflows/goreleaser.yml
vendored
4
.github/workflows/goreleaser.yml
vendored
@ -13,11 +13,11 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
uses: actions/checkout@v7
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v6
|
||||
uses: actions/setup-go@v7
|
||||
with:
|
||||
go-version: "^1"
|
||||
- name: Run GoReleaser
|
||||
|
||||
2
.github/workflows/trivy-scan.yml
vendored
2
.github/workflows/trivy-scan.yml
vendored
@ -22,7 +22,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v6
|
||||
uses: actions/checkout@v7
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
|
||||
21
context.go
21
context.go
@ -254,16 +254,37 @@ func (c *Context) AbortWithError(code int, err error) *Error {
|
||||
/********* ERROR MANAGEMENT *********/
|
||||
/************************************/
|
||||
|
||||
// joinedError is an interface for errors that wrap multiple inner errors,
|
||||
// such as those created by errors.Join.
|
||||
type joinedError interface {
|
||||
Unwrap() []error
|
||||
}
|
||||
|
||||
// Error attaches an error to the current context. The error is pushed to a list of errors.
|
||||
// It's a good idea to call Error for each error that occurred during the resolution of a request.
|
||||
// A middleware can be used to collect all the errors and push them to a database together,
|
||||
// print a log, or append it in the HTTP response.
|
||||
// Error will panic if err is nil.
|
||||
// If err is a joined error (created by errors.Join), it is unwrapped and each
|
||||
// individual error is added as a separate entry. The last *Error added is returned.
|
||||
func (c *Context) Error(err error) *Error {
|
||||
if err == nil {
|
||||
panic("err is nil")
|
||||
}
|
||||
|
||||
// Unwrap joined errors so each one becomes a separate entry.
|
||||
if joined, ok := err.(joinedError); ok {
|
||||
errs := joined.Unwrap()
|
||||
if len(errs) > 0 {
|
||||
var last *Error
|
||||
for _, e := range errs {
|
||||
last = c.Error(e)
|
||||
}
|
||||
return last
|
||||
}
|
||||
// Fall through for empty joined errors — store as-is.
|
||||
}
|
||||
|
||||
var parsedError *Error
|
||||
ok := errors.As(err, &parsedError)
|
||||
if !ok {
|
||||
|
||||
@ -2048,6 +2048,63 @@ func TestContextTypedError(t *testing.T) {
|
||||
assert.Equal(t, []string{"externo 0", "interno 0"}, c.Errors.Errors())
|
||||
}
|
||||
|
||||
func TestContextErrorJoined(t *testing.T) {
|
||||
c, _ := CreateTestContext(httptest.NewRecorder())
|
||||
|
||||
// Single errors around the joined one.
|
||||
c.Error(errors.New("first")) //nolint: errcheck
|
||||
|
||||
joined := errors.Join(errors.New("service error"), errors.New("store error"))
|
||||
last := c.Error(joined) //nolint: errcheck
|
||||
|
||||
c.Error(errors.New("last")) //nolint: errcheck
|
||||
|
||||
// Joined error must be unwrapped into separate entries.
|
||||
assert.Len(t, c.Errors, 4)
|
||||
assert.Equal(t, "first", c.Errors[0].Error())
|
||||
assert.Equal(t, "service error", c.Errors[1].Error())
|
||||
assert.Equal(t, "store error", c.Errors[2].Error())
|
||||
assert.Equal(t, "last", c.Errors[3].Error())
|
||||
|
||||
// Return value is the last unwrapped entry.
|
||||
assert.Equal(t, "store error", last.Error())
|
||||
|
||||
// All unwrapped entries default to ErrorTypePrivate.
|
||||
for _, e := range c.Errors {
|
||||
assert.Equal(t, ErrorTypePrivate, e.Type)
|
||||
}
|
||||
|
||||
// String output should list each error individually.
|
||||
expected := "Error #01: first\nError #02: service error\nError #03: store error\nError #04: last\n"
|
||||
assert.Equal(t, expected, c.Errors.String())
|
||||
}
|
||||
|
||||
func TestContextErrorNestedJoined(t *testing.T) {
|
||||
c, _ := CreateTestContext(httptest.NewRecorder())
|
||||
|
||||
inner := errors.Join(errors.New("a"), errors.New("b"))
|
||||
outer := errors.Join(inner, errors.New("c"))
|
||||
c.Error(outer) //nolint: errcheck
|
||||
|
||||
assert.Len(t, c.Errors, 3)
|
||||
assert.Equal(t, []string{"a", "b", "c"}, c.Errors.Errors())
|
||||
}
|
||||
|
||||
func TestContextErrorJoinedWithTypedError(t *testing.T) {
|
||||
c, _ := CreateTestContext(httptest.NewRecorder())
|
||||
|
||||
typedErr := &Error{Err: errors.New("typed"), Type: ErrorTypePublic, Meta: "meta"}
|
||||
joined := errors.Join(errors.New("plain"), typedErr)
|
||||
c.Error(joined) //nolint: errcheck
|
||||
|
||||
assert.Len(t, c.Errors, 2)
|
||||
assert.Equal(t, "plain", c.Errors[0].Error())
|
||||
assert.Equal(t, ErrorTypePrivate, c.Errors[0].Type)
|
||||
assert.Equal(t, "typed", c.Errors[1].Error())
|
||||
assert.Equal(t, ErrorTypePublic, c.Errors[1].Type)
|
||||
assert.Equal(t, "meta", c.Errors[1].Meta)
|
||||
}
|
||||
|
||||
func TestContextAbortWithError(t *testing.T) {
|
||||
w := httptest.NewRecorder()
|
||||
c, _ := CreateTestContext(w)
|
||||
|
||||
8
go.mod
8
go.mod
@ -16,7 +16,7 @@ require (
|
||||
github.com/stretchr/testify v1.11.1
|
||||
github.com/ugorji/go/codec v1.3.1
|
||||
go.mongodb.org/mongo-driver/v2 v2.5.0
|
||||
golang.org/x/net v0.55.0
|
||||
golang.org/x/net v0.56.0
|
||||
google.golang.org/protobuf v1.36.11
|
||||
)
|
||||
|
||||
@ -39,7 +39,7 @@ require (
|
||||
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
|
||||
go.uber.org/mock v0.6.0 // indirect
|
||||
golang.org/x/arch v0.25.0 // indirect
|
||||
golang.org/x/crypto v0.52.0 // indirect
|
||||
golang.org/x/sys v0.45.0 // indirect
|
||||
golang.org/x/text v0.37.0 // indirect
|
||||
golang.org/x/crypto v0.53.0 // indirect
|
||||
golang.org/x/sys v0.46.0 // indirect
|
||||
golang.org/x/text v0.39.0 // indirect
|
||||
)
|
||||
|
||||
16
go.sum
16
go.sum
@ -79,15 +79,15 @@ go.uber.org/mock v0.6.0 h1:hyF9dfmbgIX5EfOdasqLsWD6xqpNZlXblLB/Dbnwv3Y=
|
||||
go.uber.org/mock v0.6.0/go.mod h1:KiVJ4BqZJaMj4svdfmHM0AUx4NJYO8ZNpPnZn1Z+BBU=
|
||||
golang.org/x/arch v0.25.0 h1:qnk6Ksugpi5Bz32947rkUgDt9/s5qvqDPl/gBKdMJLE=
|
||||
golang.org/x/arch v0.25.0/go.mod h1:0X+GdSIP+kL5wPmpK7sdkEVTt2XoYP0cSjQSbZBwOi8=
|
||||
golang.org/x/crypto v0.52.0 h1:RMs7fP2rXdep0CftQlK8Uf+kibLm7qkCcradZWYz988=
|
||||
golang.org/x/crypto v0.52.0/go.mod h1:1QgfPxDqh0T2M/elOJtp9RvuR95kVjir0e6/BvEmGbc=
|
||||
golang.org/x/net v0.55.0 h1:bcvxaJn3e1U6InsFWt1JUq1aSjnRxLzT2rtD2KfkDF8=
|
||||
golang.org/x/net v0.55.0/go.mod h1:L5U2KuzuOe1lY7Z+aWVIKK6qEeJXnXV9yzGA+WCHJww=
|
||||
golang.org/x/crypto v0.53.0 h1:QZ4Muo8THX6CizN2vPPd5fBGHyogrdK9fG4wLPFUsto=
|
||||
golang.org/x/crypto v0.53.0/go.mod h1:DNLU434OwVakk9PzuwV8w62mAJpRJL3vsgcfp4Qnsio=
|
||||
golang.org/x/net v0.56.0 h1:Rw8j/hFzGvJUZwNBXnAtf5sVDVt+65SK2C7IxCxZt5o=
|
||||
golang.org/x/net v0.56.0/go.mod h1:D3Ku6r+V6JROoZK144D2XfMHFcMq/0zSfLelVTCFKec=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.45.0 h1:dO4czNzziLiiXplLQgBCEpCvXQ3dnkn0SdaZSYdQ+FY=
|
||||
golang.org/x/sys v0.45.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
|
||||
golang.org/x/text v0.37.0 h1:Cqjiwd9eSg8e0QAkyCaQTNHFIIzWtidPahFWR83rTrc=
|
||||
golang.org/x/text v0.37.0/go.mod h1:a5sjxXGs9hsn/AJVwuElvCAo9v8QYLzvavO5z2PiM38=
|
||||
golang.org/x/sys v0.46.0 h1:noSf2Fq6F8DBgS+LysIkx7rIExoNHJsxOAtPp4rthXw=
|
||||
golang.org/x/sys v0.46.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
|
||||
golang.org/x/text v0.39.0 h1:UbZz4pLOvn600D6Oh6GGEI6VAmndrEBLv8/6BEXzyus=
|
||||
golang.org/x/text v0.39.0/go.mod h1:3UwRclnC2g0TU9x8PZiyfOajCd1zaUNHF9cvqcQZ+ZM=
|
||||
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
|
||||
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
|
||||
2
path.go
2
path.go
@ -55,7 +55,7 @@ func cleanPath(p string) string {
|
||||
|
||||
// A bit more clunky without a 'lazybuf' like the path package, but the loop
|
||||
// gets completely inlined (bufApp calls).
|
||||
// loop has no expensive function calls (except 1x make) // So in contrast to the path package this loop has no expensive function
|
||||
// So in contrast to the path package this loop has no expensive function
|
||||
// calls (except make, if needed).
|
||||
|
||||
for r < n {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user