ref(*): merge requirement.yaml into Chart.yaml

Signed-off-by: Adam Reese <adam@reese.io>
pull/4561/head
Adam Reese 7 years ago
parent 07de1018d9
commit f7a7a157ce
No known key found for this signature in database
GPG Key ID: 06F35E60A7A18DD6

@ -136,14 +136,14 @@ func (o *dependencyLisOptions) run(out io.Writer) error {
return err return err
} }
if c.Requirements == nil { if c.Metadata.Requirements == nil {
fmt.Fprintf(out, "WARNING: no requirements at %s/charts\n", o.chartpath) fmt.Fprintf(out, "WARNING: no requirements at %s/charts\n", o.chartpath)
return nil return nil
} }
o.printRequirements(out, c.Requirements) o.printRequirements(out, c.Metadata.Requirements)
fmt.Fprintln(out) fmt.Fprintln(out)
o.printMissing(out, c.Requirements) o.printMissing(out, c.Metadata.Requirements)
return nil return nil
} }
@ -222,18 +222,18 @@ func (o *dependencyLisOptions) dependencyStatus(dep *chart.Dependency) string {
} }
// printRequirements prints all of the requirements in the yaml file. // printRequirements prints all of the requirements in the yaml file.
func (o *dependencyLisOptions) printRequirements(out io.Writer, reqs *chart.Requirements) { func (o *dependencyLisOptions) printRequirements(out io.Writer, reqs []*chart.Dependency) {
table := uitable.New() table := uitable.New()
table.MaxColWidth = 80 table.MaxColWidth = 80
table.AddRow("NAME", "VERSION", "REPOSITORY", "STATUS") table.AddRow("NAME", "VERSION", "REPOSITORY", "STATUS")
for _, row := range reqs.Dependencies { for _, row := range reqs {
table.AddRow(row.Name, row.Version, row.Repository, o.dependencyStatus(row)) table.AddRow(row.Name, row.Version, row.Repository, o.dependencyStatus(row))
} }
fmt.Fprintln(out, table) fmt.Fprintln(out, table)
} }
// printMissing prints warnings about charts that are present on disk, but are not in the requirements. // printMissing prints warnings about charts that are present on disk, but are not in the requirements.
func (o *dependencyLisOptions) printMissing(out io.Writer, reqs *chart.Requirements) { func (o *dependencyLisOptions) printMissing(out io.Writer, reqs []*chart.Dependency) {
folder := filepath.Join(o.chartpath, "charts/*") folder := filepath.Join(o.chartpath, "charts/*")
files, err := filepath.Glob(folder) files, err := filepath.Glob(folder)
if err != nil { if err != nil {
@ -256,14 +256,14 @@ func (o *dependencyLisOptions) printMissing(out io.Writer, reqs *chart.Requireme
continue continue
} }
found := false found := false
for _, d := range reqs.Dependencies { for _, d := range reqs {
if d.Name == c.Name() { if d.Name == c.Name() {
found = true found = true
break break
} }
} }
if !found { if !found {
fmt.Fprintf(out, "WARNING: %q is not in requirements.yaml.\n", f) fmt.Fprintf(out, "WARNING: %q is not in Chart.yaml.\n", f)
} }
} }

@ -28,18 +28,18 @@ import (
) )
const dependencyUpDesc = ` const dependencyUpDesc = `
Update the on-disk dependencies to mirror the requirements.yaml file. Update the on-disk dependencies to mirror Chart.yaml.
This command verifies that the required charts, as expressed in 'requirements.yaml', This command verifies that the required charts, as expressed in 'Chart.yaml',
are present in 'charts/' and are at an acceptable version. It will pull down are present in 'charts/' and are at an acceptable version. It will pull down
the latest charts that satisfy the dependencies, and clean up old dependencies. the latest charts that satisfy the dependencies, and clean up old dependencies.
On successful update, this will generate a lock file that can be used to On successful update, this will generate a lock file that can be used to
rebuild the requirements to an exact version. rebuild the requirements to an exact version.
Dependencies are not required to be represented in 'requirements.yaml'. For that Dependencies are not required to be represented in 'Chart.yaml'. For that
reason, an update command will not remove charts unless they are (a) present reason, an update command will not remove charts unless they are (a) present
in the requirements.yaml file, but (b) at the wrong version. in the Chart.yaml file, but (b) at the wrong version.
` `
// dependencyUpdateOptions describes a 'helm dependency update' // dependencyUpdateOptions describes a 'helm dependency update'
@ -63,7 +63,7 @@ func newDependencyUpdateCmd(out io.Writer) *cobra.Command {
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "update CHART", Use: "update CHART",
Aliases: []string{"up"}, Aliases: []string{"up"},
Short: "update charts/ based on the contents of requirements.yaml", Short: "update charts/ based on the contents of Chart.yaml",
Long: dependencyUpDesc, Long: dependencyUpDesc,
Args: require.MaximumNArgs(1), Args: require.MaximumNArgs(1),
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {

@ -24,8 +24,6 @@ import (
"strings" "strings"
"testing" "testing"
"github.com/ghodss/yaml"
"k8s.io/helm/pkg/chart" "k8s.io/helm/pkg/chart"
"k8s.io/helm/pkg/chartutil" "k8s.io/helm/pkg/chartutil"
"k8s.io/helm/pkg/provenance" "k8s.io/helm/pkg/provenance"
@ -49,7 +47,8 @@ func TestDependencyUpdateCmd(t *testing.T) {
t.Logf("Listening on directory %s", srv.Root()) t.Logf("Listening on directory %s", srv.Root())
chartname := "depup" chartname := "depup"
if err := createTestingChart(hh.String(), chartname, srv.URL()); err != nil { md := createTestingMetadata(chartname, srv.URL())
if _, err := chartutil.Create(md, hh.String()); err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -87,14 +86,12 @@ func TestDependencyUpdateCmd(t *testing.T) {
// Now change the dependencies and update. This verifies that on update, // Now change the dependencies and update. This verifies that on update,
// old dependencies are cleansed and new dependencies are added. // old dependencies are cleansed and new dependencies are added.
reqfile := &chart.Requirements{ md.Requirements = []*chart.Dependency{
Dependencies: []*chart.Dependency{ {Name: "reqtest", Version: "0.1.0", Repository: srv.URL()},
{Name: "reqtest", Version: "0.1.0", Repository: srv.URL()}, {Name: "compressedchart", Version: "0.3.0", Repository: srv.URL()},
{Name: "compressedchart", Version: "0.3.0", Repository: srv.URL()},
},
} }
dir := hh.Path(chartname) dir := hh.Path(chartname, "Chart.yaml")
if err := writeRequirements(dir, reqfile); err != nil { if err := chartutil.SaveChartfile(dir, md); err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -209,33 +206,25 @@ func TestDependencyUpdateCmd_DontDeleteOldChartsOnError(t *testing.T) {
} }
} }
// createTestingChart creates a basic chart that depends on reqtest-0.1.0 // createTestingMetadata creates a basic chart that depends on reqtest-0.1.0
// //
// The baseURL can be used to point to a particular repository server. // The baseURL can be used to point to a particular repository server.
func createTestingChart(dest, name, baseURL string) error { func createTestingMetadata(name, baseURL string) *chart.Metadata {
cfile := &chart.Metadata{ return &chart.Metadata{
Name: name, Name: name,
Version: "1.2.3", Version: "1.2.3",
} Requirements: []*chart.Dependency{
dir := filepath.Join(dest, name)
_, err := chartutil.Create(cfile, dest)
if err != nil {
return err
}
req := &chart.Requirements{
Dependencies: []*chart.Dependency{
{Name: "reqtest", Version: "0.1.0", Repository: baseURL}, {Name: "reqtest", Version: "0.1.0", Repository: baseURL},
{Name: "compressedchart", Version: "0.1.0", Repository: baseURL}, {Name: "compressedchart", Version: "0.1.0", Repository: baseURL},
}, },
} }
return writeRequirements(dir, req)
} }
func writeRequirements(dir string, req *chart.Requirements) error { // createTestingChart creates a basic chart that depends on reqtest-0.1.0
data, err := yaml.Marshal(req) //
if err != nil { // The baseURL can be used to point to a particular repository server.
return err func createTestingChart(dest, name, baseURL string) error {
} cfile := createTestingMetadata(name, baseURL)
_, err := chartutil.Create(cfile, dest)
return ioutil.WriteFile(filepath.Join(dir, "requirements.yaml"), data, 0655) return err
} }

@ -141,12 +141,10 @@ func ensureTestHome(t *testing.T, home helmpath.Home) {
} }
} }
if r, err := repo.LoadRepositoriesFile(repoFile); err == repo.ErrRepoOutOfDate { if r, err := repo.LoadRepositoriesFile(repoFile); err == repo.ErrRepoOutOfDate {
t.Log("Updating repository file format...")
if err := r.WriteFile(repoFile, 0644); err != nil { if err := r.WriteFile(repoFile, 0644); err != nil {
t.Fatal(err) t.Fatal(err)
} }
} }
t.Logf("$HELM_HOME has been configured at %s.\n", home)
} }
// testHelmHome sets up a Helm Home in a temp dir. // testHelmHome sets up a Helm Home in a temp dir.

@ -181,7 +181,7 @@ func (o *installOptions) run(out io.Writer) error {
return err return err
} }
if req := chartRequested.Requirements; req != nil { if req := chartRequested.Metadata.Requirements; req != nil {
// If checkDependencies returns an error, we have unfulfilled dependencies. // If checkDependencies returns an error, we have unfulfilled dependencies.
// As of Helm 2.4.0, this is treated as a stopping condition: // As of Helm 2.4.0, this is treated as a stopping condition:
// https://github.com/kubernetes/helm/issues/2209 // https://github.com/kubernetes/helm/issues/2209
@ -286,11 +286,11 @@ func generateName(nameTemplate string) (string, error) {
return b.String(), err return b.String(), err
} }
func checkDependencies(ch *chart.Chart, reqs *chart.Requirements) error { func checkDependencies(ch *chart.Chart, reqs []*chart.Dependency) error {
var missing []string var missing []string
OUTER: OUTER:
for _, r := range reqs.Dependencies { for _, r := range reqs {
for _, d := range ch.Dependencies() { for _, d := range ch.Dependencies() {
if d.Name() == r.Name { if d.Name() == r.Name {
continue OUTER continue OUTER

@ -112,9 +112,9 @@ func TestInstall(t *testing.T) {
cmd: "install testdata/testcharts/chart-missing-deps", cmd: "install testdata/testcharts/chart-missing-deps",
wantError: true, wantError: true,
}, },
// Install, chart with bad requirements.yaml in /charts // Install, chart with bad dependencies in Chart.yaml in /charts
{ {
name: "install chart with bad requirements.yaml", name: "install chart with bad dependencies in Chart.yaml",
cmd: "install testdata/testcharts/chart-bad-requirements", cmd: "install testdata/testcharts/chart-bad-requirements",
wantError: true, wantError: true,
}, },

@ -102,7 +102,7 @@ func newPackageCmd(out io.Writer) *cobra.Command {
f.StringVar(&o.version, "version", "", "set the version on the chart to this semver version") f.StringVar(&o.version, "version", "", "set the version on the chart to this semver version")
f.StringVar(&o.appVersion, "app-version", "", "set the appVersion on the chart to this version") f.StringVar(&o.appVersion, "app-version", "", "set the appVersion on the chart to this version")
f.StringVarP(&o.destination, "destination", "d", ".", "location to write the chart.") f.StringVarP(&o.destination, "destination", "d", ".", "location to write the chart.")
f.BoolVarP(&o.dependencyUpdate, "dependency-update", "u", false, `update dependencies from "requirements.yaml" to dir "charts/" before packaging`) f.BoolVarP(&o.dependencyUpdate, "dependency-update", "u", false, `update dependencies from "Chart.yaml" to dir "charts/" before packaging`)
o.valuesOptions.addFlags(f) o.valuesOptions.addFlags(f)
return cmd return cmd
@ -161,7 +161,7 @@ func (o *packageOptions) run(out io.Writer) error {
return errors.Errorf("directory name (%s) and Chart.yaml name (%s) must match", filepath.Base(path), ch.Name()) return errors.Errorf("directory name (%s) and Chart.yaml name (%s) must match", filepath.Base(path), ch.Name())
} }
if reqs := ch.Requirements; reqs != nil { if reqs := ch.Metadata.Requirements; reqs != nil {
if err := checkDependencies(ch, reqs); err != nil { if err := checkDependencies(ch, reqs); err != nil {
return err return err
} }

@ -158,7 +158,7 @@ func (o *templateOptions) run(out io.Writer) error {
return err return err
} }
if req := c.Requirements; req != nil { if req := c.Metadata.Requirements; req != nil {
if err := checkDependencies(c, req); err != nil { if err := checkDependencies(c, req); err != nil {
return err return err
} }

@ -1,4 +1,5 @@
NAME VERSION REPOSITORY STATUS NAME VERSION REPOSITORY STATUS
reqsubchart 0.1.0 https://example.com/charts missing reqsubchart 0.1.0 https://example.com/charts missing
reqsubchart2 0.2.0 https://example.com/charts missing reqsubchart2 0.2.0 https://example.com/charts missing
reqsubchart3 >=0.1.0 https://example.com/charts missing

@ -1 +1 @@
Error: cannot load requirements.yaml: error converting YAML to JSON: yaml: line 2: did not find expected '-' indicator Error: cannot load Chart.yaml: error converting YAML to JSON: yaml: line 5: did not find expected '-' indicator

@ -1,3 +1,7 @@
description: A Helm chart for Kubernetes description: A Helm chart for Kubernetes
name: chart-missing-deps name: chart-missing-deps
version: 0.1.0 version: 0.1.0
dependencies:
- name: reqsubchart
version: 0.1.0
repository: "https://example.com/charts"

@ -1,3 +1,10 @@
description: A Helm chart for Kubernetes description: A Helm chart for Kubernetes
name: chart-missing-deps name: chart-missing-deps
version: 0.1.0 version: 0.1.0
dependencies:
- name: reqsubchart
version: 0.1.0
repository: "https://example.com/charts"
- name: reqsubchart2
version: 0.2.0
repository: "https://example.com/charts"

Binary file not shown.

@ -1,3 +1,13 @@
description: A Helm chart for Kubernetes description: A Helm chart for Kubernetes
name: reqtest name: reqtest
version: 0.1.0 version: 0.1.0
dependencies:
- name: reqsubchart
version: 0.1.0
repository: "https://example.com/charts"
- name: reqsubchart2
version: 0.2.0
repository: "https://example.com/charts"
- name: reqsubchart3
version: ">=0.1.0"
repository: "https://example.com/charts"

@ -154,7 +154,7 @@ func (o *upgradeOptions) run(out io.Writer) error {
if err != nil { if err != nil {
return err return err
} }
if req := ch.Requirements; req != nil { if req := ch.Metadata.Requirements; req != nil {
if err := checkDependencies(ch, req); err != nil { if err := checkDependencies(ch, req); err != nil {
return err return err
} }

@ -20,8 +20,6 @@ package chart
type Chart struct { type Chart struct {
// Metadata is the contents of the Chartfile. // Metadata is the contents of the Chartfile.
Metadata *Metadata Metadata *Metadata
// Requirements is the contents of requirements.yaml.
Requirements *Requirements
// RequirementsLock is the contents of requirements.lock. // RequirementsLock is the contents of requirements.lock.
RequirementsLock *RequirementsLock RequirementsLock *RequirementsLock
// Templates for this chart. // Templates for this chart.

@ -77,11 +77,6 @@ func LoadFiles(files []*BufferedFile) (*chart.Chart, error) {
if err := yaml.Unmarshal(f.Data, c.Metadata); err != nil { if err := yaml.Unmarshal(f.Data, c.Metadata); err != nil {
return c, errors.Wrap(err, "cannot load Chart.yaml") return c, errors.Wrap(err, "cannot load Chart.yaml")
} }
case f.Name == "requirements.yaml":
c.Requirements = new(chart.Requirements)
if err := yaml.Unmarshal(f.Data, c.Requirements); err != nil {
return c, errors.Wrap(err, "cannot load requirements.yaml")
}
case f.Name == "requirements.lock": case f.Name == "requirements.lock":
c.RequirementsLock = new(chart.RequirementsLock) c.RequirementsLock = new(chart.RequirementsLock)
if err := yaml.Unmarshal(f.Data, &c.RequirementsLock); err != nil { if err := yaml.Unmarshal(f.Data, &c.RequirementsLock); err != nil {

@ -176,15 +176,15 @@ func verifyChart(t *testing.T, c *chart.Chart) {
} }
func verifyRequirements(t *testing.T, c *chart.Chart) { func verifyRequirements(t *testing.T, c *chart.Chart) {
if len(c.Requirements.Dependencies) != 2 { if len(c.Metadata.Requirements) != 2 {
t.Errorf("Expected 2 requirements, got %d", len(c.Requirements.Dependencies)) t.Errorf("Expected 2 requirements, got %d", len(c.Metadata.Requirements))
} }
tests := []*chart.Dependency{ tests := []*chart.Dependency{
{Name: "alpine", Version: "0.1.0", Repository: "https://example.com/charts"}, {Name: "alpine", Version: "0.1.0", Repository: "https://example.com/charts"},
{Name: "mariner", Version: "4.3.2", Repository: "https://example.com/charts"}, {Name: "mariner", Version: "4.3.2", Repository: "https://example.com/charts"},
} }
for i, tt := range tests { for i, tt := range tests {
d := c.Requirements.Dependencies[i] d := c.Metadata.Requirements[i]
if d.Name != tt.Name { if d.Name != tt.Name {
t.Errorf("Expected dependency named %q, got %q", tt.Name, d.Name) t.Errorf("Expected dependency named %q, got %q", tt.Name, d.Name)
} }
@ -198,15 +198,15 @@ func verifyRequirements(t *testing.T, c *chart.Chart) {
} }
func verifyRequirementsLock(t *testing.T, c *chart.Chart) { func verifyRequirementsLock(t *testing.T, c *chart.Chart) {
if len(c.Requirements.Dependencies) != 2 { if len(c.Metadata.Requirements) != 2 {
t.Errorf("Expected 2 requirements, got %d", len(c.Requirements.Dependencies)) t.Errorf("Expected 2 requirements, got %d", len(c.Metadata.Requirements))
} }
tests := []*chart.Dependency{ tests := []*chart.Dependency{
{Name: "alpine", Version: "0.1.0", Repository: "https://example.com/charts"}, {Name: "alpine", Version: "0.1.0", Repository: "https://example.com/charts"},
{Name: "mariner", Version: "4.3.2", Repository: "https://example.com/charts"}, {Name: "mariner", Version: "4.3.2", Repository: "https://example.com/charts"},
} }
for i, tt := range tests { for i, tt := range tests {
d := c.Requirements.Dependencies[i] d := c.Metadata.Requirements[i]
if d.Name != tt.Name { if d.Name != tt.Name {
t.Errorf("Expected dependency named %q, got %q", tt.Name, d.Name) t.Errorf("Expected dependency named %q, got %q", tt.Name, d.Name)
} }
@ -224,7 +224,6 @@ func verifyFrobnitz(t *testing.T, c *chart.Chart) {
} }
func verifyChartFileAndTemplate(t *testing.T, c *chart.Chart, name string) { func verifyChartFileAndTemplate(t *testing.T, c *chart.Chart, name string) {
if c.Metadata == nil { if c.Metadata == nil {
t.Fatal("Metadata is nil") t.Fatal("Metadata is nil")
} }
@ -246,8 +245,8 @@ func verifyChartFileAndTemplate(t *testing.T, c *chart.Chart, name string) {
if len(c.Dependencies()) != 2 { if len(c.Dependencies()) != 2 {
t.Fatalf("Expected 2 Dependency, got %d", len(c.Dependencies())) t.Fatalf("Expected 2 Dependency, got %d", len(c.Dependencies()))
} }
if len(c.Requirements.Dependencies) != 2 { if len(c.Metadata.Requirements) != 2 {
t.Fatalf("Expected 2 Requirements.Dependency, got %d", len(c.Requirements.Dependencies)) t.Fatalf("Expected 2 Requirements.Dependency, got %d", len(c.Metadata.Requirements))
} }
if len(c.RequirementsLock.Dependencies) != 2 { if len(c.RequirementsLock.Dependencies) != 2 {
t.Fatalf("Expected 2 RequirementsLock.Dependency, got %d", len(c.RequirementsLock.Dependencies)) t.Fatalf("Expected 2 RequirementsLock.Dependency, got %d", len(c.RequirementsLock.Dependencies))

@ -0,0 +1,4 @@
name: albatross
description: A Helm chart for Kubernetes
version: 0.1.0
home: ""

@ -0,0 +1,4 @@
albatross: "true"
global:
author: Coleridge

Binary file not shown.

@ -18,3 +18,10 @@ icon: https://example.com/64x64.png
annotations: annotations:
extrakey: extravalue extrakey: extravalue
anotherkey: anothervalue anotherkey: anothervalue
dependencies:
- name: alpine
version: "0.1.0"
repository: https://example.com/charts
- name: mariner
version: "4.3.2"
repository: https://example.com/charts

@ -1,7 +0,0 @@
dependencies:
- name: alpine
version: "0.1.0"
repository: https://example.com/charts
- name: mariner
version: "4.3.2"
repository: https://example.com/charts

@ -18,3 +18,10 @@ icon: https://example.com/64x64.png
annotations: annotations:
extrakey: extravalue extrakey: extravalue
anotherkey: anothervalue anotherkey: anothervalue
dependencies:
- name: alpine
version: "0.1.0"
repository: https://example.com/charts
- name: mariner
version: "4.3.2"
repository: https://example.com/charts

@ -1,7 +0,0 @@
dependencies:
- name: alpine
version: "0.1.0"
repository: https://example.com/charts
- name: mariner
version: "4.3.2"
repository: https://example.com/charts

@ -0,0 +1,12 @@
#!/bin/sh
# Pack the albatross chart into the mariner chart.
echo "Packing albatross into mariner"
tar -zcvf mariner/charts/albatross-0.1.0.tgz albatross
echo "Packing mariner into frobnitz"
tar -zcvf frobnitz/charts/mariner-4.3.2.tgz mariner
# Pack the frobnitz chart.
echo "Packing frobnitz"
tar --exclude=ignore/* -zcvf frobnitz-1.2.3.tgz frobnitz

@ -0,0 +1,8 @@
name: mariner
description: A Helm chart for Kubernetes
version: 4.3.2
home: ""
dependencies:
- name: albatross
repository: https://example.com/mariner/charts
version: "0.1.0"

@ -0,0 +1,7 @@
# Default values for <CHARTNAME>.
# This is a YAML-formatted file. https://github.com/toml-lang/toml
# Declare name/value pairs to be passed into your templates.
# name: "value"
<CHARTNAME>:
test: true

@ -65,4 +65,6 @@ type Metadata struct {
Annotations map[string]string `json:"annotations,omitempty"` Annotations map[string]string `json:"annotations,omitempty"`
// KubeVersion is a SemVer constraint specifying the version of Kubernetes required. // KubeVersion is a SemVer constraint specifying the version of Kubernetes required.
KubeVersion string `json:"kubeVersion,omitempty"` KubeVersion string `json:"kubeVersion,omitempty"`
// Requirements are a list of requirements for a chart.
Requirements []*Dependency `json:"dependencies,omitempty"`
} }

@ -49,14 +49,6 @@ type Dependency struct {
Alias string `json:"alias,omitempty"` Alias string `json:"alias,omitempty"`
} }
// Requirements is a list of requirements for a chart.
//
// Requirements are charts upon which this chart depends. This expresses
// developer intent.
type Requirements struct {
Dependencies []*Dependency `json:"dependencies"`
}
// RequirementsLock is a lock file for requirements. // RequirementsLock is a lock file for requirements.
// //
// It represents the state that the dependencies should be in. // It represents the state that the dependencies should be in.

@ -318,7 +318,7 @@ func CreateFrom(chartfile *chart.Metadata, dest, src string) error {
} }
var m map[string]interface{} var m map[string]interface{}
if err := yaml.Unmarshal([]byte(transform(string(b), schart.Name())), &m); err != nil { if err := yaml.Unmarshal(transform(string(b), schart.Name()), &m); err != nil {
return err return err
} }
schart.Values = m schart.Values = m

@ -26,11 +26,11 @@ import (
) )
// ProcessRequirementsConditions disables charts based on condition path value in values // ProcessRequirementsConditions disables charts based on condition path value in values
func ProcessRequirementsConditions(reqs *chart.Requirements, cvals Values) { func ProcessRequirementsConditions(reqs []*chart.Dependency, cvals Values) {
if reqs == nil { if reqs == nil {
return return
} }
for _, r := range reqs.Dependencies { for _, r := range reqs {
var hasTrue, hasFalse bool var hasTrue, hasFalse bool
for _, c := range strings.Split(strings.TrimSpace(r.Condition), ",") { for _, c := range strings.Split(strings.TrimSpace(r.Condition), ",") {
if len(c) > 0 { if len(c) > 0 {
@ -67,7 +67,7 @@ func ProcessRequirementsConditions(reqs *chart.Requirements, cvals Values) {
} }
// ProcessRequirementsTags disables charts based on tags in values // ProcessRequirementsTags disables charts based on tags in values
func ProcessRequirementsTags(reqs *chart.Requirements, cvals Values) { func ProcessRequirementsTags(reqs []*chart.Dependency, cvals Values) {
if reqs == nil { if reqs == nil {
return return
} }
@ -75,7 +75,7 @@ func ProcessRequirementsTags(reqs *chart.Requirements, cvals Values) {
if err != nil { if err != nil {
return return
} }
for _, r := range reqs.Dependencies { for _, r := range reqs {
var hasTrue, hasFalse bool var hasTrue, hasFalse bool
for _, k := range r.Tags { for _, k := range r.Tags {
if b, ok := vt[k]; ok { if b, ok := vt[k]; ok {
@ -127,19 +127,19 @@ func getAliasDependency(charts []*chart.Chart, aliasChart *chart.Dependency) *ch
// ProcessRequirementsEnabled removes disabled charts from dependencies // ProcessRequirementsEnabled removes disabled charts from dependencies
func ProcessRequirementsEnabled(c *chart.Chart, v map[string]interface{}) error { func ProcessRequirementsEnabled(c *chart.Chart, v map[string]interface{}) error {
if c.Requirements == nil { if c.Metadata.Requirements == nil {
return nil return nil
} }
var chartDependencies []*chart.Chart var chartDependencies []*chart.Chart
// If any dependency is not a part of requirements.yaml // If any dependency is not a part of Chart.yaml
// then this should be added to chartDependencies. // then this should be added to chartDependencies.
// However, if the dependency is already specified in requirements.yaml // However, if the dependency is already specified in Chart.yaml
// we should not add it, as it would be anyways processed from requirements.yaml // we should not add it, as it would be anyways processed from Chart.yaml
for _, existingDependency := range c.Dependencies() { for _, existingDependency := range c.Dependencies() {
var dependencyFound bool var dependencyFound bool
for _, req := range c.Requirements.Dependencies { for _, req := range c.Metadata.Requirements {
if existingDependency.Metadata.Name == req.Name && version.IsCompatibleRange(req.Version, existingDependency.Metadata.Version) { if existingDependency.Metadata.Name == req.Name && version.IsCompatibleRange(req.Version, existingDependency.Metadata.Version) {
dependencyFound = true dependencyFound = true
break break
@ -150,7 +150,7 @@ func ProcessRequirementsEnabled(c *chart.Chart, v map[string]interface{}) error
} }
} }
for _, req := range c.Requirements.Dependencies { for _, req := range c.Metadata.Requirements {
if chartDependency := getAliasDependency(c.Dependencies(), req); chartDependency != nil { if chartDependency := getAliasDependency(c.Dependencies(), req); chartDependency != nil {
chartDependencies = append(chartDependencies, chartDependency) chartDependencies = append(chartDependencies, chartDependency)
} }
@ -161,7 +161,7 @@ func ProcessRequirementsEnabled(c *chart.Chart, v map[string]interface{}) error
c.SetDependencies(chartDependencies...) c.SetDependencies(chartDependencies...)
// set all to true // set all to true
for _, lr := range c.Requirements.Dependencies { for _, lr := range c.Metadata.Requirements {
lr.Enabled = true lr.Enabled = true
} }
b, _ := yaml.Marshal(v) b, _ := yaml.Marshal(v)
@ -170,11 +170,11 @@ func ProcessRequirementsEnabled(c *chart.Chart, v map[string]interface{}) error
return err return err
} }
// flag dependencies as enabled/disabled // flag dependencies as enabled/disabled
ProcessRequirementsTags(c.Requirements, cvals) ProcessRequirementsTags(c.Metadata.Requirements, cvals)
ProcessRequirementsConditions(c.Requirements, cvals) ProcessRequirementsConditions(c.Metadata.Requirements, cvals)
// make a map of charts to remove // make a map of charts to remove
rm := map[string]struct{}{} rm := map[string]struct{}{}
for _, r := range c.Requirements.Dependencies { for _, r := range c.Metadata.Requirements {
if !r.Enabled { if !r.Enabled {
// remove disabled chart // remove disabled chart
rm[r.Name] = struct{}{} rm[r.Name] = struct{}{}
@ -232,7 +232,7 @@ func pathToMap(path string, data map[string]interface{}) map[string]interface{}
// processImportValues merges values from child to parent based on the chart's dependencies' ImportValues field. // processImportValues merges values from child to parent based on the chart's dependencies' ImportValues field.
func processImportValues(c *chart.Chart) error { func processImportValues(c *chart.Chart) error {
if c.Requirements == nil { if c.Metadata.Requirements == nil {
return nil return nil
} }
// combine chart values and empty config to get Values // combine chart values and empty config to get Values
@ -242,7 +242,7 @@ func processImportValues(c *chart.Chart) error {
} }
b := make(map[string]interface{}) b := make(map[string]interface{})
// import values from each dependency if specified in import-values // import values from each dependency if specified in import-values
for _, r := range c.Requirements.Dependencies { for _, r := range c.Metadata.Requirements {
var outiv []interface{} var outiv []interface{}
for _, riv := range r.ImportValues { for _, riv := range r.ImportValues {
switch iv := riv.(type) { switch iv := riv.(type) {

@ -256,39 +256,39 @@ func TestGetAliasDependency(t *testing.T) {
t.Fatalf("Failed to load testdata: %s", err) t.Fatalf("Failed to load testdata: %s", err)
} }
req := c.Requirements req := c.Metadata.Requirements
if len(req.Dependencies) == 0 { if len(req) == 0 {
t.Fatalf("There are no requirements to test") t.Fatalf("There are no requirements to test")
} }
// Success case // Success case
aliasChart := getAliasDependency(c.Dependencies(), req.Dependencies[0]) aliasChart := getAliasDependency(c.Dependencies(), req[0])
if aliasChart == nil { if aliasChart == nil {
t.Fatalf("Failed to get dependency chart for alias %s", req.Dependencies[0].Name) t.Fatalf("Failed to get dependency chart for alias %s", req[0].Name)
} }
if req.Dependencies[0].Alias != "" { if req[0].Alias != "" {
if aliasChart.Name() != req.Dependencies[0].Alias { if aliasChart.Name() != req[0].Alias {
t.Fatalf("Dependency chart name should be %s but got %s", req.Dependencies[0].Alias, aliasChart.Name()) t.Fatalf("Dependency chart name should be %s but got %s", req[0].Alias, aliasChart.Name())
} }
} else if aliasChart.Name() != req.Dependencies[0].Name { } else if aliasChart.Name() != req[0].Name {
t.Fatalf("Dependency chart name should be %s but got %s", req.Dependencies[0].Name, aliasChart.Name()) t.Fatalf("Dependency chart name should be %s but got %s", req[0].Name, aliasChart.Name())
} }
if req.Dependencies[0].Version != "" { if req[0].Version != "" {
if !version.IsCompatibleRange(req.Dependencies[0].Version, aliasChart.Metadata.Version) { if !version.IsCompatibleRange(req[0].Version, aliasChart.Metadata.Version) {
t.Fatalf("Dependency chart version is not in the compatible range") t.Fatalf("Dependency chart version is not in the compatible range")
} }
} }
// Failure case // Failure case
req.Dependencies[0].Name = "something-else" req[0].Name = "something-else"
if aliasChart := getAliasDependency(c.Dependencies(), req.Dependencies[0]); aliasChart != nil { if aliasChart := getAliasDependency(c.Dependencies(), req[0]); aliasChart != nil {
t.Fatalf("expected no chart but got %s", aliasChart.Name()) t.Fatalf("expected no chart but got %s", aliasChart.Name())
} }
req.Dependencies[0].Version = "something else which is not in the compatible range" req[0].Version = "something else which is not in the compatible range"
if version.IsCompatibleRange(req.Dependencies[0].Version, aliasChart.Metadata.Version) { if version.IsCompatibleRange(req[0].Version, aliasChart.Metadata.Version) {
t.Fatalf("Dependency chart version which is not in the compatible range should cause a failure other than a success ") t.Fatalf("Dependency chart version which is not in the compatible range should cause a failure other than a success ")
} }
} }
@ -312,8 +312,8 @@ func TestDependentChartAliases(t *testing.T) {
t.Fatal("Expected alias dependencies to be added, but did not got that") t.Fatal("Expected alias dependencies to be added, but did not got that")
} }
if len(c.Dependencies()) != len(c.Requirements.Dependencies) { if len(c.Dependencies()) != len(c.Metadata.Requirements) {
t.Fatalf("Expected number of chart dependencies %d, but got %d", len(c.Requirements.Dependencies), len(c.Dependencies())) t.Fatalf("Expected number of chart dependencies %d, but got %d", len(c.Metadata.Requirements), len(c.Dependencies()))
} }
} }
@ -375,8 +375,8 @@ func TestDependentChartsWithSubchartsAllSpecifiedInRequirements(t *testing.T) {
t.Fatal("Expected no changes in dependencies to be, but did something got changed") t.Fatal("Expected no changes in dependencies to be, but did something got changed")
} }
if len(c.Dependencies()) != len(c.Requirements.Dependencies) { if len(c.Dependencies()) != len(c.Metadata.Requirements) {
t.Fatalf("Expected number of chart dependencies %d, but got %d", len(c.Requirements.Dependencies), len(c.Dependencies())) t.Fatalf("Expected number of chart dependencies %d, but got %d", len(c.Metadata.Requirements), len(c.Dependencies()))
} }
} }
@ -399,21 +399,21 @@ func TestDependentChartsWithSomeSubchartsSpecifiedInRequirements(t *testing.T) {
t.Fatal("Expected no changes in dependencies to be, but did something got changed") t.Fatal("Expected no changes in dependencies to be, but did something got changed")
} }
if len(c.Dependencies()) <= len(c.Requirements.Dependencies) { if len(c.Dependencies()) <= len(c.Metadata.Requirements) {
t.Fatalf("Expected more dependencies than specified in requirements.yaml(%d), but got %d", len(c.Requirements.Dependencies), len(c.Dependencies())) t.Fatalf("Expected more dependencies than specified in requirements.yaml(%d), but got %d", len(c.Metadata.Requirements), len(c.Dependencies()))
} }
} }
func verifyRequirements(t *testing.T, c *chart.Chart) { func verifyRequirements(t *testing.T, c *chart.Chart) {
if len(c.Requirements.Dependencies) != 2 { if len(c.Metadata.Requirements) != 2 {
t.Errorf("Expected 2 requirements, got %d", len(c.Requirements.Dependencies)) t.Errorf("Expected 2 requirements, got %d", len(c.Metadata.Requirements))
} }
tests := []*chart.Dependency{ tests := []*chart.Dependency{
{Name: "alpine", Version: "0.1.0", Repository: "https://example.com/charts"}, {Name: "alpine", Version: "0.1.0", Repository: "https://example.com/charts"},
{Name: "mariner", Version: "4.3.2", Repository: "https://example.com/charts"}, {Name: "mariner", Version: "4.3.2", Repository: "https://example.com/charts"},
} }
for i, tt := range tests { for i, tt := range tests {
d := c.Requirements.Dependencies[i] d := c.Metadata.Requirements[i]
if d.Name != tt.Name { if d.Name != tt.Name {
t.Errorf("Expected dependency named %q, got %q", tt.Name, d.Name) t.Errorf("Expected dependency named %q, got %q", tt.Name, d.Name)
} }
@ -427,15 +427,15 @@ func verifyRequirements(t *testing.T, c *chart.Chart) {
} }
func verifyRequirementsLock(t *testing.T, c *chart.Chart) { func verifyRequirementsLock(t *testing.T, c *chart.Chart) {
if len(c.Requirements.Dependencies) != 2 { if len(c.Metadata.Requirements) != 2 {
t.Errorf("Expected 2 requirements, got %d", len(c.Requirements.Dependencies)) t.Errorf("Expected 2 requirements, got %d", len(c.Metadata.Requirements))
} }
tests := []*chart.Dependency{ tests := []*chart.Dependency{
{Name: "alpine", Version: "0.1.0", Repository: "https://example.com/charts"}, {Name: "alpine", Version: "0.1.0", Repository: "https://example.com/charts"},
{Name: "mariner", Version: "4.3.2", Repository: "https://example.com/charts"}, {Name: "mariner", Version: "4.3.2", Repository: "https://example.com/charts"},
} }
for i, tt := range tests { for i, tt := range tests {
d := c.Requirements.Dependencies[i] d := c.Metadata.Requirements[i]
if d.Name != tt.Name { if d.Name != tt.Name {
t.Errorf("Expected dependency named %q, got %q", tt.Name, d.Name) t.Errorf("Expected dependency named %q, got %q", tt.Name, d.Name)
} }

@ -15,3 +15,15 @@ sources:
- https://example.com/foo/bar - https://example.com/foo/bar
home: http://example.com home: http://example.com
icon: https://example.com/64x64.png icon: https://example.com/64x64.png
dependencies:
- name: alpine
version: "0.1.0"
repository: https://example.com/charts
- name: mariner
version: "4.3.2"
repository: https://example.com/charts
alias: mariners2
- name: mariner
version: "4.3.2"
repository: https://example.com/charts
alias: mariners1

@ -15,3 +15,10 @@ sources:
- https://example.com/foo/bar - https://example.com/foo/bar
home: http://example.com home: http://example.com
icon: https://example.com/64x64.png icon: https://example.com/64x64.png
dependencies:
- name: alpine
version: "0.1.0"
repository: https://example.com/charts
- name: mariner
version: "4.3.2"
repository: https://example.com/charts

@ -15,3 +15,7 @@ sources:
- https://example.com/foo/bar - https://example.com/foo/bar
home: http://example.com home: http://example.com
icon: https://example.com/64x64.png icon: https://example.com/64x64.png
dependencies:
- name: alpine
version: "0.1.0"
repository: https://example.com/charts

Binary file not shown.

@ -18,3 +18,10 @@ icon: https://example.com/64x64.png
annotations: annotations:
extrakey: extravalue extrakey: extravalue
anotherkey: anothervalue anotherkey: anothervalue
dependencies:
- name: alpine
version: "0.1.0"
repository: https://example.com/charts
- name: mariner
version: "4.3.2"
repository: https://example.com/charts

@ -18,3 +18,10 @@ icon: https://example.com/64x64.png
annotations: annotations:
extrakey: extravalue extrakey: extravalue
anotherkey: anothervalue anotherkey: anothervalue
dependencies:
- name: alpine
version: "0.1.0"
repository: https://example.com/charts
- name: mariner
version: "4.3.2"
repository: https://example.com/charts

@ -2,3 +2,7 @@ name: mariner
description: A Helm chart for Kubernetes description: A Helm chart for Kubernetes
version: 4.3.2 version: 4.3.2
home: "" home: ""
dependencies:
- name: albatross
repository: https://example.com/mariner/charts
version: "0.1.0"

@ -2,3 +2,34 @@ apiVersion: v1
description: A Helm chart for Kubernetes description: A Helm chart for Kubernetes
name: parentchart name: parentchart
version: 0.1.0 version: 0.1.0
dependencies:
- name: subchart1
repository: http://localhost:10191
version: 0.1.0
condition: subchart1.enabled
tags:
- front-end
- subchart1
import-values:
- child: SC1data
parent: imported-chart1
- child: SC1data
parent: overridden-chart1
- child: imported-chartA
parent: imported-chartA
- child: imported-chartA-B
parent: imported-chartA-B
- child: overridden-chartA-B
parent: overridden-chartA-B
- child: SCBexported1A
parent: .
- SCBexported2
- SC1exported1
- name: subchart2
repository: http://localhost:10191
version: 0.1.0
condition: subchart2.enabled
tags:
- back-end
- subchart2

@ -2,3 +2,35 @@ apiVersion: v1
description: A Helm chart for Kubernetes description: A Helm chart for Kubernetes
name: subchart1 name: subchart1
version: 0.1.0 version: 0.1.0
dependencies:
- name: subcharta
repository: http://localhost:10191
version: 0.1.0
condition: subcharta.enabled,subchart1.subcharta.enabled
tags:
- front-end
- subcharta
import-values:
- child: SCAdata
parent: imported-chartA
- child: SCAdata
parent: overridden-chartA
- child: SCAdata
parent: imported-chartA-B
- name: subchartb
repository: http://localhost:10191
version: 0.1.0
condition: subchartb.enabled
import-values:
- child: SCBdata
parent: imported-chartB
- child: SCBdata
parent: imported-chartA-B
- child: exports.SCBexported2
parent: exports.SCBexported2
- SCBexported1
tags:
- front-end
- subchartb

@ -2,3 +2,18 @@ apiVersion: v1
description: A Helm chart for Kubernetes description: A Helm chart for Kubernetes
name: subchart2 name: subchart2
version: 0.1.0 version: 0.1.0
dependencies:
- name: subchartb
repository: http://localhost:10191
version: 0.1.0
condition: subchartb.enabled,subchart2.subchartb.enabled
tags:
- back-end
- subchartb
- name: subchartc
repository: http://localhost:10191
version: 0.1.0
condition: subchartc.enabled
tags:
- back-end
- subchartc

@ -151,10 +151,7 @@ func CoalesceValues(chrt *chart.Chart, vals []byte) (Values, error) {
} }
} }
cvals, err = coalesce(chrt, cvals) coalesce(chrt, cvals)
if err != nil {
return cvals, err
}
return coalesceDeps(chrt, cvals) return coalesceDeps(chrt, cvals)
} }
@ -162,14 +159,10 @@ func CoalesceValues(chrt *chart.Chart, vals []byte) (Values, error) {
// coalesce coalesces the dest values and the chart values, giving priority to the dest values. // coalesce coalesces the dest values and the chart values, giving priority to the dest values.
// //
// This is a helper function for CoalesceValues. // This is a helper function for CoalesceValues.
func coalesce(ch *chart.Chart, dest map[string]interface{}) (map[string]interface{}, error) { func coalesce(ch *chart.Chart, dest map[string]interface{}) map[string]interface{} {
var err error coalesceValues(ch, dest)
dest, err = coalesceValues(ch, dest)
if err != nil {
return dest, err
}
coalesceDeps(ch, dest) coalesceDeps(ch, dest)
return dest, nil return dest
} }
// coalesceDeps coalesces the dependencies of the given chart. // coalesceDeps coalesces the dependencies of the given chart.
@ -187,12 +180,8 @@ func coalesceDeps(chrt *chart.Chart, dest map[string]interface{}) (map[string]in
// Get globals out of dest and merge them into dvmap. // Get globals out of dest and merge them into dvmap.
coalesceGlobals(dvmap, dest) coalesceGlobals(dvmap, dest)
var err error
// Now coalesce the rest of the values. // Now coalesce the rest of the values.
dest[subchart.Name()], err = coalesce(subchart, dvmap) dest[subchart.Name()] = coalesce(subchart, dvmap)
if err != nil {
return dest, err
}
} }
} }
return dest, nil return dest, nil
@ -261,7 +250,7 @@ func copyMap(src map[string]interface{}) map[string]interface{} {
// coalesceValues builds up a values map for a particular chart. // coalesceValues builds up a values map for a particular chart.
// //
// Values in v will override the values in the chart. // Values in v will override the values in the chart.
func coalesceValues(c *chart.Chart, v map[string]interface{}) (map[string]interface{}, error) { func coalesceValues(c *chart.Chart, v map[string]interface{}) {
for key, val := range c.Values { for key, val := range c.Values {
if value, ok := v[key]; ok { if value, ok := v[key]; ok {
if value == nil { if value == nil {
@ -285,7 +274,6 @@ func coalesceValues(c *chart.Chart, v map[string]interface{}) (map[string]interf
v[key] = val v[key] = val
} }
} }
return v, nil
} }
// coalesceTables merges a source map into a destination map. // coalesceTables merges a source map into a destination map.

@ -78,10 +78,9 @@ func (m *Manager) Build() error {
return m.Update() return m.Update()
} }
// A lock must accompany a requirements.yaml file. req := c.Metadata.Requirements
req := c.Requirements
if sum, err := resolver.HashReq(req); err != nil || sum != lock.Digest { if sum, err := resolver.HashReq(req); err != nil || sum != lock.Digest {
return errors.New("requirements.lock is out of sync with requirements.yaml") return errors.New("requirements.lock is out of sync with Chart.yaml")
} }
// Check that all of the repos we're dependent on actually exist. // Check that all of the repos we're dependent on actually exist.
@ -106,7 +105,7 @@ func (m *Manager) Build() error {
// Update updates a local charts directory. // Update updates a local charts directory.
// //
// It first reads the requirements.yaml file, and then attempts to // It first reads the Chart.yaml file, and then attempts to
// negotiate versions based on that. It will download the versions // negotiate versions based on that. It will download the versions
// from remote chart repositories unless SkipUpdate is true. // from remote chart repositories unless SkipUpdate is true.
func (m *Manager) Update() error { func (m *Manager) Update() error {
@ -117,12 +116,13 @@ func (m *Manager) Update() error {
// If no requirements file is found, we consider this a successful // If no requirements file is found, we consider this a successful
// completion. // completion.
req := c.Requirements req := c.Metadata.Requirements
if req == nil { if req == nil {
return nil return nil
} }
// Hash requirements.yaml // Hash requirements.yaml
// FIXME should this hash all of Chart.yaml
hash, err := resolver.HashReq(req) hash, err := resolver.HashReq(req)
if err != nil { if err != nil {
return err return err
@ -130,7 +130,7 @@ func (m *Manager) Update() error {
// 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)
if err != nil { if err != nil {
return err return err
} }
@ -143,7 +143,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 in the Chart.yaml
lock, err := m.resolve(req, repoNames, hash) lock, err := m.resolve(req, repoNames, hash)
if err != nil { if err != nil {
return err return err
@ -176,7 +176,7 @@ 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 *chart.Requirements, repoNames map[string]string, hash string) (*chart.RequirementsLock, error) { func (m *Manager) resolve(req []*chart.Dependency, repoNames map[string]string, hash string) (*chart.RequirementsLock, error) {
res := resolver.New(m.ChartPath, m.HelmHome) res := resolver.New(m.ChartPath, m.HelmHome)
return res.Resolve(req, repoNames, hash) return res.Resolve(req, repoNames, hash)
} }

@ -47,12 +47,12 @@ 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 *chart.Requirements, repoNames map[string]string, d string) (*chart.RequirementsLock, error) { func (r *Resolver) Resolve(reqs []*chart.Dependency, repoNames map[string]string, d string) (*chart.RequirementsLock, error) {
// Now we clone the dependencies, locking as we go. // Now we clone the dependencies, locking as we go.
locked := make([]*chart.Dependency, len(reqs.Dependencies)) locked := make([]*chart.Dependency, len(reqs))
missing := []string{} missing := []string{}
for i, d := range reqs.Dependencies { for i, d := range reqs {
if strings.HasPrefix(d.Repository, "file://") { if strings.HasPrefix(d.Repository, "file://") {
if _, err := GetLocalPath(d.Repository, r.chartpath); err != nil { if _, err := GetLocalPath(d.Repository, r.chartpath); err != nil {
@ -105,7 +105,7 @@ func (r *Resolver) Resolve(reqs *chart.Requirements, repoNames map[string]string
} }
} }
if len(missing) > 0 { if len(missing) > 0 {
return nil, errors.Errorf("can't get a valid version for repositories %s. Try changing the version constraint in requirements.yaml", strings.Join(missing, ", ")) return nil, errors.Errorf("can't get a valid version for repositories %s. Try changing the version constraint in Chart.yaml", strings.Join(missing, ", "))
} }
return &chart.RequirementsLock{ return &chart.RequirementsLock{
Generated: time.Now(), Generated: time.Now(),
@ -118,7 +118,7 @@ func (r *Resolver) Resolve(reqs *chart.Requirements, repoNames map[string]string
// //
// This should be used only to compare against another hash generated by this // This should be used only to compare against another hash generated by this
// function. // function.
func HashReq(req *chart.Requirements) (string, error) { func HashReq(req []*chart.Dependency) (string, error) {
data, err := json.Marshal(req) data, err := json.Marshal(req)
if err != nil { if err != nil {
return "", err return "", err

@ -24,52 +24,42 @@ import (
func TestResolve(t *testing.T) { func TestResolve(t *testing.T) {
tests := []struct { tests := []struct {
name string name string
req *chart.Requirements req []*chart.Dependency
expect *chart.RequirementsLock expect *chart.RequirementsLock
err bool err bool
}{ }{
{ {
name: "version failure", name: "version failure",
req: &chart.Requirements{ req: []*chart.Dependency{
Dependencies: []*chart.Dependency{ {Name: "oedipus-rex", Repository: "http://example.com", Version: ">a1"},
{Name: "oedipus-rex", Repository: "http://example.com", Version: ">a1"},
},
}, },
err: true, err: true,
}, },
{ {
name: "cache index failure", name: "cache index failure",
req: &chart.Requirements{ req: []*chart.Dependency{
Dependencies: []*chart.Dependency{ {Name: "oedipus-rex", Repository: "http://example.com", Version: "1.0.0"},
{Name: "oedipus-rex", Repository: "http://example.com", Version: "1.0.0"},
},
}, },
err: true, err: true,
}, },
{ {
name: "chart not found failure", name: "chart not found failure",
req: &chart.Requirements{ req: []*chart.Dependency{
Dependencies: []*chart.Dependency{ {Name: "redis", Repository: "http://example.com", Version: "1.0.0"},
{Name: "redis", Repository: "http://example.com", Version: "1.0.0"},
},
}, },
err: true, err: true,
}, },
{ {
name: "constraint not satisfied failure", name: "constraint not satisfied failure",
req: &chart.Requirements{ req: []*chart.Dependency{
Dependencies: []*chart.Dependency{ {Name: "alpine", Repository: "http://example.com", Version: ">=1.0.0"},
{Name: "alpine", Repository: "http://example.com", Version: ">=1.0.0"},
},
}, },
err: true, err: true,
}, },
{ {
name: "valid lock", name: "valid lock",
req: &chart.Requirements{ req: []*chart.Dependency{
Dependencies: []*chart.Dependency{ {Name: "alpine", Repository: "http://example.com", Version: ">=0.1.0"},
{Name: "alpine", Repository: "http://example.com", Version: ">=0.1.0"},
},
}, },
expect: &chart.RequirementsLock{ expect: &chart.RequirementsLock{
Dependencies: []*chart.Dependency{ Dependencies: []*chart.Dependency{
@ -79,10 +69,8 @@ func TestResolve(t *testing.T) {
}, },
{ {
name: "repo from valid local path", name: "repo from valid local path",
req: &chart.Requirements{ req: []*chart.Dependency{
Dependencies: []*chart.Dependency{ {Name: "signtest", Repository: "file://../../../../cmd/helm/testdata/testcharts/signtest", Version: "0.1.0"},
{Name: "signtest", Repository: "file://../../../../cmd/helm/testdata/testcharts/signtest", Version: "0.1.0"},
},
}, },
expect: &chart.RequirementsLock{ expect: &chart.RequirementsLock{
Dependencies: []*chart.Dependency{ Dependencies: []*chart.Dependency{
@ -92,10 +80,8 @@ func TestResolve(t *testing.T) {
}, },
{ {
name: "repo from invalid local path", name: "repo from invalid local path",
req: &chart.Requirements{ req: []*chart.Dependency{
Dependencies: []*chart.Dependency{ {Name: "notexist", Repository: "file://../testdata/notexist", Version: "0.1.0"},
{Name: "notexist", Repository: "file://../testdata/notexist", Version: "0.1.0"},
},
}, },
err: true, err: true,
}, },
@ -128,7 +114,7 @@ func TestResolve(t *testing.T) {
} }
// Check fields. // Check fields.
if len(l.Dependencies) != len(tt.req.Dependencies) { if len(l.Dependencies) != len(tt.req) {
t.Errorf("%s: wrong number of dependencies in lock", tt.name) t.Errorf("%s: wrong number of dependencies in lock", tt.name)
} }
d0 := l.Dependencies[0] d0 := l.Dependencies[0]
@ -146,11 +132,9 @@ func TestResolve(t *testing.T) {
} }
func TestHashReq(t *testing.T) { func TestHashReq(t *testing.T) {
expect := "sha256:e70e41f8922e19558a8bf62f591a8b70c8e4622e3c03e5415f09aba881f13885" expect := "sha256:d661820b01ed7bcf26eed8f01cf16380e0a76326ba33058d3150f919d9b15bc0"
req := &chart.Requirements{ req := []*chart.Dependency{
Dependencies: []*chart.Dependency{ {Name: "alpine", Version: "0.1.0", Repository: "http://localhost:8879/charts"},
{Name: "alpine", Version: "0.1.0", Repository: "http://localhost:8879/charts"},
},
} }
h, err := HashReq(req) h, err := HashReq(req)
if err != nil { if err != nil {
@ -160,7 +144,7 @@ func TestHashReq(t *testing.T) {
t.Errorf("Expected %q, got %q", expect, h) t.Errorf("Expected %q, got %q", expect, h)
} }
req = &chart.Requirements{Dependencies: []*chart.Dependency{}} req = []*chart.Dependency{}
h, err = HashReq(req) h, err = HashReq(req)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)

@ -65,8 +65,9 @@ func TestEqual(t *testing.T) {
func TestExtractHostname(t *testing.T) { func TestExtractHostname(t *testing.T) {
tests := map[string]string{ tests := map[string]string{
"http://example.com": "example.com", "http://example.com": "example.com",
"https://example.com/foo": "example.com", "https://example.com/foo": "example.com",
"https://example.com:31337/not/with/a/bang/but/a/whimper": "example.com", "https://example.com:31337/not/with/a/bang/but/a/whimper": "example.com",
} }
for start, expect := range tests { for start, expect := range tests {

Loading…
Cancel
Save