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
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
......
......@@ -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
```
......
......@@ -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
......
......@@ -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 {
......
......@@ -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))
......
......@@ -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
......
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