Unverified Commit fb2cbb00 authored by Matthew Fisher's avatar Matthew Fisher Committed by GitHub

Merge pull request #6578 from bacongobbler/fix-3442

fix(helm): Accept dependency in requirements.yaml from charts directory
parents 4e8063b1 74653d37
......@@ -216,6 +216,31 @@ func (m *Manager) downloadAll(deps []*chartutil.Dependency) error {
fmt.Fprintf(m.Out, "Saving %d charts\n", len(deps))
var saveError error
for _, dep := range deps {
// No repository means the chart is in charts directory
if dep.Repository == "" {
fmt.Fprintf(m.Out, "Dependency %s did not declare a repository. Assuming it exists in the charts directory\n", dep.Name)
chartPath := filepath.Join(tmpPath, dep.Name)
ch, err := chartutil.LoadDir(chartPath)
if err != nil {
return fmt.Errorf("Unable to load chart: %v", err)
}
constraint, err := semver.NewConstraint(dep.Version)
if err != nil {
return fmt.Errorf("Dependency %s has an invalid version/constraint format: %s", dep.Name, err)
}
v, err := semver.NewVersion(ch.Metadata.Version)
if err != nil {
return fmt.Errorf("Invalid version %s for dependency %s: %s", dep.Version, dep.Name, err)
}
if !constraint.Check(v) {
saveError = fmt.Errorf("Dependency %s at version %s does not satisfy the constraint %s", dep.Name, ch.Metadata.Version, dep.Version)
break
}
continue
}
if strings.HasPrefix(dep.Repository, "file://") {
if m.Debug {
fmt.Fprintf(m.Out, "Archiving %s from repo %s\n", dep.Name, dep.Repository)
......@@ -258,10 +283,13 @@ func (m *Manager) downloadAll(deps []*chartutil.Dependency) error {
if saveError == nil {
fmt.Fprintln(m.Out, "Deleting outdated charts")
for _, dep := range deps {
// Chart from local charts directory stays in place
if dep.Repository != "" {
if err := m.safeDeleteDep(dep.Name, tmpPath); err != nil {
return err
}
}
}
if err := move(tmpPath, destPath); err != nil {
return err
}
......@@ -371,8 +399,9 @@ func (m *Manager) getRepoNames(deps []*chartutil.Dependency) (map[string]string,
// by Helm.
missing := []string{}
for _, dd := range deps {
// Don't map the repository, we don't need to download chart from charts directory
if dd.Repository == "" {
return nil, fmt.Errorf("no 'repository' field specified for dependency: %q", dd.Name)
continue
}
// if dep chart is from local path, verify the path is valid
if strings.HasPrefix(dd.Repository, "file://") {
......@@ -663,3 +692,60 @@ func move(tmpPath, destPath string) error {
}
return nil
}
func copyFile(source string, destination string) (err error) {
sourceFile, err := os.Open(source)
if err != nil {
return err
}
defer sourceFile.Close()
destinationFile, err := os.Create(destination)
if err != nil {
return err
}
defer destinationFile.Close()
_, err = io.Copy(destinationFile, sourceFile)
if err == nil {
stats, err := os.Stat(source)
if err == nil {
return os.Chmod(destination, stats.Mode())
}
}
return err
}
func copyDir(source string, destination string) (err error) {
fi, err := os.Stat(source)
if err != nil {
return err
}
if !fi.IsDir() {
return fmt.Errorf("Source is not a directory")
}
_, err = os.Open(destination)
if !os.IsNotExist(err) {
return fmt.Errorf("Destination already exists")
}
err = os.MkdirAll(destination, fi.Mode())
if err != nil {
return err
}
entries, err := ioutil.ReadDir(source)
for _, entry := range entries {
sourceFile := source + "/" + entry.Name()
destinationFile := destination + "/" + entry.Name()
if entry.IsDir() {
err = copyDir(sourceFile, destinationFile)
if err != nil {
return err
}
} else {
err = copyFile(sourceFile, destinationFile)
if err != nil {
return err
}
}
}
return
}
......@@ -113,14 +113,6 @@ func TestGetRepoNames(t *testing.T) {
},
err: true,
},
{
name: "dependency entry missing 'repository' field -- e.g. spelled 'repo'",
req: []*chartutil.Dependency{
{Name: "dependency-missing-repository-field"},
},
err: true,
expectedErr: "no 'repository' field specified for dependency: \"dependency-missing-repository-field\"",
},
{
name: "dependency repository is url but not exist in repos",
req: []*chartutil.Dependency{
......@@ -156,6 +148,13 @@ func TestGetRepoNames(t *testing.T) {
},
expect: map[string]string{"oedipus-rex": "testing"},
},
{
name: "repo from local chart under charts path",
req: []*chartutil.Dependency{
{Name: "local-subchart", Repository: ""},
},
expect: map[string]string{},
},
}
for _, tt := range tests {
......
description: A Helm chart for Kubernetes
name: local-subchart
version: 0.1.0
......@@ -53,6 +53,19 @@ func (r *Resolver) Resolve(reqs *chartutil.Requirements, repoNames map[string]st
locked := make([]*chartutil.Dependency, len(reqs.Dependencies))
missing := []string{}
for i, d := range reqs.Dependencies {
if d.Repository == "" {
// Local chart subfolder
if _, err := GetLocalPath(filepath.Join("charts", d.Name), r.chartpath); err != nil {
return nil, err
}
locked[i] = &chartutil.Dependency{
Name: d.Name,
Repository: "",
Version: d.Version,
}
continue
}
if strings.HasPrefix(d.Repository, "file://") {
if _, err := GetLocalPath(d.Repository, r.chartpath); err != nil {
......
......@@ -90,6 +90,33 @@ func TestResolve(t *testing.T) {
},
err: true,
},
{
name: "repo from valid path under charts path",
req: &chartutil.Requirements{
Dependencies: []*chartutil.Dependency{
{Name: "localdependency", Repository: "", Version: "0.1.0"},
},
},
expect: &chartutil.RequirementsLock{
Dependencies: []*chartutil.Dependency{
{Name: "localdependency", Repository: "", Version: "0.1.0"},
},
},
},
{
name: "repo from valid path under charts path",
req: &chartutil.Requirements{
Dependencies: []*chartutil.Dependency{
{Name: "nonexistentdependency", Repository: "", Version: "0.1.0"},
},
},
expect: &chartutil.RequirementsLock{
Dependencies: []*chartutil.Dependency{
{Name: "nonexistentlocaldependency", Repository: "", Version: "0.1.0"},
},
},
err: true,
},
}
repoNames := map[string]string{"alpine": "kubernetes-charts", "redis": "kubernetes-charts"}
......
description: A Helm chart for Kubernetes
name: localdependency
version: 0.1.0
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