Repository: helm/chart-testing
Pull request #470 (2022-09-14 09:37:13)

Fix parsing kubectl output with warnings
Exclude stderr (e.g. deprecation warnings) when parsing command output.

**What this PR does / why we need it**: It ensures that warnings or other output that goes to stderr won't be parsed when trying to list deployments, pods, etc. Today, this is not the case, and many  `ct` subcommands will fail in such situations (e.g. when the [gke-gcloud-auth-plugin](https://cloud.google.com/blog/products/containers-kubernetes/kubectl-auth-changes-in-gke) isn't yet installed).

**Special notes for your reviewer**:
It's possible that the original implementation wanted to include stderr in the output for these commands for a reason, but this feels like a simple oversight.

It's also possible that there are other similar places in the code that require the same modification, so please feel free to update the PR or request these changes, which I will then apply. Thanks!


Patch:
diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml
index 3c2a901..0c58367 100644
--- a/.github/workflows/ci.yaml
+++ b/.github/workflows/ci.yaml
@@ -12,7 +12,7 @@ jobs:
     steps:
 
       - name: checkout
-        uses: actions/checkout@2541b1294d2704b0964813337f33b291d3f8596b # v3.0.1
+        uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 # v3
         with:
           fetch-depth: 0
 
@@ -20,25 +20,30 @@ jobs:
         uses: ludeeus/action-shellcheck@94e0aab03ca135d11a35e5bfc14e6746dc56e7e9 # v1.1.0
 
       - name: Setup go
-        uses: actions/setup-go@84cbf8094393cdc5fe1fe1671ff2647332956b1a # v2.2.0
+        uses: actions/setup-go@d0a58c1c4d2b25278816e339b944508c875f3613 # v3.3.0
         with:
-          go-version: '1.18'
+          go-version-file: './go.mod'
           check-latest: true
 
-      - uses: azure/setup-helm@18bc76811624f360dbd7f18c2d4ecb32c7b87bab # v1.1
+      - uses: azure/setup-helm@f382f75448129b3be48f8121b9857be18d815a82 # v3.4
         with:
-          version: v3.9.2
+          version: v3.9.4
 
       - name: Install GoReleaser
-        uses: goreleaser/goreleaser-action@68acf3b1adf004ac9c2f0a4259e85c5f66e99bef # v3.0.0
+        uses: goreleaser/goreleaser-action@b508e2e3ef3b19d4e4146d4f8fb3ba9db644a757 # v3.1.0
         with:
           install-only: true
 
       - name: Install cosign
-        uses: sigstore/cosign-installer@09a077b27eb1310dcfb21981bee195b30ce09de0 # v2.4.0
+        uses: sigstore/cosign-installer@9becc617647dfa20ae7b1151972e9b3a2c338a2b # v2.6.0
 
       - name: Install syft
-        uses: anchore/sbom-action/download-syft@bb716408e75840bbb01e839347cd213767269d4a # v0.11.0
+        uses: anchore/sbom-action/download-syft@06e109483e6aa305a2b2395eabae554e51530e1d # v0.13.1
+
+      - name: Install k8s Kind
+        uses: helm/kind-action@9e8295d178de23cbfbd8fa16cf844eec1d773a07 # v1.3.0
+        with:
+          install_only: true
 
       - name: Install tools
         run: |
@@ -46,10 +51,6 @@ jobs:
           chmod +x ./kubectl
           sudo mv ./kubectl /usr/local/bin/kubectl
 
-          curl -fsSLo kind "https://github.com/kubernetes-sigs/kind/releases/download/v0.14.0/kind-linux-amd64"
-          chmod +x kind
-          sudo mv kind /usr/local/bin/kind
-
           ./setup.sh
 
       - name: Test
@@ -64,10 +65,10 @@ jobs:
           git diff --exit-code
 
       - name: Set up QEMU
-        uses: docker/setup-qemu-action@8b122486cedac8393e77aa9734c3528886e4a1a8 # v1.2.0
+        uses: docker/setup-qemu-action@e81a89b1732b9c48d79cd809d8d81d79c4647a18 # v2.0.0
 
       - name: Set up Docker Buildx
-        uses: docker/setup-buildx-action@dc7b9719a96d48369863986a06765841d7ea23f6 # v1.6.0
+        uses: docker/setup-buildx-action@8c0edbc76e98fa90f69d9a2c020dcb50019dc325 # v2.0.0
 
       - name: Build
         run: |
@@ -76,3 +77,38 @@ jobs:
 
           echo "Building snapshot..."
           ./build.sh
+
+  check-docs:
+    name: check-docs
+    runs-on: ubuntu-latest
+    steps:
+      - uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 # v3
+      - uses: actions/setup-go@d0a58c1c4d2b25278816e339b944508c875f3613 # v3
+        with:
+          go-version-file: './go.mod'
+          check-latest: true
+
+      - name: generate docs
+        run: |
+          go build -o ct-bin ./ct/main.go
+          ./ct-bin doc-gen
+          git_status="$(git status --porcelain)"
+          if [[ ${git_status} ]]; then
+              echo -e 'Documentation is outdated. Please update the docs\n'
+              echo "${git_status}"
+              exit 1
+          fi
+
+  golangci:
+    name: lint
+    runs-on: ubuntu-latest
+    steps:
+      - uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 # v3
+      - uses: actions/setup-go@d0a58c1c4d2b25278816e339b944508c875f3613 # v3
+        with:
+          go-version-file: './go.mod'
+          check-latest: true
+      - name: golangci-lint
+        uses: golangci/golangci-lint-action@0ad9a0988b3973e851ab0a07adf248ec2e100376 # v3
+        with:
+          version: v1.48.0
diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml
index bb1712b..7447c8b 100644
--- a/.github/workflows/release.yaml
+++ b/.github/workflows/release.yaml
@@ -17,7 +17,7 @@ jobs:
     steps:
 
       - name: checkout
-        uses: actions/checkout@2541b1294d2704b0964813337f33b291d3f8596b # v3.0.1
+        uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 # v3.0.1
         with:
           fetch-depth: 0
 
@@ -25,21 +25,21 @@ jobs:
         uses: ludeeus/action-shellcheck@94e0aab03ca135d11a35e5bfc14e6746dc56e7e9 # v1.1.0
 
       - name: Setup go
-        uses: actions/setup-go@84cbf8094393cdc5fe1fe1671ff2647332956b1a # v2.2.0
+        uses: actions/setup-go@d0a58c1c4d2b25278816e339b944508c875f3613 # v3.3.0
         with:
-          go-version: '1.18'
+          go-version-file: './go.mod'
           check-latest: true
 
       - name: Install GoReleaser
-        uses: goreleaser/goreleaser-action@68acf3b1adf004ac9c2f0a4259e85c5f66e99bef # v3.0.0
+        uses: goreleaser/goreleaser-action@b508e2e3ef3b19d4e4146d4f8fb3ba9db644a757 # v3.1.0
         with:
           install-only: true
 
       - name: Install cosign
-        uses: sigstore/cosign-installer@09a077b27eb1310dcfb21981bee195b30ce09de0 # v2.4.0
+        uses: sigstore/cosign-installer@9becc617647dfa20ae7b1151972e9b3a2c338a2b # v2.6.0
 
       - name: Install syft
-        uses: anchore/sbom-action/download-syft@bb716408e75840bbb01e839347cd213767269d4a # v0.11.0
+        uses: anchore/sbom-action/download-syft@06e109483e6aa305a2b2395eabae554e51530e1d # v0.13.1
 
       - name: Install tools
         run: |
@@ -53,13 +53,13 @@ jobs:
           git diff --exit-code
 
       - name: Set up QEMU
-        uses: docker/setup-qemu-action@8b122486cedac8393e77aa9734c3528886e4a1a8 # v1.2.0
+        uses: docker/setup-qemu-action@e81a89b1732b9c48d79cd809d8d81d79c4647a18 # v2.0.0
 
       - name: Set up Docker Buildx
-        uses: docker/setup-buildx-action@dc7b9719a96d48369863986a06765841d7ea23f6 # v1.6.0
+        uses: docker/setup-buildx-action@8c0edbc76e98fa90f69d9a2c020dcb50019dc325 # v2.0.0
 
       - name: Login to registry
-        uses: docker/login-action@49ed152c8eca782a232dede0303416e8f356c37b # v1.14.1
+        uses: docker/login-action@f4ef78c080cd8ba55a85445d5b36e214a81df20a # v2.0.0
         with:
           registry: quay.io
           username: ${{ secrets.DOCKER_USERNAME }}
diff --git a/.gitignore b/.gitignore
index f021794..2da204f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -5,3 +5,4 @@
 /dist
 /config.*
 vendor
+/ct-bin
diff --git a/.golangci.yml b/.golangci.yml
new file mode 100644
index 0000000..866db00
--- /dev/null
+++ b/.golangci.yml
@@ -0,0 +1,31 @@
+linters:
+  enable:
+  - asciicheck
+  - deadcode
+  - depguard
+  - errcheck
+  - errorlint
+  - gofmt
+  - goimports
+  - gosec
+  - gocritic
+  - importas
+  - prealloc
+  - revive
+  - misspell
+  - stylecheck
+  - unconvert
+  - whitespace
+output:
+  uniq-by-line: false
+issues:
+  exclude-rules:
+  - path: _test\.go
+    linters:
+    - errcheck
+    - gosec
+  max-issues-per-linter: 0
+  max-same-issues: 0
+run:
+  issues-exit-code: 1
+  timeout: 10m
diff --git a/Dockerfile b/Dockerfile
index 59be87c..8fc4558 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,4 +1,4 @@
-FROM alpine:3.16
+FROM alpine:3.17
 
 RUN apk --no-cache add \
     bash \
@@ -23,14 +23,14 @@ RUN pip install "yamale==$yamale_version"
 
 ARG TARGETPLATFORM
 # Install kubectl
-ARG kubectl_version=v1.24.3
+ARG kubectl_version=v1.24.6
 LABEL kubectl_version=$kubectl_version
 RUN curl -LO "https://storage.googleapis.com/kubernetes-release/release/$kubectl_version/bin/$TARGETPLATFORM/kubectl" && \
     chmod +x kubectl && \
     mv kubectl /usr/local/bin/
 
 # Install Helm
-ARG helm_version=v3.9.2
+ARG helm_version=v3.10.0
 LABEL helm_version=$helm_version
 RUN targetArch=$(echo $TARGETPLATFORM | cut -f2 -d '/') \
     && if [ ${targetArch} = "amd64" ]; then \
diff --git a/README.md b/README.md
index 63dcf9f..fdb7809 100644
--- a/README.md
+++ b/README.md
@@ -70,7 +70,7 @@ The following order of precedence applies:
 1. Config file
 
 Note that linting requires config file for [yamllint](https://github.com/adrienverge/yamllint) and [yamale](https://github.com/23andMe/Yamale).
-If not specified, these files are search in the current directory, `$HOME/.ct`, and `/etc/ct`, in that order.
+If not specified, these files are search in the current directory, the `.ct` directory in current directory, `$HOME/.ct`, and `/etc/ct`, in that order.
 Samples are provided in the [etc](etc) folder.
 
 ### Examples
diff --git a/ct/cmd/install.go b/ct/cmd/install.go
index 12e76b5..0fb5d0f 100644
--- a/ct/cmd/install.go
+++ b/ct/cmd/install.go
@@ -80,6 +80,8 @@ func addInstallFlags(flags *flag.FlagSet) {
 	flags.String("helm-extra-set-args", "", heredoc.Doc(`
 		Additional arguments for Helm. Must be passed as a single quoted string
 		(e.g. "--set=name=value"`))
+	flags.Bool("skip-clean-up", false, heredoc.Doc(`
+		Skip resources clean-up. Used if need to continue other flows or keep it around.`))
 }
 
 func install(cmd *cobra.Command, args []string) error {
@@ -91,7 +93,7 @@ func install(cmd *cobra.Command, args []string) error {
 	}
 	configuration, err := config.LoadConfiguration(cfgFile, cmd, printConfig)
 	if err != nil {
-		return fmt.Errorf("Error loading configuration: %s", err)
+		return fmt.Errorf("failed loading configuration: %w", err)
 	}
 
 	extraSetArgs, err := cmd.Flags().GetString("helm-extra-set-args")
@@ -106,7 +108,7 @@ func install(cmd *cobra.Command, args []string) error {
 	testing.PrintResults(results)
 
 	if err != nil {
-		return fmt.Errorf("Error installing charts: %s", err)
+		return fmt.Errorf("failed installing charts: %w", err)
 	}
 
 	fmt.Println("All charts installed successfully")
diff --git a/ct/cmd/lint.go b/ct/cmd/lint.go
index 2656a4a..dd36f0f 100644
--- a/ct/cmd/lint.go
+++ b/ct/cmd/lint.go
@@ -85,7 +85,7 @@ func lint(cmd *cobra.Command, args []string) error {
 	}
 	configuration, err := config.LoadConfiguration(cfgFile, cmd, printConfig)
 	if err != nil {
-		return fmt.Errorf("Error loading configuration: %s", err)
+		return fmt.Errorf("failed loading configuration: %w", err)
 	}
 
 	emptyExtraSetArgs := ""
@@ -97,7 +97,7 @@ func lint(cmd *cobra.Command, args []string) error {
 	testing.PrintResults(results)
 
 	if err != nil {
-		return fmt.Errorf("Error linting charts: %s", err)
+		return fmt.Errorf("failed linting charts: %w", err)
 	}
 
 	fmt.Println("All charts linted successfully")
diff --git a/ct/cmd/lintAndInstall.go b/ct/cmd/lintAndInstall.go
index 0ec6238..c42a649 100644
--- a/ct/cmd/lintAndInstall.go
+++ b/ct/cmd/lintAndInstall.go
@@ -48,7 +48,7 @@ func lintAndInstall(cmd *cobra.Command, args []string) error {
 	}
 	configuration, err := config.LoadConfiguration(cfgFile, cmd, printConfig)
 	if err != nil {
-		return fmt.Errorf("Error loading configuration: %s", err)
+		return fmt.Errorf("failed loading configuration: %w", err)
 	}
 
 	extraSetArgs, err := cmd.Flags().GetString("helm-extra-set-args")
@@ -63,7 +63,7 @@ func lintAndInstall(cmd *cobra.Command, args []string) error {
 	testing.PrintResults(results)
 
 	if err != nil {
-		return fmt.Errorf("Error linting and installing charts: %s", err)
+		return fmt.Errorf("failed linting and installing charts: %w", err)
 	}
 
 	fmt.Println("All charts linted and installed successfully")
diff --git a/ct/cmd/listChanged.go b/ct/cmd/listChanged.go
index 4c286e3..412f7c1 100644
--- a/ct/cmd/listChanged.go
+++ b/ct/cmd/listChanged.go
@@ -47,7 +47,7 @@ func listChanged(cmd *cobra.Command, args []string) error {
 	}
 	configuration, err := config.LoadConfiguration(cfgFile, cmd, printConfig)
 	if err != nil {
-		return fmt.Errorf("Error loading configuration: %s", err)
+		return fmt.Errorf("failed loading configuration: %w", err)
 	}
 
 	emptyExtraSetArgs := ""
@@ -63,5 +63,6 @@ func listChanged(cmd *cobra.Command, args []string) error {
 	for _, dir := range chartDirs {
 		fmt.Println(dir)
 	}
+
 	return nil
 }
diff --git a/ct/cmd/root.go b/ct/cmd/root.go
index c792c81..ea69004 100644
--- a/ct/cmd/root.go
+++ b/ct/cmd/root.go
@@ -49,6 +49,8 @@ func NewRootCmd() *cobra.Command {
 	cmd.AddCommand(newVersionCmd())
 	cmd.AddCommand(newGenerateDocsCmd())
 
+	cmd.DisableAutoGenTag = true
+
 	return cmd
 }
 
diff --git a/doc/ct.md b/doc/ct.md
index 3a307c0..375b140 100644
--- a/doc/ct.md
+++ b/doc/ct.md
@@ -26,4 +26,3 @@ in given chart directories.
 * [ct list-changed](ct_list-changed.md)	 - List changed charts
 * [ct version](ct_version.md)	 - Print version information
 
-###### Auto generated by spf13/cobra on 23-Mar-2022
diff --git a/doc/ct_install.md b/doc/ct_install.md
index 9263a69..b534c47 100644
--- a/doc/ct_install.md
+++ b/doc/ct_install.md
@@ -66,6 +66,7 @@ ct install [flags]
                                              This is only used if namespace is specified (default "app.kubernetes.io/instance")
       --remote string                        The name of the Git remote used to identify changed charts (default "origin")
       --since string                         The Git reference used to identify changed charts (default "HEAD")
+      --skip-clean-up                        Skip resources clean-up. Used if need to continue other flows or keep it around.
       --skip-missing-values                  When --upgrade has been passed, this flag will skip testing CI values files from the
                                              previous chart revision if they have been deleted or renamed at the current chart
                                              revision
@@ -78,4 +79,3 @@ ct install [flags]
 
 * [ct](ct.md)	 - The Helm chart testing tool
 
-###### Auto generated by spf13/cobra on 23-Mar-2022
diff --git a/doc/ct_lint-and-install.md b/doc/ct_lint-and-install.md
index 4793194..ae8808d 100644
--- a/doc/ct_lint-and-install.md
+++ b/doc/ct_lint-and-install.md
@@ -61,6 +61,7 @@ ct lint-and-install [flags]
                                              This is only used if namespace is specified (default "app.kubernetes.io/instance")
       --remote string                        The name of the Git remote used to identify changed charts (default "origin")
       --since string                         The Git reference used to identify changed charts (default "HEAD")
+      --skip-clean-up                        Skip resources clean-up. Used if need to continue other flows or keep it around.
       --skip-missing-values                  When --upgrade has been passed, this flag will skip testing CI values files from the
                                              previous chart revision if they have been deleted or renamed at the current chart
                                              revision
@@ -77,4 +78,3 @@ ct lint-and-install [flags]
 
 * [ct](ct.md)	 - The Helm chart testing tool
 
-###### Auto generated by spf13/cobra on 23-Mar-2022
diff --git a/doc/ct_lint.md b/doc/ct_lint.md
index 3b5fa3d..c7e5519 100644
--- a/doc/ct_lint.md
+++ b/doc/ct_lint.md
@@ -74,4 +74,3 @@ ct lint [flags]
 
 * [ct](ct.md)	 - The Helm chart testing tool
 
-###### Auto generated by spf13/cobra on 23-Mar-2022
diff --git a/doc/ct_list-changed.md b/doc/ct_list-changed.md
index 87c8442..3fa32c0 100644
--- a/doc/ct_list-changed.md
+++ b/doc/ct_list-changed.md
@@ -32,4 +32,3 @@ ct list-changed [flags]
 
 * [ct](ct.md)	 - The Helm chart testing tool
 
-###### Auto generated by spf13/cobra on 23-Mar-2022
diff --git a/doc/ct_version.md b/doc/ct_version.md
index 409e64e..7e5fc71 100644
--- a/doc/ct_version.md
+++ b/doc/ct_version.md
@@ -16,4 +16,3 @@ ct version [flags]
 
 * [ct](ct.md)	 - The Helm chart testing tool
 
-###### Auto generated by spf13/cobra on 23-Mar-2022
diff --git a/go.mod b/go.mod
index c6f3c81..21ba508 100644
--- a/go.mod
+++ b/go.mod
@@ -1,6 +1,6 @@
 module github.com/helm/chart-testing/v3
 
-go 1.18
+go 1.19
 
 require (
 	github.com/MakeNowJust/heredoc v1.0.0
@@ -9,37 +9,36 @@ require (
 	github.com/hashicorp/go-retryablehttp v0.7.1
 	github.com/mattn/go-shellwords v1.0.12
 	github.com/mitchellh/go-homedir v1.1.0
-	github.com/pkg/errors v0.9.1
-	github.com/spf13/cobra v1.5.0
+	github.com/spf13/cobra v1.6.1
 	github.com/spf13/pflag v1.0.5
-	github.com/spf13/viper v1.12.0
-	github.com/stretchr/testify v1.8.0
+	github.com/spf13/viper v1.14.0
+	github.com/stretchr/testify v1.8.1
 	gopkg.in/yaml.v2 v2.4.0
 )
 
 require (
 	github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect
 	github.com/davecgh/go-spew v1.1.1 // indirect
-	github.com/fsnotify/fsnotify v1.5.4 // indirect
+	github.com/fsnotify/fsnotify v1.6.0 // indirect
 	github.com/hashicorp/errwrap v1.1.0 // indirect
 	github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
 	github.com/hashicorp/hcl v1.0.0 // indirect
-	github.com/inconshreveable/mousetrap v1.0.0 // indirect
+	github.com/inconshreveable/mousetrap v1.0.1 // indirect
 	github.com/magiconair/properties v1.8.6 // indirect
 	github.com/mitchellh/mapstructure v1.5.0 // indirect
 	github.com/pelletier/go-toml v1.9.5 // indirect
-	github.com/pelletier/go-toml/v2 v2.0.2 // indirect
+	github.com/pelletier/go-toml/v2 v2.0.5 // indirect
 	github.com/pmezard/go-difflib v1.0.0 // indirect
 	github.com/rogpeppe/go-internal v1.8.0 // indirect
 	github.com/russross/blackfriday/v2 v2.1.0 // indirect
 	github.com/spf13/afero v1.9.2 // indirect
 	github.com/spf13/cast v1.5.0 // indirect
 	github.com/spf13/jwalterweatherman v1.1.0 // indirect
-	github.com/stretchr/objx v0.4.0 // indirect
-	github.com/subosito/gotenv v1.4.0 // indirect
-	golang.org/x/sys v0.0.0-20220727055044-e65921a090b8 // indirect
-	golang.org/x/text v0.3.7 // indirect
+	github.com/stretchr/objx v0.5.0 // indirect
+	github.com/subosito/gotenv v1.4.1 // indirect
+	golang.org/x/sys v0.0.0-20220908164124-27713097b956 // indirect
+	golang.org/x/text v0.4.0 // indirect
 	gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
-	gopkg.in/ini.v1 v1.66.6 // indirect
+	gopkg.in/ini.v1 v1.67.0 // indirect
 	gopkg.in/yaml.v3 v3.0.1 // indirect
 )
diff --git a/go.sum b/go.sum
index 9be4071..1ffee2b 100644
--- a/go.sum
+++ b/go.sum
@@ -63,8 +63,8 @@ github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.m
 github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
 github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w=
 github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE=
-github.com/fsnotify/fsnotify v1.5.4 h1:jRbGcIw6P2Meqdwuo0H1p6JVLbL5DHKAKlYndzMwVZI=
-github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU=
+github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
+github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
 github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
 github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
 github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
@@ -104,7 +104,7 @@ github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
 github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg=
+github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
 github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
 github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
 github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
@@ -141,8 +141,8 @@ github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
 github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
 github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
 github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
-github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
-github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
+github.com/inconshreveable/mousetrap v1.0.1 h1:U3uMjPSQEBMNp1lFxmllqCPM6P5u/Xq7Pgzkat/bFNc=
+github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
 github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
 github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
 github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
@@ -165,10 +165,9 @@ github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyua
 github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
 github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8=
 github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
-github.com/pelletier/go-toml/v2 v2.0.2 h1:+jQXlF3scKIcSEKkdHzXhCTDLPFi5r1wnK6yPS+49Gw=
-github.com/pelletier/go-toml/v2 v2.0.2/go.mod h1:MovirKjgVRESsAvNZlAjtFwV867yGuwRkXbG66OzopI=
+github.com/pelletier/go-toml/v2 v2.0.5 h1:ipoSadvV8oGUjnUbMub59IDPPwfxF694nG/jwbMiyQg=
+github.com/pelletier/go-toml/v2 v2.0.5/go.mod h1:OMHamSCAODeSsVrwwvcJOaoN0LIUIaFVNZzmWyNfXas=
 github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
-github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
 github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
 github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg=
 github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
@@ -183,27 +182,28 @@ github.com/spf13/afero v1.9.2 h1:j49Hj62F0n+DaZ1dDCvhABaPNSGNkt32oRFxI33IEMw=
 github.com/spf13/afero v1.9.2/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y=
 github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w=
 github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU=
-github.com/spf13/cobra v1.5.0 h1:X+jTBEBqF0bHN+9cSMgmfuvv2VHJ9ezmFNf9Y/XstYU=
-github.com/spf13/cobra v1.5.0/go.mod h1:dWXEIy2H428czQCjInthrTRUg7yKbok+2Qi/yBIJoUM=
+github.com/spf13/cobra v1.6.1 h1:o94oiPyS4KD1mPy2fmcYYHHfCxLqYjJOhGsCHFZtEzA=
+github.com/spf13/cobra v1.6.1/go.mod h1:IOw/AERYS7UzyrGinqmz6HLUo219MORXGxhbaJUqzrY=
 github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk=
 github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo=
 github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
 github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
-github.com/spf13/viper v1.12.0 h1:CZ7eSOd3kZoaYDLbXnmzgQI5RlciuXBMA+18HwHRfZQ=
-github.com/spf13/viper v1.12.0/go.mod h1:b6COn30jlNxbm/V2IqWiNWkJ+vZNiMNksliPCiuKtSI=
+github.com/spf13/viper v1.14.0 h1:Rg7d3Lo706X9tHsJMUjdiwMpHB7W8WnSVOssIY+JElU=
+github.com/spf13/viper v1.14.0/go.mod h1:WT//axPky3FdvXHzGw33dNdXXXfFQqmEalje+egj8As=
 github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
-github.com/stretchr/objx v0.4.0 h1:M2gUjqZET1qApGOWNSnZ49BAIMX4F/1plDv3+l31EJ4=
 github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
+github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c=
+github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
 github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
 github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
 github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
 github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
 github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
-github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals=
-github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
 github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
-github.com/subosito/gotenv v1.4.0 h1:yAzM1+SmVcz5R4tXGsNMu1jUl2aOJXoiWUCEwwnGrvs=
-github.com/subosito/gotenv v1.4.0/go.mod h1:mZd6rFysKEcUhUHXJk0C/08wAgyDBFuwEYL7vWWGaGo=
+github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
+github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
+github.com/subosito/gotenv v1.4.1 h1:jyEFiXpy21Wm81FBN71l9VoMMV8H8jG+qIK3GCpY6Qs=
+github.com/subosito/gotenv v1.4.1/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0=
 github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
 github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
 github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
@@ -338,9 +338,8 @@ golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7w
 golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20220727055044-e65921a090b8 h1:dyU22nBWzrmTQxtNrr4dzVOvaw35nUYE279vF9UmsI8=
-golang.org/x/sys v0.0.0-20220727055044-e65921a090b8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220908164124-27713097b956 h1:XeJjHH1KiLpKGb6lvMiksZ9l0fVUh+AmGcm0nOMEBOY=
+golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
 golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@@ -348,8 +347,8 @@ golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3
 golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
 golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
 golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
-golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
-golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
+golang.org/x/text v0.4.0 h1:BrVqGRd7+k1DiOgtnFvAkoQEWQvBc25ouMJM6429SFg=
+golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
 golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
 golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
 golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
@@ -497,8 +496,8 @@ gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8
 gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
 gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
 gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
-gopkg.in/ini.v1 v1.66.6 h1:LATuAqN/shcYAOkv3wl2L4rkaKqkcgTBQjOyYDvcPKI=
-gopkg.in/ini.v1 v1.66.6/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
+gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
+gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
 gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
 gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
diff --git a/pkg/chart/chart.go b/pkg/chart/chart.go
index c66c8e0..ac575d9 100644
--- a/pkg/chart/chart.go
+++ b/pkg/chart/chart.go
@@ -15,8 +15,8 @@
 package chart
 
 import (
+	"errors"
 	"fmt"
-	"io/ioutil"
 	"os"
 	"path/filepath"
 	"strings"
@@ -27,7 +27,6 @@ import (
 	"github.com/helm/chart-testing/v3/pkg/exec"
 	"github.com/helm/chart-testing/v3/pkg/tool"
 	"github.com/helm/chart-testing/v3/pkg/util"
-	"github.com/pkg/errors"
 )
 
 const maxNameLength = 63
@@ -46,7 +45,7 @@ const maxNameLength = 63
 //
 // ListChangedFilesInDirs diffs commit against HEAD and returns changed files for the specified dirs.
 //
-// GetUrlForRemote returns the repo URL for the specified remote.
+// GetURLForRemote returns the repo URL for the specified remote.
 //
 // ValidateRepository checks that the current working directory is a valid git repository,
 // and returns nil if valid.
@@ -57,17 +56,17 @@ type Git interface {
 	RemoveWorktree(path string) error
 	MergeBase(commit1 string, commit2 string) (string, error)
 	ListChangedFilesInDirs(commit string, dirs ...string) ([]string, error)
-	GetUrlForRemote(remote string) (string, error)
+	GetURLForRemote(remote string) (string, error)
 	ValidateRepository() error
 }
 
 // Helm is the interface that wraps Helm operations
 //
-// AddRepo adds a chart repository to the local Helm configuration
+// # AddRepo adds a chart repository to the local Helm configuration
 //
-// BuildDependencies builds the chart's dependencies
+// # BuildDependencies builds the chart's dependencies
 //
-// BuildDependenciesWithArgs allows passing additional arguments to BuildDependencies
+// # BuildDependenciesWithArgs allows passing additional arguments to BuildDependencies
 //
 // LintWithValues runs `helm lint` for the given chart using the specified values file.
 // Pass a zero value for valuesFile in order to run lint without specifying a values file.
@@ -95,21 +94,21 @@ type Helm interface {
 
 // Kubectl is the interface that wraps kubectl operations
 //
-// DeleteNamespace deletes a namespace
+// # DeleteNamespace deletes a namespace
 //
-// WaitForDeployments waits for a deployment to become ready
+// # WaitForDeployments waits for a deployment to become ready
 //
-// GetPodsforDeployment gets all pods for a deployment
+// # GetPodsforDeployment gets all pods for a deployment
 //
-// GetPods gets pods for the given args
+// # GetPods gets pods for the given args
 //
-// GetEvents prints all events for namespace
+// # GetEvents prints all events for namespace
 //
-// DescribePod prints the pod's description
+// # DescribePod prints the pod's description
 //
-// Logs prints the logs of container
+// # Logs prints the logs of container
 //
-// GetInitContainers gets all init containers of pod
+// # GetInitContainers gets all init containers of pod
 //
 // GetContainers gets all containers of pod
 type Kubectl interface {
@@ -127,7 +126,7 @@ type Kubectl interface {
 
 // Linter is the interface that wrap linting operations
 //
-// YamlLint runs `yamllint` on the specified file with the specified configuration
+// # YamlLint runs `yamllint` on the specified file with the specified configuration
 //
 // Yamale runs `yamale` on the specified file with the specified schema file
 type Linter interface {
@@ -149,10 +148,10 @@ type DirectoryLister interface {
 	ListChildDirs(parentDir string, test func(string) bool) ([]string, error)
 }
 
-// ChartUtils is the interface that wraps chart-related methods
+// Utils is the interface that wraps chart-related methods
 //
 // LookupChartDir looks up the chart's root directory based on some chart file that has changed
-type ChartUtils interface {
+type Utils interface {
 	LookupChartDir(chartDirs []string, dir string) (string, error)
 }
 
@@ -238,7 +237,7 @@ type Testing struct {
 	cmdExecutor              CmdExecutor
 	accountValidator         AccountValidator
 	directoryLister          DirectoryLister
-	chartUtils               ChartUtils
+	utils                    Utils
 	previousRevisionWorktree string
 }
 
@@ -268,7 +267,7 @@ func NewTesting(config config.Configuration, extraSetArgs string) (Testing, erro
 		cmdExecutor:      tool.NewCmdTemplateExecutor(procExec),
 		accountValidator: tool.AccountValidator{},
 		directoryLister:  util.DirectoryLister{},
-		chartUtils:       util.ChartUtils{},
+		utils:            util.Utils{},
 	}
 
 	versionString, err := testing.helm.Version()
@@ -294,10 +293,10 @@ func (t *Testing) computePreviousRevisionPath(fileOrDirPath string) string {
 }
 
 func (t *Testing) processCharts(action func(chart *Chart) TestResult) ([]TestResult, error) {
-	var results []TestResult
+	var results []TestResult // nolint: prealloc
 	chartDirs, err := t.FindChartDirsToBeProcessed()
 	if err != nil {
-		return nil, errors.Wrap(err, "Error identifying charts to process")
+		return nil, fmt.Errorf("failed identifying charts to process: %w", err)
 	} else if len(chartDirs) == 0 {
 		return results, nil
 	}
@@ -310,20 +309,20 @@ func (t *Testing) processCharts(action func(chart *Chart) TestResult) ([]TestRes
 		}
 
 		if t.config.ExcludeDeprecated && chart.yaml.Deprecated {
-			fmt.Printf("Chart '%s' is deprecated and will be ignored because '--exclude-deprecated' is set\n", chart.String())
+			fmt.Printf("Chart %q is deprecated and will be ignored because '--exclude-deprecated' is set\n", chart.String())
 		} else {
 			charts = append(charts, chart)
 		}
 	}
 
 	fmt.Println()
-	util.PrintDelimiterLine("-")
+	util.PrintDelimiterLineToWriter(os.Stdout, "-")
 	fmt.Println(" Charts to be processed:")
-	util.PrintDelimiterLine("-")
+	util.PrintDelimiterLineToWriter(os.Stdout, "-")
 	for _, chart := range charts {
 		fmt.Printf(" %s\n", chart)
 	}
-	util.PrintDelimiterLine("-")
+	util.PrintDelimiterLineToWriter(os.Stdout, "-")
 	fmt.Println()
 
 	repoArgs := map[string][]string{}
@@ -342,7 +341,7 @@ func (t *Testing) processCharts(action func(chart *Chart) TestResult) ([]TestRes
 
 		repoExtraArgs := repoArgs[name]
 		if err := t.helm.AddRepo(name, url, repoExtraArgs); err != nil {
-			return nil, errors.Wrapf(err, "Error adding repo: %s=%s", name, url)
+			return nil, fmt.Errorf("failed adding repo: %s=%s: %w", name, url, err)
 		}
 	}
 
@@ -355,31 +354,31 @@ func (t *Testing) processCharts(action func(chart *Chart) TestResult) ([]TestRes
 	if t.config.Upgrade {
 		mergeBase, err := t.computeMergeBase()
 		if err != nil {
-			return results, errors.Wrap(err, "Error identifying merge base")
+			return results, fmt.Errorf("failed identifying merge base: %w", err)
 		}
 		// Add worktree for the target revision
-		worktreePath, err := ioutil.TempDir("./", "ct_previous_revision")
+		worktreePath, err := os.MkdirTemp("./", "ct_previous_revision")
 		if err != nil {
-			return results, errors.Wrap(err, "Could not create previous revision directory")
+			return results, fmt.Errorf("could not create previous revision directory: %w", err)
 		}
 		t.previousRevisionWorktree = worktreePath
 		err = t.git.AddWorktree(worktreePath, mergeBase)
 		if err != nil {
-			return results, errors.Wrap(err, "Could not create worktree for previous revision")
+			return results, fmt.Errorf("could not create worktree for previous revision: %w", err)
 		}
-		defer t.git.RemoveWorktree(worktreePath)
+		defer t.git.RemoveWorktree(worktreePath) // nolint: errcheck
 
 		for _, chart := range charts {
 			if err := t.helm.BuildDependenciesWithArgs(t.computePreviousRevisionPath(chart.Path()), t.config.HelmDependencyExtraArgs); err != nil {
 				// Only print error (don't exit) if building dependencies for previous revision fails.
-				fmt.Println(errors.Wrapf(err, "Error building dependencies for previous revision of chart '%s'\n", chart))
+				fmt.Printf("failed building dependencies for previous revision of chart %q: %v\n", chart, err.Error())
 			}
 		}
 	}
 
 	for _, chart := range charts {
 		if err := t.helm.BuildDependenciesWithArgs(chart.Path(), t.config.HelmDependencyExtraArgs); err != nil {
-			return nil, errors.Wrapf(err, "Error building dependencies for chart '%s'", chart)
+			return nil, fmt.Errorf("failed building dependencies for chart %q: %w", chart, err)
 		}
 
 		result := action(chart)
@@ -392,7 +391,7 @@ func (t *Testing) processCharts(action func(chart *Chart) TestResult) ([]TestRes
 		return results, nil
 	}
 
-	return results, errors.New("Error processing charts")
+	return results, fmt.Errorf("failed processing charts")
 }
 
 // LintCharts lints charts (changed, all, specific) depending on the configuration.
@@ -412,7 +411,7 @@ func (t *Testing) LintAndInstallCharts() ([]TestResult, error) {
 
 // PrintResults writes test results to stdout.
 func (t *Testing) PrintResults(results []TestResult) {
-	util.PrintDelimiterLine("-")
+	util.PrintDelimiterLineToWriter(os.Stdout, "-")
 	if results != nil {
 		for _, result := range results {
 			err := result.Error
@@ -425,12 +424,12 @@ func (t *Testing) PrintResults(results []TestResult) {
 	} else {
 		fmt.Println("No chart changes detected.")
 	}
-	util.PrintDelimiterLine("-")
+	util.PrintDelimiterLineToWriter(os.Stdout, "-")
 }
 
 // LintChart lints the specified chart.
 func (t *Testing) LintChart(chart *Chart) TestResult {
-	fmt.Printf("Linting chart '%s'\n", chart)
+	fmt.Printf("Linting chart %q\n", chart)
 
 	result := TestResult{Chart: chart}
 
@@ -483,7 +482,7 @@ func (t *Testing) LintChart(chart *Chart) TestResult {
 
 	for _, valuesFile := range valuesFiles {
 		if valuesFile != "" {
-			fmt.Printf("\nLinting chart with values file '%s'...\n\n", valuesFile)
+			fmt.Printf("\nLinting chart with values file %q...\n\n", valuesFile)
 		}
 		if err := t.helm.LintWithValues(chart.Path(), valuesFile); err != nil {
 			result.Error = err
@@ -531,11 +530,11 @@ func (t *Testing) UpgradeChart(chart *Chart) TestResult {
 
 	if breakingChangeAllowed {
 		if err != nil {
-			fmt.Println(errors.Wrap(err, fmt.Sprintf("Skipping upgrade test of '%s' because", chart)))
+			fmt.Printf("Skipping upgrade test of %q because: %v\n", chart, err.Error())
 		}
 		return result
 	} else if err != nil {
-		fmt.Printf("Error comparing chart versions for '%s'\n", chart)
+		fmt.Printf("Error comparing chart versions for %q\n", chart)
 		result.Error = err
 		return result
 	}
@@ -548,7 +547,7 @@ func (t *Testing) UpgradeChart(chart *Chart) TestResult {
 }
 
 func (t *Testing) doInstall(chart *Chart) error {
-	fmt.Printf("Installing chart '%s'...\n", chart)
+	fmt.Printf("Installing chart %q...\n", chart)
 	valuesFiles := chart.ValuesFilePathsForCI()
 
 	// Test with defaults if no values files are specified.
@@ -558,14 +557,16 @@ func (t *Testing) doInstall(chart *Chart) error {
 
 	for _, valuesFile := range valuesFiles {
 		if valuesFile != "" {
-			fmt.Printf("\nInstalling chart with values file '%s'...\n\n", valuesFile)
+			fmt.Printf("\nInstalling chart with values file %q...\n\n", valuesFile)
 		}
 
 		// Use anonymous function. Otherwise deferred calls would pile up
 		// and be executed in reverse order after the loop.
 		fun := func() error {
 			namespace, release, releaseSelector, cleanup := t.generateInstallConfig(chart)
-			defer cleanup()
+			if !t.config.SkipCleanUp {
+				defer cleanup()
+			}
 
 			if t.config.Namespace == "" {
 				if err := t.kubectl.CreateNamespace(namespace); err != nil {
@@ -587,7 +588,7 @@ func (t *Testing) doInstall(chart *Chart) error {
 }
 
 func (t *Testing) doUpgrade(oldChart, newChart *Chart, oldChartMustPass bool) error {
-	fmt.Printf("Testing upgrades of chart '%s' relative to previous revision '%s'...\n", newChart, oldChart)
+	fmt.Printf("Testing upgrades of chart %q relative to previous revision %q...\n", newChart, oldChart)
 	valuesFiles := oldChart.ValuesFilePathsForCI()
 	if len(valuesFiles) == 0 {
 		valuesFiles = append(valuesFiles, "")
@@ -595,17 +596,19 @@ func (t *Testing) doUpgrade(oldChart, newChart *Chart, oldChartMustPass bool) er
 	for _, valuesFile := range valuesFiles {
 		if valuesFile != "" {
 			if t.config.SkipMissingValues && !newChart.HasCIValuesFile(valuesFile) {
-				fmt.Printf("Upgrade testing for values file '%s' skipped because a corresponding values file was not found in %s/ci", valuesFile, newChart.Path())
+				fmt.Printf("Upgrade testing for values file %q skipped because a corresponding values file was not found in %s/ci\n", valuesFile, newChart.Path())
 				continue
 			}
-			fmt.Printf("\nInstalling chart '%s' with values file '%s'...\n\n", oldChart, valuesFile)
+			fmt.Printf("\nInstalling chart %q with values file %q...\n\n", oldChart, valuesFile)
 		}
 
 		// Use anonymous function. Otherwise deferred calls would pile up
 		// and be executed in reverse order after the loop.
 		fun := func() error {
 			namespace, release, releaseSelector, cleanup := t.generateInstallConfig(oldChart)
-			defer cleanup()
+			if !t.config.SkipCleanUp {
+				defer cleanup()
+			}
 
 			if t.config.Namespace == "" {
 				if err := t.kubectl.CreateNamespace(namespace); err != nil {
@@ -617,14 +620,14 @@ func (t *Testing) doUpgrade(oldChart, newChart *Chart, oldChartMustPass bool) er
 				if oldChartMustPass {
 					return err
 				}
-				fmt.Println(errors.Wrap(err, fmt.Sprintf("Upgrade testing for release '%s' skipped because of previous revision installation error", release)))
+				fmt.Printf("Upgrade testing for release %q skipped because of previous revision installation error: %v\n", release, err.Error())
 				return nil
 			}
 			if err := t.testRelease(namespace, release, releaseSelector); err != nil {
 				if oldChartMustPass {
 					return err
 				}
-				fmt.Println(errors.Wrap(err, fmt.Sprintf("Upgrade testing for release '%s' skipped because of previous revision testing error", release)))
+				fmt.Printf("Upgrade testing for release %q skipped because of previous revision testing error: %v\n", release, err.Error())
 				return nil
 			}
 
@@ -656,14 +659,14 @@ func (t *Testing) testRelease(namespace, release, releaseSelector string) error
 func (t *Testing) generateInstallConfig(chart *Chart) (namespace, release, releaseSelector string, cleanup func()) {
 	if t.config.Namespace != "" {
 		namespace = t.config.Namespace
-		release, _ = chart.CreateInstallParams(t.config.BuildId)
+		release, _ = chart.CreateInstallParams(t.config.BuildID)
 		releaseSelector = fmt.Sprintf("%s=%s", t.config.ReleaseLabel, release)
 		cleanup = func() {
 			t.PrintEventsPodDetailsAndLogs(namespace, releaseSelector)
 			t.helm.DeleteRelease(namespace, release)
 		}
 	} else {
-		release, namespace = chart.CreateInstallParams(t.config.BuildId)
+		release, namespace = chart.CreateInstallParams(t.config.BuildID)
 		cleanup = func() {
 			t.PrintEventsPodDetailsAndLogs(namespace, releaseSelector)
 			t.helm.DeleteRelease(namespace, release)
@@ -698,7 +701,7 @@ func (t *Testing) FindChartDirsToBeProcessed() ([]string, error) {
 func (t *Testing) computeMergeBase() (string, error) {
 	err := t.git.ValidateRepository()
 	if err != nil {
-		return "", errors.New("Must be in a git repository")
+		return "", errors.New("must be in a git repository")
 	}
 	return t.git.MergeBase(fmt.Sprintf("%s/%s", t.config.Remote, t.config.TargetBranch), t.config.Since)
 }
@@ -715,7 +718,7 @@ func (t *Testing) ComputeChangedChartDirectories() ([]string, error) {
 
 	allChangedChartFiles, err := t.git.ListChangedFilesInDirs(mergeBase, cfg.ChartDirs...)
 	if err != nil {
-		return nil, errors.Wrap(err, "Error creating diff")
+		return nil, fmt.Errorf("failed creating diff: %w", err)
 	}
 
 	var changedChartDirs []string
@@ -726,7 +729,7 @@ func (t *Testing) ComputeChangedChartDirectories() ([]string, error) {
 		}
 		dir := filepath.Dir(file)
 		// Make sure directory is really a chart directory
-		chartDir, err := t.chartUtils.LookupChartDir(cfg.ChartDirs, dir)
+		chartDir, err := t.utils.LookupChartDir(cfg.ChartDirs, dir)
 		chartDirElement := strings.Split(chartDir, "/")
 		if err == nil {
 			if len(chartDirElement) > 1 {
@@ -740,7 +743,7 @@ func (t *Testing) ComputeChangedChartDirectories() ([]string, error) {
 				changedChartDirs = append(changedChartDirs, chartDir)
 			}
 		} else {
-			fmt.Fprintf(os.Stderr, "Directory '%s' is not a valid chart directory. Skipping...\n", dir)
+			fmt.Fprintf(os.Stderr, "Directory %q is not a valid chart directory. Skipping...\n", dir)
 		}
 	}
 
@@ -756,11 +759,11 @@ func (t *Testing) ReadAllChartDirectories() ([]string, error) {
 	for _, chartParentDir := range cfg.ChartDirs {
 		dirs, err := t.directoryLister.ListChildDirs(chartParentDir,
 			func(dir string) bool {
-				_, err := t.chartUtils.LookupChartDir(cfg.ChartDirs, dir)
+				_, err := t.utils.LookupChartDir(cfg.ChartDirs, dir)
 				return err == nil && !util.StringSliceContains(cfg.ExcludedCharts, filepath.Base(dir))
 			})
 		if err != nil {
-			return nil, errors.Wrap(err, "Error reading chart directories")
+			return nil, fmt.Errorf("failed reading chart directories: %w", err)
 		}
 		chartDirs = append(chartDirs, dirs...)
 	}
@@ -770,7 +773,7 @@ func (t *Testing) ReadAllChartDirectories() ([]string, error) {
 
 // CheckVersionIncrement checks that the new chart version is greater than the old one using semantic version comparison.
 func (t *Testing) CheckVersionIncrement(chart *Chart) error {
-	fmt.Printf("Checking chart '%s' for a version bump...\n", chart)
+	fmt.Printf("Checking chart %q for a version bump...\n", chart)
 
 	oldVersion, err := t.GetOldChartVersion(chart.Path())
 	if err != nil {
@@ -793,7 +796,7 @@ func (t *Testing) CheckVersionIncrement(chart *Chart) error {
 	}
 
 	if result >= 0 {
-		return errors.New("Chart version not ok. Needs a version bump!")
+		return errors.New("chart version not ok. Needs a version bump! ")
 	}
 
 	fmt.Println("Chart version ok.")
@@ -827,12 +830,12 @@ func (t *Testing) GetOldChartVersion(chartPath string) (string, error) {
 
 	chartYamlContents, err := t.git.Show(chartYamlFile, cfg.Remote, cfg.TargetBranch)
 	if err != nil {
-		return "", errors.Wrap(err, "Error reading old Chart.yaml")
+		return "", fmt.Errorf("failed reading old Chart.yaml: %w", err)
 	}
 
 	chartYaml, err := util.UnmarshalChartYaml([]byte(chartYamlContents))
 	if err != nil {
-		return "", errors.Wrap(err, "Error reading old chart version")
+		return "", fmt.Errorf("failed reading old chart version: %w", err)
 	}
 
 	return chartYaml.Version, nil
@@ -847,22 +850,22 @@ func (t *Testing) ValidateMaintainers(chart *Chart) error {
 
 	if chartYaml.Deprecated {
 		if len(chartYaml.Maintainers) > 0 {
-			return errors.New("Deprecated chart must not have maintainers")
+			return errors.New("deprecated chart must not have maintainers")
 		}
 		return nil
 	}
 
 	if len(chartYaml.Maintainers) == 0 {
-		return errors.New("Chart doesn't have maintainers")
+		return errors.New("chart doesn't have maintainers")
 	}
 
-	repoUrl, err := t.git.GetUrlForRemote(t.config.Remote)
+	repoURL, err := t.git.GetURLForRemote(t.config.Remote)
 	if err != nil {
 		return err
 	}
 
 	for _, maintainer := range chartYaml.Maintainers {
-		if err := t.accountValidator.Validate(repoUrl, maintainer.Name); err != nil {
+		if err := t.accountValidator.Validate(repoURL, maintainer.Name); err != nil {
 			return err
 		}
 	}
@@ -871,7 +874,7 @@ func (t *Testing) ValidateMaintainers(chart *Chart) error {
 }
 
 func (t *Testing) PrintEventsPodDetailsAndLogs(namespace string, selector string) {
-	util.PrintDelimiterLine("=")
+	util.PrintDelimiterLineToWriter(os.Stdout, "=")
 
 	printDetails(namespace, "Events of namespace", ".", func(item string) error {
 		return t.kubectl.GetEvents(namespace)
@@ -902,42 +905,44 @@ func (t *Testing) PrintEventsPodDetailsAndLogs(namespace string, selector string
 			return
 		}
 
-		printDetails(pod, "Logs of init container", "-",
-			func(item string) error {
-				return t.kubectl.Logs(namespace, pod, item)
-			}, initContainers...)
+		if t.config.PrintLogs {
+			printDetails(pod, "Logs of init container", "-",
+				func(item string) error {
+					return t.kubectl.Logs(namespace, pod, item)
+				}, initContainers...)
 
-		containers, err := t.kubectl.GetContainers(namespace, pod)
-		if err != nil {
-			fmt.Println("Error printing logs:", err)
-			return
-		}
+			containers, err := t.kubectl.GetContainers(namespace, pod)
+			if err != nil {
+				fmt.Printf("failed printing logs: %v\n", err.Error())
+				return
+			}
 
-		printDetails(pod, "Logs of container", "-",
-			func(item string) error {
-				return t.kubectl.Logs(namespace, pod, item)
-			},
-			containers...)
+			printDetails(pod, "Logs of container", "-",
+				func(item string) error {
+					return t.kubectl.Logs(namespace, pod, item)
+				},
+				containers...)
+		}
 	}
 
-	util.PrintDelimiterLine("=")
+	util.PrintDelimiterLineToWriter(os.Stdout, "=")
 }
 
 func printDetails(resource string, text string, delimiterChar string, printFunc func(item string) error, items ...string) {
 	for _, item := range items {
 		item = strings.Trim(item, "'")
 
-		util.PrintDelimiterLine(delimiterChar)
+		util.PrintDelimiterLineToWriter(os.Stdout, delimiterChar)
 		fmt.Printf("==> %s %s\n", text, resource)
-		util.PrintDelimiterLine(delimiterChar)
+		util.PrintDelimiterLineToWriter(os.Stdout, delimiterChar)
 
 		if err := printFunc(item); err != nil {
 			fmt.Println("Error printing details:", err)
 			return
 		}
 
-		util.PrintDelimiterLine(delimiterChar)
+		util.PrintDelimiterLineToWriter(os.Stdout, delimiterChar)
 		fmt.Printf("<== %s %s\n", text, resource)
-		util.PrintDelimiterLine(delimiterChar)
+		util.PrintDelimiterLineToWriter(os.Stdout, delimiterChar)
 	}
 }
diff --git a/pkg/config/config.go b/pkg/config/config.go
index 7113761..a020c7e 100644
--- a/pkg/config/config.go
+++ b/pkg/config/config.go
@@ -15,6 +15,7 @@
 package config
 
 import (
+	"errors"
 	"fmt"
 	"os"
 	"path/filepath"
@@ -25,7 +26,6 @@ import (
 	"github.com/mitchellh/go-homedir"
 
 	"github.com/helm/chart-testing/v3/pkg/util"
-	"github.com/pkg/errors"
 	"github.com/spf13/cobra"
 	flag "github.com/spf13/pflag"
 	"github.com/spf13/viper"
@@ -35,6 +35,7 @@ var (
 	homeDir, _            = homedir.Dir()
 	configSearchLocations = []string{
 		".",
+		".ct",
 		filepath.Join(homeDir, ".ct"),
 		"/usr/local/etc/ct",
 		"/etc/ct",
@@ -45,7 +46,7 @@ type Configuration struct {
 	Remote                  string        `mapstructure:"remote"`
 	TargetBranch            string        `mapstructure:"target-branch"`
 	Since                   string        `mapstructure:"since"`
-	BuildId                 string        `mapstructure:"build-id"`
+	BuildID                 string        `mapstructure:"build-id"`
 	LintConf                string        `mapstructure:"lint-conf"`
 	ChartYamlSchema         string        `mapstructure:"chart-yaml-schema"`
 	ValidateMaintainers     bool          `mapstructure:"validate-maintainers"`
@@ -64,23 +65,26 @@ type Configuration struct {
 	Debug                   bool          `mapstructure:"debug"`
 	Upgrade                 bool          `mapstructure:"upgrade"`
 	SkipMissingValues       bool          `mapstructure:"skip-missing-values"`
+	SkipCleanUp             bool          `mapstructure:"skip-clean-up"`
 	Namespace               string        `mapstructure:"namespace"`
 	ReleaseLabel            string        `mapstructure:"release-label"`
 	ExcludeDeprecated       bool          `mapstructure:"exclude-deprecated"`
 	KubectlTimeout          time.Duration `mapstructure:"kubectl-timeout"`
+	PrintLogs               bool          `mapstructure:"print-logs"`
 }
 
 func LoadConfiguration(cfgFile string, cmd *cobra.Command, printConfig bool) (*Configuration, error) {
 	v := viper.New()
 
-	v.SetDefault("kubectl-timeout", time.Duration(30*time.Second))
+	v.SetDefault("kubectl-timeout", 30*time.Second)
+	v.SetDefault("print-logs", bool(true))
 
 	cmd.Flags().VisitAll(func(flag *flag.Flag) {
 		flagName := flag.Name
 		if flagName != "config" && flagName != "help" {
 			if err := v.BindPFlag(flagName, flag); err != nil {
 				// can't really happen
-				panic(fmt.Sprintln(errors.Wrapf(err, "Error binding flag '%s'", flagName)))
+				panic(fmt.Sprintf("failed binding flag %q: %v\n", flagName, err.Error()))
 			}
 		}
 	})
@@ -105,7 +109,7 @@ func LoadConfiguration(cfgFile string, cmd *cobra.Command, printConfig bool) (*C
 	if err := v.ReadInConfig(); err != nil {
 		if cfgFile != "" {
 			// Only error out for specified config file. Ignore for default locations.
-			return nil, errors.Wrap(err, "Error loading config file")
+			return nil, fmt.Errorf("failed loading config file: %w", err)
 		}
 	} else {
 		if printConfig {
@@ -118,7 +122,7 @@ func LoadConfiguration(cfgFile string, cmd *cobra.Command, printConfig bool) (*C
 
 	cfg := &Configuration{}
 	if err := v.Unmarshal(cfg); err != nil {
-		return nil, errors.Wrap(err, "Error unmarshaling configuration")
+		return nil, fmt.Errorf("failed unmarshaling configuration: %w", err)
 	}
 
 	if cfg.ProcessAllCharts && len(cfg.Charts) > 0 {
@@ -202,5 +206,5 @@ func findConfigFile(fileName string) (string, error) {
 		}
 	}
 
-	return "", errors.New(fmt.Sprintf("Config file not found: %s", fileName))
+	return "", fmt.Errorf("config file not found: %s", fileName)
 }
diff --git a/pkg/exec/exec.go b/pkg/exec/exec.go
index 3ab4bec..b0869b3 100644
--- a/pkg/exec/exec.go
+++ b/pkg/exec/exec.go
@@ -23,7 +23,6 @@ import (
 	"strings"
 
 	"github.com/helm/chart-testing/v3/pkg/util"
-	"github.com/pkg/errors"
 )
 
 type ProcessExecutor struct {
@@ -54,7 +53,7 @@ func (p ProcessExecutor) RunProcessInDirAndCaptureOutput(workingDirectory string
 	bytes, err := cmd.CombinedOutput()
 
 	if err != nil {
-		return "", errors.Wrap(err, "Error running process")
+		return "", fmt.Errorf("failed running process: %w", err)
 	}
 	return strings.TrimSpace(string(bytes)), nil
 }
@@ -69,7 +68,7 @@ func (p ProcessExecutor) RunProcessInDirAndCaptureStdout(workingDirectory string
 	bytes, err := cmd.Output()
 
 	if err != nil {
-		return "", errors.Wrap(err, "Error running process")
+		return "", fmt.Errorf("failed running process: %w", err)
 	}
 	return strings.TrimSpace(string(bytes)), nil
 }
@@ -82,12 +81,12 @@ func (p ProcessExecutor) RunProcess(executable string, execArgs ...interface{})
 
 	outReader, err := cmd.StdoutPipe()
 	if err != nil {
-		return errors.Wrap(err, "Error getting StdoutPipe for command")
+		return fmt.Errorf("failed getting StdoutPipe for command: %w", err)
 	}
 
 	errReader, err := cmd.StderrPipe()
 	if err != nil {
-		return errors.Wrap(err, "Error getting StderrPipe for command")
+		return fmt.Errorf("failed getting StderrPipe for command: %w", err)
 	}
 
 	scanner := bufio.NewScanner(io.MultiReader(outReader, errReader))
@@ -99,12 +98,12 @@ func (p ProcessExecutor) RunProcess(executable string, execArgs ...interface{})
 
 	err = cmd.Start()
 	if err != nil {
-		return errors.Wrap(err, "Error running process")
+		return fmt.Errorf("failed running process: %w", err)
 	}
 
 	err = cmd.Wait()
 	if err != nil {
-		return errors.Wrap(err, "Error waiting for process")
+		return fmt.Errorf("failed waiting for process: %w", err)
 	}
 
 	return nil
@@ -116,7 +115,7 @@ func (p ProcessExecutor) CreateProcess(executable string, execArgs ...interface{
 		fmt.Println(">>>", executable, strings.Join(args, " "))
 	}
 	if err != nil {
-		return nil, errors.Wrap(err, "Invalid arguments supplied")
+		return nil, fmt.Errorf("invalid arguments supplied: %w", err)
 	}
 	cmd := exec.Command(executable, args...)
 
@@ -128,25 +127,25 @@ type fn func(port int) error
 func (p ProcessExecutor) RunWithProxy(withProxy fn) error {
 	randomPort, err := util.GetRandomPort()
 	if err != nil {
-		return errors.Wrap(err, "Could not find a free port for running 'kubectl proxy'")
+		return fmt.Errorf("could not find a free port for running 'kubectl proxy': %w", err)
 	}
 
 	fmt.Printf("Running 'kubectl proxy' on port %d\n", randomPort)
 	cmdProxy, err := p.CreateProcess("kubectl", "proxy", fmt.Sprintf("--port=%d", randomPort))
 	if err != nil {
-		return errors.Wrap(err, "Error creating the 'kubectl proxy' process")
+		return fmt.Errorf("failed creating the 'kubectl proxy' process: %w", err)
 	}
 	err = cmdProxy.Start()
 	if err != nil {
-		return errors.Wrap(err, "Error starting the 'kubectl proxy' process")
+		return fmt.Errorf("failed starting the 'kubectl proxy' process: %w", err)
 	}
 
 	err = withProxy(randomPort)
 
-	cmdProxy.Process.Signal(os.Kill)
+	_ = cmdProxy.Process.Signal(os.Kill)
 
 	if err != nil {
-		return errors.Wrap(err, "Error running command with proxy")
+		return fmt.Errorf("failed running command with proxy: %w", err)
 	}
 
 	return nil
diff --git a/pkg/tool/account.go b/pkg/tool/account.go
index c1433fa..26de6f1 100644
--- a/pkg/tool/account.go
+++ b/pkg/tool/account.go
@@ -18,8 +18,6 @@ import (
 	"fmt"
 	"net/http"
 	"regexp"
-
-	"github.com/pkg/errors"
 )
 
 type AccountValidator struct{}
@@ -32,12 +30,12 @@ func (v AccountValidator) Validate(repoURL string, account string) error {
 		return err
 	}
 	url := fmt.Sprintf("https://%s/%s", domain, account)
-	response, err := http.Head(url)
+	response, err := http.Head(url) // nolint: gosec
 	if err != nil {
-		return errors.Wrap(err, "Error validating maintainers")
+		return fmt.Errorf("failed validating maintainers: %w", err)
 	}
 	if response.StatusCode != 200 {
-		return fmt.Errorf("Error validating maintainer '%s': %s", account, response.Status)
+		return fmt.Errorf("failed validating maintainer %q: %s", account, response.Status)
 	}
 	return nil
 }
@@ -46,7 +44,7 @@ func parseOutGitRepoDomain(repoURL string) (string, error) {
 	// This works for GitHub, Bitbucket, and Gitlab
 	submatch := repoDomainPattern.FindStringSubmatch(repoURL)
 	if submatch == nil || len(submatch) < 2 {
-		return "", fmt.Errorf("Could not parse git repository domain for '%s'", repoURL)
+		return "", fmt.Errorf("could not parse git repository domain for %q", repoURL)
 	}
 	return submatch[1], nil
 }
diff --git a/pkg/tool/git.go b/pkg/tool/git.go
index 361a688..1fe5551 100644
--- a/pkg/tool/git.go
+++ b/pkg/tool/git.go
@@ -19,7 +19,6 @@ import (
 	"strings"
 
 	"github.com/helm/chart-testing/v3/pkg/exec"
-	"github.com/pkg/errors"
 )
 
 type Git struct {
@@ -59,7 +58,7 @@ func (g Git) ListChangedFilesInDirs(commit string, dirs ...string) ([]string, er
 	changedChartFilesString, err :=
 		g.exec.RunProcessAndCaptureOutput("git", "diff", "--find-renames", "--name-only", commit, "--", dirs)
 	if err != nil {
-		return nil, errors.Wrap(err, "Error creating diff")
+		return nil, fmt.Errorf("failed creating diff: %w", err)
 	}
 	if changedChartFilesString == "" {
 		return nil, nil
@@ -67,7 +66,7 @@ func (g Git) ListChangedFilesInDirs(commit string, dirs ...string) ([]string, er
 	return strings.Split(changedChartFilesString, "\n"), nil
 }
 
-func (g Git) GetUrlForRemote(remote string) (string, error) {
+func (g Git) GetURLForRemote(remote string) (string, error) {
 	return g.exec.RunProcessAndCaptureOutput("git", "ls-remote", "--get-url", remote)
 }
 
diff --git a/pkg/tool/helm.go b/pkg/tool/helm.go
index 44afd47..4b5f763 100644
--- a/pkg/tool/helm.go
+++ b/pkg/tool/helm.go
@@ -83,12 +83,12 @@ func (h Helm) Test(namespace string, release string) error {
 }
 
 func (h Helm) DeleteRelease(namespace string, release string) {
-	fmt.Printf("Deleting release '%s'...\n", release)
+	fmt.Printf("Deleting release %q...\n", release)
 	if err := h.exec.RunProcess("helm", "uninstall", release, "--namespace", namespace, h.extraArgs); err != nil {
 		fmt.Println("Error deleting Helm release:", err)
 	}
 }
 
 func (h Helm) Version() (string, error) {
-	return h.exec.RunProcessAndCaptureStdout("helm", "version", "--short")
+	return h.exec.RunProcessAndCaptureStdout("helm", "version", "--template", "{{ .Version }}")
 }
diff --git a/pkg/tool/kubectl.go b/pkg/tool/kubectl.go
index d2021e5..2a32817 100644
--- a/pkg/tool/kubectl.go
+++ b/pkg/tool/kubectl.go
@@ -3,6 +3,7 @@ package tool
 import (
 	"bytes"
 	"encoding/json"
+	"errors"
 	"fmt"
 	"net/http"
 	"strings"
@@ -10,7 +11,6 @@ import (
 
 	"github.com/hashicorp/go-retryablehttp"
 	"github.com/helm/chart-testing/v3/pkg/exec"
-	"github.com/pkg/errors"
 )
 
 type Kubectl struct {
@@ -27,7 +27,7 @@ func NewKubectl(exec exec.ProcessExecutor, timeout time.Duration) Kubectl {
 
 // CreateNamespace creates a new namespace with the given name.
 func (k Kubectl) CreateNamespace(namespace string) error {
-	fmt.Printf("Creating namespace '%s'...\n", namespace)
+	fmt.Printf("Creating namespace %q...\n", namespace)
 	return k.exec.RunProcess("kubectl",
 		fmt.Sprintf("--request-timeout=%s", k.timeout),
 		"create", "namespace", namespace)
@@ -36,17 +36,17 @@ func (k Kubectl) CreateNamespace(namespace string) error {
 // DeleteNamespace deletes the specified namespace. If the namespace does not terminate within 120s, pods running in the
 // namespace and, eventually, the namespace itself are force-deleted.
 func (k Kubectl) DeleteNamespace(namespace string) {
-	fmt.Printf("Deleting namespace '%s'...\n", namespace)
+	fmt.Printf("Deleting namespace %q...\n", namespace)
 	timeoutSec := "180s"
 	err := k.exec.RunProcess("kubectl",
 		fmt.Sprintf("--request-timeout=%s", k.timeout),
 		"delete", "namespace", namespace, "--timeout", timeoutSec)
 	if err != nil {
-		fmt.Printf("Namespace '%s' did not terminate after %s.\n", namespace, timeoutSec)
+		fmt.Printf("Namespace %q did not terminate after %s.\n", namespace, timeoutSec)
 	}
 
 	if k.getNamespace(namespace) {
-		fmt.Printf("Namespace '%s' did not terminate after %s.\n", namespace, timeoutSec)
+		fmt.Printf("Namespace %q did not terminate after %s.\n", namespace, timeoutSec)
 
 		fmt.Println("Force-deleting everything...")
 		err = k.exec.RunProcess("kubectl",
@@ -70,7 +70,7 @@ func (k Kubectl) DeleteNamespace(namespace string) {
 
 func (k Kubectl) forceNamespaceDeletion(namespace string) error {
 	// Getting the namespace json to remove the finalizer
-	cmdOutput, err := k.exec.RunProcessAndCaptureOutput("kubectl",
+	cmdOutput, err := k.exec.RunProcessAndCaptureStdout("kubectl",
 		fmt.Sprintf("--request-timeout=%s", k.timeout),
 		"get", "namespace", namespace, "--output=json")
 	if err != nil {
@@ -93,7 +93,7 @@ func (k Kubectl) forceNamespaceDeletion(namespace string) error {
 
 	// Remove finalizer from the namespace
 	fun := func(port int) error {
-		fmt.Printf("Removing finalizers from namespace '%s'...\n", namespace)
+		fmt.Printf("Removing finalizers from namespace %q...\n", namespace)
 
 		k8sURL := fmt.Sprintf("http://127.0.0.1:%d/api/v1/namespaces/%s/finalize", port, namespace)
 		req, err := retryablehttp.NewRequest("PUT", k8sURL, bytes.NewReader(namespaceUpdateBytes))
@@ -107,7 +107,7 @@ func (k Kubectl) forceNamespaceDeletion(namespace string) error {
 		client := retryablehttp.NewClient()
 		client.Logger = nil
 		if resp, err := client.Do(req); err != nil {
-			return errors.Wrap(err, errMsg)
+			return fmt.Errorf("%s:%w", errMsg, err)
 		} else if resp.StatusCode != http.StatusOK {
 			return errors.New(errMsg)
 		}
@@ -117,7 +117,7 @@ func (k Kubectl) forceNamespaceDeletion(namespace string) error {
 
 	err = k.exec.RunWithProxy(fun)
 	if err != nil {
-		return errors.Wrapf(err, "Cannot force-delete namespace '%s'", namespace)
+		return fmt.Errorf("cannot force-delete namespace %q: %w", namespace, err)
 	}
 
 	// Give it some more time to be deleted by K8s
@@ -128,11 +128,11 @@ func (k Kubectl) forceNamespaceDeletion(namespace string) error {
 		fmt.Sprintf("--request-timeout=%s", k.timeout),
 		"get", "namespace", namespace)
 	if err != nil {
-		fmt.Printf("Namespace '%s' terminated.\n", namespace)
+		fmt.Printf("Namespace %q terminated.\n", namespace)
 		return nil
 	}
 
-	fmt.Printf("Force-deleting namespace '%s'...\n", namespace)
+	fmt.Printf("Force-deleting namespace %q...\n", namespace)
 	err = k.exec.RunProcess("kubectl",
 		fmt.Sprintf("--request-timeout=%s", k.timeout),
 		"delete", "namespace", namespace, "--force", "--grace-period=0",
@@ -146,7 +146,7 @@ func (k Kubectl) forceNamespaceDeletion(namespace string) error {
 }
 
 func (k Kubectl) WaitForDeployments(namespace string, selector string) error {
-	output, err := k.exec.RunProcessAndCaptureOutput("kubectl",
+	output, err := k.exec.RunProcessAndCaptureStdout("kubectl",
 		fmt.Sprintf("--request-timeout=%s", k.timeout),
 		"get", "deployments", "--namespace", namespace, "--selector", selector,
 		"--output", "jsonpath={.items[*].metadata.name}")
@@ -169,7 +169,7 @@ func (k Kubectl) WaitForDeployments(namespace string, selector string) error {
 		//
 		// Just after rollout, pods from the previous deployment revision may still be in a
 		// terminating state.
-		unavailable, err := k.exec.RunProcessAndCaptureOutput("kubectl",
+		unavailable, err := k.exec.RunProcessAndCaptureStdout("kubectl",
 			fmt.Sprintf("--request-timeout=%s", k.timeout),
 			"get", "deployment", deployment, "--namespace", namespace, "--output",
 			`jsonpath={.status.unavailableReplicas}`)
@@ -185,7 +185,7 @@ func (k Kubectl) WaitForDeployments(namespace string, selector string) error {
 }
 
 func (k Kubectl) GetPodsforDeployment(namespace string, deployment string) ([]string, error) {
-	jsonString, _ := k.exec.RunProcessAndCaptureOutput("kubectl",
+	jsonString, _ := k.exec.RunProcessAndCaptureStdout("kubectl",
 		fmt.Sprintf("--request-timeout=%s", k.timeout),
 		"get", "deployment", deployment, "--namespace", namespace, "--output=json")
 	var deploymentMap map[string]interface{}
@@ -211,7 +211,7 @@ func (k Kubectl) GetPodsforDeployment(namespace string, deployment string) ([]st
 func (k Kubectl) GetPods(args ...string) ([]string, error) {
 	kubectlArgs := []string{"get", "pods"}
 	kubectlArgs = append(kubectlArgs, args...)
-	pods, err := k.exec.RunProcessAndCaptureOutput("kubectl",
+	pods, err := k.exec.RunProcessAndCaptureStdout("kubectl",
 		fmt.Sprintf("--request-timeout=%s", k.timeout), kubectlArgs)
 	if err != nil {
 		return nil, err
@@ -250,7 +250,7 @@ func (k Kubectl) getNamespace(namespace string) bool {
 		fmt.Sprintf("--request-timeout=%s", k.timeout),
 		"get", "namespace", namespace)
 	if err != nil {
-		fmt.Printf("Namespace '%s' terminated.\n", namespace)
+		fmt.Printf("Namespace %q terminated.\n", namespace)
 		return false
 	}
 
diff --git a/pkg/util/util.go b/pkg/util/util.go
index c040521..d3f1974 100644
--- a/pkg/util/util.go
+++ b/pkg/util/util.go
@@ -15,9 +15,10 @@
 package util
 
 import (
+	"errors"
 	"fmt"
 	"io"
-	"io/ioutil"
+	"io/fs"
 	"math/rand"
 	"net"
 	"os"
@@ -28,7 +29,6 @@ import (
 
 	"github.com/Masterminds/semver"
 	"github.com/hashicorp/go-multierror"
-	"github.com/pkg/errors"
 	"gopkg.in/yaml.v2"
 )
 
@@ -70,7 +70,7 @@ func doFlatten(result []string, items interface{}) ([]string, error) {
 			}
 		}
 	default:
-		return nil, errors.New(fmt.Sprintf("Flatten does not support %T", v))
+		return nil, fmt.Errorf("flatten does not support %T", v)
 	}
 
 	return result, err
@@ -97,7 +97,7 @@ func RandomString(length int) string {
 	n := len(chars)
 	bytes := make([]byte, length)
 	for i := range bytes {
-		bytes[i] = chars[rand.Intn(n)]
+		bytes[i] = chars[rand.Intn(n)] // nolint: gosec
 	}
 	return string(bytes)
 }
@@ -106,10 +106,18 @@ type DirectoryLister struct{}
 
 // ListChildDirs lists subdirectories of parentDir matching the test function.
 func (l DirectoryLister) ListChildDirs(parentDir string, test func(dir string) bool) ([]string, error) {
-	fileInfos, err := ioutil.ReadDir(parentDir)
+	entries, err := os.ReadDir(parentDir)
 	if err != nil {
 		return nil, err
 	}
+	fileInfos := make([]fs.FileInfo, 0, len(entries))
+	for _, entry := range entries {
+		info, err := entry.Info()
+		if err != nil {
+			return nil, err
+		}
+		fileInfos = append(fileInfos, info)
+	}
 
 	var dirs []string
 	for _, dir := range fileInfos {
@@ -123,9 +131,9 @@ func (l DirectoryLister) ListChildDirs(parentDir string, test func(dir string) b
 	return dirs, nil
 }
 
-type ChartUtils struct{}
+type Utils struct{}
 
-func (u ChartUtils) LookupChartDir(chartDirs []string, dir string) (string, error) {
+func (u Utils) LookupChartDir(chartDirs []string, dir string) (string, error) {
 	for _, chartDir := range chartDirs {
 		currentDir := dir
 		for {
@@ -154,9 +162,9 @@ func (u ChartUtils) LookupChartDir(chartDirs []string, dir string) (string, erro
 // and return a newly allocated ChartYaml object. If no Chart.yaml is present
 // or there is an error unmarshaling the file contents, an error will be returned.
 func ReadChartYaml(dir string) (*ChartYaml, error) {
-	yamlBytes, err := ioutil.ReadFile(filepath.Join(dir, "Chart.yaml"))
+	yamlBytes, err := os.ReadFile(filepath.Join(dir, "Chart.yaml"))
 	if err != nil {
-		return nil, errors.Wrap(err, "Could not read 'Chart.yaml'")
+		return nil, fmt.Errorf("could not read 'Chart.yaml': %w", err)
 	}
 	return UnmarshalChartYaml(yamlBytes)
 }
@@ -166,7 +174,7 @@ func ReadChartYaml(dir string) (*ChartYaml, error) {
 func UnmarshalChartYaml(yamlBytes []byte) (*ChartYaml, error) {
 	chartYaml := &ChartYaml{}
 	if err := yaml.Unmarshal(yamlBytes, chartYaml); err != nil {
-		return nil, errors.Wrap(err, "Could not unmarshal 'Chart.yaml'")
+		return nil, fmt.Errorf("could not unmarshal 'Chart.yaml': %w", err)
 	}
 	return chartYaml, nil
 }
@@ -174,11 +182,11 @@ func UnmarshalChartYaml(yamlBytes []byte) (*ChartYaml, error) {
 func CompareVersions(left string, right string) (int, error) {
 	leftVersion, err := semver.NewVersion(left)
 	if err != nil {
-		return 0, errors.Wrap(err, "Error parsing semantic version")
+		return 0, fmt.Errorf("failed parsing semantic version: %w", err)
 	}
 	rightVersion, err := semver.NewVersion(right)
 	if err != nil {
-		return 0, errors.Wrap(err, "Error parsing semantic version")
+		return 0, fmt.Errorf("failed parsing semantic version: %w", err)
 	}
 	return leftVersion.Compare(rightVersion), nil
 }
@@ -186,11 +194,11 @@ func CompareVersions(left string, right string) (int, error) {
 func BreakingChangeAllowed(left string, right string) (bool, error) {
 	leftVersion, err := semver.NewVersion(left)
 	if err != nil {
-		return false, errors.Wrap(err, "Error parsing semantic version")
+		return false, fmt.Errorf("failed parsing semantic version: %w", err)
 	}
 	rightVersion, err := semver.NewVersion(right)
 	if err != nil {
-		return false, errors.Wrap(err, "Error parsing semantic version")
+		return false, fmt.Errorf("failed parsing semantic version: %w", err)
 	}
 
 	constraintOp := "^"
@@ -199,7 +207,7 @@ func BreakingChangeAllowed(left string, right string) (bool, error) {
 	}
 	c, err := semver.NewConstraint(fmt.Sprintf("%s %s", constraintOp, leftVersion.String()))
 	if err != nil {
-		return false, errors.Wrap(err, "Error parsing semantic version constraint")
+		return false, fmt.Errorf("failed parsing semantic version constraint: %w", err)
 	}
 
 	minor, reasons := c.Validate(rightVersion)
@@ -210,11 +218,6 @@ func BreakingChangeAllowed(left string, right string) (bool, error) {
 	return !minor, err
 }
 
-// Deprecated: To be removed in v4. Use PrintDelimiterLineToWriter instead.
-func PrintDelimiterLine(delimiterChar string) {
-	PrintDelimiterLineToWriter(os.Stdout, delimiterChar)
-}
-
 func PrintDelimiterLineToWriter(w io.Writer, delimiterChar string) {
 	delim := make([]string, 120)
 	for i := 0; i < 120; i++ {
@@ -235,8 +238,8 @@ func SanitizeName(s string, maxLength int) string {
 }
 
 func GetRandomPort() (int, error) {
-	listener, err := net.Listen("tcp", ":0")
-	defer listener.Close()
+	listener, err := net.Listen("tcp", ":0") // nolint: gosec
+	defer listener.Close()                   // nolint: staticcheck
 	if err != nil {
 		return 0, err
 	}


Test patch:
diff --git a/e2e-kind.sh b/e2e-kind.sh
index 796d656..c8cff13 100755
--- a/e2e-kind.sh
+++ b/e2e-kind.sh
@@ -7,7 +7,7 @@ set -o pipefail
 CLUSTER_NAME=chart-testing
 readonly CLUSTER_NAME
 
-K8S_VERSION=v1.21.2
+K8S_VERSION=v1.22.9
 readonly K8S_VERSION
 
 create_kind_cluster() {
diff --git a/pkg/chart/chart_test.go b/pkg/chart/chart_test.go
index 2f05a31..78cf8d1 100644
--- a/pkg/chart/chart_test.go
+++ b/pkg/chart/chart_test.go
@@ -21,7 +21,6 @@ import (
 
 	"github.com/helm/chart-testing/v3/pkg/config"
 	"github.com/helm/chart-testing/v3/pkg/util"
-	"github.com/pkg/errors"
 	"github.com/stretchr/testify/assert"
 	"github.com/stretchr/testify/mock"
 )
@@ -63,7 +62,7 @@ func (g fakeGit) RemoveWorktree(path string) error {
 	return nil
 }
 
-func (g fakeGit) GetUrlForRemote(remote string) (string, error) {
+func (g fakeGit) GetURLForRemote(remote string) (string, error) {
 	return "git@github.com/helm/chart-testing", nil
 }
 
@@ -77,7 +76,7 @@ func (v fakeAccountValidator) Validate(repoDomain string, account string) error
 	if strings.HasPrefix(account, "valid") {
 		return nil
 	}
-	return errors.New(fmt.Sprintf("Error validating account: %s", account))
+	return fmt.Errorf("failed validating account: %s", account)
 }
 
 type fakeLinter struct {
@@ -145,7 +144,7 @@ func newTestingMock(cfg config.Configuration) Testing {
 		config:           cfg,
 		directoryLister:  util.DirectoryLister{},
 		git:              fakeGit{},
-		chartUtils:       util.ChartUtils{},
+		utils:            util.Utils{},
 		accountValidator: fakeAccountValidator{},
 		linter:           fakeMockLinter,
 		helm:             new(fakeHelm),
@@ -299,7 +298,6 @@ func TestLintChartSchemaValidation(t *testing.T) {
 
 	runTests(true, 0, 1)
 	runTests(false, 0, 0)
-
 }
 
 func TestLintYamlValidation(t *testing.T) {
diff --git a/pkg/chart/integration_test.go b/pkg/chart/integration_test.go
index 9d5f881..5322d0f 100644
--- a/pkg/chart/integration_test.go
+++ b/pkg/chart/integration_test.go
@@ -38,7 +38,7 @@ func newTestingHelmIntegration(cfg config.Configuration, extraSetArgs string) Te
 		config:           cfg,
 		directoryLister:  util.DirectoryLister{},
 		git:              fakeGit{},
-		chartUtils:       util.ChartUtils{},
+		utils:            util.Utils{},
 		accountValidator: fakeAccountValidator{},
 		linter:           fakeMockLinter,
 		helm:             tool.NewHelm(procExec, extraArgs, strings.Fields(extraSetArgs)),
@@ -121,7 +121,7 @@ func TestUpgradeChart(t *testing.T) {
 		Upgrade: true,
 	}
 	ct := newTestingHelmIntegration(cfg, "")
-	processError := fmt.Errorf("Error waiting for process: exit status 1")
+	processError := fmt.Errorf("failed waiting for process: exit status 1")
 
 	cases := []testCase{
 		{
diff --git a/pkg/config/config_test.go b/pkg/config/config_test.go
index 0087192..bc64131 100644
--- a/pkg/config/config_test.go
+++ b/pkg/config/config_test.go
@@ -40,7 +40,7 @@ func loadAndAssertConfigFromFile(t *testing.T, configFile string) {
 
 	require.Equal(t, "origin", cfg.Remote)
 	require.Equal(t, "main", cfg.TargetBranch)
-	require.Equal(t, "pr-42", cfg.BuildId)
+	require.Equal(t, "pr-42", cfg.BuildID)
 	require.Equal(t, "my-lint-conf.yaml", cfg.LintConf)
 	require.Equal(t, "my-chart-yaml-schema.yaml", cfg.ChartYamlSchema)
 	require.Equal(t, true, cfg.ValidateMaintainers)
@@ -59,6 +59,7 @@ func loadAndAssertConfigFromFile(t *testing.T, configFile string) {
 	require.Equal(t, "release", cfg.ReleaseLabel)
 	require.Equal(t, true, cfg.ExcludeDeprecated)
 	require.Equal(t, 120*time.Second, cfg.KubectlTimeout)
+	require.Equal(t, true, cfg.SkipCleanUp)
 }
 
 func Test_findConfigFile(t *testing.T) {
diff --git a/pkg/config/test_config.json b/pkg/config/test_config.json
index 861f8b7..df0b100 100644
--- a/pkg/config/test_config.json
+++ b/pkg/config/test_config.json
@@ -30,5 +30,6 @@
     "namespace": "default",
     "release-label": "release",
     "exclude-deprecated": true,
-    "kubectl-timeout": "120s"
+    "kubectl-timeout": "120s",
+    "skip-clean-up": true
 }
diff --git a/pkg/config/test_config.yaml b/pkg/config/test_config.yaml
index 56f4847..1381b96 100644
--- a/pkg/config/test_config.yaml
+++ b/pkg/config/test_config.yaml
@@ -26,3 +26,4 @@ namespace: default
 release-label: release
 exclude-deprecated: true
 kubectl-timeout: 120s
+skip-clean-up: true
diff --git a/pkg/tool/account_test.go b/pkg/tool/account_test.go
index 498d5e0..30a03f5 100644
--- a/pkg/tool/account_test.go
+++ b/pkg/tool/account_test.go
@@ -10,7 +10,7 @@ import (
 func TestParseOutGitDomain(t *testing.T) {
 	var testDataSlice = []struct {
 		name     string
-		repoUrl  string
+		repoURL  string
 		expected string
 		err      error
 	}{
@@ -23,12 +23,12 @@ func TestParseOutGitDomain(t *testing.T) {
 		{"Bitbucket SSH", "git@bitbucket.com:foo/bar", "bitbucket.com", nil},
 		{"Bitbucket HTTPS", "https://bitbucket.com/foo/bar", "bitbucket.com", nil},
 		{"Bitbucket HTTPS with username/password", "https://user:pass@bitbucket.com/foo/bar", "bitbucket.com", nil},
-		{"Invalid", "foo/bar", "", fmt.Errorf("Could not parse git repository domain for 'foo/bar'")},
+		{"Invalid", "foo/bar", "", fmt.Errorf("could not parse git repository domain for \"foo/bar\"")},
 	}
 
 	for _, testData := range testDataSlice {
 		t.Run(testData.name, func(t *testing.T) {
-			actual, err := parseOutGitRepoDomain(testData.repoUrl)
+			actual, err := parseOutGitRepoDomain(testData.repoURL)
 			assert.Equal(t, err, testData.err)
 			assert.Equal(t, testData.expected, actual)
 		})
diff --git a/pkg/tool/cmdexecutor_test.go b/pkg/tool/cmdexecutor_test.go
index 21cb6ea..67fb5f2 100644
--- a/pkg/tool/cmdexecutor_test.go
+++ b/pkg/tool/cmdexecutor_test.go
@@ -69,8 +69,8 @@ func TestCmdTemplateExecutor_RunCommand(t *testing.T) {
 			if err := templateExecutor.RunCommand(tt.args.cmdTemplate, tt.args.data); (err != nil) != tt.wantErr {
 				t.Errorf("RunCommand() error = %v, wantErr %v", err, tt.wantErr)
 			}
-			tt.validate(t, processExecutor)
 
+			tt.validate(t, processExecutor)
 		})
 	}
 }