fix(schema): Add schema $ref resolution for all commands

Extends JSON schema validation to support relative $ref imports
across helm lint, install, template, and upgrade commands.

Addresses George's review comments:
- Pass chartDir directly instead of deriving from valuesPath
- Create new functions instead of changing public API signatures
- Use absolute file paths for proper URL-based $ref resolution

Implementation:
- Added ValidateAgainstSchemaWithPath to resolve $ref using
  absolute file paths instead of root-relative URLs
- Thread chartDir through Install/Upgrade structs and all
  validation functions
- Updated both v2 (public) and v3 (internal) lint rules

Fixes relative $ref resolution when running commands like:
  helm lint ../sample-chart
  helm install release ../sample-chart

Signed-off-by: Benoit Tigeot <benoit.tigeot@lifen.fr>
This commit is contained in:
Benoit Tigeot 2026-02-22 14:25:39 +01:00
parent 30d803283d
commit a7884d228d
No known key found for this signature in database
GPG key ID: 8E6D4FC8AEBDA62C
25 changed files with 140 additions and 70 deletions

View file

@ -97,7 +97,7 @@ func TemplatesWithSkipSchemaValidation(linter *support.Linter, values map[string
return
}
valuesToRender, err := util.ToRenderValuesWithSchemaValidation(chart, cvals, options, caps, skipSchemaValidation)
valuesToRender, err := util.ToRenderValuesWithSchemaValidationAndPath(chart, cvals, options, caps, skipSchemaValidation, linter.ChartDir)
if err != nil {
linter.RunLinterRule(support.ErrorSev, fpath, err)
return

View file

@ -41,7 +41,7 @@ func ValuesWithOverrides(linter *support.Linter, valueOverrides map[string]any,
return
}
linter.RunLinterRule(support.ErrorSev, file, validateValuesFile(vf, valueOverrides, skipSchemaValidation))
linter.RunLinterRule(support.ErrorSev, file, validateValuesFile(linter.ChartDir, valueOverrides, skipSchemaValidation))
}
func validateValuesFileExistence(valuesPath string) error {
@ -52,7 +52,10 @@ func validateValuesFileExistence(valuesPath string) error {
return nil
}
func validateValuesFile(valuesPath string, overrides map[string]any, skipSchemaValidation bool) error {
func validateValuesFile(chartDir string, overrides map[string]any, skipSchemaValidation bool) error {
valuesPath := filepath.Join(chartDir, "values.yaml")
schemaPath := filepath.Join(chartDir, "values.schema.json")
values, err := common.ReadValuesFile(valuesPath)
if err != nil {
return fmt.Errorf("unable to parse YAML: %w", err)
@ -66,8 +69,6 @@ func validateValuesFile(valuesPath string, overrides map[string]any, skipSchemaV
coalescedValues := util.CoalesceTables(make(map[string]any, len(overrides)), overrides)
coalescedValues = util.CoalesceTables(coalescedValues, values)
ext := filepath.Ext(valuesPath)
schemaPath := valuesPath[:len(valuesPath)-len(ext)] + ".schema.json"
schema, err := os.ReadFile(schemaPath)
if len(schema) == 0 {
return nil
@ -75,9 +76,9 @@ func validateValuesFile(valuesPath string, overrides map[string]any, skipSchemaV
if err != nil {
return err
}
baseDir := filepath.Dir(schemaPath)
if !skipSchemaValidation {
return util.ValidateAgainstSingleSchema(coalescedValues, schema, baseDir)
return util.ValidateAgainstSingleSchemaWithPath(coalescedValues, schema, schemaPath)
}
return nil

View file

@ -66,8 +66,7 @@ func TestValidateValuesFileWellFormed(t *testing.T) {
not:well[]{}formed
`
tmpdir := ensure.TempFile(t, "values.yaml", []byte(badYaml))
valfile := filepath.Join(tmpdir, "values.yaml")
if err := validateValuesFile(valfile, map[string]any{}, false); err == nil {
if err := validateValuesFile(tmpdir, map[string]any{}, false); err == nil {
t.Fatal("expected values file to fail parsing")
}
}
@ -77,8 +76,7 @@ func TestValidateValuesFileSchema(t *testing.T) {
tmpdir := ensure.TempFile(t, "values.yaml", []byte(yaml))
createTestingSchema(t, tmpdir)
valfile := filepath.Join(tmpdir, "values.yaml")
if err := validateValuesFile(valfile, map[string]any{}, false); err != nil {
if err := validateValuesFile(tmpdir, map[string]any{}, false); err != nil {
t.Fatalf("Failed validation with %s", err)
}
}
@ -89,9 +87,7 @@ func TestValidateValuesFileSchemaFailure(t *testing.T) {
tmpdir := ensure.TempFile(t, "values.yaml", []byte(yaml))
createTestingSchema(t, tmpdir)
valfile := filepath.Join(tmpdir, "values.yaml")
err := validateValuesFile(valfile, map[string]any{}, false)
err := validateValuesFile(tmpdir, map[string]any{}, false)
if err == nil {
t.Fatal("expected values file to fail parsing")
}
@ -105,9 +101,7 @@ func TestValidateValuesFileSchemaFailureButWithSkipSchemaValidation(t *testing.T
tmpdir := ensure.TempFile(t, "values.yaml", []byte(yaml))
createTestingSchema(t, tmpdir)
valfile := filepath.Join(tmpdir, "values.yaml")
err := validateValuesFile(valfile, map[string]any{}, true)
err := validateValuesFile(tmpdir, map[string]any{}, true)
if err != nil {
t.Fatal("expected values file to pass parsing because of skipSchemaValidation")
}
@ -121,8 +115,7 @@ func TestValidateValuesFileSchemaOverrides(t *testing.T) {
tmpdir := ensure.TempFile(t, "values.yaml", []byte(yaml))
createTestingSchema(t, tmpdir)
valfile := filepath.Join(tmpdir, "values.yaml")
if err := validateValuesFile(valfile, overrides, false); err != nil {
if err := validateValuesFile(tmpdir, overrides, false); err != nil {
t.Fatalf("Failed validation with %s", err)
}
}
@ -157,9 +150,7 @@ func TestValidateValuesFile(t *testing.T) {
tmpdir := ensure.TempFile(t, "values.yaml", []byte(tt.yaml))
createTestingSchema(t, tmpdir)
valfile := filepath.Join(tmpdir, "values.yaml")
err := validateValuesFile(valfile, tt.overrides, false)
err := validateValuesFile(tmpdir, tt.overrides, false)
switch {
case err != nil && tt.errorMessage == "":

View file

@ -127,6 +127,9 @@ type Install struct {
// Used by helm template to add the release as part of OutputDir path
// OutputDir/<ReleaseName>
UseReleaseName bool
// ChartDir is the local directory path of the chart, used for resolving
// relative $ref in JSON schemas. Empty for remote charts.
ChartDir string
// TakeOwnership will ignore the check for helm annotations and take ownership of the resources.
TakeOwnership bool
PostRenderer postrenderer.PostRenderer
@ -358,7 +361,7 @@ func (i *Install) RunWithContext(ctx context.Context, ch ci.Charter, vals map[st
IsInstall: !isUpgrade,
IsUpgrade: isUpgrade,
}
valuesToRender, err := util.ToRenderValuesWithSchemaValidation(chrt, vals, options, caps, i.SkipSchemaValidation)
valuesToRender, err := util.ToRenderValuesWithSchemaValidationAndPath(chrt, vals, options, caps, i.SkipSchemaValidation, i.ChartDir)
if err != nil {
return nil, err
}

View file

@ -71,6 +71,10 @@ func TestLintChart(t *testing.T) {
name: "chart-with-schema",
chartPath: "testdata/charts/chart-with-schema",
},
{
name: "chart-with-schema-ref",
chartPath: "testdata/charts/chart-with-schema-ref",
},
{
name: "chart-with-schema-negative",
chartPath: "testdata/charts/chart-with-schema-negative",

View file

@ -0,0 +1,3 @@
apiVersion: v2
name: chart-with-schema-ref
version: 0.1.0

View file

@ -0,0 +1,4 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "string"
}

View file

@ -0,0 +1,7 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"properties": {
"name": { "$ref": "name.schema.json" }
}
}

View file

@ -0,0 +1 @@
name: "test"

View file

@ -113,6 +113,9 @@ type Upgrade struct {
HideNotes bool
// SkipSchemaValidation determines if JSON schema validation is disabled.
SkipSchemaValidation bool
// ChartDir is the local directory path of the chart, used for resolving
// relative $ref in JSON schemas. Empty for remote charts.
ChartDir string
// Description is the description of this operation
Description string
Labels map[string]string
@ -291,7 +294,7 @@ func (u *Upgrade) prepareUpgrade(name string, chart *chartv2.Chart, vals map[str
if err != nil {
return nil, nil, false, err
}
valuesToRender, err := util.ToRenderValuesWithSchemaValidation(chart, vals, options, caps, u.SkipSchemaValidation)
valuesToRender, err := util.ToRenderValuesWithSchemaValidationAndPath(chart, vals, options, caps, u.SkipSchemaValidation, u.ChartDir)
if err != nil {
return nil, nil, false, err
}

View file

@ -75,14 +75,31 @@ func newHTTPURLLoader() *HTTPURLLoader {
// ValidateAgainstSchema checks that values does not violate the structure laid out in schema
func ValidateAgainstSchema(ch chart.Charter, values map[string]any) error {
return ValidateAgainstSchemaWithPath(ch, values, "")
}
func ValidateAgainstSchemaWithPath(ch chart.Charter, values map[string]any, chartDir string) error {
chrt, err := chart.NewAccessor(ch)
if err != nil {
return err
}
var absChartPath string
if chartDir != "" {
absChartPath, err = filepath.Abs(chartDir)
} else {
absChartPath, err = filepath.Abs(chrt.ChartFullPath())
}
if err != nil {
return err
}
var sb strings.Builder
if chrt.Schema() != nil {
slog.Debug("chart name", "chart-name", chrt.Name())
err := ValidateAgainstSingleSchema(values, chrt.Schema(), chrt.ChartFullPath())
schemaPath := filepath.Join(absChartPath, "values.schema.json")
err = ValidateAgainstSingleSchemaWithPath(values, chrt.Schema(), schemaPath)
if err != nil {
fmt.Fprintf(&sb, "%s:\n", chrt.Name())
sb.WriteString(err.Error())
@ -109,7 +126,8 @@ func ValidateAgainstSchema(ch chart.Charter, values map[string]any) error {
continue
}
if err := ValidateAgainstSchema(subchart, subchartValues); err != nil {
subchartPath := filepath.Join(absChartPath, "charts", sub.Name())
if err := ValidateAgainstSchemaWithPath(subchart, subchartValues, subchartPath); err != nil {
sb.WriteString(err.Error())
}
}
@ -122,7 +140,13 @@ func ValidateAgainstSchema(ch chart.Charter, values map[string]any) error {
}
// ValidateAgainstSingleSchema checks that values does not violate the structure laid out in this schema
func ValidateAgainstSingleSchema(values common.Values, schemaJSON []byte, absBaseDir string) (reterr error) {
func ValidateAgainstSingleSchema(values common.Values, schemaJSON []byte) (reterr error) {
return ValidateAgainstSingleSchemaWithPath(values, schemaJSON, "/values.schema.json")
}
// ValidateAgainstSingleSchemaWithPath checks that values does not violate the structure laid out in this schema.
// schemaPath is the absolute path to the schema file, used to resolve relative $ref references.
func ValidateAgainstSingleSchemaWithPath(values common.Values, schemaJSON []byte, schemaPath string) (reterr error) {
defer func() {
if r := recover(); r != nil {
reterr = fmt.Errorf("unable to validate schema: %s", r)
@ -147,13 +171,14 @@ func ValidateAgainstSingleSchema(values common.Values, schemaJSON []byte, absBas
compiler := jsonschema.NewCompiler()
compiler.UseLoader(loader)
base := "file://" + filepath.ToSlash(absBaseDir) + "/values.schema.json"
err = compiler.AddResource(base, schema)
schemaURL := fmt.Sprintf("file://%s", schemaPath)
err = compiler.AddResource(schemaURL, schema)
if err != nil {
return err
}
validator, err := compiler.Compile(base)
validator, err := compiler.Compile(schemaURL)
if err != nil {
return err
}
@ -211,11 +236,7 @@ func (e JSONSchemaValidationError) Error() string {
// This string prefixes all of our error details. Further up the stack of helm error message
// building more detail is provided to users. This is removed.
if strings.HasPrefix(errStr, "jsonschema validation failed with ") {
if idx := strings.Index(errStr, "#'\n"); idx != -1 {
errStr = errStr[idx+3:]
}
}
errStr = strings.TrimPrefix(errStr, "jsonschema validation failed with 'file:///values.schema.json#'\n")
// The extra new line is needed for when there are sub-charts.
return errStr + "\n"

View file

@ -38,7 +38,7 @@ func TestValidateAgainstSingleSchema(t *testing.T) {
t.Fatalf("Error reading YAML file: %s", err)
}
if err := ValidateAgainstSingleSchema(values, schema, ""); err != nil {
if err := ValidateAgainstSingleSchema(values, schema); err != nil {
t.Errorf("Error validating Values against Schema: %s", err)
}
}
@ -54,7 +54,7 @@ func TestValidateAgainstInvalidSingleSchema(t *testing.T) {
}
var errString string
if err := ValidateAgainstSingleSchema(values, schema, ""); err == nil {
if err := ValidateAgainstSingleSchema(values, schema); err == nil {
t.Fatalf("Expected an error, but got nil")
} else {
errString = err.Error()
@ -78,7 +78,7 @@ func TestValidateAgainstSingleSchemaNegative(t *testing.T) {
}
var errString string
if err := ValidateAgainstSingleSchema(values, schema, ""); err == nil {
if err := ValidateAgainstSingleSchema(values, schema); err == nil {
t.Fatalf("Expected an error, but got nil")
} else {
errString = err.Error()
@ -264,19 +264,18 @@ func TestValidateWithRelativeSchemaReferencesCurrentDir(t *testing.T) {
if err != nil {
t.Fatalf("Error reading YAML file: %s", err)
}
schema, err := os.ReadFile("./testdata/current-dir-test/values.schema.json")
schemaPath := "./testdata/current-dir-test/values.schema.json"
schema, err := os.ReadFile(schemaPath)
if err != nil {
t.Fatalf("Error reading JSON schema file: %s", err)
}
// Test with absolute base directory - this should work with your fix
baseDir := "./testdata/current-dir-test"
absBaseDir, err := filepath.Abs(baseDir)
absSchemaPath, err := filepath.Abs(schemaPath)
if err != nil {
t.Fatalf("Error getting absolute path: %s", err)
}
if err := ValidateAgainstSingleSchema(values, schema, absBaseDir); err != nil {
if err := ValidateAgainstSingleSchemaWithPath(values, schema, absSchemaPath); err != nil {
t.Errorf("Error validating Values against Schema with relative references: %s", err)
}
}
@ -288,18 +287,18 @@ func TestValidateWithRelativeSchemaReferencesSubfolder(t *testing.T) {
if err != nil {
t.Fatalf("Error reading YAML file: %s", err)
}
schema, err := os.ReadFile("./testdata/subdir-test/subfolder/values.schema.json")
schemaPath := "./testdata/subdir-test/subfolder/values.schema.json"
schema, err := os.ReadFile(schemaPath)
if err != nil {
t.Fatalf("Error reading JSON schema file: %s", err)
}
baseDir := "./testdata/subdir-test/subfolder"
absBaseDir, err := filepath.Abs(baseDir)
absSchemaPath, err := filepath.Abs(schemaPath)
if err != nil {
t.Fatalf("Error getting absolute path: %s", err)
}
if err := ValidateAgainstSingleSchema(values, schema, absBaseDir); err != nil {
if err := ValidateAgainstSingleSchemaWithPath(values, schema, absSchemaPath); err != nil {
t.Errorf("Error validating Values against Schema with relative references from subfolder: %s", err)
}
}

View file

@ -34,6 +34,12 @@ func ToRenderValues(chrt chart.Charter, chrtVals map[string]any, options common.
//
// This takes both ReleaseOptions and Capabilities to merge into the render values.
func ToRenderValuesWithSchemaValidation(chrt chart.Charter, chrtVals map[string]any, options common.ReleaseOptions, caps *common.Capabilities, skipSchemaValidation bool) (common.Values, error) {
return ToRenderValuesWithSchemaValidationAndPath(chrt, chrtVals, options, caps, skipSchemaValidation, "")
}
// ToRenderValuesWithSchemaValidationAndPath is like ToRenderValuesWithSchemaValidation but accepts chartDir
// for resolving relative $ref in JSON schemas.
func ToRenderValuesWithSchemaValidationAndPath(chrt chart.Charter, chrtVals map[string]any, options common.ReleaseOptions, caps *common.Capabilities, skipSchemaValidation bool, chartDir string) (common.Values, error) {
if caps == nil {
caps = common.DefaultCapabilities
}
@ -60,7 +66,7 @@ func ToRenderValuesWithSchemaValidation(chrt chart.Charter, chrtVals map[string]
}
if !skipSchemaValidation {
if err := ValidateAgainstSchema(chrt, vals); err != nil {
if err := ValidateAgainstSchemaWithPath(chrt, vals, chartDir); err != nil {
return top, fmt.Errorf("values don't meet the specifications of the schema(s) in the following chart(s):\n%w", err)
}
}

View file

@ -128,7 +128,7 @@ func (t *templateLinter) Lint() {
return
}
valuesToRender, err := util.ToRenderValuesWithSchemaValidation(chart, cvals, options, caps, t.skipSchemaValidation)
valuesToRender, err := util.ToRenderValuesWithSchemaValidationAndPath(chart, cvals, options, caps, t.skipSchemaValidation, t.linter.ChartDir)
if err != nil {
t.linter.RunLinterRule(support.ErrorSev, templatesDir, err)
return

View file

@ -41,7 +41,7 @@ func ValuesWithOverrides(linter *support.Linter, valueOverrides map[string]any,
return
}
linter.RunLinterRule(support.ErrorSev, file, validateValuesFile(vf, valueOverrides, skipSchemaValidation))
linter.RunLinterRule(support.ErrorSev, file, validateValuesFile(linter.ChartDir, valueOverrides, skipSchemaValidation))
}
func validateValuesFileExistence(valuesPath string) error {
@ -52,7 +52,10 @@ func validateValuesFileExistence(valuesPath string) error {
return nil
}
func validateValuesFile(valuesPath string, overrides map[string]any, skipSchemaValidation bool) error {
func validateValuesFile(chartDir string, overrides map[string]any, skipSchemaValidation bool) error {
valuesPath := filepath.Join(chartDir, "values.yaml")
schemaPath := filepath.Join(chartDir, "values.schema.json")
values, err := common.ReadValuesFile(valuesPath)
if err != nil {
return fmt.Errorf("unable to parse YAML: %w", err)
@ -66,8 +69,6 @@ func validateValuesFile(valuesPath string, overrides map[string]any, skipSchemaV
coalescedValues := util.CoalesceTables(make(map[string]any, len(overrides)), overrides)
coalescedValues = util.CoalesceTables(coalescedValues, values)
ext := filepath.Ext(valuesPath)
schemaPath := valuesPath[:len(valuesPath)-len(ext)] + ".schema.json"
schema, err := os.ReadFile(schemaPath)
if len(schema) == 0 {
return nil
@ -75,9 +76,9 @@ func validateValuesFile(valuesPath string, overrides map[string]any, skipSchemaV
if err != nil {
return err
}
baseDir := filepath.Dir(schemaPath)
if !skipSchemaValidation {
return util.ValidateAgainstSingleSchema(coalescedValues, schema, baseDir)
return util.ValidateAgainstSingleSchemaWithPath(coalescedValues, schema, schemaPath)
}
return nil

View file

@ -66,8 +66,7 @@ func TestValidateValuesFileWellFormed(t *testing.T) {
not:well[]{}formed
`
tmpdir := ensure.TempFile(t, "values.yaml", []byte(badYaml))
valfile := filepath.Join(tmpdir, "values.yaml")
if err := validateValuesFile(valfile, map[string]any{}, false); err == nil {
if err := validateValuesFile(tmpdir, map[string]any{}, false); err == nil {
t.Fatal("expected values file to fail parsing")
}
}
@ -77,8 +76,7 @@ func TestValidateValuesFileSchema(t *testing.T) {
tmpdir := ensure.TempFile(t, "values.yaml", []byte(yaml))
createTestingSchema(t, tmpdir)
valfile := filepath.Join(tmpdir, "values.yaml")
if err := validateValuesFile(valfile, map[string]any{}, false); err != nil {
if err := validateValuesFile(tmpdir, map[string]any{}, false); err != nil {
t.Fatalf("Failed validation with %s", err)
}
}
@ -89,9 +87,7 @@ func TestValidateValuesFileSchemaFailure(t *testing.T) {
tmpdir := ensure.TempFile(t, "values.yaml", []byte(yaml))
createTestingSchema(t, tmpdir)
valfile := filepath.Join(tmpdir, "values.yaml")
err := validateValuesFile(valfile, map[string]any{}, false)
err := validateValuesFile(tmpdir, map[string]any{}, false)
if err == nil {
t.Fatal("expected values file to fail parsing")
}
@ -105,9 +101,7 @@ func TestValidateValuesFileSchemaFailureButWithSkipSchemaValidation(t *testing.T
tmpdir := ensure.TempFile(t, "values.yaml", []byte(yaml))
createTestingSchema(t, tmpdir)
valfile := filepath.Join(tmpdir, "values.yaml")
err := validateValuesFile(valfile, map[string]any{}, true)
err := validateValuesFile(tmpdir, map[string]any{}, true)
if err != nil {
t.Fatal("expected values file to pass parsing because of skipSchemaValidation")
}
@ -121,8 +115,7 @@ func TestValidateValuesFileSchemaOverrides(t *testing.T) {
tmpdir := ensure.TempFile(t, "values.yaml", []byte(yaml))
createTestingSchema(t, tmpdir)
valfile := filepath.Join(tmpdir, "values.yaml")
if err := validateValuesFile(valfile, overrides, false); err != nil {
if err := validateValuesFile(tmpdir, overrides, false); err != nil {
t.Fatalf("Failed validation with %s", err)
}
}
@ -157,9 +150,7 @@ func TestValidateValuesFile(t *testing.T) {
tmpdir := ensure.TempFile(t, "values.yaml", []byte(tt.yaml))
createTestingSchema(t, tmpdir)
valfile := filepath.Join(tmpdir, "values.yaml")
err := validateValuesFile(valfile, tt.overrides, false)
err := validateValuesFile(tmpdir, tt.overrides, false)
switch {
case err != nil && tt.errorMessage == "":

View file

@ -247,6 +247,7 @@ func runInstall(args []string, client *action.Install, valueOpts *values.Options
if err != nil {
return nil, err
}
client.ChartDir = cp
slog.Debug("Chart path", "path", cp)

View file

@ -231,6 +231,11 @@ func TestInstall(t *testing.T) {
cmd: "install schema testdata/testcharts/chart-with-schema-and-subchart --set lastname=doe --set subchart-with-schema.age=-25 --skip-schema-validation",
golden: "output/schema.txt",
},
{
name: "install with schema file containing $ref",
cmd: "install reftest testdata/testcharts/chart-with-schema-ref",
golden: "output/schema-ref.txt",
},
// Install deprecated chart
{
name: "install with warning about deprecated chart",

View file

@ -166,6 +166,11 @@ func TestTemplateCmd(t *testing.T) {
cmd: fmt.Sprintf("template '%s' -f %s/extra_values.yaml", chartPath, chartPath),
golden: "output/template-subchart-cm-set-file.txt",
},
{
name: "template with schema file containing $ref",
cmd: "template reftest testdata/testcharts/chart-with-schema-ref",
golden: "output/template-schema-ref.txt",
},
}
runTestCmd(t, tests)
}

View file

@ -0,0 +1,7 @@
NAME: reftest
LAST DEPLOYED: Fri Sep 2 22:04:05 1977
NAMESPACE: default
STATUS: deployed
REVISION: 1
DESCRIPTION: Install complete
TEST SUITE: None

View file

@ -0,0 +1 @@

View file

@ -0,0 +1,8 @@
Release "reftest" has been upgraded. Happy Helming!
NAME: reftest
LAST DEPLOYED: Fri Sep 2 22:04:05 1977
NAMESPACE: default
STATUS: deployed
REVISION: 2
DESCRIPTION: Upgrade complete
TEST SUITE: None

View file

@ -0,0 +1 @@
../../../action/testdata/charts/chart-with-schema-ref

View file

@ -186,6 +186,7 @@ func newUpgradeCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
if err != nil {
return err
}
client.ChartDir = chartPath
p := getter.All(settings)
vals, err := valueOpts.MergeValues(p)

View file

@ -190,6 +190,12 @@ func TestUpgradeCmd(t *testing.T) {
golden: "output/upgrade-uninstalled-with-keep-history.txt",
rels: []*release.Release{relWithStatusMock("funny-bunny", 2, ch, rcommon.StatusUninstalled)},
},
{
name: "upgrade with schema file containing $ref",
cmd: "upgrade reftest testdata/testcharts/chart-with-schema-ref",
golden: "output/upgrade-schema-ref.txt",
rels: []*release.Release{relMock("reftest", 1, ch)},
},
}
runTestCmd(t, tests)
}