From d876261677c3cdc41b63aa002d86cf206e0a2b51 Mon Sep 17 00:00:00 2001 From: Cerebrovinny Date: Wed, 30 Apr 2025 15:59:25 +0100 Subject: [PATCH 01/10] fix: nested components display --- pkg/list/list_values.go | 6 +----- pkg/list/utils/utils.go | 6 +----- 2 files changed, 2 insertions(+), 10 deletions(-) diff --git a/pkg/list/list_values.go b/pkg/list/list_values.go index 64e3bfe2b..7382ca316 100644 --- a/pkg/list/list_values.go +++ b/pkg/list/list_values.go @@ -164,11 +164,7 @@ func extractComponentValues(stacksMap map[string]interface{}, component string, func processComponentType(component string, componentFilter string, includeAbstract bool) string { // If this is a regular component query with a specific component filter if component == "" && componentFilter != "" { - // Extract component name from path - componentName := getComponentNameFromPath(componentFilter) - - // Return a direct path to the component. - return fmt.Sprintf(".components.%s.%s", KeyTerraform, componentName) + return fmt.Sprintf(".components.%s.\"%s\"", KeyTerraform, componentFilter) } // Handle special section queries. diff --git a/pkg/list/utils/utils.go b/pkg/list/utils/utils.go index f66c8be67..c8d95e594 100644 --- a/pkg/list/utils/utils.go +++ b/pkg/list/utils/utils.go @@ -31,10 +31,6 @@ func CheckComponentExists(atmosConfig *schema.AtmosConfiguration, componentName return false } - // Extract component name from path if needed - parts := strings.Split(componentName, "/") - baseName := parts[len(parts)-1] - // Get all stacks to check for the component stacksMap, err := e.ExecuteDescribeStacks(*atmosConfig, "", nil, nil, nil, false, false, false, false, nil) if err != nil { @@ -59,7 +55,7 @@ func CheckComponentExists(atmosConfig *schema.AtmosConfiguration, componentName } // Check if the component exists in this stack - _, exists := terraformComponents[baseName] + _, exists := terraformComponents[componentName] if exists { return true } From 1e272a0974e4b716c3aee270230c0899918b6fdb Mon Sep 17 00:00:00 2001 From: Cerebrovinny Date: Fri, 2 May 2025 17:09:28 +0100 Subject: [PATCH 02/10] add helmfile support --- pkg/list/utils/utils.go | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/pkg/list/utils/utils.go b/pkg/list/utils/utils.go index c8d95e594..51046b9c4 100644 --- a/pkg/list/utils/utils.go +++ b/pkg/list/utils/utils.go @@ -49,15 +49,16 @@ func CheckComponentExists(atmosConfig *schema.AtmosConfiguration, componentName continue } - terraformComponents, ok := componentsMap["terraform"].(map[string]interface{}) - if !ok { - continue - } + for _, componentTypeMap := range componentsMap { + typedComponents, ok := componentTypeMap.(map[string]interface{}) + if !ok { + continue + } - // Check if the component exists in this stack - _, exists := terraformComponents[componentName] - if exists { - return true + _, exists := typedComponents[componentName] + if exists { + return true + } } } From 68def1c744660422bf11326d4d38b9ec2caa67ac Mon Sep 17 00:00:00 2001 From: Cerebrovinny Date: Sat, 3 May 2025 11:58:45 +0100 Subject: [PATCH 03/10] clean code and add helmfile support --- pkg/list/list_values.go | 263 +++++++++++++++++++++++++++------------- 1 file changed, 182 insertions(+), 81 deletions(-) diff --git a/pkg/list/list_values.go b/pkg/list/list_values.go index 7382ca316..44a352735 100644 --- a/pkg/list/list_values.go +++ b/pkg/list/list_values.go @@ -23,6 +23,8 @@ var ( const ( // KeyTerraform is the key for terraform components. KeyTerraform = "terraform" + // KeyHelmfile is the key for helmfile components. + KeyHelmfile = "helmfile" // KeySettings is the key for settings section. KeySettings = "settings" // KeyMetadata is the key for metadata section. @@ -75,7 +77,7 @@ func FilterAndListValues(stacksMap map[string]interface{}, options *FilterOption } // Extract stack values - extractedValues, err := extractComponentValues(stacksMap, options.Component, options.ComponentFilter, options.IncludeAbstract) + extractedValues, err := extractComponentValuesFromAllStacks(stacksMap, options.Component, options.ComponentFilter, options.IncludeAbstract) if err != nil { return "", err } @@ -117,82 +119,191 @@ func createComponentError(component, componentFilter string) error { } } -// extractComponentValues extracts the component values from all stacks. -func extractComponentValues(stacksMap map[string]interface{}, component string, componentFilter string, includeAbstract bool) (map[string]interface{}, error) { - values := make(map[string]interface{}) +func extractComponentValuesFromAllStacks(stacks map[string]interface{}, component, filter string, includeAbstract bool) (map[string]interface{}, error) { + stackComponentValues := make(map[string]interface{}) - // Check if this is a regular component and use it as filter if no specific filter - isComponentSection := component != KeySettings && component != KeyMetadata - if isComponentSection && componentFilter == "" { - log.Debug("Using component as filter", KeyComponent, component) - componentFilter = component - component = "" - } - - log.Debug("Building YQ expression", KeyComponent, component, "componentFilter", componentFilter) + component, filter = normalizeComponentAndFilterInputs(component, filter) - for stackName, stackData := range stacksMap { - stack, ok := stackData.(map[string]interface{}) + for stackName, data := range stacks { + stackMap, ok := data.(map[string]interface{}) if !ok { - log.Debug("stack data is not a map", KeyStack, stackName) continue } - // Build and execute YQ expression - yqExpression := processComponentType(component, componentFilter, includeAbstract) - queryResult, err := utils.EvaluateYqExpression(nil, stack, yqExpression) - if err != nil || queryResult == nil { - log.Debug("no values found", - KeyStack, stackName, KeyComponent, component, - "componentFilter", componentFilter, "yq_expression", yqExpression, - "error", err) - continue + componentValue := extractComponentValueFromSingleStack(stackMap, stackName, component, filter, includeAbstract) + if componentValue != nil { + stackComponentValues[stackName] = componentValue + } + } + + if len(stackComponentValues) == 0 { + return nil, createComponentError(component, filter) + } + + return stackComponentValues, nil +} + +func normalizeComponentAndFilterInputs(component, filter string) (string, string) { + isRegularComponent := component != KeySettings && component != KeyMetadata + if isRegularComponent && filter == "" { + log.Debug("Using component name as filter", KeyComponent, component) + return "", component + } + return component, filter +} + +func extractComponentValueFromSingleStack(stackMap map[string]interface{}, stackName, component, filter string, includeAbstract bool) interface{} { + targetComponentName := determineTargetComponentName(component, filter) + + componentType := detectComponentTypeInStack(stackMap, targetComponentName, stackName) + if componentType == "" { + return nil + } + + value, err := executeQueryForStack( + stackName, + stackMap, + component, + filter, + targetComponentName, + componentType, + includeAbstract, + ) + + if err != nil { + log.Warn("Query failed", KeyStack, stackName, "error", err) + return nil + } + + return value +} + +func detectComponentTypeInStack(stackMap map[string]interface{}, targetComponent, stackName string) string { + if targetComponent == "" { + return KeyTerraform + } + + detectedType, err := determineComponentType(stackMap, targetComponent) + if err != nil { + log.Debug("Component not found", KeyStack, stackName, KeyComponent, targetComponent) + return "" + } + + return detectedType +} + +func executeQueryForStack( + stackName string, + stackMap map[string]interface{}, + component, componentFilter, targetComponentName, componentType string, + includeAbstract bool, +) (interface{}, error) { + yqExpression := buildYqExpressionForComponent(component, componentFilter, includeAbstract, componentType) + queryResult, err := utils.EvaluateYqExpression(nil, stackMap, yqExpression) + + if err != nil { + var logKey string + var logValue string + if targetComponentName != "" { + logKey = KeyComponent + logValue = targetComponentName + } else { + logKey = "section" + logValue = component } - // Process the result based on component type - values[stackName] = processQueryResult(component, queryResult) + log.Warn("YQ evaluation failed", + KeyStack, stackName, + "yqExpression", yqExpression, + logKey, logValue, + "error", err) + return nil, fmt.Errorf("query failed: %w", err) } - if len(values) == 0 { - return nil, createComponentError(component, componentFilter) + if queryResult == nil { + return nil, nil } - return values, nil + return extractRelevantDataFromQueryResult(component, queryResult), nil } -// processComponentType determines the YQ expression based on component type. -func processComponentType(component string, componentFilter string, includeAbstract bool) string { - // If this is a regular component query with a specific component filter +func determineTargetComponentName(component, componentFilter string) string { + if componentFilter != "" { + return getComponentNameFromPath(componentFilter) + } + + isRegularComponent := component != KeySettings && component != KeyMetadata + if isRegularComponent { + return getComponentNameFromPath(component) + } + + return "" +} + +func determineComponentType(stack map[string]interface{}, targetComponentName string) (string, error) { + if targetComponentName == "" { + return "", fmt.Errorf("targetComponentName cannot be empty") + } + + components, ok := stack[KeyComponents].(map[string]interface{}) + if !ok { + return "", fmt.Errorf("components section not found in stack") + } + + if isComponentInSection(components, KeyTerraform, targetComponentName) { + log.Debug("Component found under terraform", KeyComponent, targetComponentName) + return KeyTerraform, nil + } + + if isComponentInSection(components, KeyHelmfile, targetComponentName) { + log.Debug("Component found under helmfile", KeyComponent, targetComponentName) + return KeyHelmfile, nil + } + + return "", fmt.Errorf("component '%s' not found in terraform or helmfile sections", targetComponentName) +} + +func isComponentInSection(components map[string]interface{}, sectionKey, componentName string) bool { + section, ok := components[sectionKey].(map[string]interface{}) + if !ok { + return false + } + _, exists := section[componentName] + return exists +} + +func buildYqExpressionForComponent(component string, componentFilter string, includeAbstract bool, componentType string) string { if component == "" && componentFilter != "" { - return fmt.Sprintf(".components.%s.\"%s\"", KeyTerraform, componentFilter) + return fmt.Sprintf(".components.%s.\"%s\"", componentType, componentFilter) } - // Handle special section queries. switch component { case KeySettings: - if componentFilter != "" { - componentName := getComponentNameFromPath(componentFilter) - return fmt.Sprintf(".components.%s.%s", KeyTerraform, componentName) - } - return "select(.settings // .terraform.settings // .components.terraform.*.settings)" + return buildSettingsExpression(componentFilter, componentType) case KeyMetadata: - if componentFilter != "" { - // For metadata with component filter, target the specific component. - componentName := getComponentNameFromPath(componentFilter) - return fmt.Sprintf(".components.%s.%s", KeyTerraform, componentName) - } - // For general metadata query. - return DotChar + KeyMetadata + return buildMetadataExpression(componentFilter, componentType) default: - // Extract component name from path. componentName := getComponentNameFromPath(component) + return buildComponentYqExpression(componentName, includeAbstract, componentType) + } +} - // Build query for component vars. - return buildComponentYqExpression(componentName, includeAbstract) +func buildSettingsExpression(componentFilter, componentType string) string { + if componentFilter != "" { + componentName := getComponentNameFromPath(componentFilter) + return fmt.Sprintf(".components.%s.%s", componentType, componentName) } + return "select(.settings // .terraform.settings // .components.terraform.*.settings)" +} + +func buildMetadataExpression(componentFilter, componentType string) string { + if componentFilter != "" { + componentName := getComponentNameFromPath(componentFilter) + return fmt.Sprintf(".components.%s.%s", componentType, componentName) + } + return DotChar + KeyMetadata } -// getComponentNameFromPath extracts the component name from a potentially nested path. func getComponentNameFromPath(component string) string { parts := strings.Split(component, "/") if len(parts) > 1 { @@ -201,37 +312,33 @@ func getComponentNameFromPath(component string) string { return component } -// buildComponentYqExpression creates the YQ expression for extracting component vars. -func buildComponentYqExpression(componentName string, includeAbstract bool) string { - // Base expression to target the component - yqExpression := fmt.Sprintf("%scomponents%s%s%s%s", DotChar, DotChar, KeyTerraform, DotChar, componentName) +func buildComponentYqExpression(componentName string, includeAbstract bool, componentType string) string { + path := fmt.Sprintf("%scomponents%s%s%s%s", DotChar, DotChar, componentType, DotChar, componentName) - // If not including abstract components, filter them out if !includeAbstract { - // Only get component that either doesn't have abstract flag or has it set to false - yqExpression += fmt.Sprintf(" | select(has(\"%s\") == false or %s%s == false)", + path += fmt.Sprintf(" | select(has(\"%s\") == false or %s%s == false)", KeyAbstract, DotChar, KeyAbstract) } - // Get the vars - yqExpression += fmt.Sprintf(" | %s%s", DotChar, KeyVars) - - return yqExpression + return path + fmt.Sprintf(" | %s%s", DotChar, KeyVars) } -// processQueryResult handles the query result based on component type. -func processQueryResult(component string, queryResult interface{}) interface{} { - // Process settings specially to handle nested settings key - if component == KeySettings { - if settings, ok := queryResult.(map[string]interface{}); ok { - if settingsContent, ok := settings[KeySettings].(map[string]interface{}); ok { - return settingsContent - } - } +func extractRelevantDataFromQueryResult(component string, queryResult interface{}) interface{} { + if component != KeySettings { + return queryResult } - // Return the result as is for other components - return queryResult + settings, ok := queryResult.(map[string]interface{}) + if !ok { + return queryResult + } + + settingsContent, ok := settings[KeySettings].(map[string]interface{}) + if !ok { + return queryResult + } + + return settingsContent } // applyFilters applies stack pattern and column limits to the values. @@ -406,7 +513,7 @@ func processStackWithQuery(stackName string, stackData interface{}, query string return nil, false } - formattedResult := formatResultForDisplay(queryResult, query) + formattedResult := formatResultForDisplay(queryResult) return formattedResult, formattedResult != nil } @@ -441,16 +548,10 @@ func applyQuery(filteredValues map[string]interface{}, query string, component s } // formatResultForDisplay formats query results for display. -func formatResultForDisplay(result interface{}, query string) interface{} { - log.Debug("Formatting query result for display", - "result_type", fmt.Sprintf(TypeFormatSpec, result), - "query", query) - +func formatResultForDisplay(result interface{}) interface{} { if result == nil { - log.Debug("Skipping nil result") return nil } - return result } From c58b6ff0895f04fb5087246b5271c892b62066e2 Mon Sep 17 00:00:00 2001 From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com> Date: Sat, 3 May 2025 10:59:44 +0000 Subject: [PATCH 04/10] [autofix.ci] apply automated fixes --- pkg/list/list_values.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/pkg/list/list_values.go b/pkg/list/list_values.go index 44a352735..b165f9cb6 100644 --- a/pkg/list/list_values.go +++ b/pkg/list/list_values.go @@ -169,7 +169,6 @@ func extractComponentValueFromSingleStack(stackMap map[string]interface{}, stack componentType, includeAbstract, ) - if err != nil { log.Warn("Query failed", KeyStack, stackName, "error", err) return nil @@ -200,7 +199,6 @@ func executeQueryForStack( ) (interface{}, error) { yqExpression := buildYqExpressionForComponent(component, componentFilter, includeAbstract, componentType) queryResult, err := utils.EvaluateYqExpression(nil, stackMap, yqExpression) - if err != nil { var logKey string var logValue string From 965e0df39af38cf35490875c60eca43f1c0e99c6 Mon Sep 17 00:00:00 2001 From: Cerebrovinny Date: Sat, 3 May 2025 12:52:29 +0100 Subject: [PATCH 05/10] clean up --- pkg/list/list_values.go | 72 +++++++++++++++++++++++++---------------- 1 file changed, 45 insertions(+), 27 deletions(-) diff --git a/pkg/list/list_values.go b/pkg/list/list_values.go index b165f9cb6..e6abed406 100644 --- a/pkg/list/list_values.go +++ b/pkg/list/list_values.go @@ -16,7 +16,11 @@ import ( // Error variables for list_values package. var ( - ErrInvalidStackPattern = errors.New("invalid stack pattern") + ErrInvalidStackPattern = errors.New("invalid stack pattern") + ErrEmptyTargetComponentName = errors.New("target component name cannot be empty") + ErrComponentsSectionNotFound = errors.New("components section not found in stack") + ErrComponentNotFoundInSections = errors.New("component not found in terraform or helmfile sections") + ErrQueryFailed = errors.New("query execution failed") ) // Component and section name constants. @@ -160,15 +164,17 @@ func extractComponentValueFromSingleStack(stackMap map[string]interface{}, stack return nil } - value, err := executeQueryForStack( - stackName, - stackMap, - component, - filter, - targetComponentName, - componentType, - includeAbstract, - ) + params := QueryParams{ + StackName: stackName, + StackMap: stackMap, + Component: component, + ComponentFilter: filter, + TargetComponentName: targetComponentName, + ComponentType: componentType, + IncludeAbstract: includeAbstract, + } + + value, err := executeQueryForStack(params) if err != nil { log.Warn("Query failed", KeyStack, stackName, "error", err) return nil @@ -191,38 +197,50 @@ func detectComponentTypeInStack(stackMap map[string]interface{}, targetComponent return detectedType } -func executeQueryForStack( - stackName string, - stackMap map[string]interface{}, - component, componentFilter, targetComponentName, componentType string, - includeAbstract bool, -) (interface{}, error) { - yqExpression := buildYqExpressionForComponent(component, componentFilter, includeAbstract, componentType) - queryResult, err := utils.EvaluateYqExpression(nil, stackMap, yqExpression) +// QueryParams holds all parameters needed for executing a query on a stack. +type QueryParams struct { + StackName string + StackMap map[string]interface{} + Component string + ComponentFilter string + TargetComponentName string + ComponentType string + IncludeAbstract bool +} + +func executeQueryForStack(params QueryParams) (interface{}, error) { + yqExpression := buildYqExpressionForComponent( + params.Component, + params.ComponentFilter, + params.IncludeAbstract, + params.ComponentType, + ) + + queryResult, err := utils.EvaluateYqExpression(nil, params.StackMap, yqExpression) if err != nil { var logKey string var logValue string - if targetComponentName != "" { + if params.TargetComponentName != "" { logKey = KeyComponent - logValue = targetComponentName + logValue = params.TargetComponentName } else { logKey = "section" - logValue = component + logValue = params.Component } log.Warn("YQ evaluation failed", - KeyStack, stackName, + KeyStack, params.StackName, "yqExpression", yqExpression, logKey, logValue, "error", err) - return nil, fmt.Errorf("query failed: %w", err) + return nil, fmt.Errorf("%w: %s", ErrQueryFailed, err.Error()) } if queryResult == nil { return nil, nil } - return extractRelevantDataFromQueryResult(component, queryResult), nil + return extractRelevantDataFromQueryResult(params.Component, queryResult), nil } func determineTargetComponentName(component, componentFilter string) string { @@ -240,12 +258,12 @@ func determineTargetComponentName(component, componentFilter string) string { func determineComponentType(stack map[string]interface{}, targetComponentName string) (string, error) { if targetComponentName == "" { - return "", fmt.Errorf("targetComponentName cannot be empty") + return "", ErrEmptyTargetComponentName } components, ok := stack[KeyComponents].(map[string]interface{}) if !ok { - return "", fmt.Errorf("components section not found in stack") + return "", ErrComponentsSectionNotFound } if isComponentInSection(components, KeyTerraform, targetComponentName) { @@ -258,7 +276,7 @@ func determineComponentType(stack map[string]interface{}, targetComponentName st return KeyHelmfile, nil } - return "", fmt.Errorf("component '%s' not found in terraform or helmfile sections", targetComponentName) + return "", fmt.Errorf("%w: %s", ErrComponentNotFoundInSections, targetComponentName) } func isComponentInSection(components map[string]interface{}, sectionKey, componentName string) bool { From 2525b3f1e18da01159de85d95dafb770658e2225 Mon Sep 17 00:00:00 2001 From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com> Date: Sat, 3 May 2025 11:53:37 +0000 Subject: [PATCH 06/10] [autofix.ci] apply automated fixes --- pkg/list/list_values.go | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/pkg/list/list_values.go b/pkg/list/list_values.go index e6abed406..041bfdbe9 100644 --- a/pkg/list/list_values.go +++ b/pkg/list/list_values.go @@ -16,11 +16,11 @@ import ( // Error variables for list_values package. var ( - ErrInvalidStackPattern = errors.New("invalid stack pattern") - ErrEmptyTargetComponentName = errors.New("target component name cannot be empty") - ErrComponentsSectionNotFound = errors.New("components section not found in stack") - ErrComponentNotFoundInSections = errors.New("component not found in terraform or helmfile sections") - ErrQueryFailed = errors.New("query execution failed") + ErrInvalidStackPattern = errors.New("invalid stack pattern") + ErrEmptyTargetComponentName = errors.New("target component name cannot be empty") + ErrComponentsSectionNotFound = errors.New("components section not found in stack") + ErrComponentNotFoundInSections = errors.New("component not found in terraform or helmfile sections") + ErrQueryFailed = errors.New("query execution failed") ) // Component and section name constants. @@ -173,7 +173,7 @@ func extractComponentValueFromSingleStack(stackMap map[string]interface{}, stack ComponentType: componentType, IncludeAbstract: includeAbstract, } - + value, err := executeQueryForStack(params) if err != nil { log.Warn("Query failed", KeyStack, stackName, "error", err) @@ -210,12 +210,12 @@ type QueryParams struct { func executeQueryForStack(params QueryParams) (interface{}, error) { yqExpression := buildYqExpressionForComponent( - params.Component, - params.ComponentFilter, - params.IncludeAbstract, + params.Component, + params.ComponentFilter, + params.IncludeAbstract, params.ComponentType, ) - + queryResult, err := utils.EvaluateYqExpression(nil, params.StackMap, yqExpression) if err != nil { var logKey string From ce5a47a005b55143212dc630dde76186997994bd Mon Sep 17 00:00:00 2001 From: Cerebrovinny Date: Sat, 3 May 2025 16:14:42 +0100 Subject: [PATCH 07/10] refactor: simplify component name handling in query functions --- pkg/list/list_values.go | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/pkg/list/list_values.go b/pkg/list/list_values.go index 041bfdbe9..6ff45fa10 100644 --- a/pkg/list/list_values.go +++ b/pkg/list/list_values.go @@ -245,12 +245,12 @@ func executeQueryForStack(params QueryParams) (interface{}, error) { func determineTargetComponentName(component, componentFilter string) string { if componentFilter != "" { - return getComponentNameFromPath(componentFilter) + return componentFilter } isRegularComponent := component != KeySettings && component != KeyMetadata if isRegularComponent { - return getComponentNameFromPath(component) + return component } return "" @@ -299,23 +299,21 @@ func buildYqExpressionForComponent(component string, componentFilter string, inc case KeyMetadata: return buildMetadataExpression(componentFilter, componentType) default: - componentName := getComponentNameFromPath(component) - return buildComponentYqExpression(componentName, includeAbstract, componentType) + return buildComponentYqExpression(component, includeAbstract, componentType) } } func buildSettingsExpression(componentFilter, componentType string) string { if componentFilter != "" { - componentName := getComponentNameFromPath(componentFilter) - return fmt.Sprintf(".components.%s.%s", componentType, componentName) + return fmt.Sprintf(".components.%s.\"%s\"", componentType, componentFilter) } return "select(.settings // .terraform.settings // .components.terraform.*.settings)" } func buildMetadataExpression(componentFilter, componentType string) string { if componentFilter != "" { - componentName := getComponentNameFromPath(componentFilter) - return fmt.Sprintf(".components.%s.%s", componentType, componentName) + // Use full component path and wrap in quotes for nested support + return fmt.Sprintf(".components.%s.\"%s\"", componentType, componentFilter) } return DotChar + KeyMetadata } @@ -328,8 +326,8 @@ func getComponentNameFromPath(component string) string { return component } -func buildComponentYqExpression(componentName string, includeAbstract bool, componentType string) string { - path := fmt.Sprintf("%scomponents%s%s%s%s", DotChar, DotChar, componentType, DotChar, componentName) +func buildComponentYqExpression(component string, includeAbstract bool, componentType string) string { + path := fmt.Sprintf("%scomponents%s%s%s\"%s\"", DotChar, DotChar, componentType, DotChar, component) if !includeAbstract { path += fmt.Sprintf(" | select(has(\"%s\") == false or %s%s == false)", From 190dd90d0f1277ac46f8f8de56f897c89498ce04 Mon Sep 17 00:00:00 2001 From: Cerebrovinny Date: Sat, 3 May 2025 16:26:34 +0100 Subject: [PATCH 08/10] add helmfile to settings --- pkg/list/list_values.go | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/pkg/list/list_values.go b/pkg/list/list_values.go index 6ff45fa10..74e98c82f 100644 --- a/pkg/list/list_values.go +++ b/pkg/list/list_values.go @@ -307,7 +307,9 @@ func buildSettingsExpression(componentFilter, componentType string) string { if componentFilter != "" { return fmt.Sprintf(".components.%s.\"%s\"", componentType, componentFilter) } - return "select(.settings // .terraform.settings // .components.terraform.*.settings)" + return "select(.settings // " + + ".components." + KeyTerraform + ".*.settings // " + + ".components." + KeyHelmfile + ".*.settings)" } func buildMetadataExpression(componentFilter, componentType string) string { @@ -318,14 +320,6 @@ func buildMetadataExpression(componentFilter, componentType string) string { return DotChar + KeyMetadata } -func getComponentNameFromPath(component string) string { - parts := strings.Split(component, "/") - if len(parts) > 1 { - return parts[len(parts)-1] - } - return component -} - func buildComponentYqExpression(component string, includeAbstract bool, componentType string) string { path := fmt.Sprintf("%scomponents%s%s%s\"%s\"", DotChar, DotChar, componentType, DotChar, component) From ed89ec7ce9da63c23445315f6d27c2ec408b1c16 Mon Sep 17 00:00:00 2001 From: Cerebrovinny Date: Sat, 3 May 2025 16:27:35 +0100 Subject: [PATCH 09/10] clean code --- pkg/list/list_values.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/list/list_values.go b/pkg/list/list_values.go index 74e98c82f..e1552e06f 100644 --- a/pkg/list/list_values.go +++ b/pkg/list/list_values.go @@ -164,7 +164,7 @@ func extractComponentValueFromSingleStack(stackMap map[string]interface{}, stack return nil } - params := QueryParams{ + params := &QueryParams{ StackName: stackName, StackMap: stackMap, Component: component, @@ -208,7 +208,7 @@ type QueryParams struct { IncludeAbstract bool } -func executeQueryForStack(params QueryParams) (interface{}, error) { +func executeQueryForStack(params *QueryParams) (interface{}, error) { yqExpression := buildYqExpressionForComponent( params.Component, params.ComponentFilter, From f6b2c1affa25611a7920251304e5dd40e82f9cd5 Mon Sep 17 00:00:00 2001 From: Cerebrovinny Date: Sat, 3 May 2025 21:01:34 +0100 Subject: [PATCH 10/10] add yq tests for nested path and helmfile --- pkg/list/list_values_test.go | 46 ++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/pkg/list/list_values_test.go b/pkg/list/list_values_test.go index 65f70407b..17037b5eb 100644 --- a/pkg/list/list_values_test.go +++ b/pkg/list/list_values_test.go @@ -409,3 +409,49 @@ func TestFilterAndListValues(t *testing.T) { }) } } + +func TestBuildComponentYqExpression(t *testing.T) { + tests := []struct { + name string + component string + includeAbstract bool + componentType string + expected string + }{ + { + name: "basic component without including abstract", + component: "vpc", + includeAbstract: false, + componentType: "terraform", + expected: ".components.terraform.\"vpc\" | select(has(\"abstract\") == false or .abstract == false) | .vars", + }, + { + name: "basic component including abstract", + component: "vpc", + includeAbstract: true, + componentType: "terraform", + expected: ".components.terraform.\"vpc\" | .vars", + }, + { + name: "nested component without including abstract", + component: "nested/vpc", + includeAbstract: false, + componentType: "terraform", + expected: ".components.terraform.\"nested/vpc\" | select(has(\"abstract\") == false or .abstract == false) | .vars", + }, + { + name: "helmfile component", + component: "nginx", + includeAbstract: false, + componentType: "helmfile", + expected: ".components.helmfile.\"nginx\" | select(has(\"abstract\") == false or .abstract == false) | .vars", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result := buildComponentYqExpression(tt.component, tt.includeAbstract, tt.componentType) + assert.Equal(t, tt.expected, result) + }) + } +}