Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: Drop support for Go < 1.20 #80

Merged
merged 1 commit into from
Oct 11, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/go.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
go: ["1.19.x", "1.20.x"]
go: ["1.20.x", "1.21.x"]
include:
- go: 1.20.x
- go: 1.21.x
latest: true

steps:
Expand Down
70 changes: 50 additions & 20 deletions error.go
Original file line number Diff line number Diff line change
Expand Up @@ -115,24 +115,22 @@
// # Advanced Usage
//
// Errors returned by Combine and Append MAY implement the following
// interface.
// method.
//
// type errorGroup interface {
// // Returns a slice containing the underlying list of errors.
// //
// // This slice MUST NOT be modified by the caller.
// Errors() []error
// }
// // Returns a slice containing the underlying list of errors.
// //
// // This slice MUST NOT be modified by the caller.
// Unwrap() []error
//
// Note that if you need access to list of errors behind a multierr error, you
// should prefer using the Errors function. That said, if you need cheap
// should prefer using the [Errors] function. That said, if you need cheap
// read-only access to the underlying errors slice, you can attempt to cast
// the error to this interface. You MUST handle the failure case gracefully
// because errors returned by Combine and Append are not guaranteed to
// implement this interface.
//
// var errors []error
// group, ok := err.(errorGroup)
// group, ok := err.(interface{ Unwrap() []error })
// if ok {
// errors = group.Errors()
// } else {
Expand Down Expand Up @@ -180,10 +178,20 @@ var _bufferPool = sync.Pool{
},
}

// errorGroup is the old interface defined by multierr for combined errors.
//
// It is deprecated in favor of the Go 1.20 multi-error interface.
// However, we still need to implement and support it
// for backward compatibility.
type errorGroup interface {
Errors() []error
}

// multipleErrors matches the Go 1.20 multi-error interface.
type multipleErrors interface {
Unwrap() []error
}

// Errors returns a slice containing zero or more errors that the supplied
// error is composed of. If the error is nil, a nil slice is returned.
//
Expand All @@ -210,6 +218,13 @@ type multiError struct {
errors []error
}

// Unwrap returns a list of errors wrapped by this multierr.
//
// This satisfies the Go 1.20 multi-error interface.
func (merr *multiError) Unwrap() []error {
return merr.Errors()
}

// Errors returns the list of underlying errors.
//
// This slice MUST NOT be modified.
Expand All @@ -235,17 +250,6 @@ func (merr *multiError) Error() string {
return result
}

// Every compares every error in the given err against the given target error
// using [errors.Is], and returns true only if every comparison returned true.
func Every(err error, target error) bool {
for _, e := range extractErrors(err) {
if !errors.Is(e, target) {
return false
}
}
return true
}

func (merr *multiError) Format(f fmt.State, c rune) {
if c == 'v' && f.Flag('+') {
merr.writeMultiline(f)
Expand Down Expand Up @@ -508,6 +512,32 @@ func AppendInto(into *error, err error) (errored bool) {
return true
}

// Every compares every error in the given err against the given target error
// using [errors.Is], and returns true only if every comparison returned true.
func Every(err error, target error) bool {
for _, e := range extractErrors(err) {
if !errors.Is(e, target) {
return false
}
}
return true
}

func extractErrors(err error) []error {
if err == nil {
return nil
}

// check if the given err is an Unwrapable error that
// implements multipleErrors interface.
eg, ok := err.(multipleErrors)
if !ok {
return []error{err}
}

return append(([]error)(nil), eg.Unwrap()...)
}

// Invoker is an operation that may fail with an error. Use it with
// AppendInvoke to append the result of calling the function into an error.
// This allows you to conveniently defer capture of failing operations.
Expand Down
48 changes: 0 additions & 48 deletions error_post_go120.go

This file was deleted.

65 changes: 0 additions & 65 deletions error_post_go120_test.go

This file was deleted.

79 changes: 0 additions & 79 deletions error_pre_go120.go

This file was deleted.

36 changes: 35 additions & 1 deletion error_test.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) 2017-2021 Uber Technologies, Inc.
// Copyright (c) 2017-2023 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
Expand Down Expand Up @@ -777,3 +777,37 @@ func newCloserMock(tb testing.TB, err error) io.Closer {
return err
})
}

func TestErrorsOnErrorsJoin(t *testing.T) {
err1 := errors.New("err1")
err2 := errors.New("err2")
err := errors.Join(err1, err2)

errs := Errors(err)
assert.Equal(t, 2, len(errs))
assert.Equal(t, err1, errs[0])
assert.Equal(t, err2, errs[1])
}

func TestEveryWithErrorsJoin(t *testing.T) {
myError1 := errors.New("woeful misfortune")
myError2 := errors.New("worrisome travesty")

t.Run("all match", func(t *testing.T) {
err := errors.Join(myError1, myError1, myError1)

assert.True(t, errors.Is(err, myError1))
assert.True(t, Every(err, myError1))
assert.False(t, errors.Is(err, myError2))
assert.False(t, Every(err, myError2))
})

t.Run("one matches", func(t *testing.T) {
err := errors.Join(myError1, myError2)

assert.True(t, errors.Is(err, myError1))
assert.False(t, Every(err, myError1))
assert.True(t, errors.Is(err, myError2))
assert.False(t, Every(err, myError2))
})
}
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module go.uber.org/multierr

go 1.19
go 1.20

require github.com/stretchr/testify v1.7.0

Expand Down
2 changes: 1 addition & 1 deletion tools/go.mod
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module go.uber.org/multierr/tools

go 1.18
go 1.20

require (
golang.org/x/lint v0.0.0-20210508222113-6edffad5e616
Expand Down