mirror of
https://github.com/goreleaser/goreleaser.git
synced 2025-03-29 21:47:01 +02:00
fix: skip aware semerrgroup (#1176)
* fix: skip aware semerrgroup Signed-off-by: Carlos Alexandro Becker <caarlos0@gmail.com> * fix: skip aware semerrgroup Signed-off-by: Carlos Alexandro Becker <caarlos0@gmail.com>
This commit is contained in:
parent
50235f2974
commit
d338cf7285
internal/semerrgroup
@ -2,7 +2,12 @@
|
||||
// size, so you can control the number of tasks being executed simultaneously.
|
||||
package semerrgroup
|
||||
|
||||
import "golang.org/x/sync/errgroup"
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"github.com/goreleaser/goreleaser/internal/pipe"
|
||||
"golang.org/x/sync/errgroup"
|
||||
)
|
||||
|
||||
// Group is the Semphore ErrorGroup itself
|
||||
type Group interface {
|
||||
@ -47,7 +52,8 @@ func (s *parallelGroup) Wait() error {
|
||||
var _ Group = &serialGroup{}
|
||||
|
||||
type serialGroup struct {
|
||||
err error
|
||||
err error
|
||||
errOnce sync.Once
|
||||
}
|
||||
|
||||
// Go execs runs `fn` and saves the result if no error has been encountered.
|
||||
@ -55,10 +61,52 @@ func (s *serialGroup) Go(fn func() error) {
|
||||
if s.err != nil {
|
||||
return
|
||||
}
|
||||
s.err = fn()
|
||||
if err := fn(); err != nil {
|
||||
s.errOnce.Do(func() {
|
||||
s.err = err
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Wait waits for Go to complete and returns the first error encountered.
|
||||
func (s *serialGroup) Wait() error {
|
||||
return s.err
|
||||
}
|
||||
|
||||
var _ Group = &skipAwareGroup{}
|
||||
|
||||
// NewSkipAware returns a new Group of a given size and aware of pipe skips.
|
||||
func NewSkipAware(g Group) Group {
|
||||
return &skipAwareGroup{g: g}
|
||||
}
|
||||
|
||||
type skipAwareGroup struct {
|
||||
g Group
|
||||
skipErr error
|
||||
skipOnce sync.Once
|
||||
}
|
||||
|
||||
// Go execs runs `fn` and saves the result if no error has been encountered.
|
||||
func (s *skipAwareGroup) Go(fn func() error) {
|
||||
s.g.Go(func() error {
|
||||
var err = fn()
|
||||
// if the err is a skip, set it for later, but return nil for now so the
|
||||
// the group proceeds.
|
||||
if pipe.IsSkip(err) {
|
||||
s.skipOnce.Do(func() {
|
||||
s.skipErr = err
|
||||
})
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
})
|
||||
}
|
||||
|
||||
// Wait waits for Go to complete and returns the first error encountered.
|
||||
func (s *skipAwareGroup) Wait() error {
|
||||
// if we got a "real error", return it, otherwise return skipErr or nil.
|
||||
if err := s.g.Wait(); err != nil {
|
||||
return err
|
||||
}
|
||||
return s.skipErr
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/goreleaser/goreleaser/internal/pipe"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
@ -54,3 +55,35 @@ func TestSemaphoreOrderError(t *testing.T) {
|
||||
require.EqualError(t, g.Wait(), "fake err")
|
||||
require.Equal(t, []int{0}, output)
|
||||
}
|
||||
|
||||
func TestSemaphoreSkipAware(t *testing.T) {
|
||||
var g = NewSkipAware(New(1))
|
||||
var lock sync.Mutex
|
||||
var counter int
|
||||
for i := 0; i < 10; i++ {
|
||||
g.Go(func() error {
|
||||
time.Sleep(10 * time.Millisecond)
|
||||
lock.Lock()
|
||||
counter++
|
||||
lock.Unlock()
|
||||
return pipe.Skip("fake skip")
|
||||
})
|
||||
}
|
||||
require.EqualError(t, g.Wait(), "fake skip")
|
||||
require.Equal(t, counter, 10)
|
||||
}
|
||||
|
||||
func TestSemaphoreSkipAndRealError(t *testing.T) {
|
||||
var g = NewSkipAware(New(10))
|
||||
for i := 0; i < 100; i++ {
|
||||
g.Go(func() error {
|
||||
time.Sleep(10 * time.Millisecond)
|
||||
return pipe.Skip("fake skip")
|
||||
})
|
||||
}
|
||||
g.Go(func() error {
|
||||
time.Sleep(10 * time.Millisecond)
|
||||
return fmt.Errorf("errrrrr")
|
||||
})
|
||||
require.EqualError(t, g.Wait(), "errrrrr")
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user