Skip to content

Commit

Permalink
fix: skip aware semerrgroup (#1176)
Browse files Browse the repository at this point in the history
* 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>
  • Loading branch information
caarlos0 committed Oct 6, 2019
1 parent 50235f2 commit d338cf7
Show file tree
Hide file tree
Showing 2 changed files with 84 additions and 3 deletions.
54 changes: 51 additions & 3 deletions internal/semerrgroup/sem.go
Expand Up @@ -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 {
Expand Down Expand Up @@ -47,18 +52,61 @@ 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.
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
}
33 changes: 33 additions & 0 deletions internal/semerrgroup/sem_test.go
Expand Up @@ -6,6 +6,7 @@ import (
"testing"
"time"

"github.com/goreleaser/goreleaser/internal/pipe"
"github.com/stretchr/testify/require"
)

Expand Down Expand Up @@ -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")
}

0 comments on commit d338cf7

Please sign in to comment.