From 713c2c685678fbab43efcbf9fa48c751f835d212 Mon Sep 17 00:00:00 2001 From: qvalentin Date: Sun, 30 Jun 2024 13:03:52 +0200 Subject: [PATCH] feat(variables): add variables resolving to templatecontext --- internal/handler/completion_main_test.go | 15 +++---- internal/handler/helpers_test.go | 15 +++++++ internal/handler/hover_main_test.go | 6 +-- internal/handler/references_test.go | 9 ---- .../language_features/built_in_objects.go | 16 ++++++- .../generic_template_context.go | 2 + internal/lsp/symbol_table.go | 31 +++++++++++++- internal/lsp/symbol_table_template_context.go | 12 ++++-- ...symbol_table_template_context_variables.go | 41 ++++++++++++++++++ ...l_table_template_context_variables_test.go | 42 +++++++++++++++++++ internal/lsp/symbol_table_test.go | 29 ++++++++++++- internal/lsp/symbol_table_variables.go | 21 +++++++--- ...test.go => symbol_table_variables_test.go} | 2 +- internal/lsp/variables_visitor.go | 8 +--- internal/lsp/visitor.go | 2 + internal/util/ranges.go | 9 ++++ testdata/example/templates/deployment.yaml | 2 +- testdata/example/values.yaml | 18 ++++++++ 18 files changed, 240 insertions(+), 40 deletions(-) create mode 100644 internal/handler/helpers_test.go create mode 100644 internal/lsp/symbol_table_template_context_variables.go create mode 100644 internal/lsp/symbol_table_template_context_variables_test.go rename internal/lsp/{symbol_table_variable_test.go => symbol_table_variables_test.go} (95%) diff --git a/internal/handler/completion_main_test.go b/internal/handler/completion_main_test.go index ba5de282..01c363ec 100644 --- a/internal/handler/completion_main_test.go +++ b/internal/handler/completion_main_test.go @@ -4,7 +4,6 @@ import ( "context" "errors" "os" - "strings" "testing" "github.com/mrjosh/helm-ls/internal/adapter/yamlls" @@ -13,7 +12,6 @@ import ( lsplocal "github.com/mrjosh/helm-ls/internal/lsp" "github.com/mrjosh/helm-ls/internal/util" "github.com/stretchr/testify/assert" - "go.lsp.dev/protocol" lsp "go.lsp.dev/protocol" "go.lsp.dev/uri" ) @@ -176,17 +174,20 @@ func TestCompletionMainSingleLines(t *testing.T) { {`Test completion on {{ range .Values.ingress.hosts }} {{ .^ }} {{ end }}`, []string{"host", "paths"}, []string{}, nil}, {`Test completion on {{ range .Values.ingress.hosts }} {{ .ho^ }} {{ end }}`, []string{"host", "paths"}, []string{}, nil}, {`Test completion on {{ range .Values.ingress.hosts }} {{ range .paths }} {{ .^ }} {{ end }} {{ end }}`, []string{"pathType", "path"}, []string{}, nil}, - {`Test completion on {{ root := . }} {{ $root.test.^ }}`, []string{}, []string{}, errors.New("[$root test ] is no valid template context for helm")}, + {`Test completion on {{ $root := . }} {{ $root.test.^ }}`, []string{}, []string{}, errors.New("[test ] is no valid template context for helm")}, {`Test completion on {{ range $type, $config := $.Values.deployments }} {{ .^ }} {{ end }}`, []string{"some"}, []string{}, nil}, {`Test completion on {{ range $type, $config := $.Values.deployments }} {{ .s^ }} {{ end }}`, []string{"some"}, []string{}, nil}, + {`Test completion on {{ range $type, $config := $.Values.deployments }} {{ $config.^ }} {{ end }}`, []string{"some"}, []string{}, nil}, + {`Test completion on {{ range .Values.deploymentsWithNestedStuff }} {{ .hpa.cpuUtilization.^ }} {{ end }}`, []string{"targetAverageUtilization", "enabled"}, []string{}, nil}, + {`Test completion on {{ range $type, $config := .Values.deploymentsWithNestedStuff }} {{ .hpa.cpuUtilization.^ }} {{ end }}`, []string{"targetAverageUtilization", "enabled"}, []string{}, nil}, + {`Test completion on {{ range $type, $config := .Values.deploymentsWithNestedStuff }} {{ $config.hpa.cpuUtilization.^ }} {{ end }}`, []string{"targetAverageUtilization", "enabled"}, []string{}, nil}, + {`Test completion on {{ range $type, $config := $.Values.deployments }} {{ $config.s^ }} {{ end }}`, []string{"some"}, []string{}, nil}, } for _, tt := range testCases { t.Run(tt.templateWithMark, func(t *testing.T) { - // seen chars up to ^ - col := strings.Index(tt.templateWithMark, "^") - buf := strings.Replace(tt.templateWithMark, "^", "", 1) - pos := protocol.Position{Line: 0, Character: uint32(col)} + pos, buf := getPositionForMarkedTestLine(tt.templateWithMark) + // to get the correct values file ../../testdata/example/values.yaml fileURI := uri.File("../../testdata/example/templates/completion-test.yaml") diff --git a/internal/handler/helpers_test.go b/internal/handler/helpers_test.go new file mode 100644 index 00000000..f9fd365f --- /dev/null +++ b/internal/handler/helpers_test.go @@ -0,0 +1,15 @@ +package handler + +import ( + "strings" + + "go.lsp.dev/protocol" +) + +// Takes a string with a mark (^) in it and returns the position and the string without the mark +func getPositionForMarkedTestLine(buf string) (protocol.Position, string) { + col := strings.Index(buf, "^") + buf = strings.Replace(buf, "^", "", 1) + pos := protocol.Position{Line: 0, Character: uint32(col)} + return pos, buf +} diff --git a/internal/handler/hover_main_test.go b/internal/handler/hover_main_test.go index fe7f5a49..531d838d 100644 --- a/internal/handler/hover_main_test.go +++ b/internal/handler/hover_main_test.go @@ -38,16 +38,16 @@ func TestHoverMain(t *testing.T) { Line: 74, Character: 50, }, - expected: "$root.Values.deployments", + expected: fmt.Sprintf("### %s\n%s\n\n\n", filepath.Join("..", "..", "testdata", "example", "values.yaml"), "first:\n some: value\nsecond:\n some: value"), expectedError: nil, }, { desc: "Test hover on template context with variables in range loop", position: lsp.Position{ Line: 80, - Character: 35, + Character: 31, }, - expected: "$config.hpa.minReplicas", + expected: fmt.Sprintf("### %s\n%s\n\n", filepath.Join("..", "..", "testdata", "example", "values.yaml"), "value"), expectedError: nil, }, { diff --git a/internal/handler/references_test.go b/internal/handler/references_test.go index 039bd24e..ba106d66 100644 --- a/internal/handler/references_test.go +++ b/internal/handler/references_test.go @@ -3,7 +3,6 @@ package handler import ( "context" "os" - "strings" "testing" "github.com/mrjosh/helm-ls/internal/adapter/yamlls" @@ -241,11 +240,3 @@ func TestRefercesSingleLines(t *testing.T) { }) } } - -// Takes a string with a mark (^) in it and returns the position and the string without the mark -func getPositionForMarkedTestLine(buf string) (protocol.Position, string) { - col := strings.Index(buf, "^") - buf = strings.Replace(buf, "^", "", 1) - pos := protocol.Position{Line: 0, Character: uint32(col)} - return pos, buf -} diff --git a/internal/language_features/built_in_objects.go b/internal/language_features/built_in_objects.go index dbeaf044..c7c026be 100644 --- a/internal/language_features/built_in_objects.go +++ b/internal/language_features/built_in_objects.go @@ -32,18 +32,24 @@ func (f *BuiltInObjectsFeature) AppropriateForNode() bool { if err != nil || len(templateContext) != 1 { return false } + for _, allowedBuiltIn := range allowedBuiltIns { if templateContext[0] == allowedBuiltIn { return true } } + return false } func (f *BuiltInObjectsFeature) References() (result []lsp.Location, err error) { - templateContext, _ := f.getTemplateContext() + templateContext, err := f.getTemplateContext() + if err != nil { + return []lsp.Location{}, err + } locations := f.getReferencesFromSymbolTable(templateContext) + return append(locations, f.getDefinitionLocations(templateContext)...), err } @@ -55,6 +61,7 @@ func (f *BuiltInObjectsFeature) getDefinitionLocations(templateContext lsplocal. for _, valueFile := range f.Chart.ValuesFiles.AllValuesFiles() { locations = append(locations, lsp.Location{URI: valueFile.URI}) } + return locations case "Chart": return []lsp.Location{{URI: f.Chart.ChartMetadata.URI}} @@ -64,9 +71,13 @@ func (f *BuiltInObjectsFeature) getDefinitionLocations(templateContext lsplocal. } func (f *BuiltInObjectsFeature) Hover() (string, error) { - templateContext, _ := f.getTemplateContext() + templateContext, err := f.getTemplateContext() + if err != nil { + return "", err + } docs, err := f.builtInOjectDocsLookup(templateContext[0], helmdocs.BuiltInObjects) + return docs.Doc, err } @@ -75,5 +86,6 @@ func (f *BuiltInObjectsFeature) Definition() (result []lsp.Location, err error) if err != nil { return []lsp.Location{}, err } + return f.getDefinitionLocations(templateContext), nil } diff --git a/internal/language_features/generic_template_context.go b/internal/language_features/generic_template_context.go index 13bf565b..77dffc70 100644 --- a/internal/language_features/generic_template_context.go +++ b/internal/language_features/generic_template_context.go @@ -19,6 +19,7 @@ func (f *GenericTemplateContextFeature) getTemplateContext() (lsplocal.TemplateC func (f *GenericTemplateContextFeature) getReferencesFromSymbolTable(templateContext lsplocal.TemplateContext) []lsp.Location { locations := []lsp.Location{} + for _, doc := range f.GenericDocumentUseCase.DocumentStore.GetAllDocs() { referenceRanges := doc.SymbolTable.GetTemplateContextRanges(templateContext) for _, referenceRange := range referenceRanges { @@ -35,5 +36,6 @@ func (f *GenericTemplateContextFeature) builtInOjectDocsLookup(key string, docs return item, nil } } + return helmdocs.HelmDocumentation{}, fmt.Errorf("key %s not found on built-in object", key) } diff --git a/internal/lsp/symbol_table.go b/internal/lsp/symbol_table.go index 17c153f3..741e11c6 100644 --- a/internal/lsp/symbol_table.go +++ b/internal/lsp/symbol_table.go @@ -17,6 +17,7 @@ func (t TemplateContext) Copy() TemplateContext { return append(TemplateContext{}, t...) } +// Return everything except the first context func (t TemplateContext) Tail() TemplateContext { return t[1:] } @@ -25,11 +26,38 @@ func (t TemplateContext) IsVariable() bool { return len(t) > 0 && strings.HasPrefix(t[0], "$") } +// Adds a suffix to the last context func (t TemplateContext) AppendSuffix(suffix string) TemplateContext { t[len(t)-1] = t[len(t)-1] + suffix return t } +// Adds a new context to the beginning +func (t TemplateContext) PrependContext(context string) TemplateContext { + if context == "." { + return t + } + return append(TemplateContext{ensureNoLeadingDot(context)}, t...) +} + +func NewTemplateContext(string string) TemplateContext { + if string == "." { + return TemplateContext{} + } + splitted := strings.Split(string, ".") + if len(splitted) > 0 && splitted[0] == "" { + return splitted[1:] + } + return splitted +} + +func ensureNoLeadingDot(context string) string { + if context[0] == '.' && len(context) > 1 { + return context[1:] + } + return context +} + type SymbolTable struct { contexts map[string][]sitter.Range contextsReversed map[sitter.Range]TemplateContext @@ -58,6 +86,7 @@ func (s *SymbolTable) AddTemplateContext(templateContext TemplateContext, pointR // we can just remove it from the template context templateContext = templateContext.Tail() } + s.contexts[templateContext.Format()] = append(s.contexts[templateContext.Format()], pointRange) sliceCopy := make(TemplateContext, len(templateContext)) copy(sliceCopy, templateContext) @@ -74,7 +103,7 @@ func (s *SymbolTable) GetTemplateContext(pointRange sitter.Range) (TemplateConte return result, fmt.Errorf("no template context found") } // return a copy to never modify the original - return result.Copy(), nil + return s.ResolveVariablesInTemplateContext(result.Copy(), pointRange) } func (s *SymbolTable) AddIncludeDefinition(symbol string, pointRange sitter.Range) { diff --git a/internal/lsp/symbol_table_template_context.go b/internal/lsp/symbol_table_template_context.go index c83199b7..0becc8cc 100644 --- a/internal/lsp/symbol_table_template_context.go +++ b/internal/lsp/symbol_table_template_context.go @@ -30,6 +30,9 @@ func (v *TemplateContextVisitor) PushContextMany(context []string) { } func (v *TemplateContextVisitor) PopContext() { + if len(v.currentContext) == 0 { + return + } v.currentContext = v.currentContext[:len(v.currentContext)-1] } @@ -60,10 +63,11 @@ func (v *TemplateContextVisitor) Enter(node *sitter.Node) { v.symbolTable.AddTemplateContext(append(v.currentContext, content), GetRangeForNode(node.ChildByFieldName("name"))) case gotemplate.NodeTypeUnfinishedSelectorExpression: operandNode := node.ChildByFieldName("operand") - if operandNode.Type() == gotemplate.NodeTypeVariable { - v.StashContext() + content := getContextForSelectorExpression(operandNode, v.content) + if !content.IsVariable() { + content = append(v.currentContext, content...) } - v.symbolTable.AddTemplateContext(append(getContextForSelectorExpression(operandNode, v.content), ""), + v.symbolTable.AddTemplateContext(append(content, ""), GetRangeForNode(node.Child(int(node.ChildCount())-1))) case gotemplate.NodeTypeSelectorExpression: operandNode := node.ChildByFieldName("operand") @@ -76,7 +80,7 @@ func (v *TemplateContextVisitor) Enter(node *sitter.Node) { func (v *TemplateContextVisitor) Exit(node *sitter.Node) { switch node.Type() { - case gotemplate.NodeTypeSelectorExpression, gotemplate.NodeTypeUnfinishedSelectorExpression: + case gotemplate.NodeTypeSelectorExpression: operandNode := node.ChildByFieldName("operand") if operandNode.Type() == gotemplate.NodeTypeVariable { v.PopContext() diff --git a/internal/lsp/symbol_table_template_context_variables.go b/internal/lsp/symbol_table_template_context_variables.go new file mode 100644 index 00000000..65f41d8f --- /dev/null +++ b/internal/lsp/symbol_table_template_context_variables.go @@ -0,0 +1,41 @@ +package lsp + +import ( + "fmt" + + sitter "github.com/smacker/go-tree-sitter" +) + +func (s *SymbolTable) ResolveVariablesInTemplateContext(templateContext TemplateContext, pointRange sitter.Range) (TemplateContext, error) { + if !templateContext.IsVariable() { + return templateContext, nil + } + + variableName := templateContext[0] + if variableName == "$" { + return templateContext.Tail(), nil + } + + variableDefinitions := s.variableDefinitions[variableName] + + if len(variableDefinitions) == 0 { + return templateContext, fmt.Errorf("variable %s not found", variableName) + } + + definition, err := findDefinitionForRange(variableDefinitions, pointRange) + if err != nil { + return templateContext, fmt.Errorf("variable %s not found %e", variableName, err) + } + + prefix := getPrefixTemplateContextForVariable(definition) + + return s.ResolveVariablesInTemplateContext(append(prefix, templateContext.Tail()...), pointRange) +} + +func getPrefixTemplateContextForVariable(definition VariableDefinition) TemplateContext { + prefix := NewTemplateContext(definition.Value) + if definition.VariableType == VariableTypeRangeValue && len(prefix) > 0 { + prefix[len(prefix)-1] = prefix[len(prefix)-1] + "[]" + } + return prefix +} diff --git a/internal/lsp/symbol_table_template_context_variables_test.go b/internal/lsp/symbol_table_template_context_variables_test.go new file mode 100644 index 00000000..b5e6c584 --- /dev/null +++ b/internal/lsp/symbol_table_template_context_variables_test.go @@ -0,0 +1,42 @@ +package lsp + +import ( + "strings" + "testing" + + sitter "github.com/smacker/go-tree-sitter" + "github.com/stretchr/testify/assert" +) + +func TestResolveVariablesInTemplateContext(t *testing.T) { + tests := []struct { + template string + templateCtx TemplateContext + expectedCtx TemplateContext + expectedErr error + }{ + {"{{ $values := .Values }} {{ $values.te^st }}", TemplateContext{"$values", "test"}, TemplateContext{"Values", "test"}, nil}, + {"{{- range $type, $config := .Values.deployments }} {{ $config.te^st }}", TemplateContext{"$config", "test"}, TemplateContext{"Values", "deployments[]", "test"}, nil}, + {" {{ $values := .Values }} {{- range $type, $config := $values.deployments }} {{ $config.te^st }}", TemplateContext{"$config", "test"}, TemplateContext{"Values", "deployments[]", "test"}, nil}, + } + + for _, tt := range tests { + t.Run(tt.template, func(t *testing.T) { + col := strings.Index(tt.template, "^") + buf := strings.Replace(tt.template, "^", "", 1) + ast := ParseAst(nil, tt.template) + symbolTable := NewSymbolTable(ast, []byte(buf)) + + result, err := symbolTable.ResolveVariablesInTemplateContext( + tt.templateCtx, sitter.Range{StartByte: uint32(col), EndByte: uint32(col + 1)}) + + if tt.expectedErr != nil { + assert.Error(t, err) + assert.Equal(t, tt.expectedErr, err) + } else { + assert.NoError(t, err) + assert.Equal(t, tt.expectedCtx, result) + } + }) + } +} diff --git a/internal/lsp/symbol_table_test.go b/internal/lsp/symbol_table_test.go index c81a0867..96d30fa5 100644 --- a/internal/lsp/symbol_table_test.go +++ b/internal/lsp/symbol_table_test.go @@ -293,6 +293,33 @@ func TestSymbolTableForValuesSingleTests(t *testing.T) { }, foundContextsLen: 3, }, + { + template: `{{- range $type, $config := .Values.deployments }} {{ .test.nested }} {{ end }} `, + path: []string{"Values", "deployments[]", "test", "nested"}, + startPoint: sitter.Point{ + Row: 0, + Column: 60, + }, + foundContextsLen: 4, + }, + { + template: `{{- range $type, $config := .Values.deployments }} {{ .test.nested. }} {{ end }} `, + path: []string{"Values", "deployments[]", "test", "nested", ""}, + startPoint: sitter.Point{ + Row: 0, + Column: 66, + }, + foundContextsLen: 5, + }, + { + template: `{{- range $type, $config := .Values.deployments }} {{ $config.test.nested. }} {{ end }} `, + path: []string{"$config", "test", "nested", ""}, + startPoint: sitter.Point{ + Row: 0, + Column: 73, + }, + foundContextsLen: 5, + }, } for _, v := range testCases { @@ -304,7 +331,7 @@ func TestSymbolTableForValuesSingleTests(t *testing.T) { for _, v := range values { points = append(points, v.StartPoint) } - assert.Contains(t, points, v.startPoint) + assert.Contains(t, points, v.startPoint, "Ast was %s", ast.RootNode()) assert.Len(t, symbolTable.contexts, v.foundContextsLen) }) } diff --git a/internal/lsp/symbol_table_variables.go b/internal/lsp/symbol_table_variables.go index f120e195..45249499 100644 --- a/internal/lsp/symbol_table_variables.go +++ b/internal/lsp/symbol_table_variables.go @@ -36,12 +36,13 @@ func (s *SymbolTable) getVariableDefinition(name string, accessRange sitter.Rang if !ok || len(definitions) == 0 { return VariableDefinition{}, fmt.Errorf("variable %s not found", name) } - for _, definition := range definitions { - if util.RangeContainsRange(definition.Scope, accessRange) { - return definition, nil - } + + definition, err := findDefinitionForRange(definitions, accessRange) + if err != nil { + return VariableDefinition{}, fmt.Errorf("variable %s not found: %s", name, err.Error()) } - return VariableDefinition{}, fmt.Errorf("variable %s not found", name) + + return definition, nil } func (s *SymbolTable) GetVariableDefinitionForNode(node *sitter.Node, content []byte) (VariableDefinition, error) { @@ -67,6 +68,7 @@ func (s *SymbolTable) GetVariableReferencesForNode(node *sitter.Node, content [] return []sitter.Range{}, err } usages := s.variableUsages[name] + for _, usage := range usages { if util.RangeContainsRange(definition.Scope, usage) { ranges = append(ranges, usage) @@ -87,3 +89,12 @@ func getVariableName(node *sitter.Node, content []byte) (string, error) { } return node.Content(content), nil } + +func findDefinitionForRange(definitions []VariableDefinition, accessRange sitter.Range) (VariableDefinition, error) { + for _, definition := range definitions { + if util.RangeContainsRange(definition.Scope, accessRange) { + return definition, nil + } + } + return VariableDefinition{}, fmt.Errorf("variable not found") +} diff --git a/internal/lsp/symbol_table_variable_test.go b/internal/lsp/symbol_table_variables_test.go similarity index 95% rename from internal/lsp/symbol_table_variable_test.go rename to internal/lsp/symbol_table_variables_test.go index c6f50f1f..405ceea2 100644 --- a/internal/lsp/symbol_table_variable_test.go +++ b/internal/lsp/symbol_table_variables_test.go @@ -72,7 +72,7 @@ func TestGetVariableDefinition(t *testing.T) { EndByte: 68, }, expectedValue: ``, - expectedError: fmt.Errorf("variable $x not found"), + expectedError: fmt.Errorf("variable $x not found: variable not found"), }, } for _, tC := range testCases { diff --git a/internal/lsp/variables_visitor.go b/internal/lsp/variables_visitor.go index 4a184623..cf245cc9 100644 --- a/internal/lsp/variables_visitor.go +++ b/internal/lsp/variables_visitor.go @@ -2,6 +2,7 @@ package lsp import ( "github.com/mrjosh/helm-ls/internal/tree-sitter/gotemplate" + "github.com/mrjosh/helm-ls/internal/util" sitter "github.com/smacker/go-tree-sitter" ) @@ -114,12 +115,7 @@ func (v *VariablesVisitor) addVariableDefinition(variableType VariableType, defi } func (v *VariablesVisitor) addVariableUsage(node *sitter.Node) { - v.symbolTable.AddVariableUsage(node.Content(v.content), sitter.Range{ - StartPoint: node.StartPoint(), - EndPoint: node.EndPoint(), - StartByte: node.StartByte(), - EndByte: node.EndByte(), - }) + v.symbolTable.AddVariableUsage(node.Content(v.content), util.NodeToRange(node)) } func (v *VariablesVisitor) EnterContextShift(_ *sitter.Node, _ string) {} diff --git a/internal/lsp/visitor.go b/internal/lsp/visitor.go index ae964cd1..e93922fc 100644 --- a/internal/lsp/visitor.go +++ b/internal/lsp/visitor.go @@ -55,10 +55,12 @@ func (v *Visitors) visitNodesRecursiveWithScopeShift(node *sitter.Node) { for _, visitor := range v.visitors { visitor.EnterContextShift(rangeNode, "[]") } + for i := uint32(1); i < node.NamedChildCount(); i++ { body := node.NamedChild(int(i)) v.visitNodesRecursiveWithScopeShift(body) } + for _, visitor := range v.visitors { visitor.ExitContextShift(rangeNode) } diff --git a/internal/util/ranges.go b/internal/util/ranges.go index a256de57..d9756630 100644 --- a/internal/util/ranges.go +++ b/internal/util/ranges.go @@ -5,3 +5,12 @@ import sitter "github.com/smacker/go-tree-sitter" func RangeContainsRange(surrounding, including sitter.Range) bool { return surrounding.StartByte <= including.StartByte && surrounding.EndByte >= including.EndByte } + +func NodeToRange(node *sitter.Node) sitter.Range { + return sitter.Range{ + StartPoint: node.StartPoint(), + EndPoint: node.EndPoint(), + StartByte: node.StartByte(), + EndByte: node.EndByte(), + } +} diff --git a/testdata/example/templates/deployment.yaml b/testdata/example/templates/deployment.yaml index 50d3c002..3f86c96e 100644 --- a/testdata/example/templates/deployment.yaml +++ b/testdata/example/templates/deployment.yaml @@ -78,7 +78,7 @@ spec: metadata: name: my-app-{{ $type }} spec: - replicas: {{ $config.hpa.minReplicas }} + replicas: {{ $config.some }} test: {{ $.Values.ingress.hosts }} --- {{- end }} diff --git a/testdata/example/values.yaml b/testdata/example/values.yaml index 515e40d7..0bec67bc 100644 --- a/testdata/example/values.yaml +++ b/testdata/example/values.yaml @@ -112,3 +112,21 @@ deployments: some: value second: some: value + +deploymentsWithNestedStuff: + spot: + hpa: + enabled: true + minReplicas: 2 + maxReplicas: 10 + cpuUtilization: + enabled: true + targetAverageUtilization: 80 + ondemand: + hpa: + enabled: true + minReplicas: 2 + maxReplicas: 4 + cpuUtilization: + enabled: true + targetAverageUtilization: 80