Merge pull request #13460 from justenstall/stdlib-errors-2

fix: replace "github.com/pkg/errors" with stdlib "errors" package
pull/30786/head
George Jenkins 5 months ago committed by GitHub
commit ecf1730689
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -20,6 +20,8 @@ linters:
deny: deny:
- pkg: github.com/hashicorp/go-multierror - pkg: github.com/hashicorp/go-multierror
desc: "use errors instead" desc: "use errors instead"
- pkg: github.com/pkg/errors
desc: "use errors instead"
dupl: dupl:
threshold: 400 threshold: 400
exclusions: exclusions:

@ -26,7 +26,6 @@ require (
github.com/moby/term v0.5.2 github.com/moby/term v0.5.2
github.com/opencontainers/image-spec v1.1.1 github.com/opencontainers/image-spec v1.1.1
github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5
github.com/pkg/errors v0.9.1
github.com/rubenv/sql-migrate v1.8.0 github.com/rubenv/sql-migrate v1.8.0
github.com/santhosh-tekuri/jsonschema/v6 v6.0.1 github.com/santhosh-tekuri/jsonschema/v6 v6.0.1
github.com/spf13/cobra v1.9.1 github.com/spf13/cobra v1.9.1
@ -120,6 +119,7 @@ require (
github.com/onsi/gomega v1.36.2 // indirect github.com/onsi/gomega v1.36.2 // indirect
github.com/opencontainers/go-digest v1.0.0 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect
github.com/peterbourgon/diskv v2.0.1+incompatible // indirect github.com/peterbourgon/diskv v2.0.1+incompatible // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/prometheus/client_golang v1.20.5 // indirect github.com/prometheus/client_golang v1.20.5 // indirect
github.com/prometheus/client_model v0.6.1 // indirect github.com/prometheus/client_model v0.6.1 // indirect

@ -18,14 +18,15 @@ package resolver
import ( import (
"bytes" "bytes"
"encoding/json" "encoding/json"
"errors"
"fmt" "fmt"
"io/fs"
"os" "os"
"path/filepath" "path/filepath"
"strings" "strings"
"time" "time"
"github.com/Masterminds/semver/v3" "github.com/Masterminds/semver/v3"
"github.com/pkg/errors"
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"
@ -60,7 +61,7 @@ func (r *Resolver) Resolve(reqs []*chart.Dependency, repoNames map[string]string
for i, d := range reqs { for i, d := range reqs {
constraint, err := semver.NewConstraint(d.Version) constraint, err := semver.NewConstraint(d.Version)
if err != nil { if err != nil {
return nil, errors.Wrapf(err, "dependency %q has an invalid version/constraint format", d.Name) return nil, fmt.Errorf("dependency %q has an invalid version/constraint format: %w", d.Name, err)
} }
if d.Repository == "" { if d.Repository == "" {
@ -124,12 +125,12 @@ func (r *Resolver) Resolve(reqs []*chart.Dependency, repoNames map[string]string
if !registry.IsOCI(d.Repository) { if !registry.IsOCI(d.Repository) {
repoIndex, err := repo.LoadIndexFile(filepath.Join(r.cachepath, helmpath.CacheIndexFile(repoName))) repoIndex, err := repo.LoadIndexFile(filepath.Join(r.cachepath, helmpath.CacheIndexFile(repoName)))
if err != nil { if err != nil {
return nil, errors.Wrapf(err, "no cached repository for %s found. (try 'helm repo update')", repoName) return nil, fmt.Errorf("no cached repository for %s found. (try 'helm repo update'): %w", repoName, err)
} }
vs, ok = repoIndex.Entries[d.Name] vs, ok = repoIndex.Entries[d.Name]
if !ok { if !ok {
return nil, errors.Errorf("%s chart not found in repo %s", d.Name, d.Repository) return nil, fmt.Errorf("%s chart not found in repo %s", d.Name, d.Repository)
} }
found = false found = false
} else { } else {
@ -151,7 +152,7 @@ func (r *Resolver) Resolve(reqs []*chart.Dependency, repoNames map[string]string
ref := fmt.Sprintf("%s/%s", strings.TrimPrefix(d.Repository, fmt.Sprintf("%s://", registry.OCIScheme)), d.Name) ref := fmt.Sprintf("%s/%s", strings.TrimPrefix(d.Repository, fmt.Sprintf("%s://", registry.OCIScheme)), d.Name)
tags, err := r.registryClient.Tags(ref) tags, err := r.registryClient.Tags(ref)
if err != nil { if err != nil {
return nil, errors.Wrapf(err, "could not retrieve list of tags for repository %s", d.Repository) return nil, fmt.Errorf("could not retrieve list of tags for repository %s: %w", d.Repository, err)
} }
vs = make(repo.ChartVersions, len(tags)) vs = make(repo.ChartVersions, len(tags))
@ -192,7 +193,7 @@ func (r *Resolver) Resolve(reqs []*chart.Dependency, repoNames map[string]string
} }
} }
if len(missing) > 0 { if len(missing) > 0 {
return nil, errors.Errorf("can't get a valid version for %d subchart(s): %s. Make sure a matching chart version exists in the repo, or change the version constraint in Chart.yaml", len(missing), strings.Join(missing, ", ")) return nil, fmt.Errorf("can't get a valid version for %d subchart(s): %s. Make sure a matching chart version exists in the repo, or change the version constraint in Chart.yaml", len(missing), strings.Join(missing, ", "))
} }
digest, err := HashReq(reqs, locked) digest, err := HashReq(reqs, locked)
@ -252,8 +253,8 @@ func GetLocalPath(repo, chartpath string) (string, error) {
depPath = filepath.Join(chartpath, p) depPath = filepath.Join(chartpath, p)
} }
if _, err = os.Stat(depPath); os.IsNotExist(err) { if _, err = os.Stat(depPath); errors.Is(err, fs.ErrNotExist) {
return "", errors.Errorf("directory %s not found", depPath) return "", fmt.Errorf("directory %s not found", depPath)
} else if err != nil { } else if err != nil {
return "", err return "", err
} }

@ -21,12 +21,11 @@ limitations under the License.
package sympath package sympath
import ( import (
"fmt"
"log/slog" "log/slog"
"os" "os"
"path/filepath" "path/filepath"
"sort" "sort"
"github.com/pkg/errors"
) )
// Walk walks the file tree rooted at root, calling walkFn for each file or directory // Walk walks the file tree rooted at root, calling walkFn for each file or directory
@ -69,7 +68,7 @@ func symwalk(path string, info os.FileInfo, walkFn filepath.WalkFunc) error {
if IsSymlink(info) { if IsSymlink(info) {
resolved, err := filepath.EvalSymlinks(path) resolved, err := filepath.EvalSymlinks(path)
if err != nil { if err != nil {
return errors.Wrapf(err, "error evaluating symlink %s", path) return fmt.Errorf("error evaluating symlink %s: %w", path, err)
} }
//This log message is to highlight a symlink that is being used within a chart, symlinks can be used for nefarious reasons. //This log message is to highlight a symlink that is being used within a chart, symlinks can be used for nefarious reasons.
slog.Info("found symbolic link in path. Contents of linked file included and used", "path", path, "resolved", resolved) slog.Info("found symbolic link in path. Contents of linked file included and used", "path", path, "resolved", resolved)

@ -19,10 +19,9 @@ package test
import ( import (
"bytes" "bytes"
"flag" "flag"
"fmt"
"os" "os"
"path/filepath" "path/filepath"
"github.com/pkg/errors"
) )
// UpdateGolden writes out the golden files with the latest values, rather than failing the test. // UpdateGolden writes out the golden files with the latest values, rather than failing the test.
@ -75,11 +74,11 @@ func compare(actual []byte, filename string) error {
expected, err := os.ReadFile(filename) expected, err := os.ReadFile(filename)
if err != nil { if err != nil {
return errors.Wrapf(err, "unable to read testdata %s", filename) return fmt.Errorf("unable to read testdata %s: %w", filename, err)
} }
expected = normalize(expected) expected = normalize(expected)
if !bytes.Equal(expected, actual) { if !bytes.Equal(expected, actual) {
return errors.Errorf("does not match golden file %s\n\nWANT:\n'%s'\n\nGOT:\n'%s'", filename, expected, actual) return fmt.Errorf("does not match golden file %s\n\nWANT:\n'%s'\n\nGOT:\n'%s'", filename, expected, actual)
} }
return nil return nil
} }

@ -32,13 +32,14 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package fs package fs
import ( import (
"errors"
"fmt"
"io" "io"
"io/fs"
"os" "os"
"path/filepath" "path/filepath"
"runtime" "runtime"
"syscall" "syscall"
"github.com/pkg/errors"
) )
// fs contains a copy of a few functions from dep tool code to avoid a dependency on golang/dep. // fs contains a copy of a few functions from dep tool code to avoid a dependency on golang/dep.
@ -51,7 +52,7 @@ import (
func RenameWithFallback(src, dst string) error { func RenameWithFallback(src, dst string) error {
_, err := os.Stat(src) _, err := os.Stat(src)
if err != nil { if err != nil {
return errors.Wrapf(err, "cannot stat %s", src) return fmt.Errorf("cannot stat %s: %w", src, err)
} }
err = os.Rename(src, dst) err = os.Rename(src, dst)
@ -69,20 +70,24 @@ func renameByCopy(src, dst string) error {
if dir, _ := IsDir(src); dir { if dir, _ := IsDir(src); dir {
cerr = CopyDir(src, dst) cerr = CopyDir(src, dst)
if cerr != nil { if cerr != nil {
cerr = errors.Wrap(cerr, "copying directory failed") cerr = fmt.Errorf("copying directory failed: %w", cerr)
} }
} else { } else {
cerr = copyFile(src, dst) cerr = copyFile(src, dst)
if cerr != nil { if cerr != nil {
cerr = errors.Wrap(cerr, "copying file failed") cerr = fmt.Errorf("copying file failed: %w", cerr)
} }
} }
if cerr != nil { if cerr != nil {
return errors.Wrapf(cerr, "rename fallback failed: cannot rename %s to %s", src, dst) return fmt.Errorf("rename fallback failed: cannot rename %s to %s: %w", src, dst, cerr)
}
if err := os.RemoveAll(src); err != nil {
return fmt.Errorf("cannot delete %s: %w", src, err)
} }
return errors.Wrapf(os.RemoveAll(src), "cannot delete %s", src) return nil
} }
var ( var (
@ -107,7 +112,7 @@ func CopyDir(src, dst string) error {
} }
_, err = os.Stat(dst) _, err = os.Stat(dst)
if err != nil && !os.IsNotExist(err) { if err != nil && !errors.Is(err, fs.ErrNotExist) {
return err return err
} }
if err == nil { if err == nil {
@ -115,12 +120,12 @@ func CopyDir(src, dst string) error {
} }
if err = os.MkdirAll(dst, fi.Mode()); err != nil { if err = os.MkdirAll(dst, fi.Mode()); err != nil {
return errors.Wrapf(err, "cannot mkdir %s", dst) return fmt.Errorf("cannot mkdir %s: %w", dst, err)
} }
entries, err := os.ReadDir(src) entries, err := os.ReadDir(src)
if err != nil { if err != nil {
return errors.Wrapf(err, "cannot read directory %s", dst) return fmt.Errorf("cannot read directory %s: %w", dst, err)
} }
for _, entry := range entries { for _, entry := range entries {
@ -129,13 +134,13 @@ func CopyDir(src, dst string) error {
if entry.IsDir() { if entry.IsDir() {
if err = CopyDir(srcPath, dstPath); err != nil { if err = CopyDir(srcPath, dstPath); err != nil {
return errors.Wrap(err, "copying directory failed") return fmt.Errorf("copying directory failed: %w", err)
} }
} else { } else {
// This will include symlinks, which is what we want when // This will include symlinks, which is what we want when
// copying things. // copying things.
if err = copyFile(srcPath, dstPath); err != nil { if err = copyFile(srcPath, dstPath); err != nil {
return errors.Wrap(err, "copying file failed") return fmt.Errorf("copying file failed: %w", err)
} }
} }
} }
@ -149,7 +154,7 @@ func CopyDir(src, dst string) error {
// of the source file. The file mode will be copied from the source. // of the source file. The file mode will be copied from the source.
func copyFile(src, dst string) (err error) { func copyFile(src, dst string) (err error) {
if sym, err := IsSymlink(src); err != nil { if sym, err := IsSymlink(src); err != nil {
return errors.Wrap(err, "symlink check failed") return fmt.Errorf("symlink check failed: %w", err)
} else if sym { } else if sym {
if err := cloneSymlink(src, dst); err != nil { if err := cloneSymlink(src, dst); err != nil {
if runtime.GOOS == "windows" { if runtime.GOOS == "windows" {
@ -226,7 +231,7 @@ func IsDir(name string) (bool, error) {
return false, err return false, err
} }
if !fi.IsDir() { if !fi.IsDir() {
return false, errors.Errorf("%q is not a directory", name) return false, fmt.Errorf("%q is not a directory", name)
} }
return true, nil return true, nil
} }

@ -34,10 +34,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package fs package fs
import ( import (
"fmt"
"os" "os"
"syscall" "syscall"
"github.com/pkg/errors"
) )
// renameFallback attempts to determine the appropriate fallback to failed rename // renameFallback attempts to determine the appropriate fallback to failed rename
@ -51,7 +50,7 @@ func renameFallback(err error, src, dst string) error {
if !ok { if !ok {
return err return err
} else if terr.Err != syscall.EXDEV { } else if terr.Err != syscall.EXDEV {
return errors.Wrapf(terr, "link error: cannot rename %s to %s", src, dst) return fmt.Errorf("link error: cannot rename %s to %s: %w", src, dst, err)
} }
return renameByCopy(src, dst) return renameByCopy(src, dst)

@ -34,10 +34,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package fs package fs
import ( import (
"errors"
"os" "os"
"syscall" "syscall"
"github.com/pkg/errors"
) )
// renameFallback attempts to determine the appropriate fallback to failed rename // renameFallback attempts to determine the appropriate fallback to failed rename

@ -18,6 +18,7 @@ package action
import ( import (
"bytes" "bytes"
"errors"
"fmt" "fmt"
"io" "io"
"log/slog" "log/slog"
@ -27,7 +28,6 @@ import (
"strings" "strings"
"text/template" "text/template"
"github.com/pkg/errors"
"k8s.io/apimachinery/pkg/api/meta" "k8s.io/apimachinery/pkg/api/meta"
"k8s.io/cli-runtime/pkg/genericclioptions" "k8s.io/cli-runtime/pkg/genericclioptions"
"k8s.io/client-go/discovery" "k8s.io/client-go/discovery"
@ -105,7 +105,7 @@ func (cfg *Configuration) renderResources(ch *chart.Chart, values chartutil.Valu
if ch.Metadata.KubeVersion != "" { if ch.Metadata.KubeVersion != "" {
if !chartutil.IsCompatibleRange(ch.Metadata.KubeVersion, caps.KubeVersion.String()) { if !chartutil.IsCompatibleRange(ch.Metadata.KubeVersion, caps.KubeVersion.String()) {
return hs, b, "", errors.Errorf("chart requires kubeVersion: %s which is incompatible with Kubernetes %s", ch.Metadata.KubeVersion, caps.KubeVersion.String()) return hs, b, "", fmt.Errorf("chart requires kubeVersion: %s which is incompatible with Kubernetes %s", ch.Metadata.KubeVersion, caps.KubeVersion.String())
} }
} }
@ -220,7 +220,7 @@ func (cfg *Configuration) renderResources(ch *chart.Chart, values chartutil.Valu
if pr != nil { if pr != nil {
b, err = pr.Run(b) b, err = pr.Run(b)
if err != nil { if err != nil {
return hs, b, notes, errors.Wrap(err, "error while running post render on files") return hs, b, notes, fmt.Errorf("error while running post render on files: %w", err)
} }
} }
@ -241,13 +241,13 @@ func (cfg *Configuration) getCapabilities() (*chartutil.Capabilities, error) {
} }
dc, err := cfg.RESTClientGetter.ToDiscoveryClient() dc, err := cfg.RESTClientGetter.ToDiscoveryClient()
if err != nil { if err != nil {
return nil, errors.Wrap(err, "could not get Kubernetes discovery client") return nil, fmt.Errorf("could not get Kubernetes discovery client: %w", err)
} }
// force a discovery cache invalidation to always fetch the latest server version/capabilities. // force a discovery cache invalidation to always fetch the latest server version/capabilities.
dc.Invalidate() dc.Invalidate()
kubeVersion, err := dc.ServerVersion() kubeVersion, err := dc.ServerVersion()
if err != nil { if err != nil {
return nil, errors.Wrap(err, "could not get server version from Kubernetes") return nil, fmt.Errorf("could not get server version from Kubernetes: %w", err)
} }
// Issue #6361: // Issue #6361:
// Client-Go emits an error when an API service is registered but unimplemented. // Client-Go emits an error when an API service is registered but unimplemented.
@ -260,7 +260,7 @@ func (cfg *Configuration) getCapabilities() (*chartutil.Capabilities, error) {
slog.Warn("the kubernetes server has an orphaned API service", slog.Any("error", err)) slog.Warn("the kubernetes server has an orphaned API service", slog.Any("error", err))
slog.Warn("to fix this, kubectl delete apiservice <service-name>") slog.Warn("to fix this, kubectl delete apiservice <service-name>")
} else { } else {
return nil, errors.Wrap(err, "could not get apiVersions from Kubernetes") return nil, fmt.Errorf("could not get apiVersions from Kubernetes: %w", err)
} }
} }
@ -280,7 +280,7 @@ func (cfg *Configuration) getCapabilities() (*chartutil.Capabilities, error) {
func (cfg *Configuration) KubernetesClientSet() (kubernetes.Interface, error) { func (cfg *Configuration) KubernetesClientSet() (kubernetes.Interface, error) {
conf, err := cfg.RESTClientGetter.ToRESTConfig() conf, err := cfg.RESTClientGetter.ToRESTConfig()
if err != nil { if err != nil {
return nil, errors.Wrap(err, "unable to generate config for kubernetes client") return nil, fmt.Errorf("unable to generate config for kubernetes client: %w", err)
} }
return kubernetes.NewForConfig(conf) return kubernetes.NewForConfig(conf)
@ -296,7 +296,7 @@ func (cfg *Configuration) Now() time.Time {
func (cfg *Configuration) releaseContent(name string, version int) (*release.Release, error) { func (cfg *Configuration) releaseContent(name string, version int) (*release.Release, error) {
if err := chartutil.ValidateReleaseName(name); err != nil { if err := chartutil.ValidateReleaseName(name); err != nil {
return nil, errors.Errorf("releaseContent: Release name is invalid: %s", name) return nil, fmt.Errorf("releaseContent: Release name is invalid: %s", name)
} }
if version <= 0 { if version <= 0 {
@ -310,7 +310,7 @@ func (cfg *Configuration) releaseContent(name string, version int) (*release.Rel
func GetVersionSet(client discovery.ServerResourcesInterface) (chartutil.VersionSet, error) { func GetVersionSet(client discovery.ServerResourcesInterface) (chartutil.VersionSet, error) {
groups, resources, err := client.ServerGroupsAndResources() groups, resources, err := client.ServerGroupsAndResources()
if err != nil && !discovery.IsGroupDiscoveryFailedError(err) { if err != nil && !discovery.IsGroupDiscoveryFailedError(err) {
return chartutil.DefaultVersionSet, errors.Wrap(err, "could not get apiVersions from Kubernetes") return chartutil.DefaultVersionSet, fmt.Errorf("could not get apiVersions from Kubernetes: %w", err)
} }
// FIXME: The Kubernetes test fixture for cli appears to always return nil // FIXME: The Kubernetes test fixture for cli appears to always return nil
@ -399,11 +399,11 @@ func (cfg *Configuration) Init(getter genericclioptions.RESTClientGetter, namesp
namespace, namespace,
) )
if err != nil { if err != nil {
return errors.Wrap(err, "unable to instantiate SQL driver") return fmt.Errorf("unable to instantiate SQL driver: %w", err)
} }
store = storage.Init(d) store = storage.Init(d)
default: default:
return errors.Errorf("unknown driver %q", helmDriver) return fmt.Errorf("unknown driver %q", helmDriver)
} }
cfg.RESTClientGetter = getter cfg.RESTClientGetter = getter

@ -19,7 +19,7 @@ package action
import ( import (
"log/slog" "log/slog"
"github.com/pkg/errors" "fmt"
chartutil "helm.sh/helm/v4/pkg/chart/v2/util" chartutil "helm.sh/helm/v4/pkg/chart/v2/util"
release "helm.sh/helm/v4/pkg/release/v1" release "helm.sh/helm/v4/pkg/release/v1"
@ -52,7 +52,7 @@ func (h *History) Run(name string) ([]*release.Release, error) {
} }
if err := chartutil.ValidateReleaseName(name); err != nil { if err := chartutil.ValidateReleaseName(name); err != nil {
return nil, errors.Errorf("release name is invalid: %s", name) return nil, fmt.Errorf("release name is invalid: %s", name)
} }
slog.Debug("getting history for release", "release", name) slog.Debug("getting history for release", "release", name)

@ -25,10 +25,8 @@ import (
"helm.sh/helm/v4/pkg/kube" "helm.sh/helm/v4/pkg/kube"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"github.com/pkg/errors"
"gopkg.in/yaml.v3" "gopkg.in/yaml.v3"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
release "helm.sh/helm/v4/pkg/release/v1" release "helm.sh/helm/v4/pkg/release/v1"
helmtime "helm.sh/helm/v4/pkg/time" helmtime "helm.sh/helm/v4/pkg/time"
@ -65,7 +63,7 @@ func (cfg *Configuration) execHook(rl *release.Release, hook release.HookEvent,
resources, err := cfg.KubeClient.Build(bytes.NewBufferString(h.Manifest), true) resources, err := cfg.KubeClient.Build(bytes.NewBufferString(h.Manifest), true)
if err != nil { if err != nil {
return errors.Wrapf(err, "unable to build kubernetes object for %s hook %s", hook, h.Path) return fmt.Errorf("unable to build kubernetes object for %s hook %s: %w", hook, h.Path, err)
} }
// Record the time at which the hook was applied to the cluster // Record the time at which the hook was applied to the cluster
@ -84,12 +82,12 @@ func (cfg *Configuration) execHook(rl *release.Release, hook release.HookEvent,
if _, err := cfg.KubeClient.Create(resources); err != nil { if _, err := cfg.KubeClient.Create(resources); err != nil {
h.LastRun.CompletedAt = helmtime.Now() h.LastRun.CompletedAt = helmtime.Now()
h.LastRun.Phase = release.HookPhaseFailed h.LastRun.Phase = release.HookPhaseFailed
return errors.Wrapf(err, "warning: Hook %s %s failed", hook, h.Path) return fmt.Errorf("warning: Hook %s %s failed: %w", hook, h.Path, err)
} }
waiter, err := cfg.KubeClient.GetWaiter(waitStrategy) waiter, err := cfg.KubeClient.GetWaiter(waitStrategy)
if err != nil { if err != nil {
return errors.Wrapf(err, "unable to get waiter") return fmt.Errorf("unable to get waiter: %w", err)
} }
// Watch hook resources until they have completed // Watch hook resources until they have completed
err = waiter.WatchUntilReady(resources, timeout) err = waiter.WatchUntilReady(resources, timeout)
@ -159,11 +157,11 @@ func (cfg *Configuration) deleteHookByPolicy(h *release.Hook, policy release.Hoo
if hookHasDeletePolicy(h, policy) { if hookHasDeletePolicy(h, policy) {
resources, err := cfg.KubeClient.Build(bytes.NewBufferString(h.Manifest), false) resources, err := cfg.KubeClient.Build(bytes.NewBufferString(h.Manifest), false)
if err != nil { if err != nil {
return errors.Wrapf(err, "unable to build kubernetes object for deleting hook %s", h.Path) return fmt.Errorf("unable to build kubernetes object for deleting hook %s: %w", h.Path, err)
} }
_, errs := cfg.KubeClient.Delete(resources) _, errs := cfg.KubeClient.Delete(resources)
if len(errs) > 0 { if len(errs) > 0 {
return errors.New(joinErrors(errs)) return joinErrors(errs, "; ")
} }
waiter, err := cfg.KubeClient.GetWaiter(waitStrategy) waiter, err := cfg.KubeClient.GetWaiter(waitStrategy)
@ -239,7 +237,7 @@ func (cfg *Configuration) deriveNamespace(h *release.Hook, namespace string) (st
}{} }{}
err := yaml.Unmarshal([]byte(h.Manifest), &tmp) err := yaml.Unmarshal([]byte(h.Manifest), &tmp)
if err != nil { if err != nil {
return "", errors.Wrapf(err, "unable to parse metadata.namespace from kubernetes manifest for output logs hook %s", h.Path) return "", fmt.Errorf("unable to parse metadata.namespace from kubernetes manifest for output logs hook %s: %w", h.Path, err)
} }
if tmp.Metadata.Namespace == "" { if tmp.Metadata.Namespace == "" {
return namespace, nil return namespace, nil

@ -19,8 +19,10 @@ package action
import ( import (
"bytes" "bytes"
"context" "context"
"errors"
"fmt" "fmt"
"io" "io"
"io/fs"
"log/slog" "log/slog"
"net/url" "net/url"
"os" "os"
@ -32,7 +34,6 @@ import (
"time" "time"
"github.com/Masterminds/sprig/v3" "github.com/Masterminds/sprig/v3"
"github.com/pkg/errors"
v1 "k8s.io/api/core/v1" v1 "k8s.io/api/core/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors" apierrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/api/meta" "k8s.io/apimachinery/pkg/api/meta"
@ -165,7 +166,7 @@ func (i *Install) installCRDs(crds []chart.CRD) error {
// Read in the resources // Read in the resources
res, err := i.cfg.KubeClient.Build(bytes.NewBuffer(obj.File.Data), false) res, err := i.cfg.KubeClient.Build(bytes.NewBuffer(obj.File.Data), false)
if err != nil { if err != nil {
return errors.Wrapf(err, "failed to install CRD %s", obj.Name) return fmt.Errorf("failed to install CRD %s: %w", obj.Name, err)
} }
// Send them to Kube // Send them to Kube
@ -176,14 +177,14 @@ func (i *Install) installCRDs(crds []chart.CRD) error {
slog.Debug("CRD is already present. Skipping", "crd", crdName) slog.Debug("CRD is already present. Skipping", "crd", crdName)
continue continue
} }
return errors.Wrapf(err, "failed to install CRD %s", obj.Name) return fmt.Errorf("failed to install CRD %s: %w", obj.Name, err)
} }
totalItems = append(totalItems, res...) totalItems = append(totalItems, res...)
} }
if len(totalItems) > 0 { if len(totalItems) > 0 {
waiter, err := i.cfg.KubeClient.GetWaiter(i.WaitStrategy) waiter, err := i.cfg.KubeClient.GetWaiter(i.WaitStrategy)
if err != nil { if err != nil {
return errors.Wrapf(err, "unable to get waiter") return fmt.Errorf("unable to get waiter: %w", err)
} }
// Give time for the CRD to be recognized. // Give time for the CRD to be recognized.
if err := waiter.Wait(totalItems, 60*time.Second); err != nil { if err := waiter.Wait(totalItems, 60*time.Second); err != nil {
@ -239,24 +240,24 @@ func (i *Install) RunWithContext(ctx context.Context, chrt *chart.Chart, vals ma
if !i.ClientOnly { if !i.ClientOnly {
if err := i.cfg.KubeClient.IsReachable(); err != nil { if err := i.cfg.KubeClient.IsReachable(); err != nil {
slog.Error(fmt.Sprintf("cluster reachability check failed: %v", err)) slog.Error(fmt.Sprintf("cluster reachability check failed: %v", err))
return nil, errors.Wrap(err, "cluster reachability check failed") return nil, fmt.Errorf("cluster reachability check failed: %w", err)
} }
} }
// HideSecret must be used with dry run. Otherwise, return an error. // HideSecret must be used with dry run. Otherwise, return an error.
if !i.isDryRun() && i.HideSecret { if !i.isDryRun() && i.HideSecret {
slog.Error("hiding Kubernetes secrets requires a dry-run mode") slog.Error("hiding Kubernetes secrets requires a dry-run mode")
return nil, errors.New("Hiding Kubernetes secrets requires a dry-run mode") return nil, errors.New("hiding Kubernetes secrets requires a dry-run mode")
} }
if err := i.availableName(); err != nil { if err := i.availableName(); err != nil {
slog.Error("release name check failed", slog.Any("error", err)) slog.Error("release name check failed", slog.Any("error", err))
return nil, errors.Wrap(err, "release name check failed") return nil, fmt.Errorf("release name check failed: %w", err)
} }
if err := chartutil.ProcessDependencies(chrt, vals); err != nil { if err := chartutil.ProcessDependencies(chrt, vals); err != nil {
slog.Error("chart dependencies processing failed", slog.Any("error", err)) slog.Error("chart dependencies processing failed", slog.Any("error", err))
return nil, errors.Wrap(err, "chart dependencies processing failed") return nil, fmt.Errorf("chart dependencies processing failed: %w", err)
} }
var interactWithRemote bool var interactWithRemote bool
@ -342,7 +343,7 @@ func (i *Install) RunWithContext(ctx context.Context, chrt *chart.Chart, vals ma
var toBeAdopted kube.ResourceList var toBeAdopted kube.ResourceList
resources, err := i.cfg.KubeClient.Build(bytes.NewBufferString(rel.Manifest), !i.DisableOpenAPIValidation) resources, err := i.cfg.KubeClient.Build(bytes.NewBufferString(rel.Manifest), !i.DisableOpenAPIValidation)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "unable to build kubernetes objects from release manifest") return nil, fmt.Errorf("unable to build kubernetes objects from release manifest: %w", err)
} }
// It is safe to use "force" here because these are resources currently rendered by the chart. // It is safe to use "force" here because these are resources currently rendered by the chart.
@ -364,7 +365,7 @@ func (i *Install) RunWithContext(ctx context.Context, chrt *chart.Chart, vals ma
toBeAdopted, err = existingResourceConflict(resources, rel.Name, rel.Namespace) toBeAdopted, err = existingResourceConflict(resources, rel.Name, rel.Namespace)
} }
if err != nil { if err != nil {
return nil, errors.Wrap(err, "Unable to continue with install") return nil, fmt.Errorf("unable to continue with install: %w", err)
} }
} }
@ -525,9 +526,9 @@ func (i *Install) failRelease(rel *release.Release, err error) (*release.Release
uninstall.KeepHistory = false uninstall.KeepHistory = false
uninstall.Timeout = i.Timeout uninstall.Timeout = i.Timeout
if _, uninstallErr := uninstall.Run(i.ReleaseName); uninstallErr != nil { if _, uninstallErr := uninstall.Run(i.ReleaseName); uninstallErr != nil {
return rel, errors.Wrapf(uninstallErr, "an error occurred while uninstalling the release. original install error: %s", err) return rel, fmt.Errorf("an error occurred while uninstalling the release. original install error: %w: %w", err, uninstallErr)
} }
return rel, errors.Wrapf(err, "release %s failed, and has been uninstalled due to atomic being set", i.ReleaseName) return rel, fmt.Errorf("release %s failed, and has been uninstalled due to atomic being set: %w", i.ReleaseName, err)
} }
i.recordRelease(rel) // Ignore the error, since we have another error to deal with. i.recordRelease(rel) // Ignore the error, since we have another error to deal with.
return rel, err return rel, err
@ -545,7 +546,7 @@ func (i *Install) availableName() error {
start := i.ReleaseName start := i.ReleaseName
if err := chartutil.ValidateReleaseName(start); err != nil { if err := chartutil.ValidateReleaseName(start); err != nil {
return errors.Wrapf(err, "release name %q", start) return fmt.Errorf("release name %q: %w", start, err)
} }
// On dry run, bail here // On dry run, bail here
if i.isDryRun() { if i.isDryRun() {
@ -653,7 +654,7 @@ func createOrOpenFile(filename string, appendData bool) (*os.File, error) {
func ensureDirectoryForFile(file string) error { func ensureDirectoryForFile(file string) error {
baseDir := path.Dir(file) baseDir := path.Dir(file)
_, err := os.Stat(baseDir) _, err := os.Stat(baseDir)
if err != nil && !os.IsNotExist(err) { if err != nil && !errors.Is(err, fs.ErrNotExist) {
return err return err
} }
@ -675,7 +676,7 @@ func (i *Install) NameAndChart(args []string) (string, string, error) {
} }
if len(args) > 2 { if len(args) > 2 {
return args[0], args[1], errors.Errorf("expected at most two arguments, unexpected arguments: %v", strings.Join(args[2:], ", ")) return args[0], args[1], fmt.Errorf("expected at most two arguments, unexpected arguments: %v", strings.Join(args[2:], ", "))
} }
if len(args) == 2 { if len(args) == 2 {
@ -740,7 +741,7 @@ OUTER:
} }
if len(missing) > 0 { if len(missing) > 0 {
return errors.Errorf("found in Chart.yaml, but missing in charts/ directory: %s", strings.Join(missing, ", ")) return fmt.Errorf("found in Chart.yaml, but missing in charts/ directory: %s", strings.Join(missing, ", "))
} }
return nil return nil
} }
@ -776,7 +777,7 @@ func (c *ChartPathOptions) LocateChart(name string, settings *cli.EnvSettings) (
return abs, nil return abs, nil
} }
if filepath.IsAbs(name) || strings.HasPrefix(name, ".") { if filepath.IsAbs(name) || strings.HasPrefix(name, ".") {
return name, errors.Errorf("path %q not found", name) return name, fmt.Errorf("path %q not found", name)
} }
dl := downloader.ChartDownloader{ dl := downloader.ChartDownloader{

@ -19,8 +19,10 @@ package action
import ( import (
"bytes" "bytes"
"context" "context"
"errors"
"fmt" "fmt"
"io" "io"
"io/fs"
"net/http" "net/http"
"os" "os"
"path/filepath" "path/filepath"
@ -210,7 +212,7 @@ func TestInstallReleaseWithTakeOwnership_ResourceOwnedNoFlag(t *testing.T) {
instAction := installActionWithConfig(config) instAction := installActionWithConfig(config)
_, err := instAction.Run(buildChart(), nil) _, err := instAction.Run(buildChart(), nil)
is.Error(err) is.Error(err)
is.Contains(err.Error(), "Unable to continue with install") is.Contains(err.Error(), "unable to continue with install")
} }
func TestInstallReleaseWithValues(t *testing.T) { func TestInstallReleaseWithValues(t *testing.T) {
@ -756,7 +758,7 @@ func TestInstallReleaseOutputDir(t *testing.T) {
test.AssertGoldenFile(t, filepath.Join(dir, "hello/templates/rbac"), "rbac.txt") test.AssertGoldenFile(t, filepath.Join(dir, "hello/templates/rbac"), "rbac.txt")
_, err = os.Stat(filepath.Join(dir, "hello/templates/empty")) _, err = os.Stat(filepath.Join(dir, "hello/templates/empty"))
is.True(os.IsNotExist(err)) is.True(errors.Is(err, fs.ErrNotExist))
} }
func TestInstallOutputDirWithReleaseName(t *testing.T) { func TestInstallOutputDirWithReleaseName(t *testing.T) {
@ -792,7 +794,7 @@ func TestInstallOutputDirWithReleaseName(t *testing.T) {
test.AssertGoldenFile(t, filepath.Join(newDir, "hello/templates/rbac"), "rbac.txt") test.AssertGoldenFile(t, filepath.Join(newDir, "hello/templates/rbac"), "rbac.txt")
_, err = os.Stat(filepath.Join(newDir, "hello/templates/empty")) _, err = os.Stat(filepath.Join(newDir, "hello/templates/empty"))
is.True(os.IsNotExist(err)) is.True(errors.Is(err, fs.ErrNotExist))
} }
func TestNameAndChart(t *testing.T) { func TestNameAndChart(t *testing.T) {

@ -17,12 +17,11 @@ limitations under the License.
package action package action
import ( import (
"fmt"
"os" "os"
"path/filepath" "path/filepath"
"strings" "strings"
"github.com/pkg/errors"
chartutil "helm.sh/helm/v4/pkg/chart/v2/util" chartutil "helm.sh/helm/v4/pkg/chart/v2/util"
"helm.sh/helm/v4/pkg/lint" "helm.sh/helm/v4/pkg/lint"
"helm.sh/helm/v4/pkg/lint/support" "helm.sh/helm/v4/pkg/lint/support"
@ -94,26 +93,26 @@ func lintChart(path string, vals map[string]interface{}, namespace string, kubeV
if strings.HasSuffix(path, ".tgz") || strings.HasSuffix(path, ".tar.gz") { if strings.HasSuffix(path, ".tgz") || strings.HasSuffix(path, ".tar.gz") {
tempDir, err := os.MkdirTemp("", "helm-lint") tempDir, err := os.MkdirTemp("", "helm-lint")
if err != nil { if err != nil {
return linter, errors.Wrap(err, "unable to create temp dir to extract tarball") return linter, fmt.Errorf("unable to create temp dir to extract tarball: %w", err)
} }
defer os.RemoveAll(tempDir) defer os.RemoveAll(tempDir)
file, err := os.Open(path) file, err := os.Open(path)
if err != nil { if err != nil {
return linter, errors.Wrap(err, "unable to open tarball") return linter, fmt.Errorf("unable to open tarball: %w", err)
} }
defer file.Close() defer file.Close()
if err = chartutil.Expand(tempDir, file); err != nil { if err = chartutil.Expand(tempDir, file); err != nil {
return linter, errors.Wrap(err, "unable to extract tarball") return linter, fmt.Errorf("unable to extract tarball: %w", err)
} }
files, err := os.ReadDir(tempDir) files, err := os.ReadDir(tempDir)
if err != nil { if err != nil {
return linter, errors.Wrapf(err, "unable to read temporary output directory %s", tempDir) return linter, fmt.Errorf("unable to read temporary output directory %s: %w", tempDir, err)
} }
if !files[0].IsDir() { if !files[0].IsDir() {
return linter, errors.Errorf("unexpected file %s in temporary output directory %s", files[0].Name(), tempDir) return linter, fmt.Errorf("unexpected file %s in temporary output directory %s", files[0].Name(), tempDir)
} }
chartPath = filepath.Join(tempDir, files[0].Name()) chartPath = filepath.Join(tempDir, files[0].Name())
@ -123,7 +122,7 @@ func lintChart(path string, vals map[string]interface{}, namespace string, kubeV
// Guard: Error out if this is not a chart. // Guard: Error out if this is not a chart.
if _, err := os.Stat(filepath.Join(chartPath, "Chart.yaml")); err != nil { if _, err := os.Stat(filepath.Join(chartPath, "Chart.yaml")); err != nil {
return linter, errors.Wrap(err, "unable to check Chart.yaml file in chart") return linter, fmt.Errorf("unable to check Chart.yaml file in chart: %w", err)
} }
return lint.RunAll( return lint.RunAll(

@ -18,12 +18,12 @@ package action
import ( import (
"bufio" "bufio"
"errors"
"fmt" "fmt"
"os" "os"
"syscall" "syscall"
"github.com/Masterminds/semver/v3" "github.com/Masterminds/semver/v3"
"github.com/pkg/errors"
"golang.org/x/term" "golang.org/x/term"
"helm.sh/helm/v4/pkg/chart/v2/loader" "helm.sh/helm/v4/pkg/chart/v2/loader"
@ -105,7 +105,7 @@ func (p *Package) Run(path string, _ map[string]interface{}) (string, error) {
name, err := chartutil.Save(ch, dest) name, err := chartutil.Save(ch, dest)
if err != nil { if err != nil {
return "", errors.Wrap(err, "failed to save") return "", fmt.Errorf("failed to save: %w", err)
} }
if p.Sign { if p.Sign {

@ -22,8 +22,6 @@ import (
"path/filepath" "path/filepath"
"strings" "strings"
"github.com/pkg/errors"
chartutil "helm.sh/helm/v4/pkg/chart/v2/util" chartutil "helm.sh/helm/v4/pkg/chart/v2/util"
"helm.sh/helm/v4/pkg/cli" "helm.sh/helm/v4/pkg/cli"
"helm.sh/helm/v4/pkg/downloader" "helm.sh/helm/v4/pkg/downloader"
@ -111,7 +109,7 @@ func (p *Pull) Run(chartRef string) (string, error) {
var err error var err error
dest, err = os.MkdirTemp("", "helm-") dest, err = os.MkdirTemp("", "helm-")
if err != nil { if err != nil {
return out.String(), errors.Wrap(err, "failed to untar") return out.String(), fmt.Errorf("failed to untar: %w", err)
} }
defer os.RemoveAll(dest) defer os.RemoveAll(dest)
} }
@ -163,11 +161,10 @@ func (p *Pull) Run(chartRef string) (string, error) {
if _, err := os.Stat(udCheck); err != nil { if _, err := os.Stat(udCheck); err != nil {
if err := os.MkdirAll(udCheck, 0755); err != nil { if err := os.MkdirAll(udCheck, 0755); err != nil {
return out.String(), errors.Wrap(err, "failed to untar (mkdir)") return out.String(), fmt.Errorf("failed to untar (mkdir): %w", err)
} }
} else { } else {
return out.String(), errors.Errorf("failed to untar: a file or directory with the name %s already exists", udCheck) return out.String(), fmt.Errorf("failed to untar: a file or directory with the name %s already exists", udCheck)
} }
return out.String(), chartutil.ExpandFile(ud, saved) return out.String(), chartutil.ExpandFile(ud, saved)

@ -24,7 +24,6 @@ import (
"sort" "sort"
"time" "time"
"github.com/pkg/errors"
v1 "k8s.io/api/core/v1" v1 "k8s.io/api/core/v1"
chartutil "helm.sh/helm/v4/pkg/chart/v2/util" chartutil "helm.sh/helm/v4/pkg/chart/v2/util"
@ -64,7 +63,7 @@ func (r *ReleaseTesting) Run(name string) (*release.Release, error) {
} }
if err := chartutil.ValidateReleaseName(name); err != nil { if err := chartutil.ValidateReleaseName(name); err != nil {
return nil, errors.Errorf("releaseTest: Release name is invalid: %s", name) return nil, fmt.Errorf("releaseTest: Release name is invalid: %s", name)
} }
// finds the non-deleted release with the given name // finds the non-deleted release with the given name
@ -113,7 +112,7 @@ func (r *ReleaseTesting) Run(name string) (*release.Release, error) {
func (r *ReleaseTesting) GetPodLogs(out io.Writer, rel *release.Release) error { func (r *ReleaseTesting) GetPodLogs(out io.Writer, rel *release.Release) error {
client, err := r.cfg.KubernetesClientSet() client, err := r.cfg.KubernetesClientSet()
if err != nil { if err != nil {
return errors.Wrap(err, "unable to get kubernetes client to fetch pod logs") return fmt.Errorf("unable to get kubernetes client to fetch pod logs: %w", err)
} }
hooksByWight := append([]*release.Hook{}, rel.Hooks...) hooksByWight := append([]*release.Hook{}, rel.Hooks...)
@ -130,14 +129,14 @@ func (r *ReleaseTesting) GetPodLogs(out io.Writer, rel *release.Release) error {
req := client.CoreV1().Pods(r.Namespace).GetLogs(h.Name, &v1.PodLogOptions{}) req := client.CoreV1().Pods(r.Namespace).GetLogs(h.Name, &v1.PodLogOptions{})
logReader, err := req.Stream(context.Background()) logReader, err := req.Stream(context.Background())
if err != nil { if err != nil {
return errors.Wrapf(err, "unable to get pod logs for %s", h.Name) return fmt.Errorf("unable to get pod logs for %s: %w", h.Name, err)
} }
fmt.Fprintf(out, "POD LOGS: %s\n", h.Name) fmt.Fprintf(out, "POD LOGS: %s\n", h.Name)
_, err = io.Copy(out, logReader) _, err = io.Copy(out, logReader)
fmt.Fprintln(out) fmt.Fprintln(out)
if err != nil { if err != nil {
return errors.Wrapf(err, "unable to write pod logs for %s", h.Name) return fmt.Errorf("unable to write pod logs for %s: %w", h.Name, err)
} }
} }
} }

@ -23,8 +23,6 @@ import (
"strings" "strings"
"time" "time"
"github.com/pkg/errors"
chartutil "helm.sh/helm/v4/pkg/chart/v2/util" chartutil "helm.sh/helm/v4/pkg/chart/v2/util"
"helm.sh/helm/v4/pkg/kube" "helm.sh/helm/v4/pkg/kube"
release "helm.sh/helm/v4/pkg/release/v1" release "helm.sh/helm/v4/pkg/release/v1"
@ -95,7 +93,7 @@ func (r *Rollback) Run(name string) error {
// the previous release's configuration // the previous release's configuration
func (r *Rollback) prepareRollback(name string) (*release.Release, *release.Release, error) { func (r *Rollback) prepareRollback(name string) (*release.Release, *release.Release, error) {
if err := chartutil.ValidateReleaseName(name); err != nil { if err := chartutil.ValidateReleaseName(name); err != nil {
return nil, nil, errors.Errorf("prepareRollback: Release name is invalid: %s", name) return nil, nil, fmt.Errorf("prepareRollback: Release name is invalid: %s", name)
} }
if r.Version < 0 { if r.Version < 0 {
@ -127,7 +125,7 @@ func (r *Rollback) prepareRollback(name string) (*release.Release, *release.Rele
} }
} }
if !previousVersionExist { if !previousVersionExist {
return nil, nil, errors.Errorf("release has no %d version", previousVersion) return nil, nil, fmt.Errorf("release has no %d version", previousVersion)
} }
slog.Debug("rolling back", "name", name, "currentVersion", currentRelease.Version, "targetVersion", previousVersion) slog.Debug("rolling back", "name", name, "currentVersion", currentRelease.Version, "targetVersion", previousVersion)
@ -169,11 +167,11 @@ func (r *Rollback) performRollback(currentRelease, targetRelease *release.Releas
current, err := r.cfg.KubeClient.Build(bytes.NewBufferString(currentRelease.Manifest), false) current, err := r.cfg.KubeClient.Build(bytes.NewBufferString(currentRelease.Manifest), false)
if err != nil { if err != nil {
return targetRelease, errors.Wrap(err, "unable to build kubernetes objects from current release manifest") return targetRelease, fmt.Errorf("unable to build kubernetes objects from current release manifest: %w", err)
} }
target, err := r.cfg.KubeClient.Build(bytes.NewBufferString(targetRelease.Manifest), false) target, err := r.cfg.KubeClient.Build(bytes.NewBufferString(targetRelease.Manifest), false)
if err != nil { if err != nil {
return targetRelease, errors.Wrap(err, "unable to build kubernetes objects from new release manifest") return targetRelease, fmt.Errorf("unable to build kubernetes objects from new release manifest: %w", err)
} }
// pre-rollback hooks // pre-rollback hooks
@ -188,7 +186,7 @@ func (r *Rollback) performRollback(currentRelease, targetRelease *release.Releas
// It is safe to use "force" here because these are resources currently rendered by the chart. // It is safe to use "force" here because these are resources currently rendered by the chart.
err = target.Visit(setMetadataVisitor(targetRelease.Name, targetRelease.Namespace, true)) err = target.Visit(setMetadataVisitor(targetRelease.Name, targetRelease.Namespace, true))
if err != nil { if err != nil {
return targetRelease, errors.Wrap(err, "unable to set metadata visitor from target release") return targetRelease, fmt.Errorf("unable to set metadata visitor from target release: %w", err)
} }
results, err := r.cfg.KubeClient.Update(current, target, r.Force) results, err := r.cfg.KubeClient.Update(current, target, r.Force)
@ -204,11 +202,9 @@ func (r *Rollback) performRollback(currentRelease, targetRelease *release.Releas
slog.Debug("cleanup on fail set, cleaning up resources", "count", len(results.Created)) slog.Debug("cleanup on fail set, cleaning up resources", "count", len(results.Created))
_, errs := r.cfg.KubeClient.Delete(results.Created) _, errs := r.cfg.KubeClient.Delete(results.Created)
if errs != nil { if errs != nil {
var errorList []string return targetRelease, fmt.Errorf(
for _, e := range errs { "an error occurred while cleaning up resources. original rollback error: %w",
errorList = append(errorList, e.Error()) fmt.Errorf("unable to cleanup resources: %w", joinErrors(errs, ", ")))
}
return targetRelease, errors.Wrapf(fmt.Errorf("unable to cleanup resources: %s", strings.Join(errorList, ", ")), "an error occurred while cleaning up resources. original rollback error: %s", err)
} }
slog.Debug("resource cleanup complete") slog.Debug("resource cleanup complete")
} }
@ -226,21 +222,21 @@ func (r *Rollback) performRollback(currentRelease, targetRelease *release.Releas
} }
waiter, err := r.cfg.KubeClient.GetWaiter(r.WaitStrategy) waiter, err := r.cfg.KubeClient.GetWaiter(r.WaitStrategy)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "unable to set metadata visitor from target release") return nil, fmt.Errorf("unable to set metadata visitor from target release: %w", err)
} }
if r.WaitForJobs { if r.WaitForJobs {
if err := waiter.WaitWithJobs(target, r.Timeout); err != nil { if err := waiter.WaitWithJobs(target, r.Timeout); err != nil {
targetRelease.SetStatus(release.StatusFailed, fmt.Sprintf("Release %q failed: %s", targetRelease.Name, err.Error())) targetRelease.SetStatus(release.StatusFailed, fmt.Sprintf("Release %q failed: %s", targetRelease.Name, err.Error()))
r.cfg.recordRelease(currentRelease) r.cfg.recordRelease(currentRelease)
r.cfg.recordRelease(targetRelease) r.cfg.recordRelease(targetRelease)
return targetRelease, errors.Wrapf(err, "release %s failed", targetRelease.Name) return targetRelease, fmt.Errorf("release %s failed: %w", targetRelease.Name, err)
} }
} else { } else {
if err := waiter.Wait(target, r.Timeout); err != nil { if err := waiter.Wait(target, r.Timeout); err != nil {
targetRelease.SetStatus(release.StatusFailed, fmt.Sprintf("Release %q failed: %s", targetRelease.Name, err.Error())) targetRelease.SetStatus(release.StatusFailed, fmt.Sprintf("Release %q failed: %s", targetRelease.Name, err.Error()))
r.cfg.recordRelease(currentRelease) r.cfg.recordRelease(currentRelease)
r.cfg.recordRelease(targetRelease) r.cfg.recordRelease(targetRelease)
return targetRelease, errors.Wrapf(err, "release %s failed", targetRelease.Name) return targetRelease, fmt.Errorf("release %s failed: %w", targetRelease.Name, err)
} }
} }

@ -21,7 +21,6 @@ import (
"fmt" "fmt"
"strings" "strings"
"github.com/pkg/errors"
"k8s.io/cli-runtime/pkg/printers" "k8s.io/cli-runtime/pkg/printers"
"sigs.k8s.io/yaml" "sigs.k8s.io/yaml"
@ -105,7 +104,7 @@ func (s *Show) Run(chartpath string) (string, error) {
if s.JSONPathTemplate != "" { if s.JSONPathTemplate != "" {
printer, err := printers.NewJSONPathPrinter(s.JSONPathTemplate) printer, err := printers.NewJSONPathPrinter(s.JSONPathTemplate)
if err != nil { if err != nil {
return "", errors.Wrapf(err, "error parsing jsonpath %s", s.JSONPathTemplate) return "", fmt.Errorf("error parsing jsonpath %s: %w", s.JSONPathTemplate, err)
} }
printer.Execute(&out, s.chart.Values) printer.Execute(&out, s.chart.Values)
} else { } else {

@ -17,12 +17,11 @@ limitations under the License.
package action package action
import ( import (
"fmt"
"log/slog" "log/slog"
"strings" "strings"
"time" "time"
"github.com/pkg/errors"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1" v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
chartutil "helm.sh/helm/v4/pkg/chart/v2/util" chartutil "helm.sh/helm/v4/pkg/chart/v2/util"
@ -76,7 +75,7 @@ func (u *Uninstall) Run(name string) (*release.UninstallReleaseResponse, error)
} }
if err := chartutil.ValidateReleaseName(name); err != nil { if err := chartutil.ValidateReleaseName(name); err != nil {
return nil, errors.Errorf("uninstall: Release name is invalid: %s", name) return nil, fmt.Errorf("uninstall: Release name is invalid: %s", name)
} }
rels, err := u.cfg.Releases.History(name) rels, err := u.cfg.Releases.History(name)
@ -84,7 +83,7 @@ func (u *Uninstall) Run(name string) (*release.UninstallReleaseResponse, error)
if u.IgnoreNotFound { if u.IgnoreNotFound {
return nil, nil return nil, nil
} }
return nil, errors.Wrapf(err, "uninstall: Release not loaded: %s", name) return nil, fmt.Errorf("uninstall: Release not loaded: %s: %w", name, err)
} }
if len(rels) < 1 { if len(rels) < 1 {
return nil, errMissingRelease return nil, errMissingRelease
@ -98,11 +97,11 @@ func (u *Uninstall) Run(name string) (*release.UninstallReleaseResponse, error)
if rel.Info.Status == release.StatusUninstalled { if rel.Info.Status == release.StatusUninstalled {
if !u.KeepHistory { if !u.KeepHistory {
if err := u.purgeReleases(rels...); err != nil { if err := u.purgeReleases(rels...); err != nil {
return nil, errors.Wrap(err, "uninstall: Failed to purge the release") return nil, fmt.Errorf("uninstall: Failed to purge the release: %w", err)
} }
return &release.UninstallReleaseResponse{Release: rel}, nil return &release.UninstallReleaseResponse{Release: rel}, nil
} }
return nil, errors.Errorf("the release named %q is already deleted", name) return nil, fmt.Errorf("the release named %q is already deleted", name)
} }
slog.Debug("uninstall: deleting release", "name", name) slog.Debug("uninstall: deleting release", "name", name)
@ -128,7 +127,7 @@ func (u *Uninstall) Run(name string) (*release.UninstallReleaseResponse, error)
deletedResources, kept, errs := u.deleteRelease(rel) deletedResources, kept, errs := u.deleteRelease(rel)
if errs != nil { if errs != nil {
slog.Debug("uninstall: Failed to delete release", slog.Any("error", errs)) slog.Debug("uninstall: Failed to delete release", slog.Any("error", errs))
return nil, errors.Errorf("failed to delete release: %s", name) return nil, fmt.Errorf("failed to delete release: %s", name)
} }
if kept != "" { if kept != "" {
@ -157,12 +156,12 @@ func (u *Uninstall) Run(name string) (*release.UninstallReleaseResponse, error)
slog.Debug("purge requested", "release", name) slog.Debug("purge requested", "release", name)
err := u.purgeReleases(rels...) err := u.purgeReleases(rels...)
if err != nil { if err != nil {
errs = append(errs, errors.Wrap(err, "uninstall: Failed to purge the release")) errs = append(errs, fmt.Errorf("uninstall: Failed to purge the release: %w", err))
} }
// Return the errors that occurred while deleting the release, if any // Return the errors that occurred while deleting the release, if any
if len(errs) > 0 { if len(errs) > 0 {
return res, errors.Errorf("uninstallation completed with %d error(s): %s", len(errs), joinErrors(errs)) return res, fmt.Errorf("uninstallation completed with %d error(s): %w", len(errs), joinErrors(errs, "; "))
} }
return res, nil return res, nil
@ -173,7 +172,7 @@ func (u *Uninstall) Run(name string) (*release.UninstallReleaseResponse, error)
} }
if len(errs) > 0 { if len(errs) > 0 {
return res, errors.Errorf("uninstallation completed with %d error(s): %s", len(errs), joinErrors(errs)) return res, fmt.Errorf("uninstallation completed with %d error(s): %w", len(errs), joinErrors(errs, "; "))
} }
return res, nil return res, nil
} }
@ -187,12 +186,28 @@ func (u *Uninstall) purgeReleases(rels ...*release.Release) error {
return nil return nil
} }
func joinErrors(errs []error) string { type joinedErrors struct {
es := make([]string, 0, len(errs)) errs []error
for _, e := range errs { sep string
es = append(es, e.Error()) }
func joinErrors(errs []error, sep string) error {
return &joinedErrors{
errs: errs,
sep: sep,
}
}
func (e *joinedErrors) Error() string {
errs := make([]string, 0, len(e.errs))
for _, err := range e.errs {
errs = append(errs, err.Error())
} }
return strings.Join(es, "; ") return strings.Join(errs, e.sep)
}
func (e *joinedErrors) Unwrap() []error {
return e.errs
} }
// deleteRelease deletes the release and returns list of delete resources and manifests that were kept in the deletion process // deleteRelease deletes the release and returns list of delete resources and manifests that were kept in the deletion process
@ -206,7 +221,7 @@ func (u *Uninstall) deleteRelease(rel *release.Release) (kube.ResourceList, stri
// FIXME: One way to delete at this point would be to try a label-based // FIXME: One way to delete at this point would be to try a label-based
// deletion. The problem with this is that we could get a false positive // deletion. The problem with this is that we could get a false positive
// and delete something that was not legitimately part of this release. // and delete something that was not legitimately part of this release.
return nil, rel.Manifest, []error{errors.Wrap(err, "corrupted release record. You must manually delete the resources")} return nil, rel.Manifest, []error{fmt.Errorf("corrupted release record. You must manually delete the resources: %w", err)}
} }
filesToKeep, filesToDelete := filterManifestsToKeep(files) filesToKeep, filesToDelete := filterManifestsToKeep(files)
@ -222,7 +237,7 @@ func (u *Uninstall) deleteRelease(rel *release.Release) (kube.ResourceList, stri
resources, err := u.cfg.KubeClient.Build(strings.NewReader(builder.String()), false) resources, err := u.cfg.KubeClient.Build(strings.NewReader(builder.String()), false)
if err != nil { if err != nil {
return nil, "", []error{errors.Wrap(err, "unable to build kubernetes objects for delete")} return nil, "", []error{fmt.Errorf("unable to build kubernetes objects for delete: %w", err)}
} }
if len(resources) > 0 { if len(resources) > 0 {
if kubeClient, ok := u.cfg.KubeClient.(kube.InterfaceDeletionPropagation); ok { if kubeClient, ok := u.cfg.KubeClient.(kube.InterfaceDeletionPropagation); ok {

@ -19,13 +19,13 @@ package action
import ( import (
"bytes" "bytes"
"context" "context"
"errors"
"fmt" "fmt"
"log/slog" "log/slog"
"strings" "strings"
"sync" "sync"
"time" "time"
"github.com/pkg/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/cli-runtime/pkg/resource" "k8s.io/cli-runtime/pkg/resource"
@ -161,7 +161,7 @@ func (u *Upgrade) RunWithContext(ctx context.Context, name string, chart *chart.
} }
if err := chartutil.ValidateReleaseName(name); err != nil { if err := chartutil.ValidateReleaseName(name); err != nil {
return nil, errors.Errorf("release name is invalid: %s", name) return nil, fmt.Errorf("release name is invalid: %s", name)
} }
slog.Debug("preparing upgrade", "name", name) slog.Debug("preparing upgrade", "name", name)
@ -205,7 +205,7 @@ func (u *Upgrade) prepareUpgrade(name string, chart *chart.Chart, vals map[strin
// HideSecret must be used with dry run. Otherwise, return an error. // HideSecret must be used with dry run. Otherwise, return an error.
if !u.isDryRun() && u.HideSecret { if !u.isDryRun() && u.HideSecret {
return nil, nil, errors.New("Hiding Kubernetes secrets requires a dry-run mode") return nil, nil, errors.New("hiding Kubernetes secrets requires a dry-run mode")
} }
// finds the last non-deleted release with the given name // finds the last non-deleted release with the given name
@ -316,15 +316,15 @@ func (u *Upgrade) performUpgrade(ctx context.Context, originalRelease, upgradedR
// Checking for removed Kubernetes API error so can provide a more informative error message to the user // Checking for removed Kubernetes API error so can provide a more informative error message to the user
// Ref: https://github.com/helm/helm/issues/7219 // Ref: https://github.com/helm/helm/issues/7219
if strings.Contains(err.Error(), "unable to recognize \"\": no matches for kind") { if strings.Contains(err.Error(), "unable to recognize \"\": no matches for kind") {
return upgradedRelease, errors.Wrap(err, "current release manifest contains removed kubernetes api(s) for this "+ return upgradedRelease, fmt.Errorf("current release manifest contains removed kubernetes api(s) for this "+
"kubernetes version and it is therefore unable to build the kubernetes "+ "kubernetes version and it is therefore unable to build the kubernetes "+
"objects for performing the diff. error from kubernetes") "objects for performing the diff. error from kubernetes: %w", err)
} }
return upgradedRelease, errors.Wrap(err, "unable to build kubernetes objects from current release manifest") return upgradedRelease, fmt.Errorf("unable to build kubernetes objects from current release manifest: %w", err)
} }
target, err := u.cfg.KubeClient.Build(bytes.NewBufferString(upgradedRelease.Manifest), !u.DisableOpenAPIValidation) target, err := u.cfg.KubeClient.Build(bytes.NewBufferString(upgradedRelease.Manifest), !u.DisableOpenAPIValidation)
if err != nil { if err != nil {
return upgradedRelease, errors.Wrap(err, "unable to build kubernetes objects from new release manifest") return upgradedRelease, fmt.Errorf("unable to build kubernetes objects from new release manifest: %w", err)
} }
// It is safe to use force only on target because these are resources currently rendered by the chart. // It is safe to use force only on target because these are resources currently rendered by the chart.
@ -353,7 +353,7 @@ func (u *Upgrade) performUpgrade(ctx context.Context, originalRelease, upgradedR
toBeUpdated, err = existingResourceConflict(toBeCreated, upgradedRelease.Name, upgradedRelease.Namespace) toBeUpdated, err = existingResourceConflict(toBeCreated, upgradedRelease.Name, upgradedRelease.Namespace)
} }
if err != nil { if err != nil {
return nil, errors.Wrap(err, "Unable to continue with update") return nil, fmt.Errorf("unable to continue with update: %w", err)
} }
toBeUpdated.Visit(func(r *resource.Info, err error) error { toBeUpdated.Visit(func(r *resource.Info, err error) error {
@ -496,11 +496,14 @@ func (u *Upgrade) failRelease(rel *release.Release, created kube.ResourceList, e
slog.Debug("cleanup on fail set", "cleaning_resources", len(created)) slog.Debug("cleanup on fail set", "cleaning_resources", len(created))
_, errs := u.cfg.KubeClient.Delete(created) _, errs := u.cfg.KubeClient.Delete(created)
if errs != nil { if errs != nil {
var errorList []string return rel, fmt.Errorf(
for _, e := range errs { "an error occurred while cleaning up resources. original upgrade error: %w: %w",
errorList = append(errorList, e.Error()) err,
} fmt.Errorf(
return rel, errors.Wrapf(fmt.Errorf("unable to cleanup resources: %s", strings.Join(errorList, ", ")), "an error occurred while cleaning up resources. original upgrade error: %s", err) "unable to cleanup resources: %w",
joinErrors(errs, ", "),
),
)
} }
slog.Debug("resource cleanup complete") slog.Debug("resource cleanup complete")
} }
@ -512,7 +515,7 @@ func (u *Upgrade) failRelease(rel *release.Release, created kube.ResourceList, e
hist := NewHistory(u.cfg) hist := NewHistory(u.cfg)
fullHistory, herr := hist.Run(rel.Name) fullHistory, herr := hist.Run(rel.Name)
if herr != nil { if herr != nil {
return rel, errors.Wrapf(herr, "an error occurred while finding last successful release. original upgrade error: %s", err) return rel, fmt.Errorf("an error occurred while finding last successful release. original upgrade error: %w: %w", err, herr)
} }
// There isn't a way to tell if a previous release was successful, but // There isn't a way to tell if a previous release was successful, but
@ -522,7 +525,7 @@ func (u *Upgrade) failRelease(rel *release.Release, created kube.ResourceList, e
return r.Info.Status == release.StatusSuperseded || r.Info.Status == release.StatusDeployed return r.Info.Status == release.StatusSuperseded || r.Info.Status == release.StatusDeployed
}).Filter(fullHistory) }).Filter(fullHistory)
if len(filteredHistory) == 0 { if len(filteredHistory) == 0 {
return rel, errors.Wrap(err, "unable to find a previously successful release when attempting to rollback. original upgrade error") return rel, fmt.Errorf("unable to find a previously successful release when attempting to rollback. original upgrade error: %w", err)
} }
releaseutil.Reverse(filteredHistory, releaseutil.SortByRevision) releaseutil.Reverse(filteredHistory, releaseutil.SortByRevision)
@ -538,9 +541,9 @@ func (u *Upgrade) failRelease(rel *release.Release, created kube.ResourceList, e
rollin.Force = u.Force rollin.Force = u.Force
rollin.Timeout = u.Timeout rollin.Timeout = u.Timeout
if rollErr := rollin.Run(rel.Name); rollErr != nil { if rollErr := rollin.Run(rel.Name); rollErr != nil {
return rel, errors.Wrapf(rollErr, "an error occurred while rolling back the release. original upgrade error: %s", err) return rel, fmt.Errorf("an error occurred while rolling back the release. original upgrade error: %w: %w", err, rollErr)
} }
return rel, errors.Wrapf(err, "release %s failed, and has been rolled back due to atomic being set", rel.Name) return rel, fmt.Errorf("release %s failed, and has been rolled back due to atomic being set: %w", rel.Name, err)
} }
return rel, err return rel, err
@ -568,7 +571,7 @@ func (u *Upgrade) reuseValues(chart *chart.Chart, current *release.Release, newV
// We have to regenerate the old coalesced values: // We have to regenerate the old coalesced values:
oldVals, err := chartutil.CoalesceValues(current.Chart, current.Config) oldVals, err := chartutil.CoalesceValues(current.Chart, current.Config)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "failed to rebuild old values") return nil, fmt.Errorf("failed to rebuild old values: %w", err)
} }
newVals = chartutil.CoalesceTables(newVals, current.Config) newVals = chartutil.CoalesceTables(newVals, current.Config)
@ -614,21 +617,21 @@ func recreate(cfg *Configuration, resources kube.ResourceList) error {
client, err := cfg.KubernetesClientSet() client, err := cfg.KubernetesClientSet()
if err != nil { if err != nil {
return errors.Wrapf(err, "unable to recreate pods for object %s/%s because an error occurred", res.Namespace, res.Name) return fmt.Errorf("unable to recreate pods for object %s/%s because an error occurred: %w", res.Namespace, res.Name, err)
} }
pods, err := client.CoreV1().Pods(res.Namespace).List(context.Background(), metav1.ListOptions{ pods, err := client.CoreV1().Pods(res.Namespace).List(context.Background(), metav1.ListOptions{
LabelSelector: selector.String(), LabelSelector: selector.String(),
}) })
if err != nil { if err != nil {
return errors.Wrapf(err, "unable to recreate pods for object %s/%s because an error occurred", res.Namespace, res.Name) return fmt.Errorf("unable to recreate pods for object %s/%s because an error occurred: %w", res.Namespace, res.Name, err)
} }
// Restart pods // Restart pods
for _, pod := range pods.Items { for _, pod := range pods.Items {
// Delete each pod for get them restarted with changed spec. // Delete each pod for get them restarted with changed spec.
if err := client.CoreV1().Pods(pod.Namespace).Delete(context.Background(), pod.Name, *metav1.NewPreconditionDeleteOptions(string(pod.UID))); err != nil { if err := client.CoreV1().Pods(pod.Namespace).Delete(context.Background(), pod.Name, *metav1.NewPreconditionDeleteOptions(string(pod.UID))); err != nil {
return errors.Wrapf(err, "unable to recreate pods for object %s/%s because an error occurred", res.Namespace, res.Name) return fmt.Errorf("unable to recreate pods for object %s/%s because an error occurred: %w", res.Namespace, res.Name, err)
} }
} }
} }

@ -19,7 +19,6 @@ package action
import ( import (
"fmt" "fmt"
"github.com/pkg/errors"
apierrors "k8s.io/apimachinery/pkg/api/errors" apierrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/api/meta" "k8s.io/apimachinery/pkg/api/meta"
"k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime"
@ -52,7 +51,7 @@ func requireAdoption(resources kube.ResourceList) (kube.ResourceList, error) {
if apierrors.IsNotFound(err) { if apierrors.IsNotFound(err) {
return nil return nil
} }
return errors.Wrapf(err, "could not get information about the resource %s", resourceString(info)) return fmt.Errorf("could not get information about the resource %s: %w", resourceString(info), err)
} }
requireUpdate.Append(info) requireUpdate.Append(info)
@ -76,7 +75,7 @@ func existingResourceConflict(resources kube.ResourceList, releaseName, releaseN
if apierrors.IsNotFound(err) { if apierrors.IsNotFound(err) {
return nil return nil
} }
return errors.Wrapf(err, "could not get information about the resource %s", resourceString(info)) return fmt.Errorf("could not get information about the resource %s: %w", resourceString(info), err)
} }
// 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.
@ -113,11 +112,7 @@ func checkOwnership(obj runtime.Object, releaseName, releaseNamespace string) er
} }
if len(errs) > 0 { if len(errs) > 0 {
err := errors.New("invalid ownership metadata") return fmt.Errorf("invalid ownership metadata; %w", joinErrors(errs, "; "))
for _, e := range errs {
err = fmt.Errorf("%w; %s", err, e)
}
return err
} }
return nil return nil

@ -20,6 +20,7 @@ import (
"archive/tar" "archive/tar"
"bytes" "bytes"
"compress/gzip" "compress/gzip"
"errors"
"fmt" "fmt"
"io" "io"
"net/http" "net/http"
@ -28,8 +29,6 @@ import (
"regexp" "regexp"
"strings" "strings"
"github.com/pkg/errors"
chart "helm.sh/helm/v4/pkg/chart/v2" chart "helm.sh/helm/v4/pkg/chart/v2"
) )
@ -170,7 +169,7 @@ func LoadArchiveFiles(in io.Reader) ([]*BufferedFile, error) {
n = path.Clean(n) n = path.Clean(n)
if n == "." { if n == "." {
// In this case, the original path was relative when it should have been absolute. // In this case, the original path was relative when it should have been absolute.
return nil, errors.Errorf("chart illegally contains content outside the base directory: %q", hd.Name) return nil, fmt.Errorf("chart illegally contains content outside the base directory: %q", hd.Name)
} }
if strings.HasPrefix(n, "..") { if strings.HasPrefix(n, "..") {
return nil, errors.New("chart illegally references parent directory") return nil, errors.New("chart illegally references parent directory")

@ -23,8 +23,6 @@ import (
"path/filepath" "path/filepath"
"strings" "strings"
"github.com/pkg/errors"
"helm.sh/helm/v4/internal/sympath" "helm.sh/helm/v4/internal/sympath"
chart "helm.sh/helm/v4/pkg/chart/v2" chart "helm.sh/helm/v4/pkg/chart/v2"
"helm.sh/helm/v4/pkg/ignore" "helm.sh/helm/v4/pkg/ignore"
@ -107,7 +105,7 @@ func LoadDir(dir string) (*chart.Chart, error) {
data, err := os.ReadFile(name) data, err := os.ReadFile(name)
if err != nil { if err != nil {
return errors.Wrapf(err, "error reading %s", n) return fmt.Errorf("error reading %s: %w", n, err)
} }
data = bytes.TrimPrefix(data, utf8bom) data = bytes.TrimPrefix(data, utf8bom)

@ -20,13 +20,14 @@ import (
"bufio" "bufio"
"bytes" "bytes"
"encoding/json" "encoding/json"
"errors"
"fmt"
"io" "io"
"log" "log"
"os" "os"
"path/filepath" "path/filepath"
"strings" "strings"
"github.com/pkg/errors"
utilyaml "k8s.io/apimachinery/pkg/util/yaml" utilyaml "k8s.io/apimachinery/pkg/util/yaml"
"sigs.k8s.io/yaml" "sigs.k8s.io/yaml"
@ -48,7 +49,6 @@ func Loader(name string) (ChartLoader, error) {
return DirLoader(name), nil return DirLoader(name), nil
} }
return FileLoader(name), nil return FileLoader(name), nil
} }
// Load takes a string name, tries to resolve it to a file or directory, and then loads it. // Load takes a string name, tries to resolve it to a file or directory, and then loads it.
@ -86,7 +86,7 @@ func LoadFiles(files []*BufferedFile) (*chart.Chart, error) {
c.Metadata = new(chart.Metadata) c.Metadata = new(chart.Metadata)
} }
if err := yaml.Unmarshal(f.Data, c.Metadata); err != nil { if err := yaml.Unmarshal(f.Data, c.Metadata); err != nil {
return c, errors.Wrap(err, "cannot load Chart.yaml") return c, fmt.Errorf("cannot load Chart.yaml: %w", err)
} }
// NOTE(bacongobbler): while the chart specification says that APIVersion must be set, // NOTE(bacongobbler): while the chart specification says that APIVersion must be set,
// Helm 2 accepted charts that did not provide an APIVersion in their chart metadata. // Helm 2 accepted charts that did not provide an APIVersion in their chart metadata.
@ -104,12 +104,12 @@ func LoadFiles(files []*BufferedFile) (*chart.Chart, error) {
case f.Name == "Chart.lock": case f.Name == "Chart.lock":
c.Lock = new(chart.Lock) c.Lock = new(chart.Lock)
if err := yaml.Unmarshal(f.Data, &c.Lock); err != nil { if err := yaml.Unmarshal(f.Data, &c.Lock); err != nil {
return c, errors.Wrap(err, "cannot load Chart.lock") return c, fmt.Errorf("cannot load Chart.lock: %w", err)
} }
case f.Name == "values.yaml": case f.Name == "values.yaml":
values, err := LoadValues(bytes.NewReader(f.Data)) values, err := LoadValues(bytes.NewReader(f.Data))
if err != nil { if err != nil {
return c, errors.Wrap(err, "cannot load values.yaml") return c, fmt.Errorf("cannot load values.yaml: %w", err)
} }
c.Values = values c.Values = values
case f.Name == "values.schema.json": case f.Name == "values.schema.json":
@ -125,7 +125,7 @@ func LoadFiles(files []*BufferedFile) (*chart.Chart, error) {
log.Printf("Warning: Dependencies are handled in Chart.yaml since apiVersion \"v2\". We recommend migrating dependencies to Chart.yaml.") log.Printf("Warning: Dependencies are handled in Chart.yaml since apiVersion \"v2\". We recommend migrating dependencies to Chart.yaml.")
} }
if err := yaml.Unmarshal(f.Data, c.Metadata); err != nil { if err := yaml.Unmarshal(f.Data, c.Metadata); err != nil {
return c, errors.Wrap(err, "cannot load requirements.yaml") return c, fmt.Errorf("cannot load requirements.yaml: %w", err)
} }
if c.Metadata.APIVersion == chart.APIVersionV1 { if c.Metadata.APIVersion == chart.APIVersionV1 {
c.Files = append(c.Files, &chart.File{Name: f.Name, Data: f.Data}) c.Files = append(c.Files, &chart.File{Name: f.Name, Data: f.Data})
@ -134,7 +134,7 @@ func LoadFiles(files []*BufferedFile) (*chart.Chart, error) {
case f.Name == "requirements.lock": case f.Name == "requirements.lock":
c.Lock = new(chart.Lock) c.Lock = new(chart.Lock)
if err := yaml.Unmarshal(f.Data, &c.Lock); err != nil { if err := yaml.Unmarshal(f.Data, &c.Lock); err != nil {
return c, errors.Wrap(err, "cannot load requirements.lock") return c, fmt.Errorf("cannot load requirements.lock: %w", err)
} }
if c.Metadata == nil { if c.Metadata == nil {
c.Metadata = new(chart.Metadata) c.Metadata = new(chart.Metadata)
@ -163,7 +163,7 @@ func LoadFiles(files []*BufferedFile) (*chart.Chart, error) {
} }
if c.Metadata == nil { if c.Metadata == nil {
return c, errors.New("Chart.yaml file is missing") return c, errors.New("Chart.yaml file is missing") //nolint:staticcheck
} }
if err := c.Validate(); err != nil { if err := c.Validate(); err != nil {
@ -179,7 +179,7 @@ func LoadFiles(files []*BufferedFile) (*chart.Chart, error) {
case filepath.Ext(n) == ".tgz": case filepath.Ext(n) == ".tgz":
file := files[0] file := files[0]
if file.Name != n { if file.Name != n {
return c, errors.Errorf("error unpacking subchart tar in %s: expected %s, got %s", c.Name(), n, file.Name) return c, fmt.Errorf("error unpacking subchart tar in %s: expected %s, got %s", c.Name(), n, file.Name)
} }
// Untar the chart and add to c.Dependencies // Untar the chart and add to c.Dependencies
sc, err = LoadArchive(bytes.NewBuffer(file.Data)) sc, err = LoadArchive(bytes.NewBuffer(file.Data))
@ -199,7 +199,7 @@ func LoadFiles(files []*BufferedFile) (*chart.Chart, error) {
} }
if err != nil { if err != nil {
return c, errors.Wrapf(err, "error unpacking subchart %s in %s", n, c.Name()) return c, fmt.Errorf("error unpacking subchart %s in %s: %w", n, c.Name(), err)
} }
c.AddDependency(sc) c.AddDependency(sc)
} }
@ -221,13 +221,13 @@ func LoadValues(data io.Reader) (map[string]interface{}, error) {
if err == io.EOF { if err == io.EOF {
break break
} }
return nil, errors.Wrap(err, "error reading yaml document") return nil, fmt.Errorf("error reading yaml document: %w", err)
} }
if err := yaml.Unmarshal(raw, &currentMap, func(d *json.Decoder) *json.Decoder { if err := yaml.Unmarshal(raw, &currentMap, func(d *json.Decoder) *json.Decoder {
d.UseNumber() d.UseNumber()
return d return d
}); err != nil { }); err != nil {
return nil, errors.Wrap(err, "cannot unmarshal yaml document") return nil, fmt.Errorf("cannot unmarshal yaml document: %w", err)
} }
values = MergeMaps(values, currentMap) values = MergeMaps(values, currentMap)
} }

@ -17,10 +17,12 @@ limitations under the License.
package util package util
import ( import (
"errors"
"fmt"
"io/fs"
"os" "os"
"path/filepath" "path/filepath"
"github.com/pkg/errors"
"sigs.k8s.io/yaml" "sigs.k8s.io/yaml"
chart "helm.sh/helm/v4/pkg/chart/v2" chart "helm.sh/helm/v4/pkg/chart/v2"
@ -75,17 +77,17 @@ func IsChartDir(dirName string) (bool, error) {
if fi, err := os.Stat(dirName); err != nil { if fi, err := os.Stat(dirName); err != nil {
return false, err return false, err
} else if !fi.IsDir() { } else if !fi.IsDir() {
return false, errors.Errorf("%q is not a directory", dirName) return false, fmt.Errorf("%q is not a directory", dirName)
} }
chartYaml := filepath.Join(dirName, ChartfileName) chartYaml := filepath.Join(dirName, ChartfileName)
if _, err := os.Stat(chartYaml); os.IsNotExist(err) { if _, err := os.Stat(chartYaml); errors.Is(err, fs.ErrNotExist) {
return false, errors.Errorf("no %s exists in directory %q", ChartfileName, dirName) return false, fmt.Errorf("no %s exists in directory %q", ChartfileName, dirName)
} }
chartYamlContent, err := os.ReadFile(chartYaml) chartYamlContent, err := os.ReadFile(chartYaml)
if err != nil { if err != nil {
return false, errors.Errorf("cannot read %s in directory %q", ChartfileName, dirName) return false, fmt.Errorf("cannot read %s in directory %q", ChartfileName, dirName)
} }
chartContent := new(chart.Metadata) chartContent := new(chart.Metadata)
@ -93,10 +95,10 @@ func IsChartDir(dirName string) (bool, error) {
return false, err return false, err
} }
if chartContent == nil { if chartContent == nil {
return false, errors.Errorf("chart metadata (%s) missing", ChartfileName) return false, fmt.Errorf("chart metadata (%s) missing", ChartfileName)
} }
if chartContent.Name == "" { if chartContent.Name == "" {
return false, errors.Errorf("invalid chart (%s): name must not be empty", ChartfileName) return false, fmt.Errorf("invalid chart (%s): name must not be empty", ChartfileName)
} }
return true, nil return true, nil

@ -21,7 +21,6 @@ import (
"log" "log"
"github.com/mitchellh/copystructure" "github.com/mitchellh/copystructure"
"github.com/pkg/errors"
chart "helm.sh/helm/v4/pkg/chart/v2" chart "helm.sh/helm/v4/pkg/chart/v2"
) )
@ -108,7 +107,7 @@ func coalesceDeps(printf printFn, chrt *chart.Chart, dest map[string]interface{}
// If dest doesn't already have the key, create it. // If dest doesn't already have the key, create it.
dest[subchart.Name()] = make(map[string]interface{}) dest[subchart.Name()] = make(map[string]interface{})
} else if !istable(c) { } else if !istable(c) {
return dest, errors.Errorf("type mismatch on %s: %t", subchart.Name(), c) return dest, fmt.Errorf("type mismatch on %s: %t", subchart.Name(), c)
} }
if dv, ok := dest[subchart.Name()]; ok { if dv, ok := dest[subchart.Name()]; ok {
dvmap := dv.(map[string]interface{}) dvmap := dv.(map[string]interface{})

@ -24,7 +24,6 @@ import (
"regexp" "regexp"
"strings" "strings"
"github.com/pkg/errors"
"sigs.k8s.io/yaml" "sigs.k8s.io/yaml"
chart "helm.sh/helm/v4/pkg/chart/v2" chart "helm.sh/helm/v4/pkg/chart/v2"
@ -651,7 +650,7 @@ var Stderr io.Writer = os.Stderr
func CreateFrom(chartfile *chart.Metadata, dest, src string) error { func CreateFrom(chartfile *chart.Metadata, dest, src string) error {
schart, err := loader.Load(src) schart, err := loader.Load(src)
if err != nil { if err != nil {
return errors.Wrapf(err, "could not load %s", src) return fmt.Errorf("could not load %s: %w", src, err)
} }
schart.Metadata = chartfile schart.Metadata = chartfile
@ -666,12 +665,12 @@ func CreateFrom(chartfile *chart.Metadata, dest, src string) error {
schart.Templates = updatedTemplates schart.Templates = updatedTemplates
b, err := yaml.Marshal(schart.Values) b, err := yaml.Marshal(schart.Values)
if err != nil { if err != nil {
return errors.Wrap(err, "reading values file") return fmt.Errorf("reading values file: %w", err)
} }
var m map[string]interface{} var m map[string]interface{}
if err := yaml.Unmarshal(transform(string(b), schart.Name()), &m); err != nil { if err := yaml.Unmarshal(transform(string(b), schart.Name()), &m); err != nil {
return errors.Wrap(err, "transforming values file") return fmt.Errorf("transforming values file: %w", err)
} }
schart.Values = m schart.Values = m
@ -715,12 +714,12 @@ func Create(name, dir string) (string, error) {
if fi, err := os.Stat(path); err != nil { if fi, err := os.Stat(path); err != nil {
return path, err return path, err
} else if !fi.IsDir() { } else if !fi.IsDir() {
return path, errors.Errorf("no such directory %s", path) return path, fmt.Errorf("no such directory %s", path)
} }
cdir := filepath.Join(path, name) cdir := filepath.Join(path, name)
if fi, err := os.Stat(cdir); err == nil && !fi.IsDir() { if fi, err := os.Stat(cdir); err == nil && !fi.IsDir() {
return cdir, errors.Errorf("file %s already exists and is not a directory", cdir) return cdir, fmt.Errorf("file %s already exists and is not a directory", cdir)
} }
// Note: If adding a new template below (i.e., to `helm create`) which is disabled by default (similar to hpa and // Note: If adding a new template below (i.e., to `helm create`) which is disabled by default (similar to hpa and

@ -17,12 +17,13 @@ limitations under the License.
package util package util
import ( import (
"errors"
"fmt"
"io" "io"
"os" "os"
"path/filepath" "path/filepath"
securejoin "github.com/cyphar/filepath-securejoin" securejoin "github.com/cyphar/filepath-securejoin"
"github.com/pkg/errors"
"sigs.k8s.io/yaml" "sigs.k8s.io/yaml"
chart "helm.sh/helm/v4/pkg/chart/v2" chart "helm.sh/helm/v4/pkg/chart/v2"
@ -42,7 +43,7 @@ func Expand(dir string, r io.Reader) error {
if file.Name == "Chart.yaml" { if file.Name == "Chart.yaml" {
ch := &chart.Metadata{} ch := &chart.Metadata{}
if err := yaml.Unmarshal(file.Data, ch); err != nil { if err := yaml.Unmarshal(file.Data, ch); err != nil {
return errors.Wrap(err, "cannot load Chart.yaml") return fmt.Errorf("cannot load Chart.yaml: %w", err)
} }
chartName = ch.Name chartName = ch.Name
} }

@ -18,11 +18,11 @@ package util
import ( import (
"bytes" "bytes"
"errors"
"fmt" "fmt"
"log/slog" "log/slog"
"strings" "strings"
"github.com/pkg/errors"
"github.com/santhosh-tekuri/jsonschema/v6" "github.com/santhosh-tekuri/jsonschema/v6"
chart "helm.sh/helm/v4/pkg/chart/v2" chart "helm.sh/helm/v4/pkg/chart/v2"

@ -20,12 +20,13 @@ import (
"archive/tar" "archive/tar"
"compress/gzip" "compress/gzip"
"encoding/json" "encoding/json"
"errors"
"fmt" "fmt"
"io/fs"
"os" "os"
"path/filepath" "path/filepath"
"time" "time"
"github.com/pkg/errors"
"sigs.k8s.io/yaml" "sigs.k8s.io/yaml"
chart "helm.sh/helm/v4/pkg/chart/v2" chart "helm.sh/helm/v4/pkg/chart/v2"
@ -45,7 +46,7 @@ func SaveDir(c *chart.Chart, dest string) error {
} }
outdir := filepath.Join(dest, c.Name()) outdir := filepath.Join(dest, c.Name())
if fi, err := os.Stat(outdir); err == nil && !fi.IsDir() { if fi, err := os.Stat(outdir); err == nil && !fi.IsDir() {
return errors.Errorf("file %s already exists and is not a directory", outdir) return fmt.Errorf("file %s already exists and is not a directory", outdir)
} }
if err := os.MkdirAll(outdir, 0755); err != nil { if err := os.MkdirAll(outdir, 0755); err != nil {
return err return err
@ -89,7 +90,7 @@ func SaveDir(c *chart.Chart, dest string) error {
for _, dep := range c.Dependencies() { for _, dep := range c.Dependencies() {
// Here, we write each dependency as a tar file. // Here, we write each dependency as a tar file.
if _, err := Save(dep, base); err != nil { if _, err := Save(dep, base); err != nil {
return errors.Wrapf(err, "saving %s", dep.ChartFullPath()) return fmt.Errorf("saving %s: %w", dep.ChartFullPath(), err)
} }
} }
return nil return nil
@ -105,22 +106,22 @@ func SaveDir(c *chart.Chart, dest string) error {
// This returns the absolute path to the chart archive file. // This returns the absolute path to the chart archive file.
func Save(c *chart.Chart, outDir string) (string, error) { func Save(c *chart.Chart, outDir string) (string, error) {
if err := c.Validate(); err != nil { if err := c.Validate(); err != nil {
return "", errors.Wrap(err, "chart validation") return "", fmt.Errorf("chart validation: %w", err)
} }
filename := fmt.Sprintf("%s-%s.tgz", c.Name(), c.Metadata.Version) filename := fmt.Sprintf("%s-%s.tgz", c.Name(), c.Metadata.Version)
filename = filepath.Join(outDir, filename) filename = filepath.Join(outDir, filename)
dir := filepath.Dir(filename) dir := filepath.Dir(filename)
if stat, err := os.Stat(dir); err != nil { if stat, err := os.Stat(dir); err != nil {
if os.IsNotExist(err) { if errors.Is(err, fs.ErrNotExist) {
if err2 := os.MkdirAll(dir, 0755); err2 != nil { if err2 := os.MkdirAll(dir, 0755); err2 != nil {
return "", err2 return "", err2
} }
} else { } else {
return "", errors.Wrapf(err, "stat %s", dir) return "", fmt.Errorf("stat %s: %w", dir, err)
} }
} else if !stat.IsDir() { } else if !stat.IsDir() {
return "", errors.Errorf("is not a directory: %s", dir) return "", fmt.Errorf("is not a directory: %s", dir)
} }
f, err := os.Create(filename) f, err := os.Create(filename)
@ -203,7 +204,7 @@ func writeTarContents(out *tar.Writer, c *chart.Chart, prefix string) error {
// Save values.schema.json if it exists // Save values.schema.json if it exists
if c.Schema != nil { if c.Schema != nil {
if !json.Valid(c.Schema) { if !json.Valid(c.Schema) {
return errors.New("Invalid JSON in " + SchemafileName) return errors.New("invalid JSON in " + SchemafileName)
} }
if err := writeToTar(out, filepath.Join(base, SchemafileName), c.Schema); err != nil { if err := writeToTar(out, filepath.Join(base, SchemafileName), c.Schema); err != nil {
return err return err

@ -17,10 +17,9 @@ limitations under the License.
package util package util
import ( import (
"errors"
"fmt" "fmt"
"regexp" "regexp"
"github.com/pkg/errors"
) )
// validName is a regular expression for resource names. // validName is a regular expression for resource names.

@ -18,12 +18,12 @@ package util
import ( import (
"encoding/json" "encoding/json"
"errors"
"fmt" "fmt"
"io" "io"
"os" "os"
"strings" "strings"
"github.com/pkg/errors"
"sigs.k8s.io/yaml" "sigs.k8s.io/yaml"
chart "helm.sh/helm/v4/pkg/chart/v2" chart "helm.sh/helm/v4/pkg/chart/v2"
@ -169,8 +169,7 @@ func ToRenderValuesWithSchemaValidation(chrt *chart.Chart, chrtVals map[string]i
if !skipSchemaValidation { if !skipSchemaValidation {
if err := ValidateAgainstSchema(chrt, vals); err != nil { if err := ValidateAgainstSchema(chrt, vals); err != nil {
errFmt := "values don't meet the specifications of the schema(s) in the following chart(s):\n%s" return top, fmt.Errorf("values don't meet the specifications of the schema(s) in the following chart(s):\n%w", err)
return top, fmt.Errorf(errFmt, err.Error())
} }
} }

@ -22,7 +22,6 @@ import (
"io" "io"
"github.com/gosuri/uitable" "github.com/gosuri/uitable"
"github.com/pkg/errors"
"sigs.k8s.io/yaml" "sigs.k8s.io/yaml"
) )
@ -107,7 +106,7 @@ func EncodeJSON(out io.Writer, obj interface{}) error {
enc := json.NewEncoder(out) enc := json.NewEncoder(out)
err := enc.Encode(obj) err := enc.Encode(obj)
if err != nil { if err != nil {
return errors.Wrap(err, "unable to write JSON output") return fmt.Errorf("unable to write JSON output: %w", err)
} }
return nil return nil
} }
@ -117,12 +116,12 @@ func EncodeJSON(out io.Writer, obj interface{}) error {
func EncodeYAML(out io.Writer, obj interface{}) error { func EncodeYAML(out io.Writer, obj interface{}) error {
raw, err := yaml.Marshal(obj) raw, err := yaml.Marshal(obj)
if err != nil { if err != nil {
return errors.Wrap(err, "unable to write YAML output") return fmt.Errorf("unable to write YAML output: %w", err)
} }
_, err = out.Write(raw) _, err = out.Write(raw)
if err != nil { if err != nil {
return errors.Wrap(err, "unable to write YAML output") return fmt.Errorf("unable to write YAML output: %w", err)
} }
return nil return nil
} }
@ -134,7 +133,7 @@ func EncodeTable(out io.Writer, table *uitable.Table) error {
raw = append(raw, []byte("\n")...) raw = append(raw, []byte("\n")...)
_, err := out.Write(raw) _, err := out.Write(raw)
if err != nil { if err != nil {
return errors.Wrap(err, "unable to write table output") return fmt.Errorf("unable to write table output: %w", err)
} }
return nil return nil
} }

@ -19,13 +19,12 @@ package values
import ( import (
"bytes" "bytes"
"encoding/json" "encoding/json"
"fmt"
"io" "io"
"net/url" "net/url"
"os" "os"
"strings" "strings"
"github.com/pkg/errors"
"helm.sh/helm/v4/pkg/chart/v2/loader" "helm.sh/helm/v4/pkg/chart/v2/loader"
"helm.sh/helm/v4/pkg/getter" "helm.sh/helm/v4/pkg/getter"
"helm.sh/helm/v4/pkg/strvals" "helm.sh/helm/v4/pkg/strvals"
@ -54,7 +53,7 @@ func (opts *Options) MergeValues(p getter.Providers) (map[string]interface{}, er
} }
currentMap, err := loader.LoadValues(bytes.NewReader(raw)) currentMap, err := loader.LoadValues(bytes.NewReader(raw))
if err != nil { if err != nil {
return nil, errors.Wrapf(err, "failed to parse %s", filePath) return nil, fmt.Errorf("failed to parse %s: %w", filePath, err)
} }
// Merge with the previous map // Merge with the previous map
base = loader.MergeMaps(base, currentMap) base = loader.MergeMaps(base, currentMap)
@ -67,13 +66,13 @@ func (opts *Options) MergeValues(p getter.Providers) (map[string]interface{}, er
// If value is JSON object format, parse it as map // If value is JSON object format, parse it as map
var jsonMap map[string]interface{} var jsonMap map[string]interface{}
if err := json.Unmarshal([]byte(trimmedValue), &jsonMap); err != nil { if err := json.Unmarshal([]byte(trimmedValue), &jsonMap); err != nil {
return nil, errors.Errorf("failed parsing --set-json data JSON: %s", value) return nil, fmt.Errorf("failed parsing --set-json data JSON: %s", value)
} }
base = loader.MergeMaps(base, jsonMap) base = loader.MergeMaps(base, jsonMap)
} else { } else {
// Otherwise, parse it as key=value format // Otherwise, parse it as key=value format
if err := strvals.ParseJSON(value, base); err != nil { if err := strvals.ParseJSON(value, base); err != nil {
return nil, errors.Errorf("failed parsing --set-json data %s", value) return nil, fmt.Errorf("failed parsing --set-json data %s", value)
} }
} }
} }
@ -81,14 +80,14 @@ func (opts *Options) MergeValues(p getter.Providers) (map[string]interface{}, er
// User specified a value via --set // User specified a value via --set
for _, value := range opts.Values { for _, value := range opts.Values {
if err := strvals.ParseInto(value, base); err != nil { if err := strvals.ParseInto(value, base); err != nil {
return nil, errors.Wrap(err, "failed parsing --set data") return nil, fmt.Errorf("failed parsing --set data: %w", err)
} }
} }
// User specified a value via --set-string // User specified a value via --set-string
for _, value := range opts.StringValues { for _, value := range opts.StringValues {
if err := strvals.ParseIntoString(value, base); err != nil { if err := strvals.ParseIntoString(value, base); err != nil {
return nil, errors.Wrap(err, "failed parsing --set-string data") return nil, fmt.Errorf("failed parsing --set-string data: %w", err)
} }
} }
@ -102,14 +101,14 @@ func (opts *Options) MergeValues(p getter.Providers) (map[string]interface{}, er
return string(bytes), err return string(bytes), err
} }
if err := strvals.ParseIntoFile(value, base, reader); err != nil { if err := strvals.ParseIntoFile(value, base, reader); err != nil {
return nil, errors.Wrap(err, "failed parsing --set-file data") return nil, fmt.Errorf("failed parsing --set-file data: %w", err)
} }
} }
// User specified a value via --set-literal // User specified a value via --set-literal
for _, value := range opts.LiteralValues { for _, value := range opts.LiteralValues {
if err := strvals.ParseLiteralInto(value, base); err != nil { if err := strvals.ParseLiteralInto(value, base); err != nil {
return nil, errors.Wrap(err, "failed parsing --set-literal data") return nil, fmt.Errorf("failed parsing --set-literal data: %w", err)
} }
} }

@ -16,7 +16,9 @@ limitations under the License.
package cmd package cmd
import ( import (
"errors"
"fmt" "fmt"
"io/fs"
"os" "os"
"path/filepath" "path/filepath"
"strings" "strings"
@ -202,7 +204,7 @@ 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); !os.IsNotExist(err) { if _, err := os.Stat(tmpPath); !errors.Is(err, fs.ErrNotExist) {
t.Fatalf("tmpcharts dir still exists") t.Fatalf("tmpcharts dir still exists")
} }
} }

@ -22,7 +22,6 @@ import (
"path/filepath" "path/filepath"
"strings" "strings"
"github.com/pkg/errors"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"github.com/spf13/cobra/doc" "github.com/spf13/cobra/doc"
"golang.org/x/text/cases" "golang.org/x/text/cases"
@ -99,6 +98,6 @@ func (o *docsOptions) run(_ io.Writer) error {
case "bash": case "bash":
return o.topCmd.GenBashCompletionFile(filepath.Join(o.dest, "completions.bash")) return o.topCmd.GenBashCompletionFile(filepath.Join(o.dest, "completions.bash"))
default: default:
return errors.Errorf("unknown doc type %q. Try 'markdown' or 'man'", o.docTypeString) return fmt.Errorf("unknown doc type %q. Try 'markdown' or 'man'", o.docTypeString)
} }
} }

@ -18,6 +18,7 @@ package cmd
import ( import (
"context" "context"
"errors"
"fmt" "fmt"
"io" "io"
"log" "log"
@ -27,7 +28,6 @@ import (
"syscall" "syscall"
"time" "time"
"github.com/pkg/errors"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"github.com/spf13/pflag" "github.com/spf13/pflag"
@ -159,7 +159,7 @@ func newInstallCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
} }
rel, err := runInstall(args, client, valueOpts, out) rel, err := runInstall(args, client, valueOpts, out)
if err != nil { if err != nil {
return errors.Wrap(err, "INSTALLATION FAILED") return fmt.Errorf("INSTALLATION FAILED: %w", err)
} }
return outfmt.Write(out, &statusPrinter{ return outfmt.Write(out, &statusPrinter{
@ -274,7 +274,6 @@ func runInstall(args []string, client *action.Install, valueOpts *values.Options
// As of Helm 2.4.0, this is treated as a stopping condition: // As of Helm 2.4.0, this is treated as a stopping condition:
// https://github.com/helm/helm/issues/2209 // https://github.com/helm/helm/issues/2209
if err := action.CheckDependencies(chartRequested, req); err != nil { if err := action.CheckDependencies(chartRequested, req); err != nil {
err = errors.Wrap(err, "An error occurred while checking for chart dependencies. You may need to run `helm dependency build` to fetch missing dependencies")
if client.DependencyUpdate { if client.DependencyUpdate {
man := &downloader.Manager{ man := &downloader.Manager{
Out: out, Out: out,
@ -292,10 +291,10 @@ func runInstall(args []string, client *action.Install, valueOpts *values.Options
} }
// Reload the chart with the updated Chart.lock file. // Reload the chart with the updated Chart.lock file.
if chartRequested, err = loader.Load(cp); err != nil { if chartRequested, err = loader.Load(cp); err != nil {
return nil, errors.Wrap(err, "failed reloading chart after repo update") return nil, fmt.Errorf("failed reloading chart after repo update: %w", err)
} }
} else { } else {
return nil, err return nil, fmt.Errorf("an error occurred while checking for chart dependencies. You may need to run `helm dependency build` to fetch missing dependencies: %w", err)
} }
} }
} }
@ -333,7 +332,7 @@ func checkIfInstallable(ch *chart.Chart) error {
case "", "application": case "", "application":
return nil return nil
} }
return errors.Errorf("%s charts are not installable", ch.Metadata.Type) return fmt.Errorf("%s charts are not installable", ch.Metadata.Type)
} }
// Provide dynamic auto-completion for the install and template commands // Provide dynamic auto-completion for the install and template commands
@ -359,7 +358,7 @@ func validateDryRunOptionFlag(dryRunOptionFlagValue string) error {
} }
} }
if !isAllowed { if !isAllowed {
return errors.New("Invalid dry-run flag. Flag must one of the following: false, true, none, client, server") return errors.New("invalid dry-run flag. Flag must one of the following: false, true, none, client, server")
} }
return nil return nil
} }

@ -17,13 +17,13 @@ limitations under the License.
package cmd package cmd
import ( import (
"errors"
"fmt" "fmt"
"io" "io"
"os" "os"
"path/filepath" "path/filepath"
"strings" "strings"
"github.com/pkg/errors"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"helm.sh/helm/v4/pkg/action" "helm.sh/helm/v4/pkg/action"

@ -27,7 +27,6 @@ import (
"strings" "strings"
"syscall" "syscall"
"github.com/pkg/errors"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"sigs.k8s.io/yaml" "sigs.k8s.io/yaml"
@ -50,7 +49,6 @@ type PluginError struct {
// to inspect its environment and then add commands to the base command // to inspect its environment and then add commands to the base command
// as it finds them. // as it finds them.
func loadPlugins(baseCmd *cobra.Command, out io.Writer) { func loadPlugins(baseCmd *cobra.Command, out io.Writer) {
// If HELM_NO_PLUGINS is set to 1, do not load plugins. // If HELM_NO_PLUGINS is set to 1, do not load plugins.
if os.Getenv("HELM_NO_PLUGINS") == "1" { if os.Getenv("HELM_NO_PLUGINS") == "1" {
return return
@ -87,7 +85,7 @@ func loadPlugins(baseCmd *cobra.Command, out io.Writer) {
main, argv, prepCmdErr := plug.PrepareCommand(u) main, argv, prepCmdErr := plug.PrepareCommand(u)
if prepCmdErr != nil { if prepCmdErr != nil {
os.Stderr.WriteString(prepCmdErr.Error()) os.Stderr.WriteString(prepCmdErr.Error())
return errors.Errorf("plugin %q exited with error", md.Name) return fmt.Errorf("plugin %q exited with error", md.Name)
} }
return callPluginExecutable(md.Name, main, argv, out) return callPluginExecutable(md.Name, main, argv, out)
@ -139,7 +137,7 @@ func callPluginExecutable(pluginName string, main string, argv []string, out io.
os.Stderr.Write(eerr.Stderr) os.Stderr.Write(eerr.Stderr)
status := eerr.Sys().(syscall.WaitStatus) status := eerr.Sys().(syscall.WaitStatus)
return PluginError{ return PluginError{
error: errors.Errorf("plugin %q exited with error", pluginName), error: fmt.Errorf("plugin %q exited with error", pluginName),
Code: status.ExitStatus(), Code: status.ExitStatus(),
} }
} }

@ -17,12 +17,12 @@ limitations under the License.
package cmd package cmd
import ( import (
"errors"
"fmt" "fmt"
"io" "io"
"os" "os"
"path/filepath" "path/filepath"
"github.com/pkg/errors"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"helm.sh/helm/v4/pkg/action" "helm.sh/helm/v4/pkg/action"
@ -57,7 +57,7 @@ func newPackageCmd(out io.Writer) *cobra.Command {
Long: packageDesc, Long: packageDesc,
RunE: func(_ *cobra.Command, args []string) error { RunE: func(_ *cobra.Command, args []string) error {
if len(args) == 0 { if len(args) == 0 {
return errors.Errorf("need at least one argument, the path to the chart") return fmt.Errorf("need at least one argument, the path to the chart")
} }
if client.Sign { if client.Sign {
if client.Key == "" { if client.Key == "" {

@ -16,12 +16,12 @@ limitations under the License.
package cmd package cmd
import ( import (
"fmt"
"io" "io"
"log/slog" "log/slog"
"os" "os"
"os/exec" "os/exec"
"github.com/pkg/errors"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"helm.sh/helm/v4/pkg/plugin" "helm.sh/helm/v4/pkg/plugin"
@ -73,7 +73,7 @@ func runHook(p *plugin.Plugin, event string) error {
if err := prog.Run(); err != nil { if err := prog.Run(); err != nil {
if eerr, ok := err.(*exec.ExitError); ok { if eerr, ok := err.(*exec.ExitError); ok {
os.Stderr.Write(eerr.Stderr) os.Stderr.Write(eerr.Stderr)
return errors.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)
} }
return err return err
} }

@ -20,7 +20,6 @@ import (
"io" "io"
"log/slog" "log/slog"
"github.com/pkg/errors"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"helm.sh/helm/v4/pkg/cmd/require" "helm.sh/helm/v4/pkg/cmd/require"
@ -83,7 +82,7 @@ func (o *pluginInstallOptions) run(out io.Writer) error {
slog.Debug("loading plugin", "path", i.Path()) slog.Debug("loading plugin", "path", i.Path())
p, err := plugin.LoadDir(i.Path()) p, err := plugin.LoadDir(i.Path())
if err != nil { if err != nil {
return errors.Wrap(err, "plugin is installed but unusable") return fmt.Errorf("plugin is installed but unusable: %w", err)
} }
if err := runHook(p, plugin.Install); err != nil { if err := runHook(p, plugin.Install); err != nil {

@ -16,13 +16,12 @@ limitations under the License.
package cmd package cmd
import ( import (
"errors"
"fmt" "fmt"
"io" "io"
"log/slog" "log/slog"
"os" "os"
"strings"
"github.com/pkg/errors"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"helm.sh/helm/v4/pkg/plugin" "helm.sh/helm/v4/pkg/plugin"
@ -66,20 +65,20 @@ func (o *pluginUninstallOptions) run(out io.Writer) error {
if err != nil { if err != nil {
return err return err
} }
var errorPlugins []string var errorPlugins []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.Sprintf("Failed to uninstall plugin %s, got error (%v)", name, err)) errorPlugins = append(errorPlugins, fmt.Errorf("failed to uninstall plugin %s, got error (%v)", name, err))
} else { } else {
fmt.Fprintf(out, "Uninstalled plugin: %s\n", name) fmt.Fprintf(out, "Uninstalled plugin: %s\n", name)
} }
} else { } else {
errorPlugins = append(errorPlugins, fmt.Sprintf("Plugin: %s not found", name)) errorPlugins = append(errorPlugins, fmt.Errorf("plugin: %s not found", name))
} }
} }
if len(errorPlugins) > 0 { if len(errorPlugins) > 0 {
return errors.New(strings.Join(errorPlugins, "\n")) return errors.Join(errorPlugins...)
} }
return nil return nil
} }

@ -16,13 +16,12 @@ limitations under the License.
package cmd package cmd
import ( import (
"errors"
"fmt" "fmt"
"io" "io"
"log/slog" "log/slog"
"path/filepath" "path/filepath"
"strings"
"github.com/pkg/errors"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"helm.sh/helm/v4/pkg/plugin" "helm.sh/helm/v4/pkg/plugin"
@ -68,21 +67,21 @@ func (o *pluginUpdateOptions) run(out io.Writer) error {
if err != nil { if err != nil {
return err return err
} }
var errorPlugins []string var errorPlugins []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.Sprintf("Failed to update plugin %s, got error (%v)", name, err)) errorPlugins = append(errorPlugins, fmt.Errorf("failed to update plugin %s, got error (%v)", name, err))
} else { } else {
fmt.Fprintf(out, "Updated plugin: %s\n", name) fmt.Fprintf(out, "Updated plugin: %s\n", name)
} }
} else { } else {
errorPlugins = append(errorPlugins, fmt.Sprintf("Plugin: %s not found", name)) errorPlugins = append(errorPlugins, fmt.Errorf("plugin: %s not found", name))
} }
} }
if len(errorPlugins) > 0 { if len(errorPlugins) > 0 {
return errors.New(strings.Join(errorPlugins, "\n")) return errors.Join(errorPlugins...)
} }
return nil return nil
} }

@ -17,10 +17,10 @@ limitations under the License.
package cmd package cmd
import ( import (
"errors"
"io" "io"
"os" "io/fs"
"github.com/pkg/errors"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"helm.sh/helm/v4/pkg/cmd/require" "helm.sh/helm/v4/pkg/cmd/require"
@ -50,5 +50,5 @@ func newRepoCmd(out io.Writer) *cobra.Command {
} }
func isNotExist(err error) bool { func isNotExist(err error) bool {
return os.IsNotExist(errors.Cause(err)) return errors.Is(err, fs.ErrNotExist)
} }

@ -18,15 +18,16 @@ package cmd
import ( import (
"context" "context"
"errors"
"fmt" "fmt"
"io" "io"
"io/fs"
"os" "os"
"path/filepath" "path/filepath"
"strings" "strings"
"time" "time"
"github.com/gofrs/flock" "github.com/gofrs/flock"
"github.com/pkg/errors"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"golang.org/x/term" "golang.org/x/term"
"sigs.k8s.io/yaml" "sigs.k8s.io/yaml"
@ -135,7 +136,7 @@ func (o *repoAddOptions) run(out io.Writer) error {
} }
b, err := os.ReadFile(o.repoFile) b, err := os.ReadFile(o.repoFile)
if err != nil && !os.IsNotExist(err) { if err != nil && !errors.Is(err, fs.ErrNotExist) {
return err return err
} }
@ -179,7 +180,7 @@ func (o *repoAddOptions) run(out io.Writer) error {
// Check if the repo name is legal // Check if the repo name is legal
if strings.Contains(o.name, "/") { if strings.Contains(o.name, "/") {
return errors.Errorf("repository name (%s) contains '/', please specify a different name without '/'", o.name) return fmt.Errorf("repository name (%s) contains '/', please specify a different name without '/'", o.name)
} }
// If the repo exists do one of two things: // If the repo exists do one of two things:
@ -188,10 +189,9 @@ func (o *repoAddOptions) run(out io.Writer) error {
if !o.forceUpdate && f.Has(o.name) { if !o.forceUpdate && f.Has(o.name) {
existing := f.Get(o.name) existing := f.Get(o.name)
if c != *existing { if c != *existing {
// The input coming in for the name is different from what is already // The input coming in for the name is different from what is already
// configured. Return an error. // configured. Return an error.
return errors.Errorf("repository name (%s) already exists, please specify a different name", o.name) return fmt.Errorf("repository name (%s) already exists, please specify a different name", o.name)
} }
// The add is idempotent so do nothing // The add is idempotent so do nothing
@ -208,12 +208,12 @@ func (o *repoAddOptions) run(out io.Writer) error {
r.CachePath = o.repoCache r.CachePath = o.repoCache
} }
if _, err := r.DownloadIndexFile(); err != nil { if _, err := r.DownloadIndexFile(); err != nil {
return errors.Wrapf(err, "looks like %q is not a valid chart repository or cannot be reached", o.url) return fmt.Errorf("looks like %q is not a valid chart repository or cannot be reached: %w", o.url, err)
} }
f.Update(&c) f.Update(&c)
if err := f.WriteFile(o.repoFile, 0600); err != nil { if err := f.WriteFile(o.repoFile, 0o600); err != nil {
return err return err
} }
fmt.Fprintf(out, "%q has been added to your repositories\n", o.name) fmt.Fprintf(out, "%q has been added to your repositories\n", o.name)

@ -17,8 +17,10 @@ limitations under the License.
package cmd package cmd
import ( import (
"errors"
"fmt" "fmt"
"io" "io"
"io/fs"
"os" "os"
"path/filepath" "path/filepath"
"strings" "strings"
@ -113,11 +115,11 @@ func TestRepoAdd(t *testing.T) {
} }
idx := filepath.Join(helmpath.CachePath("repository"), helmpath.CacheIndexFile(testRepoName)) idx := filepath.Join(helmpath.CachePath("repository"), helmpath.CacheIndexFile(testRepoName))
if _, err := os.Stat(idx); os.IsNotExist(err) { if _, err := os.Stat(idx); errors.Is(err, fs.ErrNotExist) {
t.Errorf("Error cache index file was not created for repository %s", testRepoName) t.Errorf("Error cache index file was not created for repository %s", testRepoName)
} }
idx = filepath.Join(helmpath.CachePath("repository"), helmpath.CacheChartsFile(testRepoName)) idx = filepath.Join(helmpath.CachePath("repository"), helmpath.CacheChartsFile(testRepoName))
if _, err := os.Stat(idx); os.IsNotExist(err) { if _, err := os.Stat(idx); errors.Is(err, fs.ErrNotExist) {
t.Errorf("Error cache charts file was not created for repository %s", testRepoName) t.Errorf("Error cache charts file was not created for repository %s", testRepoName)
} }

@ -17,11 +17,13 @@ limitations under the License.
package cmd package cmd
import ( import (
"errors"
"fmt"
"io" "io"
"io/fs"
"os" "os"
"path/filepath" "path/filepath"
"github.com/pkg/errors"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"helm.sh/helm/v4/pkg/cmd/require" "helm.sh/helm/v4/pkg/cmd/require"
@ -97,13 +99,13 @@ func index(dir, url, mergeTo string, json bool) error {
if mergeTo != "" { if mergeTo != "" {
// if index.yaml is missing then create an empty one to merge into // if index.yaml is missing then create an empty one to merge into
var i2 *repo.IndexFile var i2 *repo.IndexFile
if _, err := os.Stat(mergeTo); os.IsNotExist(err) { if _, err := os.Stat(mergeTo); errors.Is(err, fs.ErrNotExist) {
i2 = repo.NewIndexFile() i2 = repo.NewIndexFile()
writeIndexFile(i2, mergeTo, json) writeIndexFile(i2, mergeTo, json)
} else { } else {
i2, err = repo.LoadIndexFile(mergeTo) i2, err = repo.LoadIndexFile(mergeTo)
if err != nil { if err != nil {
return errors.Wrap(err, "merge failed") return fmt.Errorf("merge failed: %w", err)
} }
} }
i.Merge(i2) i.Merge(i2)
@ -114,7 +116,7 @@ func index(dir, url, mergeTo string, json bool) error {
func writeIndexFile(i *repo.IndexFile, out string, json bool) error { func writeIndexFile(i *repo.IndexFile, out string, json bool) error {
if json { if json {
return i.WriteJSONFile(out, 0644) return i.WriteJSONFile(out, 0o644)
} }
return i.WriteFile(out, 0644) return i.WriteFile(out, 0o644)
} }

@ -17,11 +17,11 @@ limitations under the License.
package cmd package cmd
import ( import (
"errors"
"fmt" "fmt"
"io" "io"
"github.com/gosuri/uitable" "github.com/gosuri/uitable"
"github.com/pkg/errors"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"helm.sh/helm/v4/pkg/cli/output" "helm.sh/helm/v4/pkg/cli/output"

@ -17,12 +17,13 @@ limitations under the License.
package cmd package cmd
import ( import (
"errors"
"fmt" "fmt"
"io" "io"
"io/fs"
"os" "os"
"path/filepath" "path/filepath"
"github.com/pkg/errors"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"helm.sh/helm/v4/pkg/cmd/require" "helm.sh/helm/v4/pkg/cmd/require"
@ -65,7 +66,7 @@ func (o *repoRemoveOptions) run(out io.Writer) error {
for _, name := range o.names { for _, name := range o.names {
if !r.Remove(name) { if !r.Remove(name) {
return errors.Errorf("no repo named %q found", name) return fmt.Errorf("no repo named %q found", name)
} }
if err := r.WriteFile(o.repoFile, 0600); err != nil { if err := r.WriteFile(o.repoFile, 0600); err != nil {
return err return err
@ -87,10 +88,10 @@ func removeRepoCache(root, name string) error {
} }
idx = filepath.Join(root, helmpath.CacheIndexFile(name)) idx = filepath.Join(root, helmpath.CacheIndexFile(name))
if _, err := os.Stat(idx); os.IsNotExist(err) { if _, err := os.Stat(idx); errors.Is(err, fs.ErrNotExist) {
return nil return nil
} else if err != nil { } else if err != nil {
return errors.Wrapf(err, "can't remove index file %s", idx) return fmt.Errorf("can't remove index file %s: %w", idx, err)
} }
return os.Remove(idx) return os.Remove(idx)
} }

@ -17,12 +17,12 @@ limitations under the License.
package cmd package cmd
import ( import (
"errors"
"fmt" "fmt"
"io" "io"
"slices" "slices"
"sync" "sync"
"github.com/pkg/errors"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"helm.sh/helm/v4/pkg/cmd/require" "helm.sh/helm/v4/pkg/cmd/require"
@ -77,7 +77,7 @@ func (o *repoUpdateOptions) run(out io.Writer) error {
case isNotExist(err): case isNotExist(err):
return errNoRepositories return errNoRepositories
case err != nil: case err != nil:
return errors.Wrapf(err, "failed loading file: %s", o.repoFile) return fmt.Errorf("failed loading file: %s: %w", o.repoFile, err)
case len(f.Repositories) == 0: case len(f.Repositories) == 0:
return errNoRepositories return errNoRepositories
} }
@ -155,7 +155,7 @@ func checkRequestedRepos(requestedRepos []string, validRepos []*repo.Entry) erro
} }
} }
if !found { if !found {
return errors.Errorf("no repositories found matching '%s'. Nothing will be updated", requestedRepo) return fmt.Errorf("no repositories found matching '%s'. Nothing will be updated", requestedRepo)
} }
} }
return nil return nil

@ -16,14 +16,15 @@ limitations under the License.
package require package require
import ( import (
"github.com/pkg/errors" "fmt"
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
// NoArgs returns an error if any args are included. // NoArgs returns an error if any args are included.
func NoArgs(cmd *cobra.Command, args []string) error { func NoArgs(cmd *cobra.Command, args []string) error {
if len(args) > 0 { if len(args) > 0 {
return errors.Errorf( return fmt.Errorf(
"%q accepts no arguments\n\nUsage: %s", "%q accepts no arguments\n\nUsage: %s",
cmd.CommandPath(), cmd.CommandPath(),
cmd.UseLine(), cmd.UseLine(),
@ -36,7 +37,7 @@ func NoArgs(cmd *cobra.Command, args []string) error {
func ExactArgs(n int) cobra.PositionalArgs { func ExactArgs(n int) cobra.PositionalArgs {
return func(cmd *cobra.Command, args []string) error { return func(cmd *cobra.Command, args []string) error {
if len(args) != n { if len(args) != n {
return errors.Errorf( return fmt.Errorf(
"%q requires %d %s\n\nUsage: %s", "%q requires %d %s\n\nUsage: %s",
cmd.CommandPath(), cmd.CommandPath(),
n, n,
@ -52,7 +53,7 @@ func ExactArgs(n int) cobra.PositionalArgs {
func MaximumNArgs(n int) cobra.PositionalArgs { func MaximumNArgs(n int) cobra.PositionalArgs {
return func(cmd *cobra.Command, args []string) error { return func(cmd *cobra.Command, args []string) error {
if len(args) > n { if len(args) > n {
return errors.Errorf( return fmt.Errorf(
"%q accepts at most %d %s\n\nUsage: %s", "%q accepts at most %d %s\n\nUsage: %s",
cmd.CommandPath(), cmd.CommandPath(),
n, n,
@ -68,7 +69,7 @@ func MaximumNArgs(n int) cobra.PositionalArgs {
func MinimumNArgs(n int) cobra.PositionalArgs { func MinimumNArgs(n int) cobra.PositionalArgs {
return func(cmd *cobra.Command, args []string) error { return func(cmd *cobra.Command, args []string) error {
if len(args) < n { if len(args) < n {
return errors.Errorf( return fmt.Errorf(
"%q requires at least %d %s\n\nUsage: %s", "%q requires at least %d %s\n\nUsage: %s",
cmd.CommandPath(), cmd.CommandPath(),
n, n,

@ -23,7 +23,6 @@ import (
"strings" "strings"
"github.com/gosuri/uitable" "github.com/gosuri/uitable"
"github.com/pkg/errors"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"helm.sh/helm/v4/internal/monocular" "helm.sh/helm/v4/internal/monocular"
@ -84,7 +83,7 @@ func newSearchHubCmd(out io.Writer) *cobra.Command {
func (o *searchHubOptions) run(out io.Writer, args []string) error { func (o *searchHubOptions) run(out io.Writer, args []string) error {
c, err := monocular.New(o.searchEndpoint) c, err := monocular.New(o.searchEndpoint)
if err != nil { if err != nil {
return errors.Wrap(err, fmt.Sprintf("unable to create connection to %q", o.searchEndpoint)) return fmt.Errorf("unable to create connection to %q: %w", o.searchEndpoint, err)
} }
q := strings.Join(args, " ") q := strings.Join(args, " ")

@ -19,6 +19,7 @@ package cmd
import ( import (
"bufio" "bufio"
"bytes" "bytes"
"errors"
"fmt" "fmt"
"io" "io"
"log/slog" "log/slog"
@ -28,7 +29,6 @@ import (
"github.com/Masterminds/semver/v3" "github.com/Masterminds/semver/v3"
"github.com/gosuri/uitable" "github.com/gosuri/uitable"
"github.com/pkg/errors"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"helm.sh/helm/v4/pkg/cli/output" "helm.sh/helm/v4/pkg/cli/output"
@ -153,7 +153,7 @@ func (o *searchRepoOptions) applyConstraint(res []*search.Result) ([]*search.Res
constraint, err := semver.NewConstraint(o.version) constraint, err := semver.NewConstraint(o.version)
if err != nil { if err != nil {
return res, errors.Wrap(err, "an invalid version/constraint format") return res, fmt.Errorf("an invalid version/constraint format: %w", err)
} }
data := res[:0] data := res[:0]

@ -18,8 +18,10 @@ package cmd
import ( import (
"bytes" "bytes"
"errors"
"fmt" "fmt"
"io" "io"
"io/fs"
"os" "os"
"path" "path"
"path/filepath" "path/filepath"
@ -250,7 +252,7 @@ func createOrOpenFile(filename string, appendData bool) (*os.File, error) {
func ensureDirectoryForFile(file string) error { func ensureDirectoryForFile(file string) error {
baseDir := path.Dir(file) baseDir := path.Dir(file)
_, err := os.Stat(baseDir) _, err := os.Stat(baseDir)
if err != nil && !os.IsNotExist(err) { if err != nil && !errors.Is(err, fs.ErrNotExist) {
return err return err
} }

@ -1 +1 @@
Error: INSTALLATION FAILED: Hiding Kubernetes secrets requires a dry-run mode Error: INSTALLATION FAILED: hiding Kubernetes secrets requires a dry-run mode

@ -1 +1 @@
Error: An error occurred while checking for chart dependencies. You may need to run `helm dependency build` to fetch missing dependencies: found in Chart.yaml, but missing in charts/ directory: reqsubchart2 Error: an error occurred while checking for chart dependencies. You may need to run `helm dependency build` to fetch missing dependencies: found in Chart.yaml, but missing in charts/ directory: reqsubchart2

@ -27,7 +27,6 @@ import (
"syscall" "syscall"
"time" "time"
"github.com/pkg/errors"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"helm.sh/helm/v4/pkg/action" "helm.sh/helm/v4/pkg/action"
@ -200,7 +199,7 @@ func newUpgradeCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
} }
if req := ch.Metadata.Dependencies; req != nil { if req := ch.Metadata.Dependencies; req != nil {
if err := action.CheckDependencies(ch, req); err != nil { if err := action.CheckDependencies(ch, req); err != nil {
err = errors.Wrap(err, "An error occurred while checking for chart dependencies. You may need to run `helm dependency build` to fetch missing dependencies") err = fmt.Errorf("an error occurred while checking for chart dependencies. You may need to run `helm dependency build` to fetch missing dependencies: %w", err)
if client.DependencyUpdate { if client.DependencyUpdate {
man := &downloader.Manager{ man := &downloader.Manager{
Out: out, Out: out,
@ -217,7 +216,7 @@ func newUpgradeCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
} }
// Reload the chart with the updated Chart.lock file. // Reload the chart with the updated Chart.lock file.
if ch, err = loader.Load(chartPath); err != nil { if ch, err = loader.Load(chartPath); err != nil {
return errors.Wrap(err, "failed reloading chart after repo update") return fmt.Errorf("failed reloading chart after repo update: %w", err)
} }
} else { } else {
return err return err
@ -246,7 +245,7 @@ func newUpgradeCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
rel, err := client.RunWithContext(ctx, args[0], ch, vals) rel, err := client.RunWithContext(ctx, args[0], ch, vals)
if err != nil { if err != nil {
return errors.Wrap(err, "UPGRADE FAILED") return fmt.Errorf("UPGRADE FAILED: %w", err)
} }
if outfmt == output.Table { if outfmt == output.Table {

@ -16,15 +16,15 @@ limitations under the License.
package downloader package downloader
import ( import (
"errors"
"fmt" "fmt"
"io" "io"
"io/fs"
"net/url" "net/url"
"os" "os"
"path/filepath" "path/filepath"
"strings" "strings"
"github.com/pkg/errors"
"helm.sh/helm/v4/internal/fileutil" "helm.sh/helm/v4/internal/fileutil"
"helm.sh/helm/v4/internal/urlutil" "helm.sh/helm/v4/internal/urlutil"
"helm.sh/helm/v4/pkg/getter" "helm.sh/helm/v4/pkg/getter"
@ -120,7 +120,7 @@ func (c *ChartDownloader) DownloadTo(ref, version, dest string) (string, *proven
body, err := g.Get(u.String() + ".prov") body, err := g.Get(u.String() + ".prov")
if err != nil { if err != nil {
if c.Verify == VerifyAlways { if c.Verify == VerifyAlways {
return destfile, ver, errors.Errorf("failed to fetch provenance %q", u.String()+".prov") return destfile, ver, fmt.Errorf("failed to fetch provenance %q", u.String()+".prov")
} }
fmt.Fprintf(c.Out, "WARNING: Verification not found for %s: %s\n", ref, err) fmt.Fprintf(c.Out, "WARNING: Verification not found for %s: %s\n", ref, err)
return destfile, ver, nil return destfile, ver, nil
@ -160,7 +160,7 @@ func (c *ChartDownloader) DownloadTo(ref, version, dest string) (string, *proven
func (c *ChartDownloader) ResolveChartVersion(ref, version string) (*url.URL, error) { func (c *ChartDownloader) ResolveChartVersion(ref, version string) (*url.URL, error) {
u, err := url.Parse(ref) u, err := url.Parse(ref)
if err != nil { if err != nil {
return nil, errors.Errorf("invalid chart URL format: %s", ref) return nil, fmt.Errorf("invalid chart URL format: %s", ref)
} }
if registry.IsOCI(u.String()) { if registry.IsOCI(u.String()) {
@ -213,13 +213,12 @@ func (c *ChartDownloader) ResolveChartVersion(ref, version string) (*url.URL, er
// See if it's of the form: repo/path_to_chart // See if it's of the form: repo/path_to_chart
p := strings.SplitN(u.Path, "/", 2) p := strings.SplitN(u.Path, "/", 2)
if len(p) < 2 { if len(p) < 2 {
return u, errors.Errorf("non-absolute URLs should be in form of repo_name/path_to_chart, got: %s", u) return u, fmt.Errorf("non-absolute URLs should be in form of repo_name/path_to_chart, got: %s", u)
} }
repoName := p[0] repoName := p[0]
chartName := p[1] chartName := p[1]
rc, err := pickChartRepositoryConfigByName(repoName, rf.Repositories) rc, err := pickChartRepositoryConfigByName(repoName, rf.Repositories)
if err != nil { if err != nil {
return u, err return u, err
} }
@ -249,23 +248,22 @@ func (c *ChartDownloader) ResolveChartVersion(ref, version string) (*url.URL, er
idxFile := filepath.Join(c.RepositoryCache, helmpath.CacheIndexFile(r.Config.Name)) idxFile := filepath.Join(c.RepositoryCache, helmpath.CacheIndexFile(r.Config.Name))
i, err := repo.LoadIndexFile(idxFile) i, err := repo.LoadIndexFile(idxFile)
if err != nil { if err != nil {
return u, errors.Wrap(err, "no cached repo found. (try 'helm repo update')") return u, fmt.Errorf("no cached repo found. (try 'helm repo update'): %w", err)
} }
cv, err := i.Get(chartName, version) cv, err := i.Get(chartName, version)
if err != nil { if err != nil {
return u, errors.Wrapf(err, "chart %q matching %s not found in %s index. (try 'helm repo update')", chartName, version, r.Config.Name) return u, fmt.Errorf("chart %q matching %s not found in %s index. (try 'helm repo update'): %w", chartName, version, r.Config.Name, err)
} }
if len(cv.URLs) == 0 { if len(cv.URLs) == 0 {
return u, errors.Errorf("chart %q has no downloadable URLs", ref) return u, fmt.Errorf("chart %q has no downloadable URLs", ref)
} }
// TODO: Seems that picking first URL is not fully correct // TODO: Seems that picking first URL is not fully correct
resolvedURL, err := repo.ResolveReferenceURL(rc.URL, cv.URLs[0]) resolvedURL, err := repo.ResolveReferenceURL(rc.URL, cv.URLs[0])
if err != nil { if err != nil {
return u, errors.Errorf("invalid chart URL format: %s", ref) return u, fmt.Errorf("invalid chart URL format: %s", ref)
} }
return url.Parse(resolvedURL) return url.Parse(resolvedURL)
@ -288,12 +286,12 @@ func VerifyChart(path, keyring string) (*provenance.Verification, error) {
provfile := path + ".prov" provfile := path + ".prov"
if _, err := os.Stat(provfile); err != nil { if _, err := os.Stat(provfile); err != nil {
return nil, errors.Wrapf(err, "could not load provenance file %s", provfile) return nil, fmt.Errorf("could not load provenance file %s: %w", provfile, err)
} }
sig, err := provenance.NewFromKeyring(keyring, "") sig, err := provenance.NewFromKeyring(keyring, "")
if err != nil { if err != nil {
return nil, errors.Wrap(err, "failed to load keyring") return nil, fmt.Errorf("failed to load keyring: %w", err)
} }
return sig.Verify(path, provfile) return sig.Verify(path, provfile)
} }
@ -310,12 +308,12 @@ func pickChartRepositoryConfigByName(name string, cfgs []*repo.Entry) (*repo.Ent
for _, rc := range cfgs { for _, rc := range cfgs {
if rc.Name == name { if rc.Name == name {
if rc.URL == "" { if rc.URL == "" {
return nil, errors.Errorf("no URL found for repository %s", name) return nil, fmt.Errorf("no URL found for repository %s", name)
} }
return rc, nil return rc, nil
} }
} }
return nil, errors.Errorf("repo %s not found", name) return nil, fmt.Errorf("repo %s not found", name)
} }
// scanReposForURL scans all repos to find which repo contains the given URL. // scanReposForURL scans all repos to find which repo contains the given URL.
@ -348,7 +346,7 @@ func (c *ChartDownloader) scanReposForURL(u string, rf *repo.File) (*repo.Entry,
idxFile := filepath.Join(c.RepositoryCache, helmpath.CacheIndexFile(r.Config.Name)) idxFile := filepath.Join(c.RepositoryCache, helmpath.CacheIndexFile(r.Config.Name))
i, err := repo.LoadIndexFile(idxFile) i, err := repo.LoadIndexFile(idxFile)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "no cached repo found. (try 'helm repo update')") return nil, fmt.Errorf("no cached repo found. (try 'helm repo update'): %w", err)
} }
for _, entry := range i.Entries { for _, entry := range i.Entries {
@ -367,7 +365,7 @@ func (c *ChartDownloader) scanReposForURL(u string, rf *repo.File) (*repo.Entry,
func loadRepoConfig(file string) (*repo.File, error) { func loadRepoConfig(file string) (*repo.File, error) {
r, err := repo.LoadFile(file) r, err := repo.LoadFile(file)
if err != nil && !os.IsNotExist(errors.Cause(err)) { if err != nil && !errors.Is(err, fs.ErrNotExist) {
return nil, err return nil, err
} }
return r, nil return r, nil

@ -18,8 +18,10 @@ package downloader
import ( import (
"crypto" "crypto"
"encoding/hex" "encoding/hex"
"errors"
"fmt" "fmt"
"io" "io"
stdfs "io/fs"
"log" "log"
"net/url" "net/url"
"os" "os"
@ -30,7 +32,6 @@ import (
"sync" "sync"
"github.com/Masterminds/semver/v3" "github.com/Masterminds/semver/v3"
"github.com/pkg/errors"
"sigs.k8s.io/yaml" "sigs.k8s.io/yaml"
"helm.sh/helm/v4/internal/resolver" "helm.sh/helm/v4/internal/resolver"
@ -220,7 +221,7 @@ func (m *Manager) Update() error {
func (m *Manager) loadChartDir() (*chart.Chart, error) { func (m *Manager) loadChartDir() (*chart.Chart, error) {
if fi, err := os.Stat(m.ChartPath); err != nil { if fi, err := os.Stat(m.ChartPath); err != nil {
return nil, errors.Wrapf(err, "could not find %s", m.ChartPath) return nil, fmt.Errorf("could not find %s: %w", m.ChartPath, err)
} else if !fi.IsDir() { } else if !fi.IsDir() {
return nil, errors.New("only unpacked charts can be updated") return nil, errors.New("only unpacked charts can be updated")
} }
@ -251,9 +252,9 @@ func (m *Manager) downloadAll(deps []*chart.Dependency) error {
// Check if 'charts' directory is not actually a directory. If it does not exist, create it. // Check if 'charts' directory is not actually a directory. If it does not exist, create it.
if fi, err := os.Stat(destPath); err == nil { if fi, err := os.Stat(destPath); err == nil {
if !fi.IsDir() { if !fi.IsDir() {
return errors.Errorf("%q is not a directory", destPath) return fmt.Errorf("%q is not a directory", destPath)
} }
} else if os.IsNotExist(err) { } else if errors.Is(err, stdfs.ErrNotExist) {
if err := os.MkdirAll(destPath, 0755); err != nil { if err := os.MkdirAll(destPath, 0755); err != nil {
return err return err
} }
@ -314,7 +315,7 @@ func (m *Manager) downloadAll(deps []*chart.Dependency) error {
// https://github.com/helm/helm/issues/1439 // https://github.com/helm/helm/issues/1439
churl, username, password, insecureskiptlsverify, passcredentialsall, caFile, certFile, keyFile, err := m.findChartURL(dep.Name, dep.Version, dep.Repository, repos) churl, username, password, insecureskiptlsverify, passcredentialsall, caFile, certFile, keyFile, err := m.findChartURL(dep.Name, dep.Version, dep.Repository, repos)
if err != nil { if err != nil {
saveError = errors.Wrapf(err, "could not find %s", churl) saveError = fmt.Errorf("could not find %s: %w", churl, err)
break break
} }
@ -345,7 +346,7 @@ func (m *Manager) downloadAll(deps []*chart.Dependency) error {
if registry.IsOCI(churl) { if registry.IsOCI(churl) {
churl, version, err = parseOCIRef(churl) churl, version, err = parseOCIRef(churl)
if err != nil { if err != nil {
return errors.Wrapf(err, "could not parse OCI reference") return fmt.Errorf("could not parse OCI reference: %w", err)
} }
dl.Options = append(dl.Options, dl.Options = append(dl.Options,
getter.WithRegistryClient(m.RegistryClient), getter.WithRegistryClient(m.RegistryClient),
@ -353,7 +354,7 @@ func (m *Manager) downloadAll(deps []*chart.Dependency) error {
} }
if _, _, err = dl.DownloadTo(churl, version, tmpPath); err != nil { if _, _, err = dl.DownloadTo(churl, version, tmpPath); err != nil {
saveError = errors.Wrapf(err, "could not download %s", churl) saveError = fmt.Errorf("could not download %s: %w", churl, err)
break break
} }
@ -377,7 +378,7 @@ func parseOCIRef(chartRef string) (string, string, error) {
refTagRegexp := regexp.MustCompile(`^(oci://[^:]+(:[0-9]{1,5})?[^:]+):(.*)$`) refTagRegexp := regexp.MustCompile(`^(oci://[^:]+(:[0-9]{1,5})?[^:]+):(.*)$`)
caps := refTagRegexp.FindStringSubmatch(chartRef) caps := refTagRegexp.FindStringSubmatch(chartRef)
if len(caps) != 4 { if len(caps) != 4 {
return "", "", errors.Errorf("improperly formatted oci chart reference: %s", chartRef) return "", "", fmt.Errorf("improperly formatted oci chart reference: %s", chartRef)
} }
chartRef = caps[1] chartRef = caps[1]
tag := caps[3] tag := caps[3]
@ -559,7 +560,7 @@ func (m *Manager) ensureMissingRepos(repoNames map[string]string, deps []*chart.
func (m *Manager) resolveRepoNames(deps []*chart.Dependency) (map[string]string, error) { func (m *Manager) resolveRepoNames(deps []*chart.Dependency) (map[string]string, error) {
rf, err := loadRepoConfig(m.RepositoryConfig) rf, err := loadRepoConfig(m.RepositoryConfig)
if err != nil { if err != nil {
if os.IsNotExist(err) { if errors.Is(err, stdfs.ErrNotExist) {
return make(map[string]string), nil return make(map[string]string), nil
} }
return nil, err return nil, err
@ -764,7 +765,7 @@ func (m *Manager) findChartURL(name, version, repoURL string, repos map[string]*
if err == nil { if err == nil {
return url, username, password, false, false, "", "", "", err return url, username, password, false, false, "", "", "", err
} }
err = errors.Errorf("chart %s not found in %s: %s", name, repoURL, err) err = fmt.Errorf("chart %s not found in %s: %w", name, repoURL, err)
return url, username, password, false, false, "", "", "", err return url, username, password, false, false, "", "", "", err
} }
@ -820,7 +821,7 @@ func normalizeURL(baseURL, urlOrPath string) (string, error) {
} }
u2, err := url.Parse(baseURL) u2, err := url.Parse(baseURL)
if err != nil { if err != nil {
return urlOrPath, errors.Wrap(err, "base URL failed to parse") return urlOrPath, fmt.Errorf("base URL failed to parse: %w", err)
} }
u2.RawPath = path.Join(u2.RawPath, urlOrPath) u2.RawPath = path.Join(u2.RawPath, urlOrPath)
@ -838,7 +839,7 @@ func (m *Manager) loadChartRepositories() (map[string]*repo.ChartRepository, err
// Load repositories.yaml file // Load repositories.yaml file
rf, err := loadRepoConfig(m.RepositoryConfig) rf, err := loadRepoConfig(m.RepositoryConfig)
if err != nil { if err != nil {
return indices, errors.Wrapf(err, "failed to load %s", m.RepositoryConfig) return indices, fmt.Errorf("failed to load %s: %w", m.RepositoryConfig, err)
} }
for _, re := range rf.Repositories { for _, re := range rf.Repositories {
@ -876,7 +877,7 @@ func writeLock(chartpath string, lock *chart.Lock, legacyLockfile bool) error {
// archive a dep chart from local directory and save it into destPath // archive a dep chart from local directory and save it into destPath
func tarFromLocalDir(chartpath, name, repo, version, destPath string) (string, error) { func tarFromLocalDir(chartpath, name, repo, version, destPath string) (string, error) {
if !strings.HasPrefix(repo, "file://") { if !strings.HasPrefix(repo, "file://") {
return "", errors.Errorf("wrong format: chart %s repository %s", name, repo) return "", fmt.Errorf("wrong format: chart %s repository %s", name, repo)
} }
origPath, err := resolver.GetLocalPath(repo, chartpath) origPath, err := resolver.GetLocalPath(repo, chartpath)
@ -891,7 +892,7 @@ func tarFromLocalDir(chartpath, name, repo, version, destPath string) (string, e
constraint, err := semver.NewConstraint(version) constraint, err := semver.NewConstraint(version)
if err != nil { if err != nil {
return "", errors.Wrapf(err, "dependency %s has an invalid version/constraint format", name) return "", fmt.Errorf("dependency %s has an invalid version/constraint format: %w", name, err)
} }
v, err := semver.NewVersion(ch.Metadata.Version) v, err := semver.NewVersion(ch.Metadata.Version)
@ -904,7 +905,7 @@ func tarFromLocalDir(chartpath, name, repo, version, destPath string) (string, e
return ch.Metadata.Version, err return ch.Metadata.Version, err
} }
return "", errors.Errorf("can't get a valid version for dependency %s", name) return "", fmt.Errorf("can't get a valid version for dependency %s", name)
} }
// The prefix to use for cache keys created by the manager for repo names // The prefix to use for cache keys created by the manager for repo names

@ -17,6 +17,8 @@ package downloader
import ( import (
"bytes" "bytes"
"errors"
"io/fs"
"os" "os"
"path/filepath" "path/filepath"
"reflect" "reflect"
@ -262,7 +264,7 @@ func TestDownloadAll(t *testing.T) {
t.Error(err) t.Error(err)
} }
if _, err := os.Stat(filepath.Join(chartPath, "charts", "signtest-0.1.0.tgz")); os.IsNotExist(err) { if _, err := os.Stat(filepath.Join(chartPath, "charts", "signtest-0.1.0.tgz")); errors.Is(err, fs.ErrNotExist) {
t.Error(err) t.Error(err)
} }

@ -17,6 +17,7 @@ limitations under the License.
package engine package engine
import ( import (
"errors"
"fmt" "fmt"
"log/slog" "log/slog"
"path" "path"
@ -26,7 +27,6 @@ import (
"strings" "strings"
"text/template" "text/template"
"github.com/pkg/errors"
"k8s.io/client-go/rest" "k8s.io/client-go/rest"
chart "helm.sh/helm/v4/pkg/chart/v2" chart "helm.sh/helm/v4/pkg/chart/v2"
@ -133,7 +133,9 @@ func includeFun(t *template.Template, includedNames map[string]int) func(string,
var buf strings.Builder var buf strings.Builder
if v, ok := includedNames[name]; ok { if v, ok := includedNames[name]; ok {
if v > recursionMaxNums { if v > recursionMaxNums {
return "", errors.Wrapf(fmt.Errorf("unable to execute template"), "rendering template has a nested reference name: %s", name) return "", fmt.Errorf(
"rendering template has a nested reference name: %s: %w",
name, errors.New("unable to execute template"))
} }
includedNames[name]++ includedNames[name]++
} else { } else {
@ -151,7 +153,7 @@ func tplFun(parent *template.Template, includedNames map[string]int, strict bool
return func(tpl string, vals interface{}) (string, error) { return func(tpl string, vals interface{}) (string, error) {
t, err := parent.Clone() t, err := parent.Clone()
if err != nil { if err != nil {
return "", errors.Wrapf(err, "cannot clone template") return "", fmt.Errorf("cannot clone template: %w", err)
} }
// Re-inject the missingkey option, see text/template issue https://github.com/golang/go/issues/43022 // Re-inject the missingkey option, see text/template issue https://github.com/golang/go/issues/43022
@ -178,12 +180,12 @@ func tplFun(parent *template.Template, includedNames map[string]int, strict bool
// text string. (Maybe we could use a hash appended to the name?) // text string. (Maybe we could use a hash appended to the name?)
t, err = t.New(parent.Name()).Parse(tpl) t, err = t.New(parent.Name()).Parse(tpl)
if err != nil { if err != nil {
return "", errors.Wrapf(err, "cannot parse template %q", tpl) return "", fmt.Errorf("cannot parse template %q: %w", tpl, err)
} }
var buf strings.Builder var buf strings.Builder
if err := t.Execute(&buf, vals); err != nil { if err := t.Execute(&buf, vals); err != nil {
return "", errors.Wrapf(err, "error during tpl function execution for %q", tpl) return "", fmt.Errorf("error during tpl function execution for %q: %w", tpl, err)
} }
// See comment in renderWithReferences explaining the <no value> hack. // See comment in renderWithReferences explaining the <no value> hack.
@ -265,7 +267,7 @@ func (e Engine) render(tpls map[string]renderable) (rendered map[string]string,
// template engine. // template engine.
defer func() { defer func() {
if r := recover(); r != nil { if r := recover(); r != nil {
err = errors.Errorf("rendering template failed: %v", r) err = fmt.Errorf("rendering template failed: %v", r)
} }
}() }()
t := template.New("gotpl") t := template.New("gotpl")

@ -18,10 +18,10 @@ package engine
import ( import (
"context" "context"
"fmt"
"log/slog" "log/slog"
"strings" "strings"
"github.com/pkg/errors"
apierrors "k8s.io/apimachinery/pkg/api/errors" apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/runtime/schema"
@ -99,7 +99,7 @@ func getDynamicClientOnKind(apiversion string, kind string, config *rest.Config)
apiRes, err := getAPIResourceForGVK(gvk, config) apiRes, err := getAPIResourceForGVK(gvk, config)
if err != nil { if err != nil {
slog.Error("unable to get apiresource", "groupVersionKind", gvk.String(), slog.Any("error", err)) slog.Error("unable to get apiresource", "groupVersionKind", gvk.String(), slog.Any("error", err))
return nil, false, errors.Wrapf(err, "unable to get apiresource from unstructured: %s", gvk.String()) return nil, false, fmt.Errorf("unable to get apiresource from unstructured: %s: %w", gvk.String(), err)
} }
gvr := schema.GroupVersionResource{ gvr := schema.GroupVersionResource{
Group: apiRes.Group, Group: apiRes.Group,

@ -18,11 +18,10 @@ package getter
import ( import (
"bytes" "bytes"
"fmt"
"net/http" "net/http"
"time" "time"
"github.com/pkg/errors"
"helm.sh/helm/v4/pkg/cli" "helm.sh/helm/v4/pkg/cli"
"helm.sh/helm/v4/pkg/registry" "helm.sh/helm/v4/pkg/registry"
) )
@ -184,7 +183,7 @@ func (p Providers) ByScheme(scheme string) (Getter, error) {
return pp.New() return pp.New()
} }
} }
return nil, errors.Errorf("scheme %q not supported", scheme) return nil, fmt.Errorf("scheme %q not supported", scheme)
} }
const ( const (

@ -18,13 +18,12 @@ package getter
import ( import (
"bytes" "bytes"
"crypto/tls" "crypto/tls"
"fmt"
"io" "io"
"net/http" "net/http"
"net/url" "net/url"
"sync" "sync"
"github.com/pkg/errors"
"helm.sh/helm/v4/internal/tlsutil" "helm.sh/helm/v4/internal/tlsutil"
"helm.sh/helm/v4/internal/version" "helm.sh/helm/v4/internal/version"
) )
@ -65,11 +64,11 @@ func (g *HTTPGetter) get(href string) (*bytes.Buffer, error) {
// with the basic auth is the one being fetched. // with the basic auth is the one being fetched.
u1, err := url.Parse(g.opts.url) u1, err := url.Parse(g.opts.url)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "Unable to parse getter URL") return nil, fmt.Errorf("unable to parse getter URL: %w", err)
} }
u2, err := url.Parse(href) u2, err := url.Parse(href)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "Unable to parse URL getting from") return nil, fmt.Errorf("unable to parse URL getting from: %w", err)
} }
// Host on URL (returned from url.Parse) contains the port if present. // Host on URL (returned from url.Parse) contains the port if present.
@ -92,7 +91,7 @@ func (g *HTTPGetter) get(href string) (*bytes.Buffer, error) {
} }
defer resp.Body.Close() defer resp.Body.Close()
if resp.StatusCode != http.StatusOK { if resp.StatusCode != http.StatusOK {
return nil, errors.Errorf("failed to fetch %s : %s", href, resp.Status) return nil, fmt.Errorf("failed to fetch %s : %s", href, resp.Status)
} }
buf := bytes.NewBuffer(nil) buf := bytes.NewBuffer(nil)
@ -133,7 +132,7 @@ func (g *HTTPGetter) httpClient() (*http.Client, error) {
tlsutil.WithCAFile(g.opts.caFile), tlsutil.WithCAFile(g.opts.caFile),
) )
if err != nil { if err != nil {
return nil, errors.Wrap(err, "can't create TLS config for client") return nil, fmt.Errorf("can't create TLS config for client: %w", err)
} }
g.transport.TLSClientConfig = tlsConf g.transport.TLSClientConfig = tlsConf

@ -28,8 +28,6 @@ import (
"testing" "testing"
"time" "time"
"github.com/pkg/errors"
"helm.sh/helm/v4/internal/tlsutil" "helm.sh/helm/v4/internal/tlsutil"
"helm.sh/helm/v4/internal/version" "helm.sh/helm/v4/internal/version"
"helm.sh/helm/v4/pkg/cli" "helm.sh/helm/v4/pkg/cli"
@ -317,7 +315,7 @@ func TestDownloadTLS(t *testing.T) {
tlsutil.WithCAFile(ca), tlsutil.WithCAFile(ca),
) )
if err != nil { if err != nil {
t.Fatal(errors.Wrap(err, "can't create TLS config for client")) t.Fatal(fmt.Errorf("can't create TLS config for client: %w", err))
} }
tlsConf.ServerName = "helm.sh" tlsConf.ServerName = "helm.sh"
tlsSrv.TLS = tlsConf tlsSrv.TLS = tlsConf
@ -372,7 +370,7 @@ func TestDownloadTLSWithRedirect(t *testing.T) {
) )
if err != nil { if err != nil {
t.Fatal(errors.Wrap(err, "can't create TLS config for client")) t.Fatal(fmt.Errorf("can't create TLS config for client: %w", err))
} }
tlsSrv2 := httptest.NewUnstartedServer(http.HandlerFunc(func(rw http.ResponseWriter, _ *http.Request) { tlsSrv2 := httptest.NewUnstartedServer(http.HandlerFunc(func(rw http.ResponseWriter, _ *http.Request) {
@ -393,7 +391,7 @@ func TestDownloadTLSWithRedirect(t *testing.T) {
) )
if err != nil { if err != nil {
t.Fatal(errors.Wrap(err, "can't create TLS config for client")) t.Fatal(fmt.Errorf("can't create TLS config for client: %w", err))
} }
tlsSrv1 := httptest.NewUnstartedServer(http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) { tlsSrv1 := httptest.NewUnstartedServer(http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {

@ -23,8 +23,6 @@ import (
"path/filepath" "path/filepath"
"strings" "strings"
"github.com/pkg/errors"
"helm.sh/helm/v4/pkg/cli" "helm.sh/helm/v4/pkg/cli"
"helm.sh/helm/v4/pkg/plugin" "helm.sh/helm/v4/pkg/plugin"
) )
@ -86,7 +84,7 @@ func (p *pluginGetter) Get(href string, options ...Option) (*bytes.Buffer, error
if err := prog.Run(); err != nil { if err := prog.Run(); err != nil {
if eerr, ok := err.(*exec.ExitError); ok { if eerr, ok := err.(*exec.ExitError); ok {
os.Stderr.Write(eerr.Stderr) os.Stderr.Write(eerr.Stderr)
return nil, errors.Errorf("plugin %q exited with error", p.command) return nil, fmt.Errorf("plugin %q exited with error", p.command)
} }
return nil, err return nil, err
} }

@ -19,13 +19,12 @@ package ignore
import ( import (
"bufio" "bufio"
"bytes" "bytes"
"errors"
"io" "io"
"log/slog" "log/slog"
"os" "os"
"path/filepath" "path/filepath"
"strings" "strings"
"github.com/pkg/errors"
) )
// HelmIgnore default name of an ignorefile. // HelmIgnore default name of an ignorefile.

@ -20,6 +20,7 @@ import (
"bytes" "bytes"
"context" "context"
"encoding/json" "encoding/json"
"errors"
"fmt" "fmt"
"io" "io"
"log/slog" "log/slog"
@ -30,7 +31,6 @@ import (
"sync" "sync"
jsonpatch "github.com/evanphx/json-patch" jsonpatch "github.com/evanphx/json-patch"
"github.com/pkg/errors"
v1 "k8s.io/api/core/v1" v1 "k8s.io/api/core/v1"
apiextv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" apiextv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
apiextv1beta1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1" apiextv1beta1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
@ -183,13 +183,13 @@ func (c *Client) IsReachable() error {
if err == genericclioptions.ErrEmptyConfig { if 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")
} }
if err != nil { if err != nil {
return errors.Wrap(err, "Kubernetes cluster unreachable") return fmt.Errorf("kubernetes cluster unreachable: %w", err)
} }
if _, err := client.Discovery().ServerVersion(); err != nil { if _, err := client.Discovery().ServerVersion(); err != nil {
return errors.Wrap(err, "Kubernetes cluster unreachable") return fmt.Errorf("kubernetes cluster unreachable: %w", err)
} }
return nil return nil
} }
@ -398,7 +398,7 @@ func (c *Client) BuildTable(reader io.Reader, validate bool) (ResourceList, erro
} }
func (c *Client) update(original, target ResourceList, force, threeWayMerge bool) (*Result, error) { func (c *Client) update(original, target ResourceList, force, threeWayMerge bool) (*Result, error) {
updateErrors := []string{} updateErrors := []error{}
res := &Result{} res := &Result{}
slog.Debug("checking resources for changes", "resources", len(target)) slog.Debug("checking resources for changes", "resources", len(target))
@ -410,7 +410,7 @@ func (c *Client) update(original, target ResourceList, force, threeWayMerge bool
helper := resource.NewHelper(info.Client, info.Mapping).WithFieldManager(getManagedFieldsManager()) helper := resource.NewHelper(info.Client, info.Mapping).WithFieldManager(getManagedFieldsManager())
if _, err := helper.Get(info.Namespace, info.Name); err != nil { if _, err := helper.Get(info.Namespace, info.Name); err != nil {
if !apierrors.IsNotFound(err) { if !apierrors.IsNotFound(err) {
return errors.Wrap(err, "could not get information about the resource") return fmt.Errorf("could not get information about the resource: %w", err)
} }
// Append the created resource to the results, even if something fails // Append the created resource to the results, even if something fails
@ -418,7 +418,7 @@ func (c *Client) update(original, target ResourceList, force, threeWayMerge bool
// Since the resource does not exist, create it. // Since the resource does not exist, create it.
if err := createResource(info); err != nil { if err := createResource(info); err != nil {
return errors.Wrap(err, "failed to create resource") return fmt.Errorf("failed to create resource: %w", err)
} }
kind := info.Mapping.GroupVersionKind.Kind kind := info.Mapping.GroupVersionKind.Kind
@ -429,12 +429,12 @@ func (c *Client) update(original, target ResourceList, force, threeWayMerge bool
originalInfo := original.Get(info) originalInfo := original.Get(info)
if originalInfo == nil { if originalInfo == nil {
kind := info.Mapping.GroupVersionKind.Kind kind := info.Mapping.GroupVersionKind.Kind
return errors.Errorf("no %s with the name %q found", kind, info.Name) return fmt.Errorf("no %s with the name %q found", kind, info.Name)
} }
if err := updateResource(c, info, originalInfo.Object, force, threeWayMerge); err != nil { if err := updateResource(c, info, originalInfo.Object, force, threeWayMerge); err != nil {
slog.Debug("error updating the resource", "namespace", info.Namespace, "name", info.Name, "kind", info.Mapping.GroupVersionKind.Kind, slog.Any("error", err)) slog.Debug("error updating the resource", "namespace", info.Namespace, "name", info.Name, "kind", info.Mapping.GroupVersionKind.Kind, slog.Any("error", err))
updateErrors = append(updateErrors, err.Error()) updateErrors = append(updateErrors, err)
} }
// Because we check for errors later, append the info regardless // Because we check for errors later, append the info regardless
res.Updated = append(res.Updated, info) res.Updated = append(res.Updated, info)
@ -446,7 +446,7 @@ func (c *Client) update(original, target ResourceList, force, threeWayMerge bool
case err != nil: case err != nil:
return res, err return res, err
case len(updateErrors) != 0: case len(updateErrors) != 0:
return res, errors.New(strings.Join(updateErrors, " && ")) return res, joinErrors(updateErrors, " && ")
} }
for _, info := range original.Difference(target) { for _, info := range original.Difference(target) {
@ -610,24 +610,24 @@ func deleteResource(info *resource.Info, policy metav1.DeletionPropagation) erro
func createPatch(target *resource.Info, current runtime.Object, threeWayMergeForUnstructured bool) ([]byte, types.PatchType, error) { func createPatch(target *resource.Info, current runtime.Object, threeWayMergeForUnstructured bool) ([]byte, types.PatchType, error) {
oldData, err := json.Marshal(current) oldData, err := json.Marshal(current)
if err != nil { if err != nil {
return nil, types.StrategicMergePatchType, errors.Wrap(err, "serializing current configuration") return nil, types.StrategicMergePatchType, fmt.Errorf("serializing current configuration: %w", err)
} }
newData, err := json.Marshal(target.Object) newData, err := json.Marshal(target.Object)
if err != nil { if err != nil {
return nil, types.StrategicMergePatchType, errors.Wrap(err, "serializing target configuration") return nil, types.StrategicMergePatchType, fmt.Errorf("serializing target configuration: %w", err)
} }
// Fetch the current object for the three way merge // Fetch the current object for the three way merge
helper := resource.NewHelper(target.Client, target.Mapping).WithFieldManager(getManagedFieldsManager()) helper := resource.NewHelper(target.Client, target.Mapping).WithFieldManager(getManagedFieldsManager())
currentObj, err := helper.Get(target.Namespace, target.Name) currentObj, err := helper.Get(target.Namespace, target.Name)
if err != nil && !apierrors.IsNotFound(err) { if err != nil && !apierrors.IsNotFound(err) {
return nil, types.StrategicMergePatchType, errors.Wrapf(err, "unable to get data for current object %s/%s", target.Namespace, target.Name) return nil, types.StrategicMergePatchType, fmt.Errorf("unable to get data for current object %s/%s: %w", target.Namespace, target.Name, err)
} }
// Even if currentObj is nil (because it was not found), it will marshal just fine // Even if currentObj is nil (because it was not found), it will marshal just fine
currentData, err := json.Marshal(currentObj) currentData, err := json.Marshal(currentObj)
if err != nil { if err != nil {
return nil, types.StrategicMergePatchType, errors.Wrap(err, "serializing live configuration") return nil, types.StrategicMergePatchType, fmt.Errorf("serializing live configuration: %w", err)
} }
// Get a versioned object // Get a versioned object
@ -663,7 +663,7 @@ func createPatch(target *resource.Info, current runtime.Object, threeWayMergeFor
patchMeta, err := strategicpatch.NewPatchMetaFromStruct(versionedObject) patchMeta, err := strategicpatch.NewPatchMetaFromStruct(versionedObject)
if err != nil { if err != nil {
return nil, types.StrategicMergePatchType, errors.Wrap(err, "unable to create patch metadata from object") return nil, types.StrategicMergePatchType, fmt.Errorf("unable to create patch metadata from object: %w", err)
} }
patch, err := strategicpatch.CreateThreeWayMergePatch(oldData, newData, currentData, patchMeta, true) patch, err := strategicpatch.CreateThreeWayMergePatch(oldData, newData, currentData, patchMeta, true)
@ -682,13 +682,13 @@ func updateResource(_ *Client, target *resource.Info, currentObj runtime.Object,
var err error var err error
obj, err = helper.Replace(target.Namespace, target.Name, true, target.Object) obj, err = helper.Replace(target.Namespace, target.Name, true, target.Object)
if err != nil { if err != nil {
return errors.Wrap(err, "failed to replace object") return fmt.Errorf("failed to replace object: %w", err)
} }
slog.Debug("replace succeeded", "name", target.Name, "initialKind", currentObj.GetObjectKind().GroupVersionKind().Kind, "kind", kind) slog.Debug("replace succeeded", "name", target.Name, "initialKind", currentObj.GetObjectKind().GroupVersionKind().Kind, "kind", kind)
} else { } else {
patch, patchType, err := createPatch(target, currentObj, threeWayMergeForUnstructured) patch, patchType, err := createPatch(target, currentObj, threeWayMergeForUnstructured)
if err != nil { if err != nil {
return errors.Wrap(err, "failed to create patch") return fmt.Errorf("failed to create patch: %w", err)
} }
if patch == nil || string(patch) == "{}" { if patch == nil || string(patch) == "{}" {
@ -696,7 +696,7 @@ func updateResource(_ *Client, target *resource.Info, currentObj runtime.Object,
// This needs to happen to make sure that Helm has the latest info from the API // This needs to happen to make sure that Helm has the latest info from the API
// Otherwise there will be no labels and other functions that use labels will panic // Otherwise there will be no labels and other functions that use labels will panic
if err := target.Get(); err != nil { if err := target.Get(); err != nil {
return errors.Wrap(err, "failed to refresh resource information") return fmt.Errorf("failed to refresh resource information: %w", err)
} }
return nil return nil
} }
@ -704,7 +704,7 @@ func updateResource(_ *Client, target *resource.Info, currentObj runtime.Object,
slog.Debug("patching resource", "kind", kind, "name", target.Name, "namespace", target.Namespace) slog.Debug("patching resource", "kind", kind, "name", target.Name, "namespace", target.Namespace)
obj, err = helper.Patch(target.Namespace, target.Name, patchType, patch, nil) obj, err = helper.Patch(target.Namespace, target.Name, patchType, patch, nil)
if err != nil { if err != nil {
return errors.Wrapf(err, "cannot patch %q with kind %s", target.Name, kind) return fmt.Errorf("cannot patch %q with kind %s: %w", target.Name, kind, err)
} }
} }
@ -741,12 +741,12 @@ func (c *Client) OutputContainerLogsForPodList(podList *v1.PodList, namespace st
func copyRequestStreamToWriter(request *rest.Request, podName, containerName string, writer io.Writer) error { func copyRequestStreamToWriter(request *rest.Request, podName, containerName string, writer io.Writer) error {
readCloser, err := request.Stream(context.Background()) readCloser, err := request.Stream(context.Background())
if err != nil { if err != nil {
return errors.Errorf("Failed to stream pod logs for pod: %s, container: %s", podName, containerName) return fmt.Errorf("failed to stream pod logs for pod: %s, container: %s", podName, containerName)
} }
defer readCloser.Close() defer readCloser.Close()
_, err = io.Copy(writer, readCloser) _, err = io.Copy(writer, readCloser)
if err != nil { if err != nil {
return errors.Errorf("Failed to copy IO from logs for pod: %s, container: %s", podName, containerName) return fmt.Errorf("failed to copy IO from logs for pod: %s, container: %s", podName, containerName)
} }
return nil return nil
} }
@ -763,3 +763,27 @@ func scrubValidationError(err error) error {
} }
return err return err
} }
type joinedErrors struct {
errs []error
sep string
}
func joinErrors(errs []error, sep string) error {
return &joinedErrors{
errs: errs,
sep: sep,
}
}
func (e *joinedErrors) Error() string {
errs := make([]string, 0, len(e.errs))
for _, err := range e.errs {
errs = append(errs, err.Error())
}
return strings.Join(errs, e.sep)
}
func (e *joinedErrors) Unwrap() []error {
return e.errs
}

@ -18,13 +18,12 @@ package kube // import "helm.sh/helm/v4/pkg/kube"
import ( import (
"context" "context"
stderrors "errors" "errors"
"fmt" "fmt"
"log/slog" "log/slog"
"net/http" "net/http"
"time" "time"
"github.com/pkg/errors"
appsv1 "k8s.io/api/apps/v1" appsv1 "k8s.io/api/apps/v1"
appsv1beta1 "k8s.io/api/apps/v1beta1" appsv1beta1 "k8s.io/api/apps/v1beta1"
appsv1beta2 "k8s.io/api/apps/v1beta2" appsv1beta2 "k8s.io/api/apps/v1beta2"
@ -191,7 +190,11 @@ func SelectorsForObject(object runtime.Object) (selector labels.Selector, err er
return nil, fmt.Errorf("selector for %T not implemented", object) return nil, fmt.Errorf("selector for %T not implemented", object)
} }
return selector, errors.Wrap(err, "invalid label selector") if err != nil {
return selector, fmt.Errorf("invalid label selector: %w", err)
}
return selector, nil
} }
func (hw *legacyWaiter) watchTimeout(t time.Duration) func(*resource.Info) error { func (hw *legacyWaiter) watchTimeout(t time.Duration) func(*resource.Info) error {
@ -233,7 +236,7 @@ func perform(infos ResourceList, fn func(*resource.Info) error) error {
for range infos { for range infos {
err := <-errs err := <-errs
if err != nil { if err != nil {
result = stderrors.Join(result, err) result = errors.Join(result, err)
} }
} }
@ -291,7 +294,7 @@ func (hw *legacyWaiter) watchUntilReady(timeout time.Duration, info *resource.In
case watch.Error: case watch.Error:
// Handle error and return with an error. // Handle error and return with an error.
slog.Error("error event received", "resource", info.Name) slog.Error("error event received", "resource", info.Name)
return true, errors.Errorf("failed to deploy %s", info.Name) return true, fmt.Errorf("failed to deploy %s", info.Name)
default: default:
return false, nil return false, nil
} }
@ -305,7 +308,7 @@ func (hw *legacyWaiter) watchUntilReady(timeout time.Duration, info *resource.In
func (hw *legacyWaiter) waitForJob(obj runtime.Object, name string) (bool, error) { func (hw *legacyWaiter) waitForJob(obj runtime.Object, name string) (bool, error) {
o, ok := obj.(*batchv1.Job) o, ok := obj.(*batchv1.Job)
if !ok { if !ok {
return true, errors.Errorf("expected %s to be a *batch.Job, got %T", name, obj) return true, fmt.Errorf("expected %s to be a *batch.Job, got %T", name, obj)
} }
for _, c := range o.Status.Conditions { for _, c := range o.Status.Conditions {
@ -313,7 +316,7 @@ func (hw *legacyWaiter) waitForJob(obj runtime.Object, name string) (bool, error
return true, nil return true, nil
} else if c.Type == batchv1.JobFailed && c.Status == "True" { } else if c.Type == batchv1.JobFailed && c.Status == "True" {
slog.Error("job failed", "job", name, "reason", c.Reason) slog.Error("job failed", "job", name, "reason", c.Reason)
return true, errors.Errorf("job %s failed: %s", name, c.Reason) return true, fmt.Errorf("job %s failed: %s", name, c.Reason)
} }
} }
@ -327,7 +330,7 @@ func (hw *legacyWaiter) waitForJob(obj runtime.Object, name string) (bool, error
func (hw *legacyWaiter) waitForPodSuccess(obj runtime.Object, name string) (bool, error) { func (hw *legacyWaiter) waitForPodSuccess(obj runtime.Object, name string) (bool, error) {
o, ok := obj.(*corev1.Pod) o, ok := obj.(*corev1.Pod)
if !ok { if !ok {
return true, errors.Errorf("expected %s to be a *v1.Pod, got %T", name, obj) return true, fmt.Errorf("expected %s to be a *v1.Pod, got %T", name, obj)
} }
switch o.Status.Phase { switch o.Status.Phase {
@ -336,7 +339,7 @@ func (hw *legacyWaiter) waitForPodSuccess(obj runtime.Object, name string) (bool
return true, nil return true, nil
case corev1.PodFailed: case corev1.PodFailed:
slog.Error("pod failed", "pod", o.Name) slog.Error("pod failed", "pod", o.Name)
return true, errors.Errorf("pod %s failed", o.Name) return true, fmt.Errorf("pod %s failed", o.Name)
case corev1.PodPending: case corev1.PodPending:
slog.Debug("pod pending", "pod", o.Name) slog.Debug("pod pending", "pod", o.Name)
case corev1.PodRunning: case corev1.PodRunning:

@ -17,13 +17,13 @@ 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 ( import (
"errors"
"fmt" "fmt"
"os" "os"
"path/filepath" "path/filepath"
"github.com/Masterminds/semver/v3" "github.com/Masterminds/semver/v3"
"github.com/asaskevich/govalidator" "github.com/asaskevich/govalidator"
"github.com/pkg/errors"
"sigs.k8s.io/yaml" "sigs.k8s.io/yaml"
chart "helm.sh/helm/v4/pkg/chart/v2" chart "helm.sh/helm/v4/pkg/chart/v2"
@ -84,7 +84,7 @@ func isStringValue(data map[string]interface{}, key string) error {
} }
valueType := fmt.Sprintf("%T", value) valueType := fmt.Sprintf("%T", value)
if valueType != "string" { if valueType != "string" {
return errors.Errorf("%s should be of type string but it's of type %s", key, valueType) return fmt.Errorf("%s should be of type string but it's of type %s", key, valueType)
} }
return nil return nil
} }
@ -100,14 +100,14 @@ func validateChartYamlNotDirectory(chartPath string) error {
func validateChartYamlFormat(chartFileError error) error { func validateChartYamlFormat(chartFileError error) error {
if chartFileError != nil { if chartFileError != nil {
return errors.Errorf("unable to parse YAML\n\t%s", chartFileError.Error()) return fmt.Errorf("unable to parse YAML\n\t%w", chartFileError)
} }
return nil return nil
} }
func validateChartYamlStrictFormat(chartFileError error) error { func validateChartYamlStrictFormat(chartFileError error) error {
if chartFileError != nil { if chartFileError != nil {
return errors.Errorf("failed to strictly parse chart metadata file\n\t%s", chartFileError.Error()) return fmt.Errorf("failed to strictly parse chart metadata file\n\t%w", chartFileError)
} }
return nil return nil
} }
@ -141,9 +141,8 @@ func validateChartVersion(cf *chart.Metadata) error {
} }
version, err := semver.NewVersion(cf.Version) version, err := semver.NewVersion(cf.Version)
if err != nil { if err != nil {
return errors.Errorf("version '%s' is not a valid SemVer", cf.Version) return fmt.Errorf("version '%s' is not a valid SemVer", cf.Version)
} }
c, err := semver.NewConstraint(">0.0.0-0") c, err := semver.NewConstraint(">0.0.0-0")
@ -153,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 errors.Errorf("version %v", msg[0]) return fmt.Errorf("version %v", msg[0])
} }
return nil return nil
@ -164,9 +163,9 @@ func validateChartMaintainer(cf *chart.Metadata) error {
if maintainer.Name == "" { if maintainer.Name == "" {
return errors.New("each maintainer requires a name") return errors.New("each maintainer requires a name")
} else if maintainer.Email != "" && !govalidator.IsEmail(maintainer.Email) { } else if maintainer.Email != "" && !govalidator.IsEmail(maintainer.Email) {
return errors.Errorf("invalid email '%s' for maintainer '%s'", maintainer.Email, maintainer.Name) return fmt.Errorf("invalid email '%s' for maintainer '%s'", maintainer.Email, maintainer.Name)
} else if maintainer.URL != "" && !govalidator.IsURL(maintainer.URL) { } else if maintainer.URL != "" && !govalidator.IsURL(maintainer.URL) {
return errors.Errorf("invalid url '%s' for maintainer '%s'", maintainer.URL, maintainer.Name) return fmt.Errorf("invalid url '%s' for maintainer '%s'", maintainer.URL, maintainer.Name)
} }
} }
return nil return nil
@ -175,7 +174,7 @@ func validateChartMaintainer(cf *chart.Metadata) error {
func validateChartSources(cf *chart.Metadata) error { func validateChartSources(cf *chart.Metadata) error {
for _, source := range cf.Sources { for _, source := range cf.Sources {
if source == "" || !govalidator.IsRequestURL(source) { if source == "" || !govalidator.IsRequestURL(source) {
return errors.Errorf("invalid source URL '%s'", source) return fmt.Errorf("invalid source URL '%s'", source)
} }
} }
return nil return nil
@ -190,7 +189,7 @@ func validateChartIconPresence(cf *chart.Metadata) error {
func validateChartIconURL(cf *chart.Metadata) error { func validateChartIconURL(cf *chart.Metadata) error {
if cf.Icon != "" && !govalidator.IsRequestURL(cf.Icon) { if cf.Icon != "" && !govalidator.IsRequestURL(cf.Icon) {
return errors.Errorf("invalid icon URL '%s'", cf.Icon) return fmt.Errorf("invalid icon URL '%s'", cf.Icon)
} }
return nil return nil
} }

@ -17,13 +17,12 @@ limitations under the License.
package rules package rules
import ( import (
"errors"
"os" "os"
"path/filepath" "path/filepath"
"strings" "strings"
"testing" "testing"
"github.com/pkg/errors"
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"

@ -20,8 +20,6 @@ import (
"fmt" "fmt"
"strings" "strings"
"github.com/pkg/errors"
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"
"helm.sh/helm/v4/pkg/lint/support" "helm.sh/helm/v4/pkg/lint/support"
@ -43,7 +41,7 @@ func Dependencies(linter *support.Linter) {
func validateChartFormat(chartError error) error { func validateChartFormat(chartError error) error {
if chartError != nil { if chartError != nil {
return errors.Errorf("unable to load chart\n\t%s", chartError) return fmt.Errorf("unable to load chart\n\t%w", chartError)
} }
return nil return nil
} }

@ -19,6 +19,7 @@ package rules
import ( import (
"bufio" "bufio"
"bytes" "bytes"
"errors"
"fmt" "fmt"
"io" "io"
"os" "os"
@ -26,7 +27,6 @@ import (
"path/filepath" "path/filepath"
"strings" "strings"
"github.com/pkg/errors"
"k8s.io/apimachinery/pkg/api/validation" "k8s.io/apimachinery/pkg/api/validation"
apipath "k8s.io/apimachinery/pkg/api/validation/path" apipath "k8s.io/apimachinery/pkg/api/validation/path"
"k8s.io/apimachinery/pkg/util/validation/field" "k8s.io/apimachinery/pkg/util/validation/field"
@ -212,11 +212,14 @@ func validateAllowedExtension(fileName string) error {
} }
} }
return errors.Errorf("file extension '%s' not valid. Valid extensions are .yaml, .yml, .tpl, or .txt", ext) return fmt.Errorf("file extension '%s' not valid. Valid extensions are .yaml, .yml, .tpl, or .txt", ext)
} }
func validateYamlContent(err error) error { func validateYamlContent(err error) error {
return errors.Wrap(err, "unable to parse YAML") if err != nil {
return fmt.Errorf("unable to parse YAML: %w", err)
}
return nil
} }
// validateMetadataName uses the correct validation function for the object // validateMetadataName uses the correct validation function for the object
@ -229,7 +232,7 @@ func validateMetadataName(obj *K8sYamlStruct) error {
allErrs = append(allErrs, field.Invalid(field.NewPath("metadata").Child("name"), obj.Metadata.Name, msg)) allErrs = append(allErrs, field.Invalid(field.NewPath("metadata").Child("name"), obj.Metadata.Name, msg))
} }
if len(allErrs) > 0 { if len(allErrs) > 0 {
return errors.Wrapf(allErrs.ToAggregate(), "object name does not conform to Kubernetes naming requirements: %q", obj.Metadata.Name) return fmt.Errorf("object name does not conform to Kubernetes naming requirements: %q: %w", obj.Metadata.Name, allErrs.ToAggregate())
} }
return nil return nil
} }
@ -293,6 +296,7 @@ func validateMatchSelector(yamlStruct *K8sYamlStruct, manifest string) error {
} }
return nil return nil
} }
func validateListAnnotations(yamlStruct *K8sYamlStruct, manifest string) error { func validateListAnnotations(yamlStruct *K8sYamlStruct, manifest string) error {
if yamlStruct.Kind == "List" { if yamlStruct.Kind == "List" {
m := struct { m := struct {
@ -309,7 +313,7 @@ func validateListAnnotations(yamlStruct *K8sYamlStruct, manifest string) error {
for _, i := range m.Items { for _, i := range m.Items {
if _, ok := i.Metadata.Annotations["helm.sh/resource-policy"]; ok { if _, ok := i.Metadata.Annotations["helm.sh/resource-policy"]; ok {
return errors.New("Annotation 'helm.sh/resource-policy' within List objects are ignored") return errors.New("annotation 'helm.sh/resource-policy' within List objects are ignored")
} }
} }
} }

@ -17,11 +17,10 @@ limitations under the License.
package rules package rules
import ( import (
"fmt"
"os" "os"
"path/filepath" "path/filepath"
"github.com/pkg/errors"
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"
) )
@ -47,7 +46,7 @@ func ValuesWithOverrides(linter *support.Linter, valueOverrides map[string]inter
func validateValuesFileExistence(valuesPath string) error { func validateValuesFileExistence(valuesPath string) error {
_, err := os.Stat(valuesPath) _, err := os.Stat(valuesPath)
if err != nil { if err != nil {
return errors.Errorf("file does not exist") return fmt.Errorf("file does not exist")
} }
return nil return nil
} }
@ -55,7 +54,7 @@ func validateValuesFileExistence(valuesPath string) error {
func validateValuesFile(valuesPath string, overrides map[string]interface{}) error { func validateValuesFile(valuesPath string, overrides map[string]interface{}) error {
values, err := chartutil.ReadValuesFile(valuesPath) values, err := chartutil.ReadValuesFile(valuesPath)
if err != nil { if err != nil {
return errors.Wrap(err, "unable to parse YAML") return fmt.Errorf("unable to parse YAML: %w", err)
} }
// Helm 3.0.0 carried over the values linting from Helm 2.x, which only tests the top // Helm 3.0.0 carried over the values linting from Helm 2.x, which only tests the top

@ -17,9 +17,8 @@ limitations under the License.
package support package support
import ( import (
"errors"
"testing" "testing"
"github.com/pkg/errors"
) )
var linter = Linter{} var linter = Linter{}

@ -19,6 +19,8 @@ import (
"archive/tar" "archive/tar"
"bytes" "bytes"
"compress/gzip" "compress/gzip"
"errors"
"fmt"
"io" "io"
"log/slog" "log/slog"
"os" "os"
@ -28,7 +30,6 @@ import (
"strings" "strings"
securejoin "github.com/cyphar/filepath-securejoin" securejoin "github.com/cyphar/filepath-securejoin"
"github.com/pkg/errors"
"helm.sh/helm/v4/internal/third_party/dep/fs" "helm.sh/helm/v4/internal/third_party/dep/fs"
"helm.sh/helm/v4/pkg/cli" "helm.sh/helm/v4/pkg/cli"
@ -79,7 +80,7 @@ func NewExtractor(source string) (Extractor, error) {
return extractor, nil return extractor, nil
} }
} }
return nil, errors.Errorf("no extractor implemented yet for %s", source) return nil, fmt.Errorf("no extractor implemented yet for %s", source)
} }
// NewHTTPInstaller creates a new HttpInstaller. // NewHTTPInstaller creates a new HttpInstaller.
@ -133,7 +134,7 @@ func (i *HTTPInstaller) Install() error {
} }
if err := i.extractor.Extract(pluginData, i.CacheDir); err != nil { if err := i.extractor.Extract(pluginData, i.CacheDir); err != nil {
return errors.Wrap(err, "extracting files from archive") return fmt.Errorf("extracting files from archive: %w", err)
} }
if !isPlugin(i.CacheDir) { if !isPlugin(i.CacheDir) {
@ -152,7 +153,7 @@ func (i *HTTPInstaller) Install() error {
// Update updates a local repository // Update updates a local repository
// Not implemented for now since tarball most likely will be packaged by version // Not implemented for now since tarball most likely will be packaged by version
func (i *HTTPInstaller) Update() error { func (i *HTTPInstaller) Update() error {
return errors.Errorf("method Update() not implemented for HttpInstaller") return fmt.Errorf("method Update() not implemented for HttpInstaller")
} }
// Path is overridden because we want to join on the plugin name not the file name // Path is overridden because we want to join on the plugin name not the file name
@ -265,7 +266,7 @@ func (g *TarGzExtractor) Extract(buffer *bytes.Buffer, targetDir string) error {
case tar.TypeXGlobalHeader, tar.TypeXHeader: case tar.TypeXGlobalHeader, tar.TypeXHeader:
continue continue
default: default:
return errors.Errorf("unknown type: %b in %s", header.Typeflag, header.Name) return fmt.Errorf("unknown type: %b in %s", header.Typeflag, header.Name)
} }
} }
return nil return nil

@ -20,7 +20,9 @@ import (
"bytes" "bytes"
"compress/gzip" "compress/gzip"
"encoding/base64" "encoding/base64"
"errors"
"fmt" "fmt"
"io/fs"
"net/http" "net/http"
"net/http/httptest" "net/http/httptest"
"os" "os"
@ -29,8 +31,6 @@ import (
"syscall" "syscall"
"testing" "testing"
"github.com/pkg/errors"
"helm.sh/helm/v4/internal/test/ensure" "helm.sh/helm/v4/internal/test/ensure"
"helm.sh/helm/v4/pkg/getter" "helm.sh/helm/v4/pkg/getter"
"helm.sh/helm/v4/pkg/helmpath" "helm.sh/helm/v4/pkg/helmpath"
@ -150,7 +150,7 @@ func TestHTTPInstallerNonExistentVersion(t *testing.T) {
// inject fake http client responding with error // inject fake http client responding with error
httpInstaller.getter = &TestHTTPGetter{ httpInstaller.getter = &TestHTTPGetter{
MockError: errors.Errorf("failed to download plugin for some reason"), MockError: fmt.Errorf("failed to download plugin for some reason"),
} }
// attempt to install the plugin // attempt to install the plugin
@ -276,7 +276,7 @@ func TestExtract(t *testing.T) {
pluginYAMLFullPath := filepath.Join(tempDir, "plugin.yaml") pluginYAMLFullPath := filepath.Join(tempDir, "plugin.yaml")
if info, err := os.Stat(pluginYAMLFullPath); err != nil { if info, err := os.Stat(pluginYAMLFullPath); err != nil {
if os.IsNotExist(err) { if errors.Is(err, fs.ErrNotExist) {
t.Fatalf("Expected %s to exist but doesn't", pluginYAMLFullPath) t.Fatalf("Expected %s to exist but doesn't", pluginYAMLFullPath)
} }
t.Fatal(err) t.Fatal(err)
@ -286,7 +286,7 @@ func TestExtract(t *testing.T) {
readmeFullPath := filepath.Join(tempDir, "README.md") readmeFullPath := filepath.Join(tempDir, "README.md")
if info, err := os.Stat(readmeFullPath); err != nil { if info, err := os.Stat(readmeFullPath); err != nil {
if os.IsNotExist(err) { if errors.Is(err, fs.ErrNotExist) {
t.Fatalf("Expected %s to exist but doesn't", readmeFullPath) t.Fatalf("Expected %s to exist but doesn't", readmeFullPath)
} }
t.Fatal(err) t.Fatal(err)

@ -16,13 +16,12 @@ limitations under the License.
package installer package installer
import ( import (
"errors"
"net/http" "net/http"
"os" "os"
"path/filepath" "path/filepath"
"strings" "strings"
"github.com/pkg/errors"
"helm.sh/helm/v4/pkg/plugin" "helm.sh/helm/v4/pkg/plugin"
) )

@ -16,11 +16,11 @@ limitations under the License.
package installer // import "helm.sh/helm/v4/pkg/plugin/installer" package installer // import "helm.sh/helm/v4/pkg/plugin/installer"
import ( import (
"errors"
"fmt"
"log/slog" "log/slog"
"os" "os"
"path/filepath" "path/filepath"
"github.com/pkg/errors"
) )
// ErrPluginNotAFolder indicates that the plugin path is not a folder. // ErrPluginNotAFolder indicates that the plugin path is not a folder.
@ -35,7 +35,7 @@ type LocalInstaller struct {
func NewLocalInstaller(source string) (*LocalInstaller, error) { func NewLocalInstaller(source string) (*LocalInstaller, error) {
src, err := filepath.Abs(source) src, err := filepath.Abs(source)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "unable to get absolute path to plugin") return nil, fmt.Errorf("unable to get absolute path to plugin: %w", err)
} }
i := &LocalInstaller{ i := &LocalInstaller{
base: newBase(src), base: newBase(src),

@ -16,13 +16,15 @@ limitations under the License.
package installer // import "helm.sh/helm/v4/pkg/plugin/installer" package installer // import "helm.sh/helm/v4/pkg/plugin/installer"
import ( import (
"errors"
"fmt"
stdfs "io/fs"
"log/slog" "log/slog"
"os" "os"
"sort" "sort"
"github.com/Masterminds/semver/v3" "github.com/Masterminds/semver/v3"
"github.com/Masterminds/vcs" "github.com/Masterminds/vcs"
"github.com/pkg/errors"
"helm.sh/helm/v4/internal/third_party/dep/fs" "helm.sh/helm/v4/internal/third_party/dep/fs"
"helm.sh/helm/v4/pkg/helmpath" "helm.sh/helm/v4/pkg/helmpath"
@ -145,7 +147,7 @@ func (i *VCSInstaller) solveVersion(repo vcs.Repo) (string, error) {
} }
} }
return "", errors.Errorf("requested version %q does not exist for plugin %q", i.Version, i.Repo.Remote()) return "", fmt.Errorf("requested version %q does not exist for plugin %q", i.Version, i.Repo.Remote())
} }
// setVersion attempts to checkout the version // setVersion attempts to checkout the version
@ -156,7 +158,7 @@ func (i *VCSInstaller) setVersion(repo vcs.Repo, ref string) error {
// sync will clone or update a remote repo. // sync will clone or update a remote repo.
func (i *VCSInstaller) sync(repo vcs.Repo) error { func (i *VCSInstaller) sync(repo vcs.Repo) error {
if _, err := os.Stat(repo.LocalPath()); os.IsNotExist(err) { if _, err := os.Stat(repo.LocalPath()); errors.Is(err, stdfs.ErrNotExist) {
slog.Debug("cloning", "source", repo.Remote(), "destination", repo.LocalPath()) slog.Debug("cloning", "source", repo.Remote(), "destination", repo.LocalPath())
return repo.Get() return repo.Get()
} }

@ -24,7 +24,6 @@ import (
"strings" "strings"
"unicode" "unicode"
"github.com/pkg/errors"
"sigs.k8s.io/yaml" "sigs.k8s.io/yaml"
"helm.sh/helm/v4/pkg/cli" "helm.sh/helm/v4/pkg/cli"
@ -313,12 +312,12 @@ func LoadDir(dirname string) (*Plugin, error) {
pluginfile := filepath.Join(dirname, PluginFileName) pluginfile := filepath.Join(dirname, PluginFileName)
data, err := os.ReadFile(pluginfile) data, err := os.ReadFile(pluginfile)
if err != nil { if err != nil {
return nil, errors.Wrapf(err, "failed to read plugin at %q", pluginfile) return nil, fmt.Errorf("failed to read plugin at %q: %w", pluginfile, err)
} }
plug := &Plugin{Dir: dirname} plug := &Plugin{Dir: dirname}
if err := yaml.UnmarshalStrict(data, &plug.Metadata); err != nil { if err := yaml.UnmarshalStrict(data, &plug.Metadata); err != nil {
return nil, errors.Wrapf(err, "failed to load plugin at %q", pluginfile) return nil, fmt.Errorf("failed to load plugin at %q: %w", pluginfile, err)
} }
return plug, validatePluginData(plug, pluginfile) return plug, validatePluginData(plug, pluginfile)
} }
@ -332,7 +331,7 @@ func LoadAll(basedir string) ([]*Plugin, error) {
scanpath := filepath.Join(basedir, "*", PluginFileName) scanpath := filepath.Join(basedir, "*", PluginFileName)
matches, err := filepath.Glob(scanpath) matches, err := filepath.Glob(scanpath)
if err != nil { if err != nil {
return plugins, errors.Wrapf(err, "failed to find plugins in %q", scanpath) return plugins, fmt.Errorf("failed to find plugins in %q: %w", scanpath, err)
} }
if matches == nil { if matches == nil {

@ -18,11 +18,10 @@ package postrender
import ( import (
"bytes" "bytes"
"fmt"
"io" "io"
"os/exec" "os/exec"
"path/filepath" "path/filepath"
"github.com/pkg/errors"
) )
type execRender struct { type execRender struct {
@ -61,13 +60,13 @@ func (p *execRender) Run(renderedManifests *bytes.Buffer) (*bytes.Buffer, error)
}() }()
err = cmd.Run() err = cmd.Run()
if err != nil { if err != nil {
return nil, errors.Wrapf(err, "error while running command %s. error output:\n%s", p.binaryPath, stderr.String()) return nil, fmt.Errorf("error while running command %s. error output:\n%s: %w", p.binaryPath, stderr.String(), err)
} }
// If the binary returned almost nothing, it's likely that it didn't // If the binary returned almost nothing, it's likely that it didn't
// successfully render anything // successfully render anything
if len(bytes.TrimSpace(postRendered.Bytes())) == 0 { if len(bytes.TrimSpace(postRendered.Bytes())) == 0 {
return nil, errors.Errorf("post-renderer %q produced empty output", p.binaryPath) return nil, fmt.Errorf("post-renderer %q produced empty output", p.binaryPath)
} }
return postRendered, nil return postRendered, nil
@ -95,7 +94,7 @@ func getFullPath(binaryPath string) (string, error) {
// // The plugins variable can actually contain multiple paths, so loop through those // // The plugins variable can actually contain multiple paths, so loop through those
// for _, p := range filepath.SplitList(pluginDir) { // for _, p := range filepath.SplitList(pluginDir) {
// _, err := os.Stat(filepath.Join(p, binaryPath)) // _, err := os.Stat(filepath.Join(p, binaryPath))
// if err != nil && !os.IsNotExist(err) { // if err != nil && !errors.Is(err, fs.ErrNotExist) {
// return "", err // return "", err
// } else if err == nil { // } else if err == nil {
// binaryPath = filepath.Join(p, binaryPath) // binaryPath = filepath.Join(p, binaryPath)
@ -108,7 +107,7 @@ func getFullPath(binaryPath string) (string, error) {
// the path and is executable // the path and is executable
checkedPath, err := exec.LookPath(binaryPath) checkedPath, err := exec.LookPath(binaryPath)
if err != nil { if err != nil {
return "", errors.Wrapf(err, "unable to find binary at %s", binaryPath) return "", fmt.Errorf("unable to find binary at %s: %w", binaryPath, err)
} }
return filepath.Abs(checkedPath) return filepath.Abs(checkedPath)

@ -19,12 +19,13 @@ import (
"bytes" "bytes"
"crypto" "crypto"
"encoding/hex" "encoding/hex"
"errors"
"fmt"
"io" "io"
"os" "os"
"path/filepath" "path/filepath"
"strings" "strings"
"github.com/pkg/errors"
"golang.org/x/crypto/openpgp" //nolint "golang.org/x/crypto/openpgp" //nolint
"golang.org/x/crypto/openpgp/clearsign" //nolint "golang.org/x/crypto/openpgp/clearsign" //nolint
"golang.org/x/crypto/openpgp/packet" //nolint "golang.org/x/crypto/openpgp/packet" //nolint
@ -143,7 +144,7 @@ func NewFromKeyring(keyringfile, id string) (*Signatory, error) {
} }
} }
if vague { if vague {
return s, errors.Errorf("more than one key contain the id %q", id) return s, fmt.Errorf("more than one key contain the id %q", id)
} }
s.Entity = candidate s.Entity = candidate
@ -236,12 +237,12 @@ func (s *Signatory) ClearSign(chartpath string) (string, error) {
// In other words, if we call Close here, there's a risk that there's an attempt to use the // In other words, if we call Close here, there's a risk that there's an attempt to use the
// private key to sign garbage data (since we know that io.Copy failed, `w` won't contain // private key to sign garbage data (since we know that io.Copy failed, `w` won't contain
// anything useful). // anything useful).
return "", errors.Wrap(err, "failed to write to clearsign encoder") return "", fmt.Errorf("failed to write to clearsign encoder: %w", err)
} }
err = w.Close() err = w.Close()
if err != nil { if err != nil {
return "", errors.Wrap(err, "failed to either sign or armor message block") return "", fmt.Errorf("failed to either sign or armor message block: %w", err)
} }
return out.String(), nil return out.String(), nil
@ -254,14 +255,14 @@ func (s *Signatory) Verify(chartpath, sigpath string) (*Verification, error) {
if fi, err := os.Stat(fname); err != nil { if fi, err := os.Stat(fname); err != nil {
return ver, err return ver, err
} else if fi.IsDir() { } else if fi.IsDir() {
return ver, errors.Errorf("%s cannot be a directory", fname) return ver, fmt.Errorf("%s cannot be a directory", fname)
} }
} }
// First verify the signature // First verify the signature
sig, err := s.decodeSignature(sigpath) sig, err := s.decodeSignature(sigpath)
if err != nil { if err != nil {
return ver, errors.Wrap(err, "failed to decode signature") return ver, fmt.Errorf("failed to decode signature: %w", err)
} }
by, err := s.verifySignature(sig) by, err := s.verifySignature(sig)
@ -283,9 +284,9 @@ func (s *Signatory) Verify(chartpath, sigpath string) (*Verification, error) {
sum = "sha256:" + sum sum = "sha256:" + sum
basename := filepath.Base(chartpath) basename := filepath.Base(chartpath)
if sha, ok := sums.Files[basename]; !ok { if sha, ok := sums.Files[basename]; !ok {
return ver, errors.Errorf("provenance does not contain a SHA for a file named %q", basename) return ver, fmt.Errorf("provenance does not contain a SHA for a file named %q", basename)
} else if sha != sum { } else if sha != sum {
return ver, errors.Errorf("sha256 sum does not match for %s: %q != %q", basename, sha, sum) return ver, fmt.Errorf("sha256 sum does not match for %s: %q != %q", basename, sha, sum)
} }
ver.FileHash = sum ver.FileHash = sum
ver.FileName = basename ver.FileName = basename

@ -16,7 +16,9 @@ limitations under the License.
package pusher package pusher
import ( import (
"errors"
"fmt" "fmt"
"io/fs"
"net" "net"
"net/http" "net/http"
"os" "os"
@ -24,8 +26,6 @@ import (
"strings" "strings"
"time" "time"
"github.com/pkg/errors"
"helm.sh/helm/v4/internal/tlsutil" "helm.sh/helm/v4/internal/tlsutil"
"helm.sh/helm/v4/pkg/chart/v2/loader" "helm.sh/helm/v4/pkg/chart/v2/loader"
"helm.sh/helm/v4/pkg/registry" "helm.sh/helm/v4/pkg/registry"
@ -48,8 +48,8 @@ func (pusher *OCIPusher) Push(chartRef, href string, options ...Option) error {
func (pusher *OCIPusher) push(chartRef, href string) error { func (pusher *OCIPusher) push(chartRef, href string) error {
stat, err := os.Stat(chartRef) stat, err := os.Stat(chartRef)
if err != nil { if err != nil {
if os.IsNotExist(err) { if errors.Is(err, fs.ErrNotExist) {
return errors.Errorf("%s: no such file", chartRef) return fmt.Errorf("%s: no such file", chartRef)
} }
return err return err
} }
@ -117,7 +117,7 @@ func (pusher *OCIPusher) newRegistryClient() (*registry.Client, error) {
tlsutil.WithCAFile(pusher.opts.caFile), tlsutil.WithCAFile(pusher.opts.caFile),
) )
if err != nil { if err != nil {
return nil, errors.Wrap(err, "can't create TLS config for client") return nil, fmt.Errorf("can't create TLS config for client: %w", err)
} }
registryClient, err := registry.NewClient( registryClient, err := registry.NewClient(

@ -17,7 +17,7 @@ limitations under the License.
package pusher package pusher
import ( import (
"github.com/pkg/errors" "fmt"
"helm.sh/helm/v4/pkg/cli" "helm.sh/helm/v4/pkg/cli"
"helm.sh/helm/v4/pkg/registry" "helm.sh/helm/v4/pkg/registry"
@ -106,7 +106,7 @@ func (p Providers) ByScheme(scheme string) (Pusher, error) {
return pp.New() return pp.New()
} }
} }
return nil, errors.Errorf("scheme %q not supported", scheme) return nil, fmt.Errorf("scheme %q not supported", scheme)
} }
var ociProvider = Provider{ var ociProvider = Provider{

@ -21,6 +21,7 @@ import (
"crypto/tls" "crypto/tls"
"crypto/x509" "crypto/x509"
"encoding/json" "encoding/json"
"errors"
"fmt" "fmt"
"io" "io"
"net/http" "net/http"
@ -33,7 +34,6 @@ import (
"github.com/Masterminds/semver/v3" "github.com/Masterminds/semver/v3"
"github.com/opencontainers/image-spec/specs-go" "github.com/opencontainers/image-spec/specs-go"
ocispec "github.com/opencontainers/image-spec/specs-go/v1" ocispec "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/pkg/errors"
"oras.land/oras-go/v2" "oras.land/oras-go/v2"
"oras.land/oras-go/v2/content" "oras.land/oras-go/v2/content"
"oras.land/oras-go/v2/content/memory" "oras.land/oras-go/v2/content/memory"
@ -463,7 +463,7 @@ func (c *Client) Pull(ref string, options ...PullOption) (*PullResult, error) {
PreCopy: func(_ context.Context, desc ocispec.Descriptor) error { PreCopy: func(_ context.Context, desc ocispec.Descriptor) error {
mediaType := desc.MediaType mediaType := desc.MediaType
if i := sort.SearchStrings(allowedMediaTypes, mediaType); i >= len(allowedMediaTypes) || allowedMediaTypes[i] != mediaType { if i := sort.SearchStrings(allowedMediaTypes, mediaType); i >= len(allowedMediaTypes) || allowedMediaTypes[i] != mediaType {
return errors.Errorf("media type %q is not allowed, found in descriptor with digest: %q", mediaType, desc.Digest) return fmt.Errorf("media type %q is not allowed, found in descriptor with digest: %q", mediaType, desc.Digest)
} }
mu.Lock() mu.Lock()
@ -846,7 +846,7 @@ func (c *Client) ValidateReference(ref, version string, u *url.URL) (*url.URL, e
version = registryReference.Tag version = registryReference.Tag
} else { } else {
if registryReference.Tag != "" && registryReference.Tag != version { if registryReference.Tag != "" && registryReference.Tag != version {
return nil, errors.Errorf("chart reference and version mismatch: %s is not %s", version, registryReference.Tag) return nil, fmt.Errorf("chart reference and version mismatch: %s is not %s", version, registryReference.Tag)
} }
} }
@ -865,7 +865,7 @@ func (c *Client) ValidateReference(ref, version string, u *url.URL) (*url.URL, e
return u, nil return u, nil
} }
if desc.Digest.String() != registryReference.Digest { if desc.Digest.String() != registryReference.Digest {
return nil, errors.Errorf("chart reference digest mismatch: %s is not %s", desc.Digest.String(), registryReference.Digest) return nil, fmt.Errorf("chart reference digest mismatch: %s is not %s", desc.Digest.String(), registryReference.Digest)
} }
return u, nil return u, nil
} }
@ -881,7 +881,7 @@ func (c *Client) ValidateReference(ref, version string, u *url.URL) (*url.URL, e
return nil, err return nil, err
} }
if len(tags) == 0 { if len(tags) == 0 {
return nil, errors.Errorf("Unable to locate any tags in provided repository: %s", ref) return nil, fmt.Errorf("unable to locate any tags in provided repository: %s", ref)
} }
// Determine if version provided // Determine if version provided

@ -31,7 +31,6 @@ import (
"github.com/Masterminds/semver/v3" "github.com/Masterminds/semver/v3"
ocispec "github.com/opencontainers/image-spec/specs-go/v1" ocispec "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/pkg/errors"
) )
var immutableOciAnnotations = []string{ var immutableOciAnnotations = []string{
@ -87,7 +86,7 @@ func GetTagMatchingVersionOrConstraint(tags []string, versionString string) (str
} }
} }
return "", errors.Errorf("Could not locate a version matching provided version string %s", versionString) return "", fmt.Errorf("could not locate a version matching provided version string %s", versionString)
} }
// extractChartMeta is used to extract a chart metadata from a byte array // extractChartMeta is used to extract a chart metadata from a byte array

@ -17,13 +17,13 @@ limitations under the License.
package util package util
import ( import (
"fmt"
"log/slog" "log/slog"
"path" "path"
"sort" "sort"
"strconv" "strconv"
"strings" "strings"
"github.com/pkg/errors"
"sigs.k8s.io/yaml" "sigs.k8s.io/yaml"
chartutil "helm.sh/helm/v4/pkg/chart/v2/util" chartutil "helm.sh/helm/v4/pkg/chart/v2/util"
@ -149,7 +149,7 @@ func (file *manifestFile) sort(result *result) error {
var entry SimpleHead var entry SimpleHead
if err := yaml.Unmarshal([]byte(m), &entry); err != nil { if err := yaml.Unmarshal([]byte(m), &entry); err != nil {
return errors.Wrapf(err, "YAML parse error on %s", file.path) return fmt.Errorf("YAML parse error on %s: %w", file.path, err)
} }
if !hasAnyAnnotation(entry) { if !hasAnyAnnotation(entry) {

@ -28,8 +28,6 @@ import (
"path/filepath" "path/filepath"
"strings" "strings"
"github.com/pkg/errors"
"helm.sh/helm/v4/pkg/getter" "helm.sh/helm/v4/pkg/getter"
"helm.sh/helm/v4/pkg/helmpath" "helm.sh/helm/v4/pkg/helmpath"
) )
@ -59,12 +57,12 @@ type ChartRepository struct {
func NewChartRepository(cfg *Entry, getters getter.Providers) (*ChartRepository, error) { func NewChartRepository(cfg *Entry, getters getter.Providers) (*ChartRepository, error) {
u, err := url.Parse(cfg.URL) u, err := url.Parse(cfg.URL)
if err != nil { if err != nil {
return nil, errors.Errorf("invalid chart URL format: %s", cfg.URL) return nil, fmt.Errorf("invalid chart URL format: %s", cfg.URL)
} }
client, err := getters.ByScheme(u.Scheme) client, err := getters.ByScheme(u.Scheme)
if err != nil { if err != nil {
return nil, errors.Errorf("could not find protocol handler for: %s", u.Scheme) return nil, fmt.Errorf("could not find protocol handler for: %s", u.Scheme)
} }
return &ChartRepository{ return &ChartRepository{
@ -200,7 +198,7 @@ func FindChartInRepoURL(repoURL string, chartName string, getters getter.Provide
} }
idx, err := r.DownloadIndexFile() idx, err := r.DownloadIndexFile()
if err != nil { if err != nil {
return "", errors.Wrapf(err, "looks like %q is not a valid chart repository or cannot be reached", repoURL) return "", fmt.Errorf("looks like %q is not a valid chart repository or cannot be reached: %w", repoURL, err)
} }
defer func() { defer func() {
os.RemoveAll(filepath.Join(r.CachePath, helmpath.CacheChartsFile(r.Config.Name))) os.RemoveAll(filepath.Join(r.CachePath, helmpath.CacheChartsFile(r.Config.Name)))
@ -226,14 +224,14 @@ func FindChartInRepoURL(repoURL string, chartName string, getters getter.Provide
} }
if len(cv.URLs) == 0 { if len(cv.URLs) == 0 {
return "", errors.Errorf("%s has no downloadable URLs", errMsg) return "", fmt.Errorf("%s has no downloadable URLs", errMsg)
} }
chartURL := cv.URLs[0] chartURL := cv.URLs[0]
absoluteChartURL, err := ResolveReferenceURL(repoURL, chartURL) absoluteChartURL, err := ResolveReferenceURL(repoURL, chartURL)
if err != nil { if err != nil {
return "", errors.Wrap(err, "failed to make chart URL absolute") return "", fmt.Errorf("failed to make chart URL absolute: %w", err)
} }
return absoluteChartURL, nil return absoluteChartURL, nil
@ -244,7 +242,7 @@ func FindChartInRepoURL(repoURL string, chartName string, getters getter.Provide
func ResolveReferenceURL(baseURL, refURL string) (string, error) { func ResolveReferenceURL(baseURL, refURL string) (string, error) {
parsedRefURL, err := url.Parse(refURL) parsedRefURL, err := url.Parse(refURL)
if err != nil { if err != nil {
return "", errors.Wrapf(err, "failed to parse %s as URL", refURL) return "", fmt.Errorf("failed to parse %s as URL: %w", refURL, err)
} }
if parsedRefURL.IsAbs() { if parsedRefURL.IsAbs() {
@ -253,7 +251,7 @@ func ResolveReferenceURL(baseURL, refURL string) (string, error) {
parsedBaseURL, err := url.Parse(baseURL) parsedBaseURL, err := url.Parse(baseURL)
if err != nil { if err != nil {
return "", errors.Wrapf(err, "failed to parse %s as URL", baseURL) return "", fmt.Errorf("failed to parse %s as URL: %w", baseURL, err)
} }
// We need a trailing slash for ResolveReference to work, but make sure there isn't already one // We need a trailing slash for ResolveReference to work, but make sure there isn't already one

@ -19,6 +19,8 @@ package repo
import ( import (
"bytes" "bytes"
"encoding/json" "encoding/json"
"errors"
"fmt"
"log/slog" "log/slog"
"os" "os"
"path" "path"
@ -28,7 +30,6 @@ import (
"time" "time"
"github.com/Masterminds/semver/v3" "github.com/Masterminds/semver/v3"
"github.com/pkg/errors"
"sigs.k8s.io/yaml" "sigs.k8s.io/yaml"
"helm.sh/helm/v4/internal/fileutil" "helm.sh/helm/v4/internal/fileutil"
@ -108,7 +109,7 @@ func LoadIndexFile(path string) (*IndexFile, error) {
} }
i, err := loadIndex(b, path) i, err := loadIndex(b, path)
if err != nil { if err != nil {
return nil, errors.Wrapf(err, "error loading %s", path) return nil, fmt.Errorf("error loading %s: %w", path, err)
} }
return i, nil return i, nil
} }
@ -124,7 +125,7 @@ func (i IndexFile) MustAdd(md *chart.Metadata, filename, baseURL, digest string)
md.APIVersion = chart.APIVersionV1 md.APIVersion = chart.APIVersionV1
} }
if err := md.Validate(); err != nil { if err := md.Validate(); err != nil {
return errors.Wrapf(err, "validate failed for %s", filename) return fmt.Errorf("validate failed for %s: %w", filename, err)
} }
u := filename u := filename
@ -217,7 +218,7 @@ func (i IndexFile) Get(name, version string) (*ChartVersion, error) {
return ver, nil return ver, nil
} }
} }
return nil, errors.Errorf("no chart version found for %s-%s", name, version) return nil, fmt.Errorf("no chart version found for %s-%s", name, version)
} }
// WriteFile writes an index file to the given destination path. // WriteFile writes an index file to the given destination path.
@ -330,7 +331,7 @@ func IndexDirectory(dir, baseURL string) (*IndexFile, error) {
return index, err return index, err
} }
if err := index.MustAdd(c.Metadata, fname, parentURL, hash); err != nil { if err := index.MustAdd(c.Metadata, fname, parentURL, hash); err != nil {
return index, errors.Wrapf(err, "failed adding to %s to index", fname) return index, fmt.Errorf("failed adding to %s to index: %w", fname, err)
} }
} }
return index, nil return index, nil

@ -17,11 +17,11 @@ limitations under the License.
package repo // import "helm.sh/helm/v4/pkg/repo" package repo // import "helm.sh/helm/v4/pkg/repo"
import ( import (
"fmt"
"os" "os"
"path/filepath" "path/filepath"
"time" "time"
"github.com/pkg/errors"
"sigs.k8s.io/yaml" "sigs.k8s.io/yaml"
) )
@ -48,7 +48,7 @@ func LoadFile(path string) (*File, error) {
r := new(File) r := new(File)
b, err := os.ReadFile(path) b, err := os.ReadFile(path)
if err != nil { if err != nil {
return r, errors.Wrapf(err, "couldn't load repositories file (%s)", path) return r, fmt.Errorf("couldn't load repositories file (%s): %w", path, err)
} }
err = yaml.Unmarshal(b, r) err = yaml.Unmarshal(b, r)

@ -24,7 +24,6 @@ import (
"strings" "strings"
"time" "time"
"github.com/pkg/errors"
v1 "k8s.io/api/core/v1" v1 "k8s.io/api/core/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors" apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@ -122,7 +121,7 @@ func (cfgmaps *ConfigMaps) Query(labels map[string]string) ([]*rspb.Release, err
ls := kblabels.Set{} ls := kblabels.Set{}
for k, v := range labels { for k, v := range labels {
if errs := validation.IsValidLabelValue(v); len(errs) != 0 { if errs := validation.IsValidLabelValue(v); len(errs) != 0 {
return nil, errors.Errorf("invalid label value: %q: %s", v, strings.Join(errs, "; ")) return nil, fmt.Errorf("invalid label value: %q: %s", v, strings.Join(errs, "; "))
} }
ls[k] = v ls[k] = v
} }

@ -17,10 +17,9 @@ limitations under the License.
package driver // import "helm.sh/helm/v4/pkg/storage/driver" package driver // import "helm.sh/helm/v4/pkg/storage/driver"
import ( import (
"errors"
"fmt" "fmt"
"github.com/pkg/errors"
rspb "helm.sh/helm/v4/pkg/release/v1" rspb "helm.sh/helm/v4/pkg/release/v1"
) )

@ -24,7 +24,6 @@ import (
"strings" "strings"
"time" "time"
"github.com/pkg/errors"
v1 "k8s.io/api/core/v1" v1 "k8s.io/api/core/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors" apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@ -68,12 +67,15 @@ func (secrets *Secrets) Get(key string) (*rspb.Release, error) {
if apierrors.IsNotFound(err) { if apierrors.IsNotFound(err) {
return nil, ErrReleaseNotFound return nil, ErrReleaseNotFound
} }
return nil, errors.Wrapf(err, "get: failed to get %q", key) return nil, fmt.Errorf("get: failed to get %q: %w", key, err)
} }
// found the secret, decode the base64 data string // found the secret, decode the base64 data string
r, err := decodeRelease(string(obj.Data["release"])) r, err := decodeRelease(string(obj.Data["release"]))
if err != nil {
return r, fmt.Errorf("get: failed to decode data %q: %w", key, err)
}
r.Labels = filterSystemLabels(obj.Labels) r.Labels = filterSystemLabels(obj.Labels)
return r, errors.Wrapf(err, "get: failed to decode data %q", key) return r, nil
} }
// List fetches all releases and returns the list releases such // List fetches all releases and returns the list releases such
@ -85,7 +87,7 @@ func (secrets *Secrets) List(filter func(*rspb.Release) bool) ([]*rspb.Release,
list, err := secrets.impl.List(context.Background(), opts) list, err := secrets.impl.List(context.Background(), opts)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "list: failed to list") return nil, fmt.Errorf("list: failed to list: %w", err)
} }
var results []*rspb.Release var results []*rspb.Release
@ -114,7 +116,7 @@ func (secrets *Secrets) Query(labels map[string]string) ([]*rspb.Release, error)
ls := kblabels.Set{} ls := kblabels.Set{}
for k, v := range labels { for k, v := range labels {
if errs := validation.IsValidLabelValue(v); len(errs) != 0 { if errs := validation.IsValidLabelValue(v); len(errs) != 0 {
return nil, errors.Errorf("invalid label value: %q: %s", v, strings.Join(errs, "; ")) return nil, fmt.Errorf("invalid label value: %q: %s", v, strings.Join(errs, "; "))
} }
ls[k] = v ls[k] = v
} }
@ -123,7 +125,7 @@ func (secrets *Secrets) Query(labels map[string]string) ([]*rspb.Release, error)
list, err := secrets.impl.List(context.Background(), opts) list, err := secrets.impl.List(context.Background(), opts)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "query: failed to query with labels") return nil, fmt.Errorf("query: failed to query with labels: %w", err)
} }
if len(list.Items) == 0 { if len(list.Items) == 0 {
@ -156,7 +158,7 @@ func (secrets *Secrets) Create(key string, rls *rspb.Release) error {
// create a new secret to hold the release // create a new secret to hold the release
obj, err := newSecretsObject(key, rls, lbs) obj, err := newSecretsObject(key, rls, lbs)
if err != nil { if err != nil {
return errors.Wrapf(err, "create: failed to encode release %q", rls.Name) return fmt.Errorf("create: failed to encode release %q: %w", rls.Name, err)
} }
// push the secret object out into the kubiverse // push the secret object out into the kubiverse
if _, err := secrets.impl.Create(context.Background(), obj, metav1.CreateOptions{}); err != nil { if _, err := secrets.impl.Create(context.Background(), obj, metav1.CreateOptions{}); err != nil {
@ -164,7 +166,7 @@ func (secrets *Secrets) Create(key string, rls *rspb.Release) error {
return ErrReleaseExists return ErrReleaseExists
} }
return errors.Wrap(err, "create: failed to create") return fmt.Errorf("create: failed to create: %w", err)
} }
return nil return nil
} }
@ -182,11 +184,14 @@ func (secrets *Secrets) Update(key string, rls *rspb.Release) error {
// create a new secret object to hold the release // create a new secret object to hold the release
obj, err := newSecretsObject(key, rls, lbs) obj, err := newSecretsObject(key, rls, lbs)
if err != nil { if err != nil {
return errors.Wrapf(err, "update: failed to encode release %q", rls.Name) return fmt.Errorf("update: failed to encode release %q: %w", rls.Name, err)
} }
// push the secret object out into the kubiverse // push the secret object out into the kubiverse
_, err = secrets.impl.Update(context.Background(), obj, metav1.UpdateOptions{}) _, err = secrets.impl.Update(context.Background(), obj, metav1.UpdateOptions{})
return errors.Wrap(err, "update: failed to update") if err != nil {
return fmt.Errorf("update: failed to update: %w", err)
}
return nil
} }
// Delete deletes the Secret holding the release named by key. // Delete deletes the Secret holding the release named by key.
@ -197,7 +202,10 @@ func (secrets *Secrets) Delete(key string) (rls *rspb.Release, err error) {
} }
// delete the release // delete the release
err = secrets.impl.Delete(context.Background(), key, metav1.DeleteOptions{}) err = secrets.impl.Delete(context.Background(), key, metav1.DeleteOptions{})
return rls, err if err != nil {
return nil, err
}
return rls, nil
} }
// newSecretsObject constructs a kubernetes Secret object // newSecretsObject constructs a kubernetes Secret object

@ -17,12 +17,11 @@ limitations under the License.
package storage // import "helm.sh/helm/v4/pkg/storage" package storage // import "helm.sh/helm/v4/pkg/storage"
import ( import (
"errors"
"fmt" "fmt"
"log/slog" "log/slog"
"strings" "strings"
"github.com/pkg/errors"
relutil "helm.sh/helm/v4/pkg/release/util" relutil "helm.sh/helm/v4/pkg/release/util"
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"
@ -212,7 +211,7 @@ func (s *Storage) removeLeastRecent(name string, maximum int) error {
case 1: case 1:
return errs[0] return errs[0]
default: default:
return errors.Errorf("encountered %d deletion errors. First is: %s", c, errs[0]) return fmt.Errorf("encountered %d deletion errors. First is: %w", c, errs[0])
} }
} }
@ -234,7 +233,7 @@ func (s *Storage) Last(name string) (*rspb.Release, error) {
return nil, err return nil, err
} }
if len(h) == 0 { if len(h) == 0 {
return nil, errors.Errorf("no revision for release %q", name) return nil, fmt.Errorf("no revision for release %q", name)
} }
relutil.Reverse(h, relutil.SortByRevision) relutil.Reverse(h, relutil.SortByRevision)

@ -17,12 +17,11 @@ limitations under the License.
package storage // import "helm.sh/helm/v4/pkg/storage" package storage // import "helm.sh/helm/v4/pkg/storage"
import ( import (
"errors"
"fmt" "fmt"
"reflect" "reflect"
"testing" "testing"
"github.com/pkg/errors"
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"
) )

@ -20,8 +20,6 @@ import (
"fmt" "fmt"
"io" "io"
"strconv" "strconv"
"github.com/pkg/errors"
) )
// ParseLiteral parses a set line interpreting the value as a literal string. // ParseLiteral parses a set line interpreting the value as a literal string.
@ -102,7 +100,7 @@ func (t *literalParser) key(data map[string]interface{}, nestedNameLevel int) (r
if len(key) == 0 { if len(key) == 0 {
return err return err
} }
return errors.Errorf("key %q has no value", string(key)) return fmt.Errorf("key %q has no value", string(key))
case lastRune == '=': case lastRune == '=':
// found end of key: swallow the '=' and get the value // found end of key: swallow the '=' and get the value
@ -129,7 +127,7 @@ func (t *literalParser) key(data map[string]interface{}, nestedNameLevel int) (r
// recurse on sub-tree with remaining data // recurse on sub-tree with remaining data
err := t.key(inner, nestedNameLevel) err := t.key(inner, nestedNameLevel)
if err == nil && len(inner) == 0 { if err == nil && len(inner) == 0 {
return errors.Errorf("key map %q has no value", string(key)) return fmt.Errorf("key map %q has no value", string(key))
} }
if len(inner) != 0 { if len(inner) != 0 {
set(data, string(key), inner) set(data, string(key), inner)
@ -140,7 +138,7 @@ func (t *literalParser) key(data map[string]interface{}, nestedNameLevel int) (r
// We are in a list index context, so we need to set an index. // We are in a list index context, so we need to set an index.
i, err := t.keyIndex() i, err := t.keyIndex()
if err != nil { if err != nil {
return errors.Wrap(err, "error parsing index") return fmt.Errorf("error parsing index: %w", err)
} }
kk := string(key) kk := string(key)
@ -178,7 +176,7 @@ func (t *literalParser) listItem(list []interface{}, i, nestedNameLevel int) ([]
switch key, lastRune, err := runesUntilLiteral(t.sc, stop); { switch key, lastRune, err := runesUntilLiteral(t.sc, stop); {
case len(key) > 0: case len(key) > 0:
return list, errors.Errorf("unexpected data at end of array index: %q", key) return list, fmt.Errorf("unexpected data at end of array index: %q", key)
case err != nil: case err != nil:
return list, err return list, err
@ -214,7 +212,7 @@ func (t *literalParser) listItem(list []interface{}, i, nestedNameLevel int) ([]
// now we have a nested list. Read the index and handle. // now we have a nested list. Read the index and handle.
nextI, err := t.keyIndex() nextI, err := t.keyIndex()
if err != nil { if err != nil {
return list, errors.Wrap(err, "error parsing index") return list, fmt.Errorf("error parsing index: %w", err)
} }
var crtList []interface{} var crtList []interface{}
if len(list) > i { if len(list) > i {
@ -233,7 +231,7 @@ func (t *literalParser) listItem(list []interface{}, i, nestedNameLevel int) ([]
return setIndex(list, i, list2) return setIndex(list, i, list2)
default: default:
return nil, errors.Errorf("parse error: unexpected token %v", lastRune) return nil, fmt.Errorf("parse error: unexpected token %v", lastRune)
} }
} }

@ -18,13 +18,13 @@ package strvals
import ( import (
"bytes" "bytes"
"encoding/json" "encoding/json"
"errors"
"fmt" "fmt"
"io" "io"
"strconv" "strconv"
"strings" "strings"
"unicode" "unicode"
"github.com/pkg/errors"
"sigs.k8s.io/yaml" "sigs.k8s.io/yaml"
) )
@ -189,14 +189,14 @@ func (t *parser) key(data map[string]interface{}, nestedNameLevel int) (reterr e
if len(k) == 0 { if len(k) == 0 {
return err return err
} }
return errors.Errorf("key %q has no value", string(k)) return fmt.Errorf("key %q has no value", string(k))
//set(data, string(k), "") //set(data, string(k), "")
//return err //return err
case last == '[': case last == '[':
// We are in a list index context, so we need to set an index. // We are in a list index context, so we need to set an index.
i, err := t.keyIndex() i, err := t.keyIndex()
if err != nil { if err != nil {
return errors.Wrap(err, "error parsing index") return fmt.Errorf("error parsing index: %w", err)
} }
kk := string(k) kk := string(k)
// Find or create target list // Find or create target list
@ -261,7 +261,7 @@ func (t *parser) key(data map[string]interface{}, nestedNameLevel int) (reterr e
case last == ',': case last == ',':
// No value given. Set the value to empty string. Return error. // No value given. Set the value to empty string. Return error.
set(data, string(k), "") set(data, string(k), "")
return errors.Errorf("key %q has no value (cannot end with ,)", string(k)) return fmt.Errorf("key %q has no value (cannot end with ,)", string(k))
case last == '.': case last == '.':
// Check value name is within the maximum nested name level // Check value name is within the maximum nested name level
nestedNameLevel++ nestedNameLevel++
@ -278,7 +278,7 @@ func (t *parser) key(data map[string]interface{}, nestedNameLevel int) (reterr e
// Recurse // Recurse
e := t.key(inner, nestedNameLevel) e := t.key(inner, nestedNameLevel)
if e == nil && len(inner) == 0 { if e == nil && len(inner) == 0 {
return errors.Errorf("key map %q has no value", string(k)) return fmt.Errorf("key map %q has no value", string(k))
} }
if len(inner) != 0 { if len(inner) != 0 {
set(data, string(k), inner) set(data, string(k), inner)
@ -332,6 +332,7 @@ func (t *parser) keyIndex() (int, error) {
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) {
if i < 0 { if i < 0 {
return list, fmt.Errorf("negative %d index not allowed", i) return list, fmt.Errorf("negative %d index not allowed", i)
@ -339,7 +340,7 @@ func (t *parser) listItem(list []interface{}, i, nestedNameLevel int) ([]interfa
stop := runeSet([]rune{'[', '.', '='}) stop := runeSet([]rune{'[', '.', '='})
switch k, last, err := runesUntil(t.sc, stop); { switch k, last, err := runesUntil(t.sc, stop); {
case len(k) > 0: case len(k) > 0:
return list, errors.Errorf("unexpected data at end of array index: %q", k) return list, fmt.Errorf("unexpected data at end of array index: %q", k)
case err != nil: case err != nil:
return list, err return list, err
case last == '=': case last == '=':
@ -394,7 +395,7 @@ func (t *parser) listItem(list []interface{}, i, nestedNameLevel int) ([]interfa
// now we have a nested list. Read the index and handle. // now we have a nested list. Read the index and handle.
nextI, err := t.keyIndex() nextI, err := t.keyIndex()
if err != nil { if err != nil {
return list, errors.Wrap(err, "error parsing index") return list, fmt.Errorf("error parsing index: %w", err)
} }
var crtList []interface{} var crtList []interface{}
if len(list) > i { if len(list) > i {
@ -430,7 +431,7 @@ func (t *parser) listItem(list []interface{}, i, nestedNameLevel int) ([]interfa
} }
return setIndex(list, i, inner) return setIndex(list, i, inner)
default: default:
return nil, errors.Errorf("parse error: unexpected token %v", last) return nil, fmt.Errorf("parse error: unexpected token %v", last)
} }
} }

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save