fix(errors): use errors.As for wrapped error handling (#462)
IsSilentExit used type assertion which fails on wrapped errors. Changed to errors.As to properly unwrap and detect SilentExitError. Added test to verify wrapped error detection works.
This commit is contained in:
@@ -1,6 +1,9 @@
|
|||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import "fmt"
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
// SilentExitError signals that the command should exit with a specific code
|
// SilentExitError signals that the command should exit with a specific code
|
||||||
// without printing an error message. This is used for scripting purposes
|
// without printing an error message. This is used for scripting purposes
|
||||||
@@ -19,12 +22,14 @@ func NewSilentExit(code int) *SilentExitError {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// IsSilentExit checks if an error is a SilentExitError and returns its code.
|
// IsSilentExit checks if an error is a SilentExitError and returns its code.
|
||||||
|
// Uses errors.As to properly handle wrapped errors.
|
||||||
// Returns 0 and false if err is nil or not a SilentExitError.
|
// Returns 0 and false if err is nil or not a SilentExitError.
|
||||||
func IsSilentExit(err error) (int, bool) {
|
func IsSilentExit(err error) (int, bool) {
|
||||||
if err == nil {
|
if err == nil {
|
||||||
return 0, false
|
return 0, false
|
||||||
}
|
}
|
||||||
if se, ok := err.(*SilentExitError); ok {
|
var se *SilentExitError
|
||||||
|
if errors.As(err, &se) {
|
||||||
return se.Code, true
|
return se.Code, true
|
||||||
}
|
}
|
||||||
return 0, false
|
return 0, false
|
||||||
|
|||||||
@@ -54,9 +54,9 @@ func TestNewSilentExit(t *testing.T) {
|
|||||||
|
|
||||||
func TestIsSilentExit(t *testing.T) {
|
func TestIsSilentExit(t *testing.T) {
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
err error
|
err error
|
||||||
wantCode int
|
wantCode int
|
||||||
wantIsSilent bool
|
wantIsSilent bool
|
||||||
}{
|
}{
|
||||||
{"nil error", nil, 0, false},
|
{"nil error", nil, 0, false},
|
||||||
@@ -64,7 +64,7 @@ func TestIsSilentExit(t *testing.T) {
|
|||||||
{"silent exit code 1", NewSilentExit(1), 1, true},
|
{"silent exit code 1", NewSilentExit(1), 1, true},
|
||||||
{"silent exit code 2", NewSilentExit(2), 2, true},
|
{"silent exit code 2", NewSilentExit(2), 2, true},
|
||||||
{"other error", errors.New("some error"), 0, false},
|
{"other error", errors.New("some error"), 0, false},
|
||||||
// Note: wrapped errors require errors.As fix - see PR #462
|
{"wrapped silent exit", fmt.Errorf("wrapped: %w", NewSilentExit(5)), 5, true},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
@@ -81,7 +81,6 @@ func TestIsSilentExit(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestSilentExitError_Is(t *testing.T) {
|
func TestSilentExitError_Is(t *testing.T) {
|
||||||
// Test that SilentExitError works with errors.Is
|
|
||||||
err := NewSilentExit(1)
|
err := NewSilentExit(1)
|
||||||
var target *SilentExitError
|
var target *SilentExitError
|
||||||
if !errors.As(err, &target) {
|
if !errors.As(err, &target) {
|
||||||
|
|||||||
Reference in New Issue
Block a user