diff --git a/detect.go b/detect.go index 232a0255..50ccbecd 100644 --- a/detect.go +++ b/detect.go @@ -9,11 +9,6 @@ import ( "github.com/paketo-buildpacks/packit/internal" ) -// Fail is a sentinal value that can be used to indicate a failure to detect -// during the detect phase. Fail implements the Error interface and should be -// returned as the error value in the DetectFunc signature. -var Fail = internal.Fail - // DetectContext provides the contextual details that are made available by the // buildpack lifecycle during the detect phase. This context is populated by // the Detect function and passed to the DetectFunc during execution. diff --git a/detect_test.go b/detect_test.go index b7cfe227..d5b2d1ac 100644 --- a/detect_test.go +++ b/detect_test.go @@ -1,6 +1,7 @@ package packit_test import ( + "bytes" "errors" "io/ioutil" "os" @@ -230,14 +231,24 @@ some-key = "some-value" context("when the DetectFunc fails", func() { it("calls the ExitHandler with the correct exit code", func() { var exitCode int + buffer := bytes.NewBuffer(nil) packit.Detect(func(ctx packit.DetectContext) (packit.DetectResult, error) { - return packit.DetectResult{}, packit.Fail - }, packit.WithArgs([]string{binaryPath, "", ""}), packit.WithExitHandler(internal.NewExitHandler(internal.WithExitHandlerExitFunc(func(code int) { - exitCode = code - })))) + return packit.DetectResult{}, packit.Fail.WithMessage("failure message") + }, + packit.WithArgs([]string{binaryPath, "", ""}), + packit.WithExitHandler( + internal.NewExitHandler( + internal.WithExitHandlerExitFunc(func(code int) { + exitCode = code + }), + internal.WithExitHandlerStderr(buffer), + ), + ), + ) Expect(exitCode).To(Equal(100)) + Expect(buffer.String()).To(Equal("failure message\n")) }) }) diff --git a/fail.go b/fail.go new file mode 100644 index 00000000..ae69c0bd --- /dev/null +++ b/fail.go @@ -0,0 +1,12 @@ +package packit + +import "github.com/paketo-buildpacks/packit/internal" + +// Fail is a sentinal value that can be used to indicate a failure to detect +// during the detect phase. Fail implements the Error interface and should be +// returned as the error value in the DetectFunc signature. Fail also supports +// a modifier function, WithMessage, that allows the caller to set a custom +// failure message. The WithMessage function supports a fmt.Printf-like format +// string and variadic arguments to build a message, eg: +// packit.Fail.WithMessage("failed: %w", err). +var Fail = internal.Fail diff --git a/internal/exit_handler.go b/internal/exit_handler.go index 9e4f480e..8bb1306a 100644 --- a/internal/exit_handler.go +++ b/internal/exit_handler.go @@ -1,14 +1,11 @@ package internal import ( - "errors" "fmt" "io" "os" ) -var Fail = errors.New("failed") - type Option func(handler ExitHandler) ExitHandler func WithExitHandlerStderr(stderr io.Writer) Option { @@ -57,8 +54,8 @@ func (h ExitHandler) Error(err error) { fmt.Fprintln(h.stderr, err) var code int - switch err { - case Fail: + switch err.(type) { + case failError: code = 100 case nil: code = 0 diff --git a/internal/fail.go b/internal/fail.go new file mode 100644 index 00000000..b1393759 --- /dev/null +++ b/internal/fail.go @@ -0,0 +1,16 @@ +package internal + +import ( + "errors" + "fmt" +) + +var Fail = failError{error: errors.New("failed")} + +type failError struct { + error +} + +func (f failError) WithMessage(format string, v ...interface{}) failError { + return failError{error: fmt.Errorf(format, v...)} +} diff --git a/internal/fail_test.go b/internal/fail_test.go new file mode 100644 index 00000000..055aeb65 --- /dev/null +++ b/internal/fail_test.go @@ -0,0 +1,28 @@ +package internal_test + +import ( + "testing" + + "github.com/paketo-buildpacks/packit/internal" + "github.com/sclevine/spec" + + . "github.com/onsi/gomega" +) + +func testFail(t *testing.T, context spec.G, it spec.S) { + var ( + Expect = NewWithT(t).Expect + ) + + it("acts as an error", func() { + fail := internal.Fail + Expect(fail).To(MatchError("failed")) + }) + + context("when given a message", func() { + it("acts as an error with that message", func() { + fail := internal.Fail.WithMessage("this is a %s", "failure message") + Expect(fail).To(MatchError("this is a failure message")) + }) + }) +} diff --git a/internal/init_test.go b/internal/init_test.go index e30c9e54..baf05c62 100644 --- a/internal/init_test.go +++ b/internal/init_test.go @@ -11,6 +11,7 @@ func TestUnitInternal(t *testing.T) { suite := spec.New("packit/internal", spec.Report(report.Terminal{})) suite("EnvironmentWriter", testEnvironmentWriter) suite("ExitHandler", testExitHandler) + suite("Fail", testFail) suite("TOMLWriter", testTOMLWriter) suite.Run(t) }