chore: enable errorlint

Signed-off-by: Matthieu MOREL <matthieu.morel35@gmail.com>
pull/30808/head
Matthieu MOREL 5 months ago
parent 505b487de2
commit a96dda4f43

@ -20,6 +20,7 @@ linters:
enable: enable:
- depguard - depguard
- dupl - dupl
- errorlint
- gomodguard - gomodguard
- govet - govet
- ineffassign - ineffassign

@ -17,6 +17,7 @@ limitations under the License.
package main // import "helm.sh/helm/v4/cmd/helm" package main // import "helm.sh/helm/v4/cmd/helm"
import ( import (
"errors"
"log/slog" "log/slog"
"os" "os"
@ -41,8 +42,9 @@ func main() {
} }
if err := cmd.Execute(); err != nil { if err := cmd.Execute(); err != nil {
switch e := err.(type) { var e helmcmd.PluginError
case helmcmd.PluginError: switch {
case errors.As(err, &e):
os.Exit(e.Code) os.Exit(e.Code)
default: default:
os.Exit(1) os.Exit(1)

@ -22,6 +22,8 @@ import (
"os/exec" "os/exec"
"runtime" "runtime"
"testing" "testing"
"github.com/stretchr/testify/require"
) )
func TestPluginExitCode(t *testing.T) { func TestPluginExitCode(t *testing.T) {
@ -57,11 +59,9 @@ func TestPluginExitCode(t *testing.T) {
cmd.Stdout = stdout cmd.Stdout = stdout
cmd.Stderr = stderr cmd.Stderr = stderr
err := cmd.Run() err := cmd.Run()
exiterr, ok := err.(*exec.ExitError) var exiterr *exec.ExitError
if !ok { require.ErrorAs(t, err, &exiterr, "Unexpected error returned by os.Exit: %T", err)
t.Fatalf("Unexpected error returned by os.Exit: %T", err)
}
if stdout.String() != "" { if stdout.String() != "" {
t.Errorf("Expected no write to stdout: Got %q", stdout.String()) t.Errorf("Expected no write to stdout: Got %q", stdout.String())

@ -72,8 +72,8 @@ func LoadFile(name string) (*chart.Chart, error) {
c, err := LoadArchive(raw) c, err := LoadArchive(raw)
if err != nil { if err != nil {
if err == gzip.ErrHeader { if errors.Is(err, gzip.ErrHeader) {
return nil, fmt.Errorf("file '%s' does not appear to be a valid chart file (details: %s)", name, err) return nil, fmt.Errorf("file '%s' does not appear to be a valid chart file (details: %w)", name, err)
} }
} }
return c, err return c, err
@ -91,7 +91,7 @@ func ensureArchive(name string, raw *os.File) error {
buffer := make([]byte, 512) buffer := make([]byte, 512)
_, err := raw.Read(buffer) _, err := raw.Read(buffer)
if err != nil && err != io.EOF { if err != nil && err != io.EOF {
return fmt.Errorf("file '%s' cannot be read: %s", name, err) return fmt.Errorf("file '%s' cannot be read: %w", name, err)
} }
// Helm may identify achieve of the application/x-gzip as application/vnd.ms-fontobject. // Helm may identify achieve of the application/x-gzip as application/vnd.ms-fontobject.
@ -131,7 +131,7 @@ func LoadArchiveFiles(in io.Reader) ([]*BufferedFile, error) {
for { for {
b := bytes.NewBuffer(nil) b := bytes.NewBuffer(nil)
hd, err := tr.Next() hd, err := tr.Next()
if err == io.EOF { if errors.Is(err, io.EOF) {
break break
} }
if err != nil { if err != nil {

@ -186,7 +186,7 @@ func LoadValues(data io.Reader) (map[string]interface{}, error) {
currentMap := map[string]interface{}{} currentMap := map[string]interface{}{}
raw, err := reader.Read() raw, err := reader.Read()
if err != nil { if err != nil {
if err == io.EOF { if errors.Is(err, io.EOF) {
break break
} }
return nil, fmt.Errorf("error reading yaml document: %w", err) return nil, fmt.Errorf("error reading yaml document: %w", err)

@ -16,6 +16,7 @@ limitations under the License.
package v3 package v3
import ( import (
"errors"
"testing" "testing"
) )
@ -181,7 +182,7 @@ func TestValidate(t *testing.T) {
for _, tt := range tests { for _, tt := range tests {
result := tt.md.Validate() result := tt.md.Validate()
if result != tt.err { if !errors.Is(result, tt.err) {
t.Errorf("expected %q, got %q in test %q", tt.err, result, tt.name) t.Errorf("expected %q, got %q in test %q", tt.err, result, tt.name)
} }
} }

@ -16,6 +16,7 @@ limitations under the License.
package util package util
import ( import (
"errors"
"log/slog" "log/slog"
"strings" "strings"
@ -42,6 +43,7 @@ func processDependencyConditions(reqs []*chart.Dependency, cvals Values, cpath s
if len(c) > 0 { if len(c) > 0 {
// retrieve value // retrieve value
vv, err := cvals.PathValue(cpath + c) vv, err := cvals.PathValue(cpath + c)
var errNoValue ErrNoValue
if err == nil { if err == nil {
// if not bool, warn // if not bool, warn
if bv, ok := vv.(bool); ok { if bv, ok := vv.(bool); ok {
@ -49,7 +51,7 @@ func processDependencyConditions(reqs []*chart.Dependency, cvals Values, cpath s
break break
} }
slog.Warn("returned non-bool value", "path", c, "chart", r.Name) slog.Warn("returned non-bool value", "path", c, "chart", r.Name)
} else if _, ok := err.(ErrNoValue); !ok { } else if !errors.As(err, &errNoValue) {
// this is a real error // this is a real error
slog.Warn("the method PathValue returned error", slog.Any("error", err)) slog.Warn("the method PathValue returned error", slog.Any("error", err))
} }

@ -21,6 +21,8 @@ import (
"strconv" "strconv"
"testing" "testing"
"github.com/stretchr/testify/require"
chart "helm.sh/helm/v4/internal/chart/v3" chart "helm.sh/helm/v4/internal/chart/v3"
"helm.sh/helm/v4/internal/chart/v3/loader" "helm.sh/helm/v4/internal/chart/v3/loader"
) )
@ -250,12 +252,8 @@ func TestProcessDependencyImportValues(t *testing.T) {
if err == nil { if err == nil {
t.Error("expect nil value not found but found it") t.Error("expect nil value not found but found it")
} }
switch xerr := err.(type) { var errNoValue ErrNoValue
case ErrNoValue: require.ErrorAs(t, err, &errNoValue, "expected an ErrNoValue but got %q instead", err)
// We found what we expected
default:
t.Errorf("expected an ErrNoValue but got %q instead", xerr)
}
c = loadChart(t, "testdata/subpop") c = loadChart(t, "testdata/subpop")
if err := processDependencyImportValues(c, true); err != nil { if err := processDependencyImportValues(c, true); err != nil {

@ -21,6 +21,7 @@ limitations under the License.
package sympath package sympath
import ( import (
"errors"
"fmt" "fmt"
"log/slog" "log/slog"
"os" "os"
@ -40,7 +41,7 @@ func Walk(root string, walkFn filepath.WalkFunc) error {
} else { } else {
err = symwalk(root, info, walkFn) err = symwalk(root, info, walkFn)
} }
if err == filepath.SkipDir { if errors.Is(err, filepath.SkipDir) {
return nil return nil
} }
return err return err
@ -75,7 +76,7 @@ func symwalk(path string, info os.FileInfo, walkFn filepath.WalkFunc) error {
if info, err = os.Lstat(resolved); err != nil { if info, err = os.Lstat(resolved); err != nil {
return err return err
} }
if err := symwalk(path, info, walkFn); err != nil && err != filepath.SkipDir { if err := symwalk(path, info, walkFn); err != nil && !errors.Is(err, filepath.SkipDir) {
return err return err
} }
return nil return nil
@ -98,13 +99,13 @@ func symwalk(path string, info os.FileInfo, walkFn filepath.WalkFunc) error {
filename := filepath.Join(path, name) filename := filepath.Join(path, name)
fileInfo, err := os.Lstat(filename) fileInfo, err := os.Lstat(filename)
if err != nil { if err != nil {
if err := walkFn(filename, fileInfo, err); err != nil && err != filepath.SkipDir { if err := walkFn(filename, fileInfo, err); err != nil && !errors.Is(err, filepath.SkipDir) {
return err return err
} }
} else { } else {
err = symwalk(filename, fileInfo, walkFn) err = symwalk(filename, fileInfo, walkFn)
if err != nil { if err != nil {
if (!fileInfo.IsDir() && !IsSymlink(fileInfo)) || err != filepath.SkipDir { if (!fileInfo.IsDir() && !IsSymlink(fileInfo)) || !errors.Is(err, filepath.SkipDir) {
return err return err
} }
} }

@ -164,7 +164,8 @@ func copyFile(src, dst string) (err error) {
// //
// ERROR_PRIVILEGE_NOT_HELD is 1314 (0x522): // ERROR_PRIVILEGE_NOT_HELD is 1314 (0x522):
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms681385(v=vs.85).aspx // https://msdn.microsoft.com/en-us/library/windows/desktop/ms681385(v=vs.85).aspx
if lerr, ok := err.(*os.LinkError); ok && lerr.Err != syscall.Errno(1314) { var lerr *os.LinkError
if errors.As(err, &lerr) && !errors.Is(lerr.Err, syscall.Errno(1314)) {
return err return err
} }
} else { } else {

@ -36,6 +36,8 @@ import (
"path/filepath" "path/filepath"
"runtime" "runtime"
"testing" "testing"
"github.com/stretchr/testify/require"
) )
func TestRenameWithFallback(t *testing.T) { func TestRenameWithFallback(t *testing.T) {
@ -234,9 +236,7 @@ func TestCopyDirFail_SrcIsNotDir(t *testing.T) {
t.Fatalf("expected error for CopyDir(%s, %s), got none", srcdir, dstdir) t.Fatalf("expected error for CopyDir(%s, %s), got none", srcdir, dstdir)
} }
if err != errSrcNotDir { require.ErrorIsf(t, err, errSrcNotDir, "expected %v error for CopyDir(%s, %s), got %s", errSrcNotDir, srcdir, dstdir, err)
t.Fatalf("expected %v error for CopyDir(%s, %s), got %s", errSrcNotDir, srcdir, dstdir, err)
}
} }
@ -260,9 +260,7 @@ func TestCopyDirFail_DstExists(t *testing.T) {
t.Fatalf("expected error for CopyDir(%s, %s), got none", srcdir, dstdir) t.Fatalf("expected error for CopyDir(%s, %s), got none", srcdir, dstdir)
} }
if err != errDstExist { require.ErrorIsf(t, err, errDstExist, "expected %v error for CopyDir(%s, %s), got %s", errDstExist, srcdir, dstdir, err)
t.Fatalf("expected %v error for CopyDir(%s, %s), got %s", errDstExist, srcdir, dstdir, err)
}
} }
func TestCopyDirFailOpen(t *testing.T) { func TestCopyDirFailOpen(t *testing.T) {

@ -34,6 +34,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package fs package fs
import ( import (
"errors"
"fmt" "fmt"
"os" "os"
"syscall" "syscall"
@ -46,10 +47,10 @@ func renameFallback(err error, src, dst string) error {
// copy if we detect that case. syscall.EXDEV is the common name for the // copy if we detect that case. syscall.EXDEV is the common name for the
// cross device link error which has varying output text across different // cross device link error which has varying output text across different
// operating systems. // operating systems.
terr, ok := err.(*os.LinkError) var terr *os.LinkError
if !ok { if !errors.As(err, &terr) {
return err return err
} else if terr.Err != syscall.EXDEV { } else if !errors.Is(terr.Err, syscall.EXDEV) {
return fmt.Errorf("link error: cannot rename %s to %s: %w", src, dst, terr) return fmt.Errorf("link error: cannot rename %s to %s: %w", src, dst, terr)
} }

@ -460,7 +460,7 @@ func (i *Install) performInstall(rel *release.Release, toBeAdopted kube.Resource
// pre-install hooks // pre-install hooks
if !i.DisableHooks { if !i.DisableHooks {
if err := i.cfg.execHook(rel, release.HookPreInstall, i.WaitStrategy, i.Timeout); err != nil { if err := i.cfg.execHook(rel, release.HookPreInstall, i.WaitStrategy, i.Timeout); err != nil {
return rel, fmt.Errorf("failed pre-install: %s", err) return rel, fmt.Errorf("failed pre-install: %w", err)
} }
} }
@ -496,7 +496,7 @@ func (i *Install) performInstall(rel *release.Release, toBeAdopted kube.Resource
if !i.DisableHooks { if !i.DisableHooks {
if err := i.cfg.execHook(rel, release.HookPostInstall, i.WaitStrategy, i.Timeout); err != nil { if err := i.cfg.execHook(rel, release.HookPostInstall, i.WaitStrategy, i.Timeout); err != nil {
return rel, fmt.Errorf("failed post-install: %s", err) return rel, fmt.Errorf("failed post-install: %w", err)
} }
} }

@ -22,6 +22,7 @@ import (
"testing" "testing"
"github.com/Masterminds/semver/v3" "github.com/Masterminds/semver/v3"
"github.com/stretchr/testify/require"
"helm.sh/helm/v4/internal/test/ensure" "helm.sh/helm/v4/internal/test/ensure"
) )
@ -144,10 +145,7 @@ func TestValidateVersion(t *testing.T) {
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
if err := validateVersion(tt.args.ver); err != nil { if err := validateVersion(tt.args.ver); err != nil {
if err != tt.wantErr { require.ErrorIsf(t, err, tt.wantErr, "Expected {%v}, got {%v}", tt.wantErr, err)
t.Errorf("Expected {%v}, got {%v}", tt.wantErr, err)
}
} }
}) })
} }

@ -419,7 +419,7 @@ func (u *Upgrade) releasingUpgrade(c chan<- resultMessage, upgradedRelease *rele
if !u.DisableHooks { if !u.DisableHooks {
if err := u.cfg.execHook(upgradedRelease, release.HookPreUpgrade, u.WaitStrategy, u.Timeout); err != nil { if err := u.cfg.execHook(upgradedRelease, release.HookPreUpgrade, u.WaitStrategy, u.Timeout); err != nil {
u.reportToPerformUpgrade(c, upgradedRelease, kube.ResourceList{}, fmt.Errorf("pre-upgrade hooks failed: %s", err)) u.reportToPerformUpgrade(c, upgradedRelease, kube.ResourceList{}, fmt.Errorf("pre-upgrade hooks failed: %w", err))
return return
} }
} else { } else {
@ -456,7 +456,7 @@ func (u *Upgrade) releasingUpgrade(c chan<- resultMessage, upgradedRelease *rele
// post-upgrade hooks // post-upgrade hooks
if !u.DisableHooks { if !u.DisableHooks {
if err := u.cfg.execHook(upgradedRelease, release.HookPostUpgrade, u.WaitStrategy, u.Timeout); err != nil { if err := u.cfg.execHook(upgradedRelease, release.HookPostUpgrade, u.WaitStrategy, u.Timeout); err != nil {
u.reportToPerformUpgrade(c, upgradedRelease, results.Created, fmt.Errorf("post-upgrade hooks failed: %s", err)) u.reportToPerformUpgrade(c, upgradedRelease, results.Created, fmt.Errorf("post-upgrade hooks failed: %w", err))
return return
} }
} }

@ -81,7 +81,7 @@ func existingResourceConflict(resources kube.ResourceList, releaseName, releaseN
// Allow adoption of the resource if it is managed by Helm and is annotated with correct release name and namespace. // Allow adoption of the resource if it is managed by Helm and is annotated with correct release name and namespace.
if err := checkOwnership(existing, releaseName, releaseNamespace); err != nil { if err := checkOwnership(existing, releaseName, releaseNamespace); err != nil {
return fmt.Errorf("%s exists and cannot be imported into the current release: %s", resourceString(info), err) return fmt.Errorf("%s exists and cannot be imported into the current release: %w", resourceString(info), err)
} }
requireUpdate.Append(info) requireUpdate.Append(info)
@ -103,13 +103,13 @@ func checkOwnership(obj runtime.Object, releaseName, releaseNamespace string) er
var errs []error var errs []error
if err := requireValue(lbls, appManagedByLabel, appManagedByHelm); err != nil { if err := requireValue(lbls, appManagedByLabel, appManagedByHelm); err != nil {
errs = append(errs, fmt.Errorf("label validation error: %s", err)) errs = append(errs, fmt.Errorf("label validation error: %w", err))
} }
if err := requireValue(annos, helmReleaseNameAnnotation, releaseName); err != nil { if err := requireValue(annos, helmReleaseNameAnnotation, releaseName); err != nil {
errs = append(errs, fmt.Errorf("annotation validation error: %s", err)) errs = append(errs, fmt.Errorf("annotation validation error: %w", err))
} }
if err := requireValue(annos, helmReleaseNamespaceAnnotation, releaseNamespace); err != nil { if err := requireValue(annos, helmReleaseNamespaceAnnotation, releaseNamespace); err != nil {
errs = append(errs, fmt.Errorf("annotation validation error: %s", err)) errs = append(errs, fmt.Errorf("annotation validation error: %w", err))
} }
if len(errs) > 0 { if len(errs) > 0 {
@ -141,7 +141,7 @@ func setMetadataVisitor(releaseName, releaseNamespace string, forceOwnership boo
if !forceOwnership { if !forceOwnership {
if err := checkOwnership(info.Object, releaseName, releaseNamespace); err != nil { if err := checkOwnership(info.Object, releaseName, releaseNamespace); err != nil {
return fmt.Errorf("%s cannot be owned: %s", resourceString(info), err) return fmt.Errorf("%s cannot be owned: %w", resourceString(info), err)
} }
} }
@ -149,7 +149,7 @@ func setMetadataVisitor(releaseName, releaseNamespace string, forceOwnership boo
appManagedByLabel: appManagedByHelm, appManagedByLabel: appManagedByHelm,
}); err != nil { }); err != nil {
return fmt.Errorf( return fmt.Errorf(
"%s labels could not be updated: %s", "%s labels could not be updated: %w",
resourceString(info), err, resourceString(info), err,
) )
} }
@ -159,7 +159,7 @@ func setMetadataVisitor(releaseName, releaseNamespace string, forceOwnership boo
helmReleaseNamespaceAnnotation: releaseNamespace, helmReleaseNamespaceAnnotation: releaseNamespace,
}); err != nil { }); err != nil {
return fmt.Errorf( return fmt.Errorf(
"%s annotations could not be updated: %s", "%s annotations could not be updated: %w",
resourceString(info), err, resourceString(info), err,
) )
} }

@ -72,8 +72,8 @@ func LoadFile(name string) (*chart.Chart, error) {
c, err := LoadArchive(raw) c, err := LoadArchive(raw)
if err != nil { if err != nil {
if err == gzip.ErrHeader { if errors.Is(err, gzip.ErrHeader) {
return nil, fmt.Errorf("file '%s' does not appear to be a valid chart file (details: %s)", name, err) return nil, fmt.Errorf("file '%s' does not appear to be a valid chart file (details: %w)", name, err)
} }
} }
return c, err return c, err
@ -90,8 +90,8 @@ func ensureArchive(name string, raw *os.File) error {
// Check the file format to give us a chance to provide the user with more actionable feedback. // Check the file format to give us a chance to provide the user with more actionable feedback.
buffer := make([]byte, 512) buffer := make([]byte, 512)
_, err := raw.Read(buffer) _, err := raw.Read(buffer)
if err != nil && err != io.EOF { if err != nil && !errors.Is(err, io.EOF) {
return fmt.Errorf("file '%s' cannot be read: %s", name, err) return fmt.Errorf("file '%s' cannot be read: %w", name, err)
} }
// Helm may identify achieve of the application/x-gzip as application/vnd.ms-fontobject. // Helm may identify achieve of the application/x-gzip as application/vnd.ms-fontobject.
@ -131,7 +131,7 @@ func LoadArchiveFiles(in io.Reader) ([]*BufferedFile, error) {
for { for {
b := bytes.NewBuffer(nil) b := bytes.NewBuffer(nil)
hd, err := tr.Next() hd, err := tr.Next()
if err == io.EOF { if errors.Is(err, io.EOF) {
break break
} }
if err != nil { if err != nil {

@ -218,7 +218,7 @@ func LoadValues(data io.Reader) (map[string]interface{}, error) {
currentMap := map[string]interface{}{} currentMap := map[string]interface{}{}
raw, err := reader.Read() raw, err := reader.Read()
if err != nil { if err != nil {
if err == io.EOF { if errors.Is(err, io.EOF) {
break break
} }
return nil, fmt.Errorf("error reading yaml document: %w", err) return nil, fmt.Errorf("error reading yaml document: %w", err)

@ -17,6 +17,8 @@ package v2
import ( import (
"testing" "testing"
"github.com/stretchr/testify/require"
) )
func TestValidate(t *testing.T) { func TestValidate(t *testing.T) {
@ -181,9 +183,7 @@ func TestValidate(t *testing.T) {
for _, tt := range tests { for _, tt := range tests {
result := tt.md.Validate() result := tt.md.Validate()
if result != tt.err { require.ErrorIsf(t, result, tt.err, "expected %q, got %q in test %q", tt.err, result, tt.name)
t.Errorf("expected %q, got %q in test %q", tt.err, result, tt.name)
}
} }
} }

@ -16,6 +16,7 @@ limitations under the License.
package util package util
import ( import (
"errors"
"log/slog" "log/slog"
"strings" "strings"
@ -42,14 +43,16 @@ func processDependencyConditions(reqs []*chart.Dependency, cvals Values, cpath s
if len(c) > 0 { if len(c) > 0 {
// retrieve value // retrieve value
vv, err := cvals.PathValue(cpath + c) vv, err := cvals.PathValue(cpath + c)
if err == nil { var errNoValue ErrNoValue
switch {
case err == nil:
// if not bool, warn // if not bool, warn
if bv, ok := vv.(bool); ok { if bv, ok := vv.(bool); ok {
r.Enabled = bv r.Enabled = bv
break break
} }
slog.Warn("returned non-bool value", "path", c, "chart", r.Name) slog.Warn("returned non-bool value", "path", c, "chart", r.Name)
} else if _, ok := err.(ErrNoValue); !ok { case !errors.As(err, &errNoValue):
// this is a real error // this is a real error
slog.Warn("the method PathValue returned error", slog.Any("error", err)) slog.Warn("the method PathValue returned error", slog.Any("error", err))
} }

@ -21,6 +21,8 @@ import (
"strconv" "strconv"
"testing" "testing"
"github.com/stretchr/testify/require"
chart "helm.sh/helm/v4/pkg/chart/v2" chart "helm.sh/helm/v4/pkg/chart/v2"
"helm.sh/helm/v4/pkg/chart/v2/loader" "helm.sh/helm/v4/pkg/chart/v2/loader"
) )
@ -250,12 +252,8 @@ func TestProcessDependencyImportValues(t *testing.T) {
if err == nil { if err == nil {
t.Error("expect nil value not found but found it") t.Error("expect nil value not found but found it")
} }
switch xerr := err.(type) { var xerr ErrNoValue
case ErrNoValue: require.ErrorAs(t, err, &xerr, "expected an ErrNoValue but got %q instead", err)
// We found what we expected
default:
t.Errorf("expected an ErrNoValue but got %q instead", xerr)
}
c = loadChart(t, "testdata/subpop") c = loadChart(t, "testdata/subpop")
if err := processDependencyImportValues(c, true); err != nil { if err := processDependencyImportValues(c, true); err != nil {
@ -458,7 +456,6 @@ func TestDependentChartAliases(t *testing.T) {
if aliasChart := getAliasDependency(c.Dependencies(), req[2]); aliasChart != nil { if aliasChart := getAliasDependency(c.Dependencies(), req[2]); aliasChart != nil {
t.Fatalf("expected no chart but got %s", aliasChart.Name()) t.Fatalf("expected no chart but got %s", aliasChart.Name())
} }
} }
func TestDependentChartWithSubChartsAbsentInDependency(t *testing.T) { func TestDependentChartWithSubChartsAbsentInDependency(t *testing.T) {

@ -16,6 +16,7 @@ limitations under the License.
package cmd package cmd
import ( import (
"errors"
"fmt" "fmt"
"io" "io"
"os" "os"
@ -75,7 +76,8 @@ func newDependencyBuildCmd(out io.Writer) *cobra.Command {
man.Verify = downloader.VerifyIfPossible man.Verify = downloader.VerifyIfPossible
} }
err = man.Build() err = man.Build()
if e, ok := err.(downloader.ErrRepoNotFound); ok { var e downloader.ErrRepoNotFound
if errors.As(err, &e) {
return fmt.Errorf("%s. Please add the missing repos via 'helm repo add'", e.Error()) return fmt.Errorf("%s. Please add the missing repos via 'helm repo add'", e.Error())
} }
return err return err

@ -16,7 +16,6 @@ limitations under the License.
package cmd package cmd
import ( import (
"errors"
"fmt" "fmt"
"io/fs" "io/fs"
"os" "os"
@ -24,6 +23,8 @@ import (
"strings" "strings"
"testing" "testing"
"github.com/stretchr/testify/require"
"helm.sh/helm/v4/internal/test/ensure" "helm.sh/helm/v4/internal/test/ensure"
chart "helm.sh/helm/v4/pkg/chart/v2" chart "helm.sh/helm/v4/pkg/chart/v2"
chartutil "helm.sh/helm/v4/pkg/chart/v2/util" chartutil "helm.sh/helm/v4/pkg/chart/v2/util"
@ -204,9 +205,8 @@ func TestDependencyUpdateCmd_DoNotDeleteOldChartsOnError(t *testing.T) {
// Make sure tmpcharts-x is deleted // Make sure tmpcharts-x is deleted
tmpPath := filepath.Join(dir(chartname), fmt.Sprintf("tmpcharts-%d", os.Getpid())) tmpPath := filepath.Join(dir(chartname), fmt.Sprintf("tmpcharts-%d", os.Getpid()))
if _, err := os.Stat(tmpPath); !errors.Is(err, fs.ErrNotExist) { _, err = os.Stat(tmpPath)
t.Fatalf("tmpcharts dir still exists") require.ErrorIsf(t, err, fs.ErrNotExist, "tmpcharts dir still exists")
}
} }
func TestDependencyUpdateCmd_WithRepoThatWasNotAdded(t *testing.T) { func TestDependencyUpdateCmd_WithRepoThatWasNotAdded(t *testing.T) {

@ -60,7 +60,7 @@ func newLintCmd(out io.Writer) *cobra.Command {
if kubeVersion != "" { if kubeVersion != "" {
parsedKubeVersion, err := chartutil.ParseKubeVersion(kubeVersion) parsedKubeVersion, err := chartutil.ParseKubeVersion(kubeVersion)
if err != nil { if err != nil {
return fmt.Errorf("invalid kube version '%s': %s", kubeVersion, err) return fmt.Errorf("invalid kube version '%s': %w", kubeVersion, err)
} }
client.KubeVersion = parsedKubeVersion client.KubeVersion = parsedKubeVersion
} }

@ -17,6 +17,7 @@ package cmd
import ( import (
"bytes" "bytes"
"errors"
"fmt" "fmt"
"io" "io"
"log" "log"
@ -134,7 +135,8 @@ func callPluginExecutable(pluginName string, main string, argv []string, out io.
prog.Stdout = out prog.Stdout = out
prog.Stderr = os.Stderr prog.Stderr = os.Stderr
if err := prog.Run(); err != nil { if err := prog.Run(); err != nil {
if eerr, ok := err.(*exec.ExitError); ok { var eerr *exec.ExitError
if errors.As(err, &eerr) {
os.Stderr.Write(eerr.Stderr) os.Stderr.Write(eerr.Stderr)
status := eerr.Sys().(syscall.WaitStatus) status := eerr.Sys().(syscall.WaitStatus)
return PluginError{ return PluginError{

@ -16,6 +16,7 @@ limitations under the License.
package cmd package cmd
import ( import (
"errors"
"fmt" "fmt"
"io" "io"
"log/slog" "log/slog"
@ -71,7 +72,8 @@ func runHook(p *plugin.Plugin, event string) error {
prog.Stdout, prog.Stderr = os.Stdout, os.Stderr prog.Stdout, prog.Stderr = os.Stdout, os.Stderr
if err := prog.Run(); err != nil { if err := prog.Run(); err != nil {
if eerr, ok := err.(*exec.ExitError); ok { var eerr *exec.ExitError
if errors.As(err, &eerr) {
os.Stderr.Write(eerr.Stderr) os.Stderr.Write(eerr.Stderr)
return fmt.Errorf("plugin %s hook for %q exited with error", event, p.Metadata.Name) return fmt.Errorf("plugin %s hook for %q exited with error", event, p.Metadata.Name)
} }

@ -25,6 +25,7 @@ import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
"github.com/spf13/pflag" "github.com/spf13/pflag"
"github.com/stretchr/testify/require"
release "helm.sh/helm/v4/pkg/release/v1" release "helm.sh/helm/v4/pkg/release/v1"
) )
@ -142,10 +143,8 @@ func TestLoadPlugins(t *testing.T) {
if runtime.GOOS != "windows" { if runtime.GOOS != "windows" {
if err := pp.RunE(pp, tt.args); err != nil { if err := pp.RunE(pp, tt.args); err != nil {
if tt.code > 0 { if tt.code > 0 {
perr, ok := err.(PluginError) var perr PluginError
if !ok { require.ErrorAs(t, err, &perr, "Expected %s to return pluginError: got %v(%T)", tt.use, err, err)
t.Errorf("Expected %s to return pluginError: got %v(%T)", tt.use, err, err)
}
if perr.Code != tt.code { if perr.Code != tt.code {
t.Errorf("Expected %s to return %d: got %d", tt.use, tt.code, perr.Code) t.Errorf("Expected %s to return %d: got %d", tt.use, tt.code, perr.Code)
} }
@ -217,10 +216,8 @@ func TestLoadPluginsWithSpace(t *testing.T) {
if runtime.GOOS != "windows" { if runtime.GOOS != "windows" {
if err := pp.RunE(pp, tt.args); err != nil { if err := pp.RunE(pp, tt.args); err != nil {
if tt.code > 0 { if tt.code > 0 {
perr, ok := err.(PluginError) var perr PluginError
if !ok { require.ErrorAs(t, err, &perr, "Expected %s to return pluginError: got %v(%T)", tt.use, err, err)
t.Errorf("Expected %s to return pluginError: got %v(%T)", tt.use, err, err)
}
if perr.Code != tt.code { if perr.Code != tt.code {
t.Errorf("Expected %s to return %d: got %d", tt.use, tt.code, perr.Code) t.Errorf("Expected %s to return %d: got %d", tt.use, tt.code, perr.Code)
} }

@ -69,7 +69,7 @@ func (o *pluginUninstallOptions) run(out io.Writer) error {
for _, name := range o.names { for _, name := range o.names {
if found := findPlugin(plugins, name); found != nil { if found := findPlugin(plugins, name); found != nil {
if err := uninstallPlugin(found); err != nil { if err := uninstallPlugin(found); err != nil {
errorPlugins = append(errorPlugins, fmt.Errorf("failed to uninstall plugin %s, got error (%v)", name, err)) errorPlugins = append(errorPlugins, fmt.Errorf("failed to uninstall plugin %s, got error (%w)", name, err))
} else { } else {
fmt.Fprintf(out, "Uninstalled plugin: %s\n", name) fmt.Fprintf(out, "Uninstalled plugin: %s\n", name)
} }

@ -72,7 +72,7 @@ func (o *pluginUpdateOptions) run(out io.Writer) error {
for _, name := range o.names { for _, name := range o.names {
if found := findPlugin(plugins, name); found != nil { if found := findPlugin(plugins, name); found != nil {
if err := updatePlugin(found); err != nil { if err := updatePlugin(found); err != nil {
errorPlugins = append(errorPlugins, fmt.Errorf("failed to update plugin %s, got error (%v)", name, err)) errorPlugins = append(errorPlugins, fmt.Errorf("failed to update plugin %s, got error (%w)", name, err))
} else { } else {
fmt.Fprintf(out, "Updated plugin: %s\n", name) fmt.Fprintf(out, "Updated plugin: %s\n", name)
} }

@ -61,7 +61,7 @@ func newRollbackCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
if len(args) > 1 { if len(args) > 1 {
ver, err := strconv.Atoi(args[1]) ver, err := strconv.Atoi(args[1])
if err != nil { if err != nil {
return fmt.Errorf("could not convert revision to a number: %v", err) return fmt.Errorf("could not convert revision to a number: %w", err)
} }
client.Version = ver client.Version = ver
} }

@ -141,7 +141,7 @@ func (h *hubSearchWriter) WriteTable(out io.Writer) error {
_, err := out.Write([]byte("No results found\n")) _, err := out.Write([]byte("No results found\n"))
if err != nil { if err != nil {
return fmt.Errorf("unable to write results: %s", err) return fmt.Errorf("unable to write results: %w", err)
} }
return nil return nil
} }

@ -221,7 +221,7 @@ func (r *repoSearchWriter) WriteTable(out io.Writer) error {
_, err := out.Write([]byte("No results found\n")) _, err := out.Write([]byte("No results found\n"))
if err != nil { if err != nil {
return fmt.Errorf("unable to write results: %s", err) return fmt.Errorf("unable to write results: %w", err)
} }
return nil return nil
} }

@ -71,7 +71,7 @@ func newTemplateCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
if kubeVersion != "" { if kubeVersion != "" {
parsedKubeVersion, err := chartutil.ParseKubeVersion(kubeVersion) parsedKubeVersion, err := chartutil.ParseKubeVersion(kubeVersion)
if err != nil { if err != nil {
return fmt.Errorf("invalid kube version '%s': %s", kubeVersion, err) return fmt.Errorf("invalid kube version '%s': %w", kubeVersion, err)
} }
client.KubeVersion = parsedKubeVersion client.KubeVersion = parsedKubeVersion
} }

@ -18,6 +18,7 @@ package cmd
import ( import (
"context" "context"
"errors"
"fmt" "fmt"
"io" "io"
"log" "log"
@ -122,7 +123,7 @@ func newUpgradeCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
histClient := action.NewHistory(cfg) histClient := action.NewHistory(cfg)
histClient.Max = 1 histClient.Max = 1
versions, err := histClient.Run(args[0]) versions, err := histClient.Run(args[0])
if err == driver.ErrReleaseNotFound || isReleaseUninstalled(versions) { if errors.Is(err, driver.ErrReleaseNotFound) || isReleaseUninstalled(versions) {
// Only print this to stdout for table output // Only print this to stdout for table output
if outfmt == output.Table { if outfmt == output.Table {
fmt.Fprintf(out, "Release %q does not exist. Installing it now.\n", args[0]) fmt.Fprintf(out, "Release %q does not exist. Installing it now.\n", args[0])

@ -187,7 +187,7 @@ func (c *ChartDownloader) ResolveChartVersion(ref, version string) (*url.URL, er
if err != nil { if err != nil {
// If there is no special config, return the default HTTP client and // If there is no special config, return the default HTTP client and
// swallow the error. // swallow the error.
if err == ErrNoOwnerRepo { if errors.Is(err, ErrNoOwnerRepo) {
// Make sure to add the ref URL as the URL for the getter // Make sure to add the ref URL as the URL for the getter
c.Options = append(c.Options, getter.WithURL(ref)) c.Options = append(c.Options, getter.WithURL(ref))
return u, nil return u, nil

@ -20,6 +20,8 @@ import (
"path/filepath" "path/filepath"
"testing" "testing"
"github.com/stretchr/testify/require"
"helm.sh/helm/v4/internal/test/ensure" "helm.sh/helm/v4/internal/test/ensure"
"helm.sh/helm/v4/pkg/cli" "helm.sh/helm/v4/pkg/cli"
"helm.sh/helm/v4/pkg/getter" "helm.sh/helm/v4/pkg/getter"
@ -362,7 +364,6 @@ func TestScanReposForURL(t *testing.T) {
// A lookup failure should produce an ErrNoOwnerRepo // A lookup failure should produce an ErrNoOwnerRepo
u = "https://no.such.repo/foo/bar-1.23.4.tgz" u = "https://no.such.repo/foo/bar-1.23.4.tgz"
if _, err = c.scanReposForURL(u, rf); err != ErrNoOwnerRepo { _, err = c.scanReposForURL(u, rf)
t.Fatalf("expected ErrNoOwnerRepo, got %v", err) require.ErrorIs(t, err, ErrNoOwnerRepo, "expected ErrNoOwnerRepo, got %v", err)
}
} }

@ -258,7 +258,7 @@ func (m *Manager) downloadAll(deps []*chart.Dependency) error {
return err return err
} }
} else { } else {
return fmt.Errorf("unable to retrieve file info for '%s': %v", destPath, err) return fmt.Errorf("unable to retrieve file info for '%s': %w", destPath, err)
} }
// Prepare tmpPath // Prepare tmpPath
@ -278,17 +278,17 @@ func (m *Manager) downloadAll(deps []*chart.Dependency) error {
chartPath := filepath.Join(destPath, dep.Name) chartPath := filepath.Join(destPath, dep.Name)
ch, err := loader.LoadDir(chartPath) ch, err := loader.LoadDir(chartPath)
if err != nil { if err != nil {
return fmt.Errorf("unable to load chart '%s': %v", chartPath, err) return fmt.Errorf("unable to load chart '%s': %w", chartPath, err)
} }
constraint, err := semver.NewConstraint(dep.Version) constraint, err := semver.NewConstraint(dep.Version)
if err != nil { if err != nil {
return fmt.Errorf("dependency %s has an invalid version/constraint format: %s", dep.Name, err) return fmt.Errorf("dependency %s has an invalid version/constraint format: %w", dep.Name, err)
} }
v, err := semver.NewVersion(ch.Metadata.Version) v, err := semver.NewVersion(ch.Metadata.Version)
if err != nil { if err != nil {
return fmt.Errorf("invalid version %s for dependency %s: %s", dep.Version, dep.Name, err) return fmt.Errorf("invalid version %s for dependency %s: %w", dep.Version, dep.Name, err)
} }
if !constraint.Check(v) { if !constraint.Check(v) {

@ -129,9 +129,11 @@ type renderable struct {
basePath string basePath string
} }
const warnStartDelim = "HELM_ERR_START" const (
const warnEndDelim = "HELM_ERR_END" warnStartDelim = "HELM_ERR_START"
const recursionMaxNums = 1000 warnEndDelim = "HELM_ERR_END"
recursionMaxNums = 1000
)
var warnRegex = regexp.MustCompile(warnStartDelim + `((?s).*)` + warnEndDelim) var warnRegex = regexp.MustCompile(warnStartDelim + `((?s).*)` + warnEndDelim)
@ -331,7 +333,7 @@ func cleanupParseError(filename string, err error) error {
tokens := strings.Split(err.Error(), ": ") tokens := strings.Split(err.Error(), ": ")
if len(tokens) == 1 { if len(tokens) == 1 {
// This might happen if a non-templating error occurs // This might happen if a non-templating error occurs
return fmt.Errorf("parse error in (%s): %s", filename, err) return fmt.Errorf("parse error in (%s): %w", filename, err)
} }
// The first token is "template" // The first token is "template"
// The second token is either "filename:lineno" or "filename:lineNo:columnNo" // The second token is either "filename:lineno" or "filename:lineNo:columnNo"
@ -368,14 +370,15 @@ func reformatExecErrorMsg(filename string, err error) error {
// If the regex's can parse out details from that error message such as the line number, template it failed on, // If the regex's can parse out details from that error message such as the line number, template it failed on,
// and error description, then it will construct a new error that displays these details in a structured way. // and error description, then it will construct a new error that displays these details in a structured way.
// If there are issues with parsing the error message, the err passed into the function should return instead. // If there are issues with parsing the error message, the err passed into the function should return instead.
if _, isExecError := err.(template.ExecError); !isExecError { var execErr template.ExecError
if !errors.As(err, &execErr) {
return err return err
} }
tokens := strings.SplitN(err.Error(), ": ", 3) tokens := strings.SplitN(err.Error(), ": ", 3)
if len(tokens) != 3 { if len(tokens) != 3 {
// This might happen if a non-templating error occurs // This might happen if a non-templating error occurs
return fmt.Errorf("execution error in (%s): %s", filename, err) return fmt.Errorf("execution error in (%s): %w", filename, err)
} }
// The first token is "template" // The first token is "template"

@ -25,7 +25,6 @@ import (
"text/template" "text/template"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/runtime/schema"
@ -646,7 +645,6 @@ func TestRenderDependency(t *testing.T) {
if out["outerchart/templates/outer"] != expect { if out["outerchart/templates/outer"] != expect {
t.Errorf("Expected %q, got %q", expect, out["outer"]) t.Errorf("Expected %q, got %q", expect, out["outer"])
} }
} }
func TestRenderNestedValues(t *testing.T) { func TestRenderNestedValues(t *testing.T) {
@ -800,7 +798,6 @@ func TestRenderBuiltinValues(t *testing.T) {
t.Errorf("Expected %q, got %q", expect, out[file]) t.Errorf("Expected %q, got %q", expect, out[file])
} }
} }
} }
func TestAlterFuncMap_include(t *testing.T) { func TestAlterFuncMap_include(t *testing.T) {
@ -993,7 +990,6 @@ func TestAlterFuncMap_tplinclude(t *testing.T) {
if got := out["TplFunction/templates/base"]; got != expect { if got := out["TplFunction/templates/base"]; got != expect {
t.Errorf("Expected %q, got %q (%v)", expect, got, out) t.Errorf("Expected %q, got %q (%v)", expect, got, out)
} }
} }
func TestRenderRecursionLimit(t *testing.T) { func TestRenderRecursionLimit(t *testing.T) {
@ -1048,7 +1044,6 @@ func TestRenderRecursionLimit(t *testing.T) {
if got := out["overlook/templates/quote"]; got != expect { if got := out["overlook/templates/quote"]; got != expect {
t.Errorf("Expected %q, got %q (%v)", expect, got, out) t.Errorf("Expected %q, got %q (%v)", expect, got, out)
} }
} }
func TestRenderLoadTemplateForTplFromFile(t *testing.T) { func TestRenderLoadTemplateForTplFromFile(t *testing.T) {

@ -17,6 +17,7 @@ package getter
import ( import (
"bytes" "bytes"
"errors"
"fmt" "fmt"
"os" "os"
"os/exec" "os/exec"
@ -82,7 +83,8 @@ func (p *pluginGetter) Get(href string, options ...Option) (*bytes.Buffer, error
prog.Stdout = buf prog.Stdout = buf
prog.Stderr = os.Stderr prog.Stderr = os.Stderr
if err := prog.Run(); err != nil { if err := prog.Run(); err != nil {
if eerr, ok := err.(*exec.ExitError); ok { var eerr *exec.ExitError
if errors.As(err, &eerr) {
os.Stderr.Write(eerr.Stderr) os.Stderr.Write(eerr.Stderr)
return nil, fmt.Errorf("plugin %q exited with error", p.command) return nil, fmt.Errorf("plugin %q exited with error", p.command)
} }

@ -180,7 +180,7 @@ func (c *Client) getKubeClient() (kubernetes.Interface, error) {
// IsReachable tests connectivity to the cluster. // IsReachable tests connectivity to the cluster.
func (c *Client) IsReachable() error { func (c *Client) IsReachable() error {
client, err := c.getKubeClient() client, err := c.getKubeClient()
if err == genericclioptions.ErrEmptyConfig { if errors.Is(err, genericclioptions.ErrEmptyConfig) {
// re-replace kubernetes ErrEmptyConfig error with a friendly error // re-replace kubernetes ErrEmptyConfig error with a friendly error
// moar workarounds for Kubernetes API breaking. // moar workarounds for Kubernetes API breaking.
return errors.New("kubernetes cluster unreachable") return errors.New("kubernetes cluster unreachable")
@ -720,7 +720,7 @@ func updateResource(_ *Client, target *resource.Info, currentObj runtime.Object,
func (c *Client) GetPodList(namespace string, listOptions metav1.ListOptions) (*v1.PodList, error) { func (c *Client) GetPodList(namespace string, listOptions metav1.ListOptions) (*v1.PodList, error) {
podList, err := c.kubeClient.CoreV1().Pods(namespace).List(context.Background(), listOptions) podList, err := c.kubeClient.CoreV1().Pods(namespace).List(context.Background(), listOptions)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to get pod list with options: %+v with error: %v", listOptions, err) return nil, fmt.Errorf("failed to get pod list with options: %+v with error: %w", listOptions, err)
} }
return podList, nil return podList, nil
} }

@ -103,7 +103,8 @@ func (hw *legacyWaiter) isRetryableError(err error, resource *resource.Info) boo
return false return false
} }
slog.Debug("error received when checking resource status", "resource", resource.Name, slog.Any("error", err)) slog.Debug("error received when checking resource status", "resource", resource.Name, slog.Any("error", err))
if ev, ok := err.(*apierrors.StatusError); ok { var ev *apierrors.StatusError
if errors.As(err, &ev) {
statusCode := ev.Status().Code statusCode := ev.Status().Code
retryable := hw.isRetryableHTTPStatusCode(statusCode) retryable := hw.isRetryableHTTPStatusCode(statusCode)
slog.Debug("status code received", "resource", resource.Name, "statusCode", statusCode, "retryable", retryable) slog.Debug("status code received", "resource", resource.Name, "statusCode", statusCode, "retryable", retryable)

@ -152,7 +152,7 @@ func validateChartVersion(cf *chart.Metadata) error {
valid, msg := c.Validate(version) valid, msg := c.Validate(version)
if !valid && len(msg) > 0 { if !valid && len(msg) > 0 {
return fmt.Errorf("version %v", msg[0]) return fmt.Errorf("version %w", msg[0])
} }
return nil return nil

@ -70,7 +70,7 @@ func Crds(linter *support.Linter) {
var yamlStruct *k8sYamlStruct var yamlStruct *k8sYamlStruct
err := decoder.Decode(&yamlStruct) err := decoder.Decode(&yamlStruct)
if err == io.EOF { if errors.Is(err, io.EOF) {
break break
} }

@ -16,7 +16,11 @@ limitations under the License.
package rules // import "helm.sh/helm/v4/pkg/lint/rules" package rules // import "helm.sh/helm/v4/pkg/lint/rules"
import "testing" import (
"testing"
"github.com/stretchr/testify/require"
)
func TestValidateNoDeprecations(t *testing.T) { func TestValidateNoDeprecations(t *testing.T) {
deprecated := &k8sYamlStruct{ deprecated := &k8sYamlStruct{
@ -27,7 +31,8 @@ func TestValidateNoDeprecations(t *testing.T) {
if err == nil { if err == nil {
t.Fatal("Expected deprecated extension to be flagged") t.Fatal("Expected deprecated extension to be flagged")
} }
depErr := err.(deprecatedAPIError) var depErr deprecatedAPIError
require.ErrorAs(t, err, &depErr)
if depErr.Message == "" { if depErr.Message == "" {
t.Fatalf("Expected error message to be non-blank: %v", err) t.Fatalf("Expected error message to be non-blank: %v", err)
} }

@ -148,7 +148,7 @@ func TemplatesWithSkipSchemaValidation(linter *support.Linter, values map[string
var yamlStruct *k8sYamlStruct var yamlStruct *k8sYamlStruct
err := decoder.Decode(&yamlStruct) err := decoder.Decode(&yamlStruct)
if err == io.EOF { if errors.Is(err, io.EOF) {
break break
} }

@ -23,6 +23,8 @@ import (
"strings" "strings"
"testing" "testing"
"github.com/stretchr/testify/require"
chart "helm.sh/helm/v4/pkg/chart/v2" chart "helm.sh/helm/v4/pkg/chart/v2"
chartutil "helm.sh/helm/v4/pkg/chart/v2/util" chartutil "helm.sh/helm/v4/pkg/chart/v2/util"
"helm.sh/helm/v4/pkg/lint/support" "helm.sh/helm/v4/pkg/lint/support"
@ -215,7 +217,8 @@ func TestDeprecatedAPIFails(t *testing.T) {
t.Fatalf("Expected 1 lint error, got %d", l) t.Fatalf("Expected 1 lint error, got %d", l)
} }
err := linter.Messages[0].Err.(deprecatedAPIError) var err deprecatedAPIError
require.ErrorAs(t, linter.Messages[0].Err, &err)
if err.Deprecated != "apps/v1beta1 Deployment" { if err.Deprecated != "apps/v1beta1 Deployment" {
t.Errorf("Surprised to learn that %q is deprecated", err.Deprecated) t.Errorf("Surprised to learn that %q is deprecated", err.Deprecated)
} }

@ -234,7 +234,7 @@ func (g *TarGzExtractor) Extract(buffer *bytes.Buffer, targetDir string) error {
tarReader := tar.NewReader(uncompressedStream) tarReader := tar.NewReader(uncompressedStream)
for { for {
header, err := tarReader.Next() header, err := tarReader.Next()
if err == io.EOF { if errors.Is(err, io.EOF) {
break break
} }
if err != nil { if err != nil {

@ -20,6 +20,8 @@ import (
"path/filepath" "path/filepath"
"testing" "testing"
"github.com/stretchr/testify/assert"
"helm.sh/helm/v4/internal/test/ensure" "helm.sh/helm/v4/internal/test/ensure"
"helm.sh/helm/v4/pkg/helmpath" "helm.sh/helm/v4/pkg/helmpath"
) )
@ -61,7 +63,5 @@ func TestLocalInstallerNotAFolder(t *testing.T) {
if err == nil { if err == nil {
t.Fatal("expected error") t.Fatal("expected error")
} }
if err != ErrPluginNotAFolder { assert.ErrorIs(t, err, ErrPluginNotAFolder, "expected error to equal: %q", err)
t.Fatalf("expected error to equal: %q", err)
}
} }

@ -17,6 +17,7 @@ package provenance
import ( import (
"crypto" "crypto"
"errors"
"fmt" "fmt"
"io" "io"
"os" "os"
@ -323,8 +324,9 @@ func TestVerify(t *testing.T) {
t.Errorf("Expected %s to fail.", testTamperedSigBlock) t.Errorf("Expected %s to fail.", testTamperedSigBlock)
} }
switch err.(type) { var errCase0 pgperrors.SignatureError
case pgperrors.SignatureError: switch {
case errors.As(err, &errCase0):
t.Logf("Tampered sig block error: %s (%T)", err, err) t.Logf("Tampered sig block error: %s (%T)", err, err)
default: default:
t.Errorf("Expected invalid signature error, got %q (%T)", err, err) t.Errorf("Expected invalid signature error, got %q (%T)", err, err)

@ -18,6 +18,7 @@ package registry
import ( import (
"bytes" "bytes"
"errors"
"fmt" "fmt"
"io" "io"
"log/slog" "log/slog"
@ -137,7 +138,7 @@ func logResponseBody(resp *http.Response) string {
Closer: body, Closer: body,
} }
// read the body up to limit+1 to check if the body exceeds the limit // read the body up to limit+1 to check if the body exceeds the limit
if _, err := io.CopyN(buf, body, payloadSizeLimit+1); err != nil && err != io.EOF { if _, err := io.CopyN(buf, body, payloadSizeLimit+1); err != nil && !errors.Is(err, io.EOF) {
return fmt.Sprintf(" Error reading response body: %v", err) return fmt.Sprintf(" Error reading response body: %v", err)
} }

@ -102,7 +102,7 @@ func NewRegistryClientWithTLS(out io.Writer, certFile, keyFile, caFile string, i
tlsutil.WithCAFile(caFile), tlsutil.WithCAFile(caFile),
) )
if err != nil { if err != nil {
return nil, fmt.Errorf("can't create TLS config for client: %s", err) return nil, fmt.Errorf("can't create TLS config for client: %w", err)
} }
// Create a new registry client // Create a new registry client
registryClient, err := NewClient( registryClient, err := NewClient(

@ -18,7 +18,6 @@ package repo
import ( import (
"bytes" "bytes"
"errors"
"net/http" "net/http"
"net/http/httptest" "net/http/httptest"
"os" "os"
@ -27,6 +26,7 @@ import (
"testing" "testing"
"time" "time"
"github.com/stretchr/testify/require"
"sigs.k8s.io/yaml" "sigs.k8s.io/yaml"
"helm.sh/helm/v4/pkg/cli" "helm.sh/helm/v4/pkg/cli"
@ -203,9 +203,7 @@ func TestErrorFindChartInRepoURL(t *testing.T) {
} else if err.Error() != `chart "nginx1" not found in `+srv.URL+` repository` { } else if err.Error() != `chart "nginx1" not found in `+srv.URL+` repository` {
t.Errorf("Expected error for chart not found, but got a different error (%v)", err) t.Errorf("Expected error for chart not found, but got a different error (%v)", err)
} }
if !errors.Is(err, ChartNotFoundError{}) { require.ErrorIsf(t, err, ChartNotFoundError{}, "error is not of correct error type structure")
t.Errorf("error is not of correct error type structure")
}
if _, err = FindChartInRepoURL(srv.URL, "nginx1", g, WithChartVersion("0.1.0")); err == nil { if _, err = FindChartInRepoURL(srv.URL, "nginx1", g, WithChartVersion("0.1.0")); err == nil {
t.Errorf("Expected error for chart not found, but did not get any errors") t.Errorf("Expected error for chart not found, but did not get any errors")

@ -401,8 +401,8 @@ func jsonOrYamlUnmarshal(b []byte, i interface{}) error {
// And repository indexes may be generated by older/non-compliant software, which doesn't // And repository indexes may be generated by older/non-compliant software, which doesn't
// conform to all validations. // conform to all validations.
func ignoreSkippableChartValidationError(err error) error { func ignoreSkippableChartValidationError(err error) error {
verr, ok := err.(chart.ValidationError) var verr chart.ValidationError
if !ok { if !errors.As(err, &verr) {
return err return err
} }

@ -28,6 +28,8 @@ import (
"strings" "strings"
"testing" "testing"
"github.com/stretchr/testify/require"
chart "helm.sh/helm/v4/pkg/chart/v2" chart "helm.sh/helm/v4/pkg/chart/v2"
"helm.sh/helm/v4/pkg/cli" "helm.sh/helm/v4/pkg/cli"
"helm.sh/helm/v4/pkg/getter" "helm.sh/helm/v4/pkg/getter"
@ -639,10 +641,7 @@ func TestIgnoreSkippableChartValidationError(t *testing.T) {
return return
} }
if tc.Input != result { require.ErrorIs(t, tc.Input, result, "expected the result equal to input")
t.Error("expected the result equal to input")
}
}) })
} }
} }

@ -16,10 +16,11 @@ package driver
import ( import (
"encoding/base64" "encoding/base64"
"encoding/json" "encoding/json"
"errors"
"reflect" "reflect"
"testing" "testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
v1 "k8s.io/api/core/v1" v1 "k8s.io/api/core/v1"
rspb "helm.sh/helm/v4/pkg/release/v1" rspb "helm.sh/helm/v4/pkg/release/v1"
@ -160,9 +161,7 @@ func TestConfigMapQuery(t *testing.T) {
} }
_, err = cfgmaps.Query(map[string]string{"name": "notExist"}) _, err = cfgmaps.Query(map[string]string{"name": "notExist"})
if err != ErrReleaseNotFound { assert.ErrorIsf(t, err, ErrReleaseNotFound, "Expected {%v}, got {%v}", ErrReleaseNotFound, err)
t.Errorf("Expected {%v}, got {%v}", ErrReleaseNotFound, err)
}
} }
func TestConfigMapCreate(t *testing.T) { func TestConfigMapCreate(t *testing.T) {
@ -231,9 +230,7 @@ func TestConfigMapDelete(t *testing.T) {
// perform the delete on a non-existent release // perform the delete on a non-existent release
_, err := cfgmaps.Delete("nonexistent") _, err := cfgmaps.Delete("nonexistent")
if err != ErrReleaseNotFound { require.ErrorIsf(t, err, ErrReleaseNotFound, "Expected ErrReleaseNotFound: got {%v}", err)
t.Fatalf("Expected ErrReleaseNotFound: got {%v}", err)
}
// perform the delete // perform the delete
rls, err := cfgmaps.Delete(key) rls, err := cfgmaps.Delete(key)
@ -244,7 +241,5 @@ func TestConfigMapDelete(t *testing.T) {
t.Errorf("Expected {%v}, got {%v}", rel, rls) t.Errorf("Expected {%v}, got {%v}", rel, rls)
} }
_, err = cfgmaps.Get(key) _, err = cfgmaps.Get(key)
if !errors.Is(err, ErrReleaseNotFound) { require.ErrorIsf(t, err, ErrReleaseNotFound, "Expected {%v}, got {%v}", ErrReleaseNotFound, err)
t.Errorf("Expected {%v}, got {%v}", ErrReleaseNotFound, err)
}
} }

@ -16,10 +16,11 @@ package driver
import ( import (
"encoding/base64" "encoding/base64"
"encoding/json" "encoding/json"
"errors"
"reflect" "reflect"
"testing" "testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
v1 "k8s.io/api/core/v1" v1 "k8s.io/api/core/v1"
rspb "helm.sh/helm/v4/pkg/release/v1" rspb "helm.sh/helm/v4/pkg/release/v1"
@ -160,9 +161,7 @@ func TestSecretQuery(t *testing.T) {
} }
_, err = secrets.Query(map[string]string{"name": "notExist"}) _, err = secrets.Query(map[string]string{"name": "notExist"})
if err != ErrReleaseNotFound { assert.ErrorIsf(t, err, ErrReleaseNotFound, "Expected {%v}, got {%v}", ErrReleaseNotFound, err)
t.Errorf("Expected {%v}, got {%v}", ErrReleaseNotFound, err)
}
} }
func TestSecretCreate(t *testing.T) { func TestSecretCreate(t *testing.T) {
@ -231,9 +230,7 @@ func TestSecretDelete(t *testing.T) {
// perform the delete on a non-existing release // perform the delete on a non-existing release
_, err := secrets.Delete("nonexistent") _, err := secrets.Delete("nonexistent")
if err != ErrReleaseNotFound { require.ErrorIsf(t, err, ErrReleaseNotFound, "Expected ErrReleaseNotFound, got: {%v}", err)
t.Fatalf("Expected ErrReleaseNotFound, got: {%v}", err)
}
// perform the delete // perform the delete
rls, err := secrets.Delete(key) rls, err := secrets.Delete(key)
@ -244,7 +241,5 @@ func TestSecretDelete(t *testing.T) {
t.Errorf("Expected {%v}, got {%v}", rel, rls) t.Errorf("Expected {%v}, got {%v}", rel, rls)
} }
_, err = secrets.Get(key) _, err = secrets.Get(key)
if !errors.Is(err, ErrReleaseNotFound) { require.ErrorIsf(t, err, ErrReleaseNotFound, "Expected {%v}, got {%v}", ErrReleaseNotFound, err)
t.Errorf("Expected {%v}, got {%v}", ErrReleaseNotFound, err)
}
} }

@ -460,7 +460,7 @@ func (s *SQL) Create(key string, rls *rspb.Release) error {
transaction, err := s.db.Beginx() transaction, err := s.db.Beginx()
if err != nil { if err != nil {
slog.Debug("failed to start SQL transaction", slog.Any("error", err)) slog.Debug("failed to start SQL transaction", slog.Any("error", err))
return fmt.Errorf("error beginning transaction: %v", err) return fmt.Errorf("error beginning transaction: %w", err)
} }
insertQuery, args, err := s.statementBuilder. insertQuery, args, err := s.statementBuilder.
@ -594,7 +594,7 @@ func (s *SQL) Delete(key string) (*rspb.Release, error) {
transaction, err := s.db.Beginx() transaction, err := s.db.Beginx()
if err != nil { if err != nil {
slog.Debug("failed to start SQL transaction", slog.Any("error", err)) slog.Debug("failed to start SQL transaction", slog.Any("error", err))
return nil, fmt.Errorf("error beginning transaction: %v", err) return nil, fmt.Errorf("error beginning transaction: %w", err)
} }
selectQuery, args, err := s.statementBuilder. selectQuery, args, err := s.statementBuilder.

@ -22,6 +22,7 @@ import (
sqlmock "github.com/DATA-DOG/go-sqlmock" sqlmock "github.com/DATA-DOG/go-sqlmock"
migrate "github.com/rubenv/sql-migrate" migrate "github.com/rubenv/sql-migrate"
"github.com/stretchr/testify/require"
rspb "helm.sh/helm/v4/pkg/release/v1" rspb "helm.sh/helm/v4/pkg/release/v1"
) )
@ -412,11 +413,7 @@ func TestSqlQuery(t *testing.T) {
mockGetReleaseCustomLabels(mock, "", deployedRelease.Namespace, deployedRelease.Labels) mockGetReleaseCustomLabels(mock, "", deployedRelease.Namespace, deployedRelease.Labels)
_, err := sqlDriver.Query(labelSetUnknown) _, err := sqlDriver.Query(labelSetUnknown)
if err == nil { require.ErrorIsf(t, err, ErrReleaseNotFound, "failed to query for unknown smug-pigeon release: %v", err)
t.Errorf("Expected error {%v}, got nil", ErrReleaseNotFound)
} else if err != ErrReleaseNotFound {
t.Fatalf("failed to query for unknown smug-pigeon release: %v", err)
}
results, err := sqlDriver.Query(labelSetDeployed) results, err := sqlDriver.Query(labelSetDeployed)
if err != nil { if err != nil {

@ -22,6 +22,8 @@ import (
"reflect" "reflect"
"testing" "testing"
"github.com/stretchr/testify/require"
rspb "helm.sh/helm/v4/pkg/release/v1" rspb "helm.sh/helm/v4/pkg/release/v1"
"helm.sh/helm/v4/pkg/storage/driver" "helm.sh/helm/v4/pkg/storage/driver"
) )
@ -329,9 +331,7 @@ func TestMaxHistoryErrorHandling(t *testing.T) {
rls2 := ReleaseTestData{Name: name, Version: 2, Status: rspb.StatusSuperseded}.ToRelease() rls2 := ReleaseTestData{Name: name, Version: 2, Status: rspb.StatusSuperseded}.ToRelease()
wantErr := errMaxHistoryMockDriverSomethingHappened wantErr := errMaxHistoryMockDriverSomethingHappened
gotErr := storage.Create(rls2) gotErr := storage.Create(rls2)
if !errors.Is(gotErr, wantErr) { require.ErrorIsf(t, gotErr, wantErr, "Storing release 'angry-bird' (v2) should return the error %#v, but returned %#v", wantErr, gotErr)
t.Fatalf("Storing release 'angry-bird' (v2) should return the error %#v, but returned %#v", wantErr, gotErr)
}
} }
func TestStorageRemoveLeastRecent(t *testing.T) { func TestStorageRemoveLeastRecent(t *testing.T) {

@ -17,6 +17,7 @@ package strvals
import ( import (
"bytes" "bytes"
"errors"
"fmt" "fmt"
"io" "io"
"strconv" "strconv"
@ -66,7 +67,7 @@ func (t *literalParser) parse() error {
if err == nil { if err == nil {
continue continue
} }
if err == io.EOF { if errors.Is(err, io.EOF) {
return nil return nil
} }
return err return err
@ -105,7 +106,7 @@ func (t *literalParser) key(data map[string]interface{}, nestedNameLevel int) (r
case lastRune == '=': case lastRune == '=':
// found end of key: swallow the '=' and get the value // found end of key: swallow the '=' and get the value
value, err := t.val() value, err := t.val()
if err == nil && err != io.EOF { if err == nil && !errors.Is(err, io.EOF) {
return err return err
} }
set(data, string(key), string(value)) set(data, string(key), string(value))
@ -183,7 +184,7 @@ func (t *literalParser) listItem(list []interface{}, i, nestedNameLevel int) ([]
case lastRune == '=': case lastRune == '=':
value, err := t.val() value, err := t.val()
if err != nil && err != io.EOF { if err != nil && !errors.Is(err, io.EOF) {
return list, err return list, err
} }
return setIndex(list, i, string(value)) return setIndex(list, i, string(value))

@ -161,7 +161,7 @@ func (t *parser) parse() error {
if err == nil { if err == nil {
continue continue
} }
if err == io.EOF { if errors.Is(err, io.EOF) {
return nil return nil
} }
return err return err
@ -240,16 +240,16 @@ func (t *parser) key(data map[string]interface{}, nestedNameLevel int) (reterr e
// End of key. Consume =, Get value. // End of key. Consume =, Get value.
// FIXME: Get value list first // FIXME: Get value list first
vl, e := t.valList() vl, e := t.valList()
switch e { switch {
case nil: case e == nil:
set(data, string(k), vl) set(data, string(k), vl)
return nil return nil
case io.EOF: case errors.Is(e, io.EOF):
set(data, string(k), "") set(data, string(k), "")
return e return e
case ErrNotList: case errors.Is(e, ErrNotList):
rs, e := t.val() rs, e := t.val()
if e != nil && e != io.EOF { if e != nil && !errors.Is(e, io.EOF) {
return e return e
} }
v, e := t.reader(rs) v, e := t.reader(rs)
@ -330,7 +330,6 @@ func (t *parser) keyIndex() (int, error) {
} }
// v should be the index // v should be the index
return strconv.Atoi(string(v)) return strconv.Atoi(string(v))
} }
func (t *parser) listItem(list []interface{}, i, nestedNameLevel int) ([]interface{}, error) { func (t *parser) listItem(list []interface{}, i, nestedNameLevel int) ([]interface{}, error) {
@ -373,14 +372,14 @@ func (t *parser) listItem(list []interface{}, i, nestedNameLevel int) ([]interfa
return list, err return list, err
} }
vl, e := t.valList() vl, e := t.valList()
switch e { switch {
case nil: case e == nil:
return setIndex(list, i, vl) return setIndex(list, i, vl)
case io.EOF: case errors.Is(e, io.EOF):
return setIndex(list, i, "") return setIndex(list, i, "")
case ErrNotList: case errors.Is(e, ErrNotList):
rs, e := t.val() rs, e := t.val()
if e != nil && e != io.EOF { if e != nil && !errors.Is(e, io.EOF) {
return list, e return list, e
} }
v, e := t.reader(rs) v, e := t.reader(rs)
@ -479,7 +478,7 @@ func (t *parser) valList() ([]interface{}, error) {
for { for {
switch rs, last, err := runesUntil(t.sc, stop); { switch rs, last, err := runesUntil(t.sc, stop); {
case err != nil: case err != nil:
if err == io.EOF { if errors.Is(err, io.EOF) {
err = errors.New("list must terminate with '}'") err = errors.New("list must terminate with '}'")
} }
return list, err return list, err

Loading…
Cancel
Save