1
0
mirror of https://github.com/goreleaser/goreleaser.git synced 2025-03-17 20:47:50 +02:00

fix: move code to new pkg

so we can better cover it with tests
This commit is contained in:
Carlos Alexandro Becker 2017-12-30 00:55:44 -02:00
parent f422e7734d
commit ed14fe7b99
No known key found for this signature in database
GPG Key ID: E61E2F7DC14AB940
4 changed files with 156 additions and 83 deletions

View File

@ -4,9 +4,7 @@ import (
"fmt"
"io/ioutil"
"os"
"os/signal"
"strings"
"syscall"
"time"
"github.com/apex/log"
@ -15,6 +13,7 @@ import (
"github.com/goreleaser/goreleaser/config"
"github.com/goreleaser/goreleaser/context"
"github.com/goreleaser/goreleaser/internal/handler"
"github.com/goreleaser/goreleaser/pipeline"
"github.com/goreleaser/goreleaser/pipeline/archive"
"github.com/goreleaser/goreleaser/pipeline/artifactory"
@ -114,30 +113,18 @@ func Release(flags Flags) error {
}
func doRelease(ctx *context.Context) error {
var errs = make(chan error, 1)
go func() {
defer restoreOutputPadding()
return handler.New().Run(ctx, func() error {
for _, pipe := range pipes {
restoreOutputPadding()
log.Infof("\033[1m%s\033[0m", strings.ToUpper(pipe.String()))
cli.Default.Padding = increasedPadding
if err := handle(pipe.Run(ctx)); err != nil {
errs <- err
return
return err
}
}
errs <- nil
}()
defer restoreOutputPadding()
var signals = make(chan os.Signal, 1)
signal.Notify(signals, os.Interrupt, syscall.SIGTERM)
select {
case err := <-errs:
return err
case <-ctx.Done():
return ctx.Err()
case sig := <-signals:
return fmt.Errorf("canceled due to %s", sig)
}
return nil
})
}
func restoreOutputPadding() {

View File

@ -21,42 +21,29 @@ func init() {
func TestRelease(t *testing.T) {
_, back := setup(t)
defer back()
var flags = fakeFlags{
t: t,
flags: map[string]string{
"timeout": "1m",
"skip-publish": "true",
"skip-validate": "true",
"debug": "true",
"parallelism": "4",
},
}
assert.NoError(t, Release(flags))
assert.NoError(t, Release(newFlags(t, testParams())))
}
func TestReleaseTimeout(t *testing.T) {
_, back := setup(t)
defer back()
params := testParams()
params["timeout"] = "1s"
assert.EqualError(t, Release(newFlags(t, params)), `context deadline exceeded`)
}
func TestSnapshotRelease(t *testing.T) {
_, back := setup(t)
defer back()
var flags = fakeFlags{
t: t,
flags: map[string]string{
"timeout": "1m",
"snapshot": "true",
"parallelism": "4",
},
}
assert.NoError(t, Release(flags))
params := testParams()
params["snapshot"] = "true"
assert.NoError(t, Release(newFlags(t, params)))
}
func TestConfigFileIsSetAndDontExist(t *testing.T) {
var flags = fakeFlags{
t: t,
flags: map[string]string{
"timeout": "1m",
"config": "/this/wont/exist",
},
}
assert.Error(t, Release(flags))
params := testParams()
params["config"] = "/this/wont/exist"
assert.Error(t, Release(newFlags(t, params)))
}
func TestConfigFlagNotSetButExists(t *testing.T) {
@ -76,26 +63,15 @@ func TestConfigFlagNotSetButExists(t *testing.T) {
filepath.Join(folder, name),
),
)
var flags = fakeFlags{
t: t,
flags: map[string]string{
"timeout": "1m",
},
}
assert.Equal(t, name, getConfigFile(flags))
assert.Equal(t, name, getConfigFile(newFlags(t, testParams())))
})
}
}
func TestReleaseNotesFileDontExist(t *testing.T) {
var flags = fakeFlags{
t: t,
flags: map[string]string{
"timeout": "1m",
"release-notes": "/this/also/wont/exist",
},
}
assert.Error(t, Release(flags))
params := testParams()
params["release-notes"] = "/this/also/wont/exist"
assert.Error(t, Release(newFlags(t, params)))
}
func TestCustomReleaseNotesFile(t *testing.T) {
@ -103,33 +79,16 @@ func TestCustomReleaseNotesFile(t *testing.T) {
defer back()
var releaseNotes = filepath.Join(folder, "notes.md")
createFile(t, releaseNotes, "nothing important at all")
var flags = fakeFlags{
t: t,
flags: map[string]string{
"timeout": "1m",
"release-notes": releaseNotes,
"skip-publish": "true",
"skip-validate": "true",
"parallelism": "4",
},
}
assert.NoError(t, Release(flags))
var params = testParams()
params["release-notes"] = releaseNotes
assert.NoError(t, Release(newFlags(t, params)))
}
func TestBrokenPipe(t *testing.T) {
_, back := setup(t)
defer back()
createFile(t, "main.go", "not a valid go file")
var flags = fakeFlags{
t: t,
flags: map[string]string{
"timeout": "1m",
"skip-publish": "true",
"skip-validate": "true",
"parallelism": "4",
},
}
assert.Error(t, Release(flags))
assert.Error(t, Release(newFlags(t, testParams())))
}
func TestInitProject(t *testing.T) {
@ -169,6 +128,13 @@ type fakeFlags struct {
flags map[string]string
}
func newFlags(t *testing.T, params map[string]string) Flags {
return fakeFlags{
t: t,
flags: params,
}
}
func (f fakeFlags) IsSet(s string) bool {
return f.flags[s] != ""
}
@ -192,6 +158,16 @@ func (f fakeFlags) Duration(s string) time.Duration {
return result
}
func testParams() map[string]string {
return map[string]string{
"debug": "true",
"parallelism": "4",
"skip-publish": "true",
"skip-validate": "true",
"timeout": "1m",
}
}
func setup(t *testing.T) (current string, back func()) {
folder, err := ioutil.TempDir("", "goreleaser")
assert.NoError(t, err)

View File

@ -0,0 +1,53 @@
// Package handler provides a way of having a task that is context-aware and
// that also deals with interrup and term signals.
// It was externalized mostly because it would be easier to test it this way.
// The name is not ideal but I couldn't think in a better one.
package handler
import (
"context"
"fmt"
"os"
"os/signal"
"syscall"
)
// Task is function that can be executed by a Handler
type Task func() error
// Handler is the task handler
type Handler struct {
signals chan os.Signal
errs chan error
}
// New returns a new handler with its internals setup.
func New() *Handler {
return &Handler{
signals: make(chan os.Signal, 1),
errs: make(chan error, 1),
}
}
// Run executes a given task with a given context, dealing with its timeouts,
// cancels and SIGTERM and SIGINT signals.
// It will return an error if the context is canceled, if deadline exceeds,
// if a SIGTERM or SIGINT is received and of course if the task itself fails.
func (h *Handler) Run(ctx context.Context, task Task) error {
go func() {
if err := task(); err != nil {
h.errs <- err
return
}
h.errs <- nil
}()
signal.Notify(h.signals, syscall.SIGINT, syscall.SIGTERM)
select {
case err := <-h.errs:
return err
case <-ctx.Done():
return ctx.Err()
case sig := <-h.signals:
return fmt.Errorf("received: %s", sig)
}
}

View File

@ -0,0 +1,57 @@
package handler
import (
"context"
"errors"
"fmt"
"os"
"syscall"
"testing"
"time"
"github.com/stretchr/testify/assert"
)
func TestHandlerOK(t *testing.T) {
assert.NoError(t, New().Run(context.Background(), func() error {
return nil
}))
}
func TestHandlerErrors(t *testing.T) {
var err = errors.New("some error")
assert.EqualError(t, New().Run(context.Background(), func() error {
return err
}), err.Error())
}
func TestHandlerTimeout(t *testing.T) {
ctx, cancel := context.WithTimeout(context.Background(), time.Nanosecond)
defer cancel()
assert.EqualError(t, New().Run(ctx, func() error {
t.Log("slow task...")
time.Sleep(time.Minute)
return nil
}), "context deadline exceeded")
}
func TestHandlerSignals(t *testing.T) {
for _, signal := range []os.Signal{syscall.SIGINT, syscall.SIGTERM} {
signal := signal
t.Run(signal.String(), func(tt *testing.T) {
tt.Parallel()
var h = New()
var errs = make(chan error, 1)
go func() {
errs <- h.Run(context.Background(), func() error {
tt.Log("slow task...")
time.Sleep(time.Minute)
return nil
})
}()
h.signals <- signal
assert.EqualError(tt, <-errs, fmt.Sprintf("received: %s", signal))
})
}
}