Repository: helm/helm (go)

Issue:
The sdk dependency manager error refers to Helm CLI
Output of `helm version`: v3.4.0 development and previous v3 releases

The download manager within the SDK notes... https://github.com/helm/helm/blob/6a536661fcf1dc0315798ece70bbf193e725945c/pkg/downloader/manager.go#L414

The SDK should have an error that's general and the CLI code in the cmd directory should detect it and decorate with any CLI related elements. Separation of concerns and all.




Pull request description:
fix(sdk): Polish the downloader/manager package error return
Close #8471

Signed-off-by: Dong Gang <dong.gang@daocloud.io>

<!--  Thanks for sending a pull request!  Here are some tips for you:
1. Make sure to read the Contributing Guide before submitting your PR: https://github.com/helm/helm/blob/master/CONTRIBUTING.md
2. If this PR closes another issue, add 'closes #<issue number>' somewhere in the PR summary. GitHub will automatically close that issue when this PR gets merged. Alternatively, adding 'refs #<issue number>' will not close the issue, but help provide the reviewer more context.-->

**What this PR does / why we need it**:
fix #8471
**Special notes for your reviewer**:

**If applicable**:
- [ ] this PR contains documentation
- [X] this PR contains unit tests
- [ ] this PR has been tested for backwards compatibility


Patch:
diff --git a/cmd/helm/dependency_build.go b/cmd/helm/dependency_build.go
index 478b49479..4e87684ce 100644
--- a/cmd/helm/dependency_build.go
+++ b/cmd/helm/dependency_build.go
@@ -16,6 +16,7 @@ limitations under the License.
 package main
 
 import (
+	"fmt"
 	"io"
 	"os"
 	"path/filepath"
@@ -65,7 +66,11 @@ func newDependencyBuildCmd(out io.Writer) *cobra.Command {
 			if client.Verify {
 				man.Verify = downloader.VerifyIfPossible
 			}
-			return man.Build()
+			err := man.Build()
+			if e, ok := err.(downloader.ErrRepoNotFound); ok {
+				return fmt.Errorf("%s. Please add the missing repos via 'helm repo add'", e.Error())
+			}
+			return err
 		},
 	}
 
diff --git a/pkg/downloader/manager.go b/pkg/downloader/manager.go
index 00198de0c..2d6918739 100644
--- a/pkg/downloader/manager.go
+++ b/pkg/downloader/manager.go
@@ -42,6 +42,17 @@ import (
 	"helm.sh/helm/v3/pkg/repo"
 )
 
+// ErrRepoNotFound indicates that chart repositories can't be found in local repo cache.
+// The value of Repos is missing repos.
+type ErrRepoNotFound struct {
+	Repos []string
+}
+
+// Error implements the error interface.
+func (e ErrRepoNotFound) Error() string {
+	return fmt.Sprintf("no repository definition for %s", strings.Join(e.Repos, ", "))
+}
+
 // Manager handles the lifecycle of fetching, resolving, and storing dependencies.
 type Manager struct {
 	// Out is used to print warnings and notifications.
@@ -411,7 +422,7 @@ Loop:
 		missing = append(missing, dd.Repository)
 	}
 	if len(missing) > 0 {
-		return errors.Errorf("no repository definition for %s. Please add the missing repos via 'helm repo add'", strings.Join(missing, ", "))
+		return ErrRepoNotFound{missing}
 	}
 	return nil
 }


Test patch:
diff --git a/pkg/downloader/manager_test.go b/pkg/downloader/manager_test.go
index ea235c13f..dd3cbbd7b 100644
--- a/pkg/downloader/manager_test.go
+++ b/pkg/downloader/manager_test.go
@@ -360,3 +360,32 @@ func TestBuild_WithRepositoryAlias(t *testing.T) {
 		Repository: "@test",
 	})
 }
+
+func TestErrRepoNotFound_Error(t *testing.T) {
+	type fields struct {
+		Repos []string
+	}
+	tests := []struct {
+		name   string
+		fields fields
+		want   string
+	}{
+		{
+			name: "OK",
+			fields: fields{
+				Repos: []string{"https://charts1.example.com", "https://charts2.example.com"},
+			},
+			want: "no repository definition for https://charts1.example.com, https://charts2.example.com",
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			e := ErrRepoNotFound{
+				Repos: tt.fields.Repos,
+			}
+			if got := e.Error(); got != tt.want {
+				t.Errorf("Error() = %v, want %v", got, tt.want)
+			}
+		})
+	}
+}