Commit Graph

76 Commits

Author SHA1 Message Date
Jacob Oaks cf4b2327ce
CI: Test against go 1.22 (#81)
Upgrades CI workflows to use Go versions 1.21 and 1.22.

Leave `go.mod` the same to avoid forcing upgrade beyond 1.20 for users.
2024-04-29 15:14:36 -04:00
Jacob Oaks a22d13df07
CI: Upgrade actions (#82)
This PR upgrades CI actions to their latest versions.

At the very least, the codecov action is necessary because otherwise PRs
stall on codecov upload step (example:
https://github.com/uber-go/multierr/pull/81)
2024-04-29 13:28:48 -04:00
Abhinav Gupta 616f4860ca
chore: Drop support for Go < 1.20 (#80)
Drops support for versions of Go older than 1.20.
With 1.20 being the minimum supported Go version,
we can remove the pre_go120 code, and merge the post_go120 code.

With Go 1.20's multi-error interface, our errorGroup interface
is not necessary, but we need it for backwards compatibility.
Also updates the documentation to suggest Go 1.20's interface
instead of ours.
The `Errors() []error` function is now an implementation detail.
2023-10-11 14:46:30 -04:00
Sung Yoon Whang de75ae527b
Release v1.11.0 (#79)
This prepares release for v1.11.0 which contains:
* support for `Errors` on any error that implements the multiple-error
interface specified by standard library starting from Go 1.20.
* `Every`, which checks whether all errors in the error chain satisfies
the `errors.Is` comparison against the target error.
2023-03-29 16:00:37 -07:00
JacobOaks d8067ab003
Support multierr.Every (#78)
This PR introduces a new exported function in the multierr package
called `Every`, which checks every error within a given error against a
given target using `errors.Is`, and only returns true if all checks
return true.

```go
err := multierr.Combine(ErrIgnorable, errors.New("great sadness"))
fmt.Println(errors.Is(err, ErrIgnorable))      // output = "true"
fmt.Println(multierr.Every(err, ErrIgnorable)) // output = "false"

err := multierr.Combine(ErrIgnorable, ErrIgnorable)
fmt.Println(errors.Is(err, ErrIgnorable))      // output = "true"
fmt.Println(multierr.Every(err, ErrIgnorable)) // output = "true"
```

This also works when the error passed in as the first argument is not a
`multiErr`, including when it is a go1.20+ error that implements
`Unwrap() []error`.

This solves #66.
2023-03-28 16:51:02 -04:00
Abhinav Gupta d42b7a1b10
ci: Minimize permissions to workflows (#77)
Reduces the permissions available to GitHub Workflows
to read-only since they don't do much otherwise.

Resolves #76
2023-03-20 05:40:59 -07:00
Sung Yoon Whang faff69d9f0
Enable Errors support for any multi-error (#75)
Starting Go 1.20, any multi-error should conform to the standard unwrap
method: Unwrap() []error.

This changes multierr.Errors() method to support any error that complies
to that interface.

Fix #70 / GO-1883
2023-03-15 22:40:46 -07:00
Abhinav Gupta 8767aa9206
Prepare release v1.10 (#74)
Prepares a new release with support for Go 1.20's `Unwrap() []error` interface.
2023-03-08 09:40:37 -05:00
Abhinav Gupta 4504ef7e00
README: Add Features section (#73)
The package has an empty readme.
Adding some basic highlights about why this is good
makes sense.
2023-02-14 22:36:18 -08:00
Abhinav Gupta 2fd451dbf5
Drop external atomic dependency (#72)
Now that this package only supports Go 1.19 and 1.20,
it can make use of the atomic.Bool [1] added in Go 1.19.

  [1] https://pkg.go.dev/sync/atomic#Bool

This has the effect of eliminating any external dependencies
from this package -- minus testify, which is only used for testing.
2023-02-14 22:35:24 -08:00
Abhinav Gupta 7876a028b0
Remove unused glide.yaml (#71)
This hasn't been needed in ages.
2023-02-14 22:35:06 -08:00
Abhinav Gupta 55bc553b48
Support Go 1.20 Unwrap() []error (#69)
Go 1.20 includes native support for wrapping multiple errors.
Errors which wrap multiple other errors must implement,

    Unwrap() []error

If an error implements this method, `errors.Is` and `errors.As`
will descend into the list and continue matching.

Versions of Go prior to 1.20, however, still need the old
`Is` and `As` method implementations on the error object
to get a similar behavior.

This change adds the `Unwrap() []error` method
gated by a build constraint requiring Go 1.20 or higher.
It similarly moves the existing `Is` and `As` methods
to a file that is ignored on Go 1.20 or higher.

Once Go 1.21 is released and 1.19 is no longer supported,
the pre-go1.20 file may be deleted and the build constraints removed.

For details, see also the section,
"How should existing multierror types adopt the new interface?"
of the [multiple errors proposal][1].

  [1]: https://github.com/golang/go/issues/53435

Refs #64
2023-02-10 11:44:02 -08:00
Sung Yoon Whang 39ca40c628
Prepare release v1.9.0 (#68)
Release v1.9.0 with updated dependency and support for `AppendFunc`.
2022-12-12 11:30:19 -08:00
Alexandr Burdiyan 4459990373
Add a shorthand for AppendInvoke (#65)
I really like the idea of catching returned errors from deferred functions. Though having to use `multierr` package name twice in the same line makes it a bit verbose in many occasions.

This PR introduces a shorthand for AppendInvoke which allows passing function or method value directly without wrapping it into an Invoker.

So this:

```go
defer multierr.AppendInvoke(&err, multierr.Invoke(my.StopFunc))
```

could become this:

```go
defer multierr.AppendFunc(&err, my.StopFunc)
```

Co-authored-by: Sung Yoon Whang <sungyoonwhang@gmail.com>
2022-09-06 09:20:06 -07:00
Abhinav Gupta 80b07a745f
Document named return constraint for defer (#63)
As discussed in #61, if you attempt to use defer multierr.AppendInvoke
with an error that is not a named return, the system will lose the
error.
func fails() error { return errors.New("great sadness") }

func foo() error {
	var err error
	defer multierr.AppendInvoke(&err, multierr.Invoke(fails))
	return err
}

func main() {
	fmt.Println(foo()) // nil
}
https://go.dev/play/p/qK4NR-VYLvo
This isn't something the library can address because of how defers work.
This change adds a warning about the error variable being a named return
in all places where we suggest use of multierr with defer.
While we're at it, this makes use of the new [Foo] godoc syntax to
generate links to other functions in the package in "See Foo"
statements in the documentation.
2022-08-12 09:28:55 -07:00
Abhinav Gupta 492b79245a
Test and lint against Go 1.19 (#62)
Add Go 1.19 to the test matrix, and switch linting to Go 1.19 since we
prefer to lint with the latest stable release.
With Go 1.19, we need to:

Update tools dependencies
Fix any use of ioutil
gofmt all files to match new godoc format
2022-08-12 09:14:35 -07:00
Abhinav Gupta aa8f15f0a1
Upgrade to yaml.v3 3.0.1 (#60)
Supersedes #59
Refs CVE-2022-28948
2022-05-31 12:12:14 -07:00
Tom Wieczorek f46d400df0
Use append instead of copy to clone slices (#58)
The append notation is more concise and should be more efficient, since
the target slice won't be initialized with zero values first.
2022-05-18 07:18:51 -07:00
Abhinav Gupta 6fede5ccb3
CI: Test against Go 1.17/1.18 (#57) 2022-03-15 14:38:44 -07:00
Abhinav Gupta 10aaa3c357
Prepare release v1.8.0 (#56)
Release v1.8.0 with an optimized `Combine`.
Test with Go 1.17 for it.
2022-02-28 12:35:35 -08:00
Jesper Lindstrøm Nielsen cea7d2e1fc
Combine: Optimize for all nil (#55)
The current implementation of Combine returns the input slice in the
returned multierr. This causes it to escape to the heap unconditionally.
Optimizing for the no-errors case, we can copy the slice in that case
and keep it on the stack.

```
name                                old time/op    new time/op    delta
Combine/inline_1-8                    17.7ns ± 0%     2.1ns ± 0%   -88.20%  (p=0.008 n=5+5)
Combine/inline_2-8                    21.0ns ± 0%     4.4ns ± 1%   -79.03%  (p=0.008 n=5+5)
Combine/inline_3_no_error-8           24.4ns ± 0%     5.1ns ± 1%   -79.22%  (p=0.016 n=4+5)
Combine/inline_3_one_error-8          24.8ns ± 0%     5.4ns ± 1%   -78.42%  (p=0.008 n=5+5)
Combine/inline_3_multiple_errors-8    44.3ns ± 0%    54.9ns ± 0%   +23.80%  (p=0.008 n=5+5)
Combine/slice_100_no_errors-8         72.9ns ± 0%    73.4ns ± 1%    +0.68%  (p=0.008 n=5+5)
Combine/slice_100_one_error-8         74.5ns ± 0%    74.8ns ± 0%      ~     (p=0.056 n=5+5)
Combine/slice_100_multi_error-8        193ns ± 0%     193ns ± 0%      ~     (p=0.127 n=5+5)

name                                old alloc/op   new alloc/op   delta
Combine/inline_1-8                     16.0B ± 0%      0.0B       -100.00%  (p=0.008 n=5+5)
Combine/inline_2-8                     32.0B ± 0%      0.0B       -100.00%  (p=0.008 n=5+5)
Combine/inline_3_no_error-8            48.0B ± 0%      0.0B       -100.00%  (p=0.008 n=5+5)
Combine/inline_3_one_error-8           48.0B ± 0%      0.0B       -100.00%  (p=0.008 n=5+5)
Combine/inline_3_multiple_errors-8     80.0B ± 0%     80.0B ± 0%      ~     (all equal)
Combine/slice_100_no_errors-8          0.00B          0.00B           ~     (all equal)
Combine/slice_100_one_error-8          0.00B          0.00B           ~     (all equal)
Combine/slice_100_multi_error-8        64.0B ± 0%     64.0B ± 0%      ~     (all equal)

name                                old allocs/op  new allocs/op  delta
Combine/inline_1-8                      1.00 ± 0%      0.00       -100.00%  (p=0.008 n=5+5)
Combine/inline_2-8                      1.00 ± 0%      0.00       -100.00%  (p=0.008 n=5+5)
Combine/inline_3_no_error-8             1.00 ± 0%      0.00       -100.00%  (p=0.008 n=5+5)
Combine/inline_3_one_error-8            1.00 ± 0%      0.00       -100.00%  (p=0.008 n=5+5)
Combine/inline_3_multiple_errors-8      2.00 ± 0%      2.00 ± 0%      ~     (all equal)
Combine/slice_100_no_errors-8           0.00           0.00           ~     (all equal)
Combine/slice_100_one_error-8           0.00           0.00           ~     (all equal)
Combine/slice_100_multi_error-8         2.00 ± 0%      2.00 ± 0%      ~     (all equal)
```

Co-authored-by: Abhinav Gupta <abg@uber.com>
2022-02-28 12:01:14 -08:00
Abhinav Gupta d49c2ba574
doc: AppendInvoke: Fix typo (#54)
One of the examples for AppendInvoke used `AppendInvoke(err, ...)` but
the argument is supposed to be a `*error`. Fix the example.
2021-07-12 10:57:28 -07:00
Manjari Akella ee7346af51
Merge pull request #52 from uber-go/fossa
fossa: Run separately, only on push
2021-05-25 15:06:45 -07:00
Abhinav Gupta d9efa4b72b fossa: Run separately, only on push
FOSSA analysis currently blocks CI on pull requests because they are
denied access to secrets.

Run FOSSA as a separate job only when we push to a branch of the
project.
2021-05-25 14:45:43 -07:00
Manjari Akella 7c6ff6f71f
Integrate FOSSA (#51)
Add a FOSSA check to the build steps.

Resolves: GO-468
2021-05-25 12:03:16 -07:00
Abhinav Gupta a5cd550968
Release v1.7.0 (#50)
Release v1.7.0 of multierr with `AppendInvoke` support.
2021-05-06 15:23:29 -07:00
Abhinav Gupta a20a85282c
ci: Use GitHub Workflows (#49)
Use GitHub Workflows for CI instead of Travis. In the process, this resulted in
some cleanup of the Makefile (in particular, dropping the update-license tool)
and updating the licenses manually.
2021-05-06 15:23:00 -07:00
Abhinav Gupta 0b656320b9 Use GitHub workflows
Switch from Travis to GitHub Workflows for CI.
2021-05-06 10:24:39 -07:00
Abhinav Gupta 520752cf5f Update license headers everywhere
License headers should be a range, not just the current year.
2021-05-06 10:23:05 -07:00
Abhinav Gupta 40de9b04c6 tools: Update to latest versions 2021-05-06 10:23:05 -07:00
Abhinav Gupta b78aea89db tools: Delete update-license
We manage these manually at this point.
2021-05-06 10:23:05 -07:00
Abhinav Gupta 1014a7cd66
AppendInvoke: Merge test, real example (#48)
Follow up to #47 with the following changes.

- The tests for AppendInvoke with Close duplicate the tests for
  AppendInvoke. These can be merged, and the unit tests for Close only
  need to verify whether the Invoker returned by multierr.Close calls
  the Close function in the provided io.Closer.
- Replace AppendInvoke example with something more realistic.
- Update changelog.
2021-05-06 10:21:19 -07:00
baez90 a402392041
Add AppendInvoke (#47)
Add the following APIs:

    type Invoker
        type Invoke // implements Invoker
        func Close(io.Closer)     Invoker
    
    func AppendInvoke(*error, Invoker)

Together, these APIs provide support for appending to an error from a
`defer` block.

    func foo() (err error) {
        file, err := os.Open(..)
        if err != nil {
            return err
        }
        defer multierr.AppendInvoke(&err, multierr.Close(file))
        
        // ...

Resolves #46 

Co-authored-by: Abhinav Gupta <abg@uber.com>
2021-05-06 08:13:15 -07:00
Tsuji Daishiro e015acf18b
error.go: Fix typo of doc (#44) 2020-11-24 10:20:17 -08:00
haoxin 8b005e6800
doc: change godoc to go.dev (#45)
Co-authored-by: Abhinav Gupta <mail@abhinavg.net>
2020-11-24 10:18:25 -08:00
Abhinav Gupta 0eb6eb5383
Drop Go 1.12 support (#41)
Support for `errors.Is` and `errors.As` was special-cased to Go 1.13 or
higher. This is no longer necessary since, as of right now, only Go 1.14
and 1.15 need to be supported.
2020-10-27 15:00:01 -07:00
Abhinav Gupta 3114a8b704
Release v1.6.0 (#40)
Release v1.6.0 that drops the library dependency on dev-time tooling
completely.
2020-09-14 09:32:57 -07:00
Márk Sági-Kazár ac926e462b
Move tool dependencies to a submodule (#38)
Renaming tools.go to tools_test.go isn't enough because the transitive
dependency is still carried over for commands like `go mod download`,
which may be used for pre-downloading dependencies for systems like
Docker.
2020-09-14 09:19:58 -07:00
Márk Sági-Kazár 16378467a5
travis: Test with oldstable and stable (#39)
Use the most recent two minor versions of Go for testing.

Use `oldstable` and `stable` introduced in gimme v1.5.4.

Co-authored-by: Abhinav Gupta <mail@abhinavg.net>
2020-09-11 09:38:07 -07:00
George Xie 4a27324ebb
docs: Add missing value in example (#37)
Fix print statement in example to actually include the combined error
object.
2020-04-23 10:01:20 -07:00
Abhinav Gupta b587143a48
Drop library-level constraints on tools (#36)
This drops library-level dependencies on tools used during development.
See also uber-go/atomic#65.

Note that we'll also tag a release when this lands.

Resolves #35
2020-02-24 14:08:21 -08:00
Arthur Befumo 0603dab385 docs: multierr.Errors returns nil, not empty (#33)
Previously the docs incorrectly stated that `multierr.Errors(err)`
would return an empty slice rather than a nil slice, which would imply
that `multierr.Errors(nil) == []error{}`, which isn't true.

This updates the docs to reflect reality: `multierr.Errors(nil) == nil`.
2019-11-08 10:29:00 -08:00
Abhinav Gupta 824d08f797
Preparing release v1.4.0 (#32) 2019-11-04 10:42:53 -08:00
Abhinav Gupta 60a318af5f
Add AppendInto function (#31)
This adds an AppendInto function that behaves similarly to Append
except, it operates on a `*error` on the left side and it reports
whether the right side error was non-nil.

    func AppendInto(*error, error) (errored bool)

Making the left side a pointer aligns with the fast path of `Append`.

Returning whether the right error was non-nil aligns with the standard
`if err := ...; err != nil` pattern.

```diff
-if err := thing(); err != nil {
+if multierr.AppendInto(&err, thing()) {
   continue
 }
```

Resolves #21
2019-11-04 10:23:04 -08:00
Abhinav Gupta c3fc3d02ec
Preparing release v1.3.0 (#30)
This releases v1.3.0 of multierr with support for Go modules.
2019-10-29 15:18:44 -07:00
Abhinav Gupta 2577596d7f
Switch to Go modules (#27)
This switches the library over to Go modules. This significantly
simplifies the Makefile.

We can also delete the old coverage shell script now that `./...` just
works.

As per https://github.com/golang/go/wiki/Modules#how-can-i-track-tool-dependencies-for-a-module,
tool dependencies have been added to tools.go.
2019-10-29 14:20:40 -07:00
Abhinav Gupta 71e610a0e4
Preparing release v1.2.0 (#29) 2019-09-26 15:03:28 -07:00
Abhinav Gupta 127882ebf0
Support errors.As and errors.Is (#28)
Go 1.13 includes the `errors.As` and `errors.Is` APIs.

The base functionality provided by these functions is to cast errors in
an error chain to a specific type or check for equality.

The only definition of error chain currently supported is via errors
which return the underlying cause with a `Unwrap() error` method, but
the design does not make any assumptions otherwise.

Specifically, both, `errors.As` and `errors.Is` support customizing
their behavior by implementing,

    interface { As(interface{}) bool }
    interface { Is(error) bool }

This change does exactly that, making it possible to extract or match
against individual errors in a multierr error. This will work for both,
top-level errors in a multierr error, as well as for errors wrapped by
any of those errors.
2019-09-26 13:24:24 -07:00
Abhinav Gupta bd075f90b0 error.go: Remove unused variable 2019-04-29 14:04:58 -07:00
Abhinav Gupta 0c525686c4 make: Use correct golint import path 2019-04-29 14:04:58 -07:00