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:
parent
f422e7734d
commit
ed14fe7b99
@ -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() {
|
||||
|
@ -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)
|
||||
|
53
internal/handler/handler.go
Normal file
53
internal/handler/handler.go
Normal 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)
|
||||
}
|
||||
}
|
57
internal/handler/handler_test.go
Normal file
57
internal/handler/handler_test.go
Normal 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))
|
||||
})
|
||||
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user