Commit c010da4d authored by Qin Wang's avatar Qin Wang

feat(helm): add support for repo alias

support repo alias in requirements.yaml
The syntax should be like: "alias:reponame" or "@reponame".

closes: #1985
parent 1c1bfb27
...@@ -16,6 +16,8 @@ This will match version 1.2.0 and any patches to that release (1.2.1, 1.2.999, a ...@@ -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. 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. 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 ## Conditions and Tags
......
...@@ -36,8 +36,20 @@ The 'version' field should contain a semantic version or version range. ...@@ -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 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 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 repository's index.
a URL.
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 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 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 ...@@ -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 repository added to helm by "helm add repo". Version matching is also supported
for this case. for this case.
### Options inherited from parent commands ### Options inherited from parent commands
``` ```
......
...@@ -124,6 +124,13 @@ func (m *Manager) Update() error { ...@@ -124,6 +124,13 @@ func (m *Manager) Update() error {
} }
return err 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 // Check that all of the repos we're dependent on actually exist and
// the repo index names. // the repo index names.
repoNames, err := m.getRepoNames(req.Dependencies) repoNames, err := m.getRepoNames(req.Dependencies)
...@@ -140,7 +147,7 @@ func (m *Manager) Update() error { ...@@ -140,7 +147,7 @@ func (m *Manager) Update() error {
// Now we need to find out which version of a chart best satisfies the // Now we need to find out which version of a chart best satisfies the
// requirements the requirements.yaml // requirements the requirements.yaml
lock, err := m.resolve(req, repoNames) lock, err := m.resolve(req, repoNames, hash)
if err != nil { if err != nil {
return err return err
} }
...@@ -172,9 +179,9 @@ func (m *Manager) loadChartDir() (*chart.Chart, error) { ...@@ -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. // 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. // 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) 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/ // 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, ...@@ -346,7 +353,13 @@ func (m *Manager) getRepoNames(deps []*chartutil.Dependency) (map[string]string,
found := false found := false
for _, repo := range repos { 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 found = true
reposMap[dd.Name] = repo.Name reposMap[dd.Name] = repo.Name
break break
......
...@@ -120,6 +120,20 @@ func TestGetRepoNames(t *testing.T) { ...@@ -120,6 +120,20 @@ func TestGetRepoNames(t *testing.T) {
}, },
expect: map[string]string{"local-dep": "file://./testdata/signtest"}, 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 { for _, tt := range tests {
......
...@@ -47,11 +47,7 @@ func New(chartpath string, helmhome helmpath.Home) *Resolver { ...@@ -47,11 +47,7 @@ func New(chartpath string, helmhome helmpath.Home) *Resolver {
} }
// Resolve resolves dependencies and returns a lock file with the resolution. // 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) { func (r *Resolver) Resolve(reqs *chartutil.Requirements, repoNames map[string]string, d string) (*chartutil.RequirementsLock, error) {
d, err := HashReq(reqs)
if err != nil {
return nil, err
}
// Now we clone the dependencies, locking as we go. // Now we clone the dependencies, locking as we go.
locked := make([]*chartutil.Dependency, len(reqs.Dependencies)) locked := make([]*chartutil.Dependency, len(reqs.Dependencies))
......
...@@ -104,7 +104,12 @@ func TestResolve(t *testing.T) { ...@@ -104,7 +104,12 @@ func TestResolve(t *testing.T) {
repoNames := map[string]string{"alpine": "kubernetes-charts", "redis": "kubernetes-charts"} repoNames := map[string]string{"alpine": "kubernetes-charts", "redis": "kubernetes-charts"}
r := New("testdata/chartpath", "testdata/helmhome") r := New("testdata/chartpath", "testdata/helmhome")
for _, tt := range tests { 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 err != nil {
if tt.err { if tt.err {
continue continue
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment