From f7c92625d3d16c49cb9b391d5a7ab7954e521b7e Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 14 Aug 2025 00:57:13 +0000 Subject: [PATCH] Fix helmfile init panic when helm returns invalid semantic version Co-authored-by: yxxhero <11087727+yxxhero@users.noreply.github.com> --- cmd/root.go | 4 +-- cmd/root_test.go | 66 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 68 insertions(+), 2 deletions(-) create mode 100644 cmd/root_test.go diff --git a/cmd/root.go b/cmd/root.go index ed629d12..8d185913 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -1,7 +1,6 @@ package cmd import ( - "fmt" "os" "github.com/spf13/cobra" @@ -35,7 +34,8 @@ func toCLIError(g *config.GlobalImpl, err error) error { case *app.Error: return errors.NewExitError(e.Error(), e.Code()) default: - panic(fmt.Errorf("BUG: please file an github issue for this unhandled error: %T: %v", e, e)) + // Handle any other error type gracefully with exit code 1 + return errors.NewExitError(e.Error(), 1) } } return err diff --git a/cmd/root_test.go b/cmd/root_test.go new file mode 100644 index 00000000..4964522a --- /dev/null +++ b/cmd/root_test.go @@ -0,0 +1,66 @@ +package cmd + +import ( + "fmt" + "testing" + + "github.com/helmfile/helmfile/pkg/config" + "github.com/helmfile/helmfile/pkg/errors" +) + +func TestToCLIError(t *testing.T) { + globalCfg := &config.GlobalImpl{} + + tests := []struct { + name string + err error + wantCode int + wantErr bool + }{ + { + name: "nil error", + err: nil, + wantErr: false, + }, + { + name: "regular error (like from fmt.Errorf) - this was causing the panic", + err: fmt.Errorf("invalid semantic version"), + wantCode: 1, + wantErr: true, + }, + { + name: "another regular error type", + err: fmt.Errorf("some other error"), + wantCode: 1, + wantErr: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // This should not panic for any error type + defer func() { + if r := recover(); r != nil { + t.Errorf("toCLIError() panicked: %v", r) + } + }() + + err := toCLIError(globalCfg, tt.err) + + if (err != nil) != tt.wantErr { + t.Errorf("toCLIError() error = %v, wantErr %v", err, tt.wantErr) + return + } + + if err != nil { + if exitErr, ok := err.(*errors.ExitError); ok { + if exitErr.ExitCode() != tt.wantCode { + t.Errorf("toCLIError() exit code = %v, want %v", exitErr.ExitCode(), tt.wantCode) + } + } else { + t.Errorf("toCLIError() returned non-ExitError: %T", err) + } + } + }) + } +} \ No newline at end of file