diff --git a/docs/chart_best_practices/requirements.md b/docs/chart_best_practices/requirements.md index ce99649f9..0bbdfdfd7 100644 --- a/docs/chart_best_practices/requirements.md +++ b/docs/chart_best_practices/requirements.md @@ -16,6 +16,8 @@ This will match version 1.2.0 and any patches to that release (1.2.1, 1.2.999, a Where possible, use `https://` repository URLs, followed by `http://` URLs. +If the repository has been added to the repository index file, the repository name can be used as an alias of URL. Use `alias:` or `@` followed by repository names. + File URLs (`file://...`) are considered a "special case" for charts that are assembled by a fixed deployment pipeline. Charts that use `file://` in a `requirements.yaml` file are not allowed in the official Helm repository. ## Conditions and Tags diff --git a/docs/helm/helm_dependency.md b/docs/helm/helm_dependency.md index 08cf5d7c2..c2a46e39e 100644 --- a/docs/helm/helm_dependency.md +++ b/docs/helm/helm_dependency.md @@ -36,8 +36,20 @@ The 'version' field should contain a semantic version or version range. The 'repository' URL should point to a Chart Repository. Helm expects that by appending '/index.yaml' to the URL, it should be able to retrieve the chart -repository's index. Note: 'repository' cannot be a repository alias. It must be -a URL. +repository's index. + +A repository can also be represented by a repository name defined in the index file +in lieu of a repository URL. If a repository alias is used, it is expected to start with +'alias:' or '@', followed by a repository name. For example, + # requirements.yaml + dependencies: + - name: nginx + version: "1.2.3" + repository: "alias:stable" + +Note: In the above example, if the '@' syntax is used, the repository alias '@stable' +must be quoted, as YAML requires to use quotes if the value includes a special character +like '@'. Starting from 2.2.0, repository can be defined as the path to the directory of the dependency charts stored locally. The path should start with a prefix of @@ -53,7 +65,6 @@ If the dependency chart is retrieved locally, it is not required to have the repository added to helm by "helm add repo". Version matching is also supported for this case. - ### Options inherited from parent commands ``` diff --git a/pkg/downloader/manager.go b/pkg/downloader/manager.go index bf9b384fd..e64150e00 100644 --- a/pkg/downloader/manager.go +++ b/pkg/downloader/manager.go @@ -124,6 +124,13 @@ func (m *Manager) Update() error { } return err } + + // Hash requirements.yaml + hash, err := resolver.HashReq(req) + if err != nil { + return err + } + // Check that all of the repos we're dependent on actually exist and // the repo index names. repoNames, err := m.getRepoNames(req.Dependencies) @@ -140,7 +147,7 @@ func (m *Manager) Update() error { // Now we need to find out which version of a chart best satisfies the // requirements the requirements.yaml - lock, err := m.resolve(req, repoNames) + lock, err := m.resolve(req, repoNames, hash) if err != nil { return err } @@ -172,9 +179,9 @@ func (m *Manager) loadChartDir() (*chart.Chart, error) { // resolve takes a list of requirements and translates them into an exact version to download. // // This returns a lock file, which has all of the requirements normalized to a specific version. -func (m *Manager) resolve(req *chartutil.Requirements, repoNames map[string]string) (*chartutil.RequirementsLock, error) { +func (m *Manager) resolve(req *chartutil.Requirements, repoNames map[string]string, hash string) (*chartutil.RequirementsLock, error) { res := resolver.New(m.ChartPath, m.HelmHome) - return res.Resolve(req, repoNames) + return res.Resolve(req, repoNames, hash) } // downloadAll takes a list of dependencies and downloads them into charts/ @@ -346,7 +353,13 @@ func (m *Manager) getRepoNames(deps []*chartutil.Dependency) (map[string]string, found := false for _, repo := range repos { - if urlutil.Equal(repo.URL, dd.Repository) { + if (strings.HasPrefix(dd.Repository, "@") && strings.TrimPrefix(dd.Repository, "@") == repo.Name) || + (strings.HasPrefix(dd.Repository, "alias:") && strings.TrimPrefix(dd.Repository, "alias:") == repo.Name) { + found = true + dd.Repository = repo.URL + reposMap[dd.Name] = repo.Name + break + } else if urlutil.Equal(repo.URL, dd.Repository) { found = true reposMap[dd.Name] = repo.Name break diff --git a/pkg/downloader/manager_test.go b/pkg/downloader/manager_test.go index 2035676c4..683e80e00 100644 --- a/pkg/downloader/manager_test.go +++ b/pkg/downloader/manager_test.go @@ -120,6 +120,20 @@ func TestGetRepoNames(t *testing.T) { }, expect: map[string]string{"local-dep": "file://./testdata/signtest"}, }, + { + name: "repo alias (alias:)", + req: []*chartutil.Dependency{ + {Name: "oedipus-rex", Repository: "alias:testing"}, + }, + expect: map[string]string{"oedipus-rex": "testing"}, + }, + { + name: "repo alias (@)", + req: []*chartutil.Dependency{ + {Name: "oedipus-rex", Repository: "@testing"}, + }, + expect: map[string]string{"oedipus-rex": "testing"}, + }, } for _, tt := range tests { diff --git a/pkg/resolver/resolver.go b/pkg/resolver/resolver.go index 858ca272d..1db18e842 100644 --- a/pkg/resolver/resolver.go +++ b/pkg/resolver/resolver.go @@ -47,11 +47,7 @@ func New(chartpath string, helmhome helmpath.Home) *Resolver { } // Resolve resolves dependencies and returns a lock file with the resolution. -func (r *Resolver) Resolve(reqs *chartutil.Requirements, repoNames map[string]string) (*chartutil.RequirementsLock, error) { - d, err := HashReq(reqs) - if err != nil { - return nil, err - } +func (r *Resolver) Resolve(reqs *chartutil.Requirements, repoNames map[string]string, d string) (*chartutil.RequirementsLock, error) { // Now we clone the dependencies, locking as we go. locked := make([]*chartutil.Dependency, len(reqs.Dependencies)) diff --git a/pkg/resolver/resolver_test.go b/pkg/resolver/resolver_test.go index 4a4f853b7..57725355e 100644 --- a/pkg/resolver/resolver_test.go +++ b/pkg/resolver/resolver_test.go @@ -104,7 +104,12 @@ func TestResolve(t *testing.T) { repoNames := map[string]string{"alpine": "kubernetes-charts", "redis": "kubernetes-charts"} r := New("testdata/chartpath", "testdata/helmhome") for _, tt := range tests { - l, err := r.Resolve(tt.req, repoNames) + hash, err := HashReq(tt.req) + if err != nil { + t.Fatal(err) + } + + l, err := r.Resolve(tt.req, repoNames, hash) if err != nil { if tt.err { continue