diff --git a/atmos.yaml b/atmos.yaml index daa5f91cc..2dbfc2225 100644 --- a/atmos.yaml +++ b/atmos.yaml @@ -191,59 +191,6 @@ commands: - 'echo Dependencies: "{{ .ComponentConfig.deps }}"' - 'echo settings.config.is_prod: "{{ .ComponentConfig.settings.config.is_prod }}"' - 'echo ATMOS_IS_PROD: "$ATMOS_IS_PROD"' - - name: list - description: Execute 'atmos list' commands - # subcommands - commands: - - name: stacks - description: | - List all Atmos stacks. - steps: - - > - atmos describe stacks --process-templates=false --sections none | grep -e "^\S" | sed s/://g - - name: components - description: | - List all Atmos components in all stacks or in a single stack. - - Example usage: - atmos list components - atmos list components -s plat-ue2-dev - atmos list components --stack plat-uw2-prod - atmos list components -s plat-ue2-dev --type abstract - atmos list components -s plat-ue2-dev -t enabled - atmos list components -s plat-ue2-dev -t disabled - flags: - - name: stack - shorthand: s - description: Name of the stack - required: false - - name: type - shorthand: t - description: Component types - abstract, enabled, or disabled - required: false - steps: - - > - {{ if .Flags.stack }} - {{ if eq .Flags.type "enabled" }} - atmos describe stacks --stack {{ .Flags.stack }} --format json | jq '.[].components.terraform | to_entries[] | select(.value.vars.enabled == true)' | jq -r .key - {{ else if eq .Flags.type "disabled" }} - atmos describe stacks --stack {{ .Flags.stack }} --format json | jq '.[].components.terraform | to_entries[] | select(.value.vars.enabled == false)' | jq -r .key - {{ else if eq .Flags.type "abstract" }} - atmos describe stacks --stack {{ .Flags.stack }} --format json | jq '.[].components.terraform | to_entries[] | select(.value.metadata.type == "abstract")' | jq -r .key - {{ else }} - atmos describe stacks --stack {{ .Flags.stack }} --format json --sections none | jq ".[].components.terraform" | jq -s add | jq -r "keys[]" - {{ end }} - {{ else }} - {{ if eq .Flags.type "enabled" }} - atmos describe stacks --format json | jq '.[].components.terraform | to_entries[] | select(.value.vars.enabled == true)' | jq -r '[.key]' | jq -s 'add' | jq 'unique | sort' | jq -r "values[]" - {{ else if eq .Flags.type "disabled" }} - atmos describe stacks --format json | jq '.[].components.terraform | to_entries[] | select(.value.vars.enabled == false)' | jq -r '[.key]' | jq -s 'add' | jq 'unique | sort' | jq -r "values[]" - {{ else if eq .Flags.type "abstract" }} - atmos describe stacks --format json | jq '.[].components.terraform | to_entries[] | select(.value.metadata.type == "abstract")' | jq -r '[.key]' | jq -s 'add' | jq 'unique | sort' | jq -r "values[]" - {{ else }} - atmos describe stacks --format json --sections none | jq ".[].components.terraform" | jq -s add | jq -r "keys[]" - {{ end }} - {{ end }} # Integrations integrations: diff --git a/cmd/list.go b/cmd/list.go new file mode 100644 index 000000000..62862c8b2 --- /dev/null +++ b/cmd/list.go @@ -0,0 +1,17 @@ +package cmd + +import ( + "github.com/spf13/cobra" +) + +// listCmd commands list stacks and components +var listCmd = &cobra.Command{ + Use: "list", + Short: "Execute 'list' commands", + Long: `This command lists stacks and components`, + FParseErrWhitelist: struct{ UnknownFlags bool }{UnknownFlags: false}, +} + +func init() { + RootCmd.AddCommand(listCmd) +} diff --git a/cmd/list_components.go b/cmd/list_components.go new file mode 100644 index 000000000..03cf6feff --- /dev/null +++ b/cmd/list_components.go @@ -0,0 +1,54 @@ +package cmd + +import ( + "fmt" + + e "github.com/cloudposse/atmos/internal/exec" + "github.com/cloudposse/atmos/pkg/config" + l "github.com/cloudposse/atmos/pkg/list" + "github.com/cloudposse/atmos/pkg/schema" + u "github.com/cloudposse/atmos/pkg/utils" + "github.com/fatih/color" + "github.com/spf13/cobra" +) + +// listComponentsCmd lists atmos components +var listComponentsCmd = &cobra.Command{ + Use: "components", + Short: "Execute 'list components' command", + Long: `This command lists all Atmos components or filters components by stacks.`, + Example: "atmos list components\n" + + "atmos list components -s ", + Run: func(cmd *cobra.Command, args []string) { + // Check Atmos configuration + checkAtmosConfig() + + stackFlag, _ := cmd.Flags().GetString("stack") + + configAndStacksInfo := schema.ConfigAndStacksInfo{} + cliConfig, err := config.InitCliConfig(configAndStacksInfo, true) + if err != nil { + u.PrintMessageInColor(fmt.Sprintf("Error initializing CLI config: %v", err), color.New(color.FgRed)) + return + } + + stacksMap, err := e.ExecuteDescribeStacks(cliConfig, "", nil, nil, nil, false, false, false) + if err != nil { + u.PrintMessageInColor(fmt.Sprintf("Error describing stacks: %v", err), color.New(color.FgRed)) + return + } + + output, err := l.FilterAndListComponents(stackFlag, stacksMap) + if err != nil { + u.PrintMessageInColor(fmt.Sprintf("Error: %v"+"\n", err), color.New(color.FgYellow)) + return + } + + u.PrintMessageInColor(output, color.New(color.FgGreen)) + }, +} + +func init() { + listComponentsCmd.PersistentFlags().StringP("stack", "s", "", "Filter components by stack (e.g., atmos list components -s stack1)") + listCmd.AddCommand(listComponentsCmd) +} diff --git a/cmd/list_stacks.go b/cmd/list_stacks.go new file mode 100644 index 000000000..38d5e547e --- /dev/null +++ b/cmd/list_stacks.go @@ -0,0 +1,55 @@ +package cmd + +import ( + "fmt" + + e "github.com/cloudposse/atmos/internal/exec" + "github.com/cloudposse/atmos/pkg/config" + l "github.com/cloudposse/atmos/pkg/list" + "github.com/cloudposse/atmos/pkg/schema" + u "github.com/cloudposse/atmos/pkg/utils" + "github.com/fatih/color" + "github.com/spf13/cobra" +) + +// listStacksCmd lists atmos stacks +var listStacksCmd = &cobra.Command{ + Use: "stacks", + Short: "Execute 'list stacks' command", + Long: `This command lists all Atmos stacks or all stacks for the specified component: atmos list stacks -c `, + Example: "atmos list stacks\n" + + "atmos list stacks -c ", + FParseErrWhitelist: struct{ UnknownFlags bool }{UnknownFlags: false}, + Run: func(cmd *cobra.Command, args []string) { + // Check Atmos configuration + checkAtmosConfig() + + componentFlag, _ := cmd.Flags().GetString("component") + + configAndStacksInfo := schema.ConfigAndStacksInfo{} + cliConfig, err := config.InitCliConfig(configAndStacksInfo, true) + if err != nil { + u.PrintMessageInColor(fmt.Sprintf("Error initializing CLI config: %v", err), color.New(color.FgRed)) + return + } + + stacksMap, err := e.ExecuteDescribeStacks(cliConfig, "", nil, nil, nil, false, false, false) + if err != nil { + u.PrintMessageInColor(fmt.Sprintf("Error describing stacks: %v", err), color.New(color.FgRed)) + return + } + + output, err := l.FilterAndListStacks(stacksMap, componentFlag) + if err != nil { + u.PrintMessageInColor(fmt.Sprintf("Error filtering stacks: %v", err), color.New(color.FgRed)) + return + } + u.PrintMessageInColor(output, color.New(color.FgGreen)) + }, +} + +func init() { + listStacksCmd.DisableFlagParsing = false + listStacksCmd.PersistentFlags().StringP("component", "c", "", "atmos list stacks -c ") + listCmd.AddCommand(listStacksCmd) +} diff --git a/examples/quick-start-advanced/atmos.yaml b/examples/quick-start-advanced/atmos.yaml index 76af448d3..d0383d510 100644 --- a/examples/quick-start-advanced/atmos.yaml +++ b/examples/quick-start-advanced/atmos.yaml @@ -176,59 +176,6 @@ commands: - 'echo Environment: "{{ .ComponentConfig.vars.environment }}"' - 'echo Stage: "{{ .ComponentConfig.vars.stage }}"' - 'echo Dependencies: "{{ .ComponentConfig.deps }}"' - - name: list - description: Execute 'atmos list' commands - # subcommands - commands: - - name: stacks - description: | - List all Atmos stacks. - steps: - - > - atmos describe stacks --process-templates=false --sections none | grep -e "^\S" | sed s/://g - - name: components - description: | - List all Atmos components in all stacks or in a single stack. - - Example usage: - atmos list components - atmos list components -s plat-ue2-dev - atmos list components --stack plat-uw2-prod - atmos list components -s plat-ue2-dev --type abstract - atmos list components -s plat-ue2-dev -t enabled - atmos list components -s plat-ue2-dev -t disabled - flags: - - name: stack - shorthand: s - description: Name of the stack - required: false - - name: type - shorthand: t - description: Component types - abstract, enabled, or disabled - required: false - steps: - - > - {{ if .Flags.stack }} - {{ if eq .Flags.type "enabled" }} - atmos describe stacks --stack {{ .Flags.stack }} --format json | jq '.[].components.terraform | to_entries[] | select(.value.vars.enabled == true)' | jq -r .key - {{ else if eq .Flags.type "disabled" }} - atmos describe stacks --stack {{ .Flags.stack }} --format json | jq '.[].components.terraform | to_entries[] | select(.value.vars.enabled == false)' | jq -r .key - {{ else if eq .Flags.type "abstract" }} - atmos describe stacks --stack {{ .Flags.stack }} --format json | jq '.[].components.terraform | to_entries[] | select(.value.metadata.type == "abstract")' | jq -r .key - {{ else }} - atmos describe stacks --stack {{ .Flags.stack }} --format json --sections none | jq ".[].components.terraform" | jq -s add | jq -r "keys[]" - {{ end }} - {{ else }} - {{ if eq .Flags.type "enabled" }} - atmos describe stacks --format json | jq '.[].components.terraform | to_entries[] | select(.value.vars.enabled == true)' | jq -r '[.key]' | jq -s 'add' | jq 'unique | sort' | jq -r "values[]" - {{ else if eq .Flags.type "disabled" }} - atmos describe stacks --format json | jq '.[].components.terraform | to_entries[] | select(.value.vars.enabled == false)' | jq -r '[.key]' | jq -s 'add' | jq 'unique | sort' | jq -r "values[]" - {{ else if eq .Flags.type "abstract" }} - atmos describe stacks --format json | jq '.[].components.terraform | to_entries[] | select(.value.metadata.type == "abstract")' | jq -r '[.key]' | jq -s 'add' | jq 'unique | sort' | jq -r "values[]" - {{ else }} - atmos describe stacks --format json --sections none | jq ".[].components.terraform" | jq -s add | jq -r "keys[]" - {{ end }} - {{ end }} # Validation schemas (for validating atmos stacks and components) schemas: diff --git a/examples/quick-start-advanced/rootfs/usr/local/etc/atmos/atmos.yaml b/examples/quick-start-advanced/rootfs/usr/local/etc/atmos/atmos.yaml index 89b9dd84e..a17ab1468 100644 --- a/examples/quick-start-advanced/rootfs/usr/local/etc/atmos/atmos.yaml +++ b/examples/quick-start-advanced/rootfs/usr/local/etc/atmos/atmos.yaml @@ -176,60 +176,6 @@ commands: - 'echo Environment: "{{ .ComponentConfig.vars.environment }}"' - 'echo Stage: "{{ .ComponentConfig.vars.stage }}"' - 'echo Dependencies: "{{ .ComponentConfig.deps }}"' - - name: list - description: Execute 'atmos list' commands - # subcommands - commands: - - name: stacks - description: | - List all Atmos stacks. - steps: - - > - atmos describe stacks --process-templates=false --sections none | grep -e "^\S" | sed s/://g - - name: components - description: | - List all Atmos components in all stacks or in a single stack. - - Example usage: - atmos list components - atmos list components -s plat-ue2-dev - atmos list components --stack plat-uw2-prod - atmos list components -s plat-ue2-dev --type abstract - atmos list components -s plat-ue2-dev -t enabled - atmos list components -s plat-ue2-dev -t disabled - flags: - - name: stack - shorthand: s - description: Name of the stack - required: false - - name: type - shorthand: t - description: Component types - abstract, enabled, or disabled - required: false - steps: - - > - {{ if .Flags.stack }} - {{ if eq .Flags.type "enabled" }} - atmos describe stacks --stack {{ .Flags.stack }} --format json | jq '.[].components.terraform | to_entries[] | select(.value.vars.enabled == true)' | jq -r .key - {{ else if eq .Flags.type "disabled" }} - atmos describe stacks --stack {{ .Flags.stack }} --format json | jq '.[].components.terraform | to_entries[] | select(.value.vars.enabled == false)' | jq -r .key - {{ else if eq .Flags.type "abstract" }} - atmos describe stacks --stack {{ .Flags.stack }} --format json | jq '.[].components.terraform | to_entries[] | select(.value.metadata.type == "abstract")' | jq -r .key - {{ else }} - atmos describe stacks --stack {{ .Flags.stack }} --format json --sections none | jq ".[].components.terraform" | jq -s add | jq -r "keys[]" - {{ end }} - {{ else }} - {{ if eq .Flags.type "enabled" }} - atmos describe stacks --format json | jq '.[].components.terraform | to_entries[] | select(.value.vars.enabled == true)' | jq -r '[.key]' | jq -s 'add' | jq 'unique | sort' | jq -r "values[]" - {{ else if eq .Flags.type "disabled" }} - atmos describe stacks --format json | jq '.[].components.terraform | to_entries[] | select(.value.vars.enabled == false)' | jq -r '[.key]' | jq -s 'add' | jq 'unique | sort' | jq -r "values[]" - {{ else if eq .Flags.type "abstract" }} - atmos describe stacks --format json | jq '.[].components.terraform | to_entries[] | select(.value.metadata.type == "abstract")' | jq -r '[.key]' | jq -s 'add' | jq 'unique | sort' | jq -r "values[]" - {{ else }} - atmos describe stacks --format json --sections none | jq ".[].components.terraform" | jq -s add | jq -r "keys[]" - {{ end }} - {{ end }} - # Validation schemas (for validating atmos stacks and components) schemas: diff --git a/examples/tests/atmos.yaml b/examples/tests/atmos.yaml index fbbc8bc91..b3feeb7b5 100644 --- a/examples/tests/atmos.yaml +++ b/examples/tests/atmos.yaml @@ -189,37 +189,6 @@ commands: - 'echo settings.config.is_prod: "{{ .ComponentConfig.settings.config.is_prod }}"' - 'echo ATMOS_IS_PROD: "$ATMOS_IS_PROD"' - - name: list - description: Execute 'atmos list' commands - # subcommands - commands: - - name: stacks - description: | - List all Atmos stacks. - steps: - - > - atmos describe stacks --process-templates=false --sections none | grep -e "^\S" | sed s/://g - - name: components - description: | - List all Atmos components in all stacks or in a single stack. - - Example usage: - atmos list components - atmos list components -s tenant1-ue1-dev - atmos list components --stack tenant2-uw2-prod - flags: - - name: stack - shorthand: s - description: Name of the stack - required: false - steps: - - > - {{ if .Flags.stack }} - atmos describe stacks --stack {{ .Flags.stack }} --format json --sections none | jq ".[].components.terraform" | jq -s add | jq -r "keys[]" - {{ else }} - atmos describe stacks --format json --sections none | jq ".[].components.terraform" | jq -s add | jq -r "keys[]" - {{ end }} - - name: set-eks-cluster description: | Download 'kubeconfig' and set EKS cluster. diff --git a/examples/tests/rootfs/usr/local/etc/atmos/atmos.yaml b/examples/tests/rootfs/usr/local/etc/atmos/atmos.yaml index e12a087f5..591230820 100644 --- a/examples/tests/rootfs/usr/local/etc/atmos/atmos.yaml +++ b/examples/tests/rootfs/usr/local/etc/atmos/atmos.yaml @@ -184,37 +184,6 @@ commands: - 'echo settings.config.is_prod: "{{ .ComponentConfig.settings.config.is_prod }}"' - 'echo ATMOS_IS_PROD: "$ATMOS_IS_PROD"' - - name: list - description: Execute 'atmos list' commands - # subcommands - commands: - - name: stacks - description: | - List all Atmos stacks. - steps: - - > - atmos describe stacks --process-templates=false --sections none | grep -e "^\S" | sed s/://g - - name: components - description: | - List all Atmos components in all stacks or in a single stack. - - Example usage: - atmos list components - atmos list components -s tenant1-ue1-dev - atmos list components --stack tenant2-uw2-prod - flags: - - name: stack - shorthand: s - description: Name of the stack - required: false - steps: - - > - {{ if .Flags.stack }} - atmos describe stacks --stack {{ .Flags.stack }} --format json --sections none | jq ".[].components.terraform" | jq -s add | jq -r "keys[]" - {{ else }} - atmos describe stacks --format json --sections none | jq ".[].components.terraform" | jq -s add | jq -r "keys[]" - {{ end }} - - name: set-eks-cluster description: | Download 'kubeconfig' and set EKS cluster. diff --git a/pkg/aws/atmos.yaml b/pkg/aws/atmos.yaml index 686a935a0..720b7f90b 100644 --- a/pkg/aws/atmos.yaml +++ b/pkg/aws/atmos.yaml @@ -172,37 +172,6 @@ commands: - 'echo settings.config.is_prod: "{{ .ComponentConfig.settings.config.is_prod }}"' - 'echo ATMOS_IS_PROD: "$ATMOS_IS_PROD"' - - name: list - description: Execute 'atmos list' commands - # subcommands - commands: - - name: stacks - description: | - List all Atmos stacks. - steps: - - > - atmos describe stacks --process-templates=false --sections none | grep -e "^\S" | sed s/://g - - name: components - description: | - List all Atmos components in all stacks or in a single stack. - - Example usage: - atmos list components - atmos list components -s tenant1-ue1-dev - atmos list components --stack tenant2-uw2-prod - flags: - - name: stack - shorthand: s - description: Name of the stack - required: false - steps: - - > - {{ if .Flags.stack }} - atmos describe stacks --stack {{ .Flags.stack }} --format json --sections none | jq ".[].components.terraform" | jq -s add | jq -r "keys[]" - {{ else }} - atmos describe stacks --format json --sections none | jq ".[].components.terraform" | jq -s add | jq -r "keys[]" - {{ end }} - - name: set-eks-cluster description: | Download 'kubeconfig' and set EKS cluster. diff --git a/pkg/generate/atmos.yaml b/pkg/generate/atmos.yaml index 95ec5e3fe..c2c2cacb5 100644 --- a/pkg/generate/atmos.yaml +++ b/pkg/generate/atmos.yaml @@ -172,37 +172,6 @@ commands: - 'echo settings.config.is_prod: "{{ .ComponentConfig.settings.config.is_prod }}"' - 'echo ATMOS_IS_PROD: "$ATMOS_IS_PROD"' - - name: list - description: Execute 'atmos list' commands - # subcommands - commands: - - name: stacks - description: | - List all Atmos stacks. - steps: - - > - atmos describe stacks --process-templates=false --sections none | grep -e "^\S" | sed s/://g - - name: components - description: | - List all Atmos components in all stacks or in a single stack. - - Example usage: - atmos list components - atmos list components -s tenant1-ue1-dev - atmos list components --stack tenant2-uw2-prod - flags: - - name: stack - shorthand: s - description: Name of the stack - required: false - steps: - - > - {{ if .Flags.stack }} - atmos describe stacks --stack {{ .Flags.stack }} --format json --sections none | jq ".[].components.terraform" | jq -s add | jq -r "keys[]" - {{ else }} - atmos describe stacks --format json --sections none | jq ".[].components.terraform" | jq -s add | jq -r "keys[]" - {{ end }} - - name: set-eks-cluster description: | Download 'kubeconfig' and set EKS cluster. diff --git a/pkg/list/atmos.yaml b/pkg/list/atmos.yaml new file mode 100644 index 000000000..c2c2cacb5 --- /dev/null +++ b/pkg/list/atmos.yaml @@ -0,0 +1,319 @@ +# CLI config is loaded from the following locations (from lowest to highest priority): +# system dir ('/usr/local/etc/atmos' on Linux, '%LOCALAPPDATA%/atmos' on Windows) +# home dir (~/.atmos) +# current directory +# ENV vars +# Command-line arguments +# +# It supports POSIX-style Globs for file names/paths (double-star '**' is supported) +# https://en.wikipedia.org/wiki/Glob_(programming) + +# Base path for components, stacks and workflows configurations. +# Can also be set using 'ATMOS_BASE_PATH' ENV var, or '--base-path' command-line argument. +# Supports both absolute and relative paths. +# If not provided or is an empty string, 'components.terraform.base_path', 'components.helmfile.base_path', 'stacks.base_path' and 'workflows.base_path' +# are independent settings (supporting both absolute and relative paths). +# If 'base_path' is provided, 'components.terraform.base_path', 'components.helmfile.base_path', 'stacks.base_path' and 'workflows.base_path' +# are considered paths relative to 'base_path'. +base_path: "../../examples/tests" + +components: + terraform: + # Can also be set using 'ATMOS_COMPONENTS_TERRAFORM_BASE_PATH' ENV var, or '--terraform-dir' command-line argument + # Supports both absolute and relative paths + base_path: "components/terraform" + # Can also be set using 'ATMOS_COMPONENTS_TERRAFORM_APPLY_AUTO_APPROVE' ENV var + apply_auto_approve: false + # Can also be set using 'ATMOS_COMPONENTS_TERRAFORM_DEPLOY_RUN_INIT' ENV var, or '--deploy-run-init' command-line argument + deploy_run_init: true + # Can also be set using 'ATMOS_COMPONENTS_TERRAFORM_INIT_RUN_RECONFIGURE' ENV var, or '--init-run-reconfigure' command-line argument + init_run_reconfigure: true + # Can also be set using 'ATMOS_COMPONENTS_TERRAFORM_AUTO_GENERATE_BACKEND_FILE' ENV var, or '--auto-generate-backend-file' command-line argument + auto_generate_backend_file: false + helmfile: + # Can also be set using 'ATMOS_COMPONENTS_HELMFILE_BASE_PATH' ENV var, or '--helmfile-dir' command-line argument + # Supports both absolute and relative paths + base_path: "components/helmfile" + # Can also be set using 'ATMOS_COMPONENTS_HELMFILE_USE_EKS' ENV var + # If not specified, defaults to 'true' + use_eks: true + # Can also be set using 'ATMOS_COMPONENTS_HELMFILE_KUBECONFIG_PATH' ENV var + kubeconfig_path: "/dev/shm" + # Can also be set using 'ATMOS_COMPONENTS_HELMFILE_HELM_AWS_PROFILE_PATTERN' ENV var + helm_aws_profile_pattern: "{namespace}-{tenant}-gbl-{stage}-helm" + # Can also be set using 'ATMOS_COMPONENTS_HELMFILE_CLUSTER_NAME_PATTERN' ENV var + cluster_name_pattern: "{namespace}-{tenant}-{environment}-{stage}-eks-cluster" + +stacks: + # Can also be set using 'ATMOS_STACKS_BASE_PATH' ENV var, or '--config-dir' and '--stacks-dir' command-line arguments + # Supports both absolute and relative paths + base_path: "stacks" + # Can also be set using 'ATMOS_STACKS_INCLUDED_PATHS' ENV var (comma-separated values string) + included_paths: + - "orgs/**/*" + # Can also be set using 'ATMOS_STACKS_EXCLUDED_PATHS' ENV var (comma-separated values string) + excluded_paths: + - "**/_defaults.yaml" + # Can also be set using 'ATMOS_STACKS_NAME_PATTERN' ENV var + name_pattern: "{tenant}-{environment}-{stage}" + +workflows: + # Can also be set using 'ATMOS_WORKFLOWS_BASE_PATH' ENV var, or '--workflows-dir' command-line arguments + # Supports both absolute and relative paths + base_path: "stacks/workflows" + +logs: + # Can also be set using 'ATMOS_LOGS_FILE' ENV var, or '--logs-file' command-line argument + # File or standard file descriptor to write logs to + # Logs can be written to any file or any standard file descriptor, including `/dev/stdout`, `/dev/stderr` and `/dev/null` + file: "/dev/stderr" + # Supported log levels: Trace, Debug, Info, Warning, Off + # Can also be set using 'ATMOS_LOGS_LEVEL' ENV var, or '--logs-level' command-line argument + level: Info + +# Custom CLI commands +commands: + - name: tf + description: Execute 'terraform' commands + # subcommands + commands: + - name: plan + description: This command plans terraform components + arguments: + - name: component + description: Name of the component + flags: + - name: stack + shorthand: s + description: Name of the stack + required: true + env: + - key: ENV_VAR_1 + value: ENV_VAR_1_value + - key: ENV_VAR_2 + # 'valueCommand' is an external command to execute to get the value for the ENV var + # Either 'value' or 'valueCommand' can be specified for the ENV var, but not both + valueCommand: echo ENV_VAR_2_value + # steps support Go templates + steps: + - atmos terraform plan {{ .Arguments.component }} -s {{ .Flags.stack }} + - name: terraform + description: Execute 'terraform' commands + # subcommands + commands: + - name: provision + description: This command provisions terraform components + arguments: + - name: component + description: Name of the component + flags: + - name: stack + shorthand: s + description: Name of the stack + required: true + # ENV var values support Go templates + env: + - key: ATMOS_COMPONENT + value: "{{ .Arguments.component }}" + - key: ATMOS_STACK + value: "{{ .Flags.stack }}" + steps: + - atmos terraform plan $ATMOS_COMPONENT -s $ATMOS_STACK + - atmos terraform apply $ATMOS_COMPONENT -s $ATMOS_STACK + - name: show + description: Execute 'show' commands + # subcommands + commands: + - name: component + description: Execute 'show component' command + arguments: + - name: component + description: Name of the component + flags: + - name: stack + shorthand: s + description: Name of the stack + required: true + # ENV var values support Go templates and have access to {{ .ComponentConfig.xxx.yyy.zzz }} Go template variables + env: + - key: ATMOS_COMPONENT + value: "{{ .Arguments.component }}" + - key: ATMOS_STACK + value: "{{ .Flags.stack }}" + - key: ATMOS_TENANT + value: "{{ .ComponentConfig.vars.tenant }}" + - key: ATMOS_STAGE + value: "{{ .ComponentConfig.vars.stage }}" + - key: ATMOS_ENVIRONMENT + value: "{{ .ComponentConfig.vars.environment }}" + - key: ATMOS_IS_PROD + value: "{{ .ComponentConfig.settings.config.is_prod }}" + # If a custom command defines 'component_config' section with 'component' and 'stack', 'atmos' generates the config for the component in the stack + # and makes it available in {{ .ComponentConfig.xxx.yyy.zzz }} Go template variables, + # exposing all the component sections (which are also shown by 'atmos describe component' command) + component_config: + component: "{{ .Arguments.component }}" + stack: "{{ .Flags.stack }}" + # Steps support using Go templates and can access all configuration settings (e.g. {{ .ComponentConfig.xxx.yyy.zzz }}) + # Steps also have access to the ENV vars defined in the 'env' section of the 'command' + steps: + - 'echo Atmos component from argument: "{{ .Arguments.component }}"' + - 'echo ATMOS_COMPONENT: "$ATMOS_COMPONENT"' + - 'echo Atmos stack: "{{ .Flags.stack }}"' + - 'echo Terraform component: "{{ .ComponentConfig.component }}"' + - 'echo Backend S3 bucket: "{{ .ComponentConfig.backend.bucket }}"' + - 'echo Terraform workspace: "{{ .ComponentConfig.workspace }}"' + - 'echo Namespace: "{{ .ComponentConfig.vars.namespace }}"' + - 'echo Tenant: "{{ .ComponentConfig.vars.tenant }}"' + - 'echo Environment: "{{ .ComponentConfig.vars.environment }}"' + - 'echo Stage: "{{ .ComponentConfig.vars.stage }}"' + - 'echo settings.spacelift.workspace_enabled: "{{ .ComponentConfig.settings.spacelift.workspace_enabled }}"' + - 'echo Dependencies: "{{ .ComponentConfig.deps }}"' + - 'echo settings.config.is_prod: "{{ .ComponentConfig.settings.config.is_prod }}"' + - 'echo ATMOS_IS_PROD: "$ATMOS_IS_PROD"' + + - name: set-eks-cluster + description: | + Download 'kubeconfig' and set EKS cluster. + + Example usage: + atmos set-eks-cluster eks/cluster -s tenant1-ue1-dev -r admin + atmos set-eks-cluster eks/cluster -s tenant2-uw2-prod --role reader + verbose: false # Set to `true` to see verbose outputs + arguments: + - name: component + description: Name of the component + flags: + - name: stack + shorthand: s + description: Name of the stack + required: true + - name: role + shorthand: r + description: IAM role to use + required: true + # If a custom command defines 'component_config' section with 'component' and 'stack', + # Atmos generates the config for the component in the stack + # and makes it available in {{ .ComponentConfig.xxx.yyy.zzz }} Go template variables, + # exposing all the component sections (which are also shown by 'atmos describe component' command) + component_config: + component: "{{ .Arguments.component }}" + stack: "{{ .Flags.stack }}" + env: + - key: KUBECONFIG + value: /dev/shm/kubecfg.{{ .Flags.stack }}-{{ .Flags.role }} + steps: + - > + aws + --profile {{ .ComponentConfig.vars.namespace }}-{{ .ComponentConfig.vars.tenant }}-gbl-{{ .ComponentConfig.vars.stage }}-{{ .Flags.role }} + --region {{ .ComponentConfig.vars.region }} + eks update-kubeconfig + --name={{ .ComponentConfig.vars.namespace }}-{{ .Flags.stack }}-eks-cluster + --kubeconfig="${KUBECONFIG}" + > /dev/null + - chmod 600 ${KUBECONFIG} + - echo ${KUBECONFIG} + +# Integrations +integrations: + + # Atlantis integration + # https://www.runatlantis.io/docs/repo-level-atlantis-yaml.html + atlantis: + # Path and name of the Atlantis config file 'atlantis.yaml' + # Supports absolute and relative paths + # All the intermediate folders will be created automatically (e.g. 'path: /config/atlantis/atlantis.yaml') + # Can be overridden on the command line by using '--output-path' command-line argument in 'atmos atlantis generate repo-config' command + # If not specified (set to an empty string/omitted here, and set to an empty string on the command line), the content of the file will be dumped to 'stdout' + # On Linux/macOS, you can also use '--output-path=/dev/stdout' to dump the content to 'stdout' without setting it to an empty string in 'atlantis.path' + path: "atlantis.yaml" + + # Config templates + # Select a template by using the '--config-template ' command-line argument in 'atmos atlantis generate repo-config' command + config_templates: + config-1: + version: 3 + automerge: true + delete_source_branch_on_merge: true + parallel_plan: true + parallel_apply: true + allowed_regexp_prefixes: + - dev/ + - staging/ + - prod/ + + # Project templates + # Select a template by using the '--project-template ' command-line argument in 'atmos atlantis generate repo-config' command + project_templates: + project-1: + # generate a project entry for each component in every stack + name: "{tenant}-{environment}-{stage}-{component}" + workspace: "{workspace}" + dir: "{component-path}" + terraform_version: v1.2 + delete_source_branch_on_merge: true + autoplan: + enabled: true + when_modified: + - "**/*.tf" + - "varfiles/$PROJECT_NAME.tfvars.json" + apply_requirements: + - "approved" + + # Workflow templates + # https://www.runatlantis.io/docs/custom-workflows.html#custom-init-plan-apply-commands + # https://www.runatlantis.io/docs/custom-workflows.html#custom-run-command + workflow_templates: + workflow-1: + plan: + steps: + - run: terraform init -input=false + # When using workspaces, you need to select the workspace using the $WORKSPACE environment variable + - run: terraform workspace select $WORKSPACE || terraform workspace new $WORKSPACE + # You must output the plan using '-out $PLANFILE' because Atlantis expects plans to be in a specific location + - run: terraform plan -input=false -refresh -out $PLANFILE -var-file varfiles/$PROJECT_NAME.tfvars.json + apply: + steps: + - run: terraform apply $PLANFILE + +# Validation schemas (for validating atmos stacks and components) +schemas: + # https://json-schema.org + jsonschema: + # Can also be set using 'ATMOS_SCHEMAS_JSONSCHEMA_BASE_PATH' ENV var, or '--schemas-jsonschema-dir' command-line arguments + # Supports both absolute and relative paths + base_path: "stacks/schemas/jsonschema" + # https://www.openpolicyagent.org + opa: + # Can also be set using 'ATMOS_SCHEMAS_OPA_BASE_PATH' ENV var, or '--schemas-opa-dir' command-line arguments + # Supports both absolute and relative paths + base_path: "stacks/schemas/opa" + # JSON Schema to validate Atmos manifests + # https://atmos.tools/cli/schemas/ + # https://atmos.tools/cli/commands/validate/stacks/ + # https://atmos.tools/quick-start/advanced/configure-validation/ + # https://atmos.tools/schemas/atmos/atmos-manifest/1.0/atmos-manifest.json + # https://json-schema.org/draft/2020-12/release-notes + # https://www.schemastore.org/json + # https://github.com/SchemaStore/schemastore + atmos: + # Can also be set using 'ATMOS_SCHEMAS_ATMOS_MANIFEST' ENV var, or '--schemas-atmos-manifest' command-line arguments + # Supports both absolute and relative paths (relative to the `base_path` setting in `atmos.yaml`) + manifest: "../quick-start-advanced/stacks/schemas/atmos/atmos-manifest/1.0/atmos-manifest.json" + +# `Go` templates in Atmos manifests +# https://atmos.tools/core-concepts/stacks/templates +# https://pkg.go.dev/text/template +templates: + settings: + enabled: true + evaluations: 1 + # https://masterminds.github.io/sprig + sprig: + enabled: true + # https://docs.gomplate.ca + gomplate: + enabled: true + timeout: 5 + # https://docs.gomplate.ca/datasources + datasources: {} diff --git a/pkg/list/list_components.go b/pkg/list/list_components.go new file mode 100644 index 000000000..9b71ee4d3 --- /dev/null +++ b/pkg/list/list_components.go @@ -0,0 +1,65 @@ +package list + +import ( + "fmt" + "sort" + "strings" + + "github.com/samber/lo" +) + +// getStackComponents extracts Terraform components from the final map of stacks +func getStackComponents(stackData any) ([]string, error) { + stackMap, ok := stackData.(map[string]any) + if !ok { + return nil, fmt.Errorf("could not parse stacks") + } + + componentsMap, ok := stackMap["components"].(map[string]any) + if !ok { + return nil, fmt.Errorf("could not parse components") + } + + terraformComponents, ok := componentsMap["terraform"].(map[string]any) + if !ok { + return nil, fmt.Errorf("could not parse Terraform components") + } + + return lo.Keys(terraformComponents), nil +} + +// FilterAndListComponents filters and lists components based on the given stack +func FilterAndListComponents(stackFlag string, stacksMap map[string]any) (string, error) { + components := []string{} + + if stackFlag != "" { + // Filter components for the specified stack + if stackData, ok := stacksMap[stackFlag]; ok { + stackComponents, err := getStackComponents(stackData) + if err != nil { + return "", fmt.Errorf("error processing stack '%s': %w", stackFlag, err) + } + components = append(components, stackComponents...) + } else { + return "", fmt.Errorf("stack '%s' not found", stackFlag) + } + } else { + // Get all components from all stacks + for _, stackData := range stacksMap { + stackComponents, err := getStackComponents(stackData) + if err != nil { + continue // Skip invalid stacks + } + components = append(components, stackComponents...) + } + } + + // Remove duplicates and sort components + components = lo.Uniq(components) + sort.Strings(components) + + if len(components) == 0 { + return "No components found", nil + } + return strings.Join(components, "\n") + "\n", nil +} diff --git a/pkg/list/list_components_test.go b/pkg/list/list_components_test.go new file mode 100644 index 000000000..1d30b020f --- /dev/null +++ b/pkg/list/list_components_test.go @@ -0,0 +1,56 @@ +package list + +import ( + "testing" + + "github.com/stretchr/testify/assert" + + e "github.com/cloudposse/atmos/internal/exec" + cfg "github.com/cloudposse/atmos/pkg/config" + "github.com/cloudposse/atmos/pkg/schema" + u "github.com/cloudposse/atmos/pkg/utils" +) + +const ( + testStack = "tenant1-ue2-dev" +) + +func TestListComponents(t *testing.T) { + configAndStacksInfo := schema.ConfigAndStacksInfo{} + + cliConfig, err := cfg.InitCliConfig(configAndStacksInfo, true) + assert.Nil(t, err) + + stacksMap, err := e.ExecuteDescribeStacks(cliConfig, "", nil, nil, + nil, false, false, false) + assert.Nil(t, err) + + output, err := FilterAndListComponents("", stacksMap) + assert.Nil(t, err) + dependentsYaml, err := u.ConvertToYAML(output) + assert.Nil(t, err) + // Add assertions to validate the output structure + assert.NotNil(t, dependentsYaml) + assert.Greater(t, len(dependentsYaml), 0) + t.Log(dependentsYaml) +} + +func TestListComponentsWithStack(t *testing.T) { + configAndStacksInfo := schema.ConfigAndStacksInfo{} + + cliConfig, err := cfg.InitCliConfig(configAndStacksInfo, true) + assert.Nil(t, err) + + stacksMap, err := e.ExecuteDescribeStacks(cliConfig, testStack, nil, nil, + nil, false, false, false) + assert.Nil(t, err) + + output, err := FilterAndListStacks(stacksMap, testStack) + assert.Nil(t, err) + dependentsYaml, err := u.ConvertToYAML(output) + assert.Nil(t, err) + assert.NotNil(t, dependentsYaml) + assert.Greater(t, len(dependentsYaml), 0) + assert.Contains(t, dependentsYaml, testStack) + t.Log(dependentsYaml) +} diff --git a/pkg/list/list_stacks.go b/pkg/list/list_stacks.go new file mode 100644 index 000000000..6370512b6 --- /dev/null +++ b/pkg/list/list_stacks.go @@ -0,0 +1,45 @@ +package list + +import ( + "fmt" + "sort" + "strings" + + "github.com/samber/lo" +) + +// FilterAndListStacks filters stacks by the given component +func FilterAndListStacks(stacksMap map[string]any, component string) (string, error) { + if component != "" { + // Filter stacks by component + filteredStacks := []string{} + for stackName, stackData := range stacksMap { + v2, ok := stackData.(map[string]any) + if !ok { + continue + } + components, ok := v2["components"].(map[string]any) + if !ok { + continue + } + terraform, ok := components["terraform"].(map[string]any) + if !ok { + continue + } + if _, exists := terraform[component]; exists { + filteredStacks = append(filteredStacks, stackName) + } + } + + if len(filteredStacks) == 0 { + return fmt.Sprintf("No stacks found for component '%s'"+"\n", component), nil + } + sort.Strings(filteredStacks) + return strings.Join(filteredStacks, "\n") + "\n", nil + } + + // List all stacks + stacks := lo.Keys(stacksMap) + sort.Strings(stacks) + return strings.Join(stacks, "\n") + "\n", nil +} diff --git a/pkg/list/list_stacks_test.go b/pkg/list/list_stacks_test.go new file mode 100644 index 000000000..190b69016 --- /dev/null +++ b/pkg/list/list_stacks_test.go @@ -0,0 +1,54 @@ +package list + +import ( + "testing" + + "github.com/stretchr/testify/assert" + + e "github.com/cloudposse/atmos/internal/exec" + cfg "github.com/cloudposse/atmos/pkg/config" + "github.com/cloudposse/atmos/pkg/schema" + u "github.com/cloudposse/atmos/pkg/utils" +) + +const ( + testComponent = "infra/vpc" +) + +func TestListStacks(t *testing.T) { + configAndStacksInfo := schema.ConfigAndStacksInfo{} + + cliConfig, err := cfg.InitCliConfig(configAndStacksInfo, true) + assert.Nil(t, err) + + stacksMap, err := e.ExecuteDescribeStacks(cliConfig, "", nil, nil, + nil, false, false, false) + assert.Nil(t, err) + + output, err := FilterAndListStacks(stacksMap, "") + assert.Nil(t, err) + dependentsYaml, err := u.ConvertToYAML(output) + assert.NotEmpty(t, dependentsYaml) +} + +func TestListStacksWithComponent(t *testing.T) { + configAndStacksInfo := schema.ConfigAndStacksInfo{} + + cliConfig, err := cfg.InitCliConfig(configAndStacksInfo, true) + assert.Nil(t, err) + component := testComponent + + stacksMap, err := e.ExecuteDescribeStacks(cliConfig, component, nil, nil, + nil, false, false, false) + assert.Nil(t, err) + + output, err := FilterAndListStacks(stacksMap, component) + assert.Nil(t, err) + dependentsYaml, err := u.ConvertToYAML(output) + assert.Nil(t, err) + + // Verify the output structure + assert.NotEmpty(t, dependentsYaml) + // Verify that only stacks with the specified component are included + assert.Contains(t, dependentsYaml, testComponent) +} diff --git a/pkg/validate/atmos.yaml b/pkg/validate/atmos.yaml index 95ec5e3fe..c2c2cacb5 100644 --- a/pkg/validate/atmos.yaml +++ b/pkg/validate/atmos.yaml @@ -172,37 +172,6 @@ commands: - 'echo settings.config.is_prod: "{{ .ComponentConfig.settings.config.is_prod }}"' - 'echo ATMOS_IS_PROD: "$ATMOS_IS_PROD"' - - name: list - description: Execute 'atmos list' commands - # subcommands - commands: - - name: stacks - description: | - List all Atmos stacks. - steps: - - > - atmos describe stacks --process-templates=false --sections none | grep -e "^\S" | sed s/://g - - name: components - description: | - List all Atmos components in all stacks or in a single stack. - - Example usage: - atmos list components - atmos list components -s tenant1-ue1-dev - atmos list components --stack tenant2-uw2-prod - flags: - - name: stack - shorthand: s - description: Name of the stack - required: false - steps: - - > - {{ if .Flags.stack }} - atmos describe stacks --stack {{ .Flags.stack }} --format json --sections none | jq ".[].components.terraform" | jq -s add | jq -r "keys[]" - {{ else }} - atmos describe stacks --format json --sections none | jq ".[].components.terraform" | jq -s add | jq -r "keys[]" - {{ end }} - - name: set-eks-cluster description: | Download 'kubeconfig' and set EKS cluster. diff --git a/website/docs/cli/commands/list/_category_.json b/website/docs/cli/commands/list/_category_.json new file mode 100644 index 000000000..db8f13d4c --- /dev/null +++ b/website/docs/cli/commands/list/_category_.json @@ -0,0 +1,11 @@ +{ + "label": "list", + "position": 6, + "className": "command", + "collapsible": true, + "collapsed": true, + "link": { + "type": "doc", + "id": "usage" + } +} diff --git a/website/docs/cli/commands/list/list-components.mdx b/website/docs/cli/commands/list/list-components.mdx new file mode 100644 index 000000000..016b4b4ca --- /dev/null +++ b/website/docs/cli/commands/list/list-components.mdx @@ -0,0 +1,45 @@ +--- +title: atmos list components +sidebar_label: components +sidebar_class_name: command +id: component +description: Use this command to list Atmos components +--- +import Screengrab from '@site/src/components/Screengrab' + +:::note purpose +Use this command to list all Atmos components or Atmos components in a specified stack. +::: + + + +## Usage + +Execute the `list components` command like this: + +```shell +atmos list components +``` + +This command lists Atmos components in a specified stack. + +```shell +atmos list components -s +``` + +:::tip +Run `atmos list components --help` to see all the available options +::: + +## Examples + +```shell +atmos list components +atmos list components -s tenant1-ue2-dev +``` + +## Flags + +| Flag | Description | Alias | Required | +|:-----------------|:------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:------|:---------| +| `--stack` | Atmos stack | `-s` | no | diff --git a/website/docs/cli/commands/list/list-stacks.mdx b/website/docs/cli/commands/list/list-stacks.mdx new file mode 100644 index 000000000..ae261d3f0 --- /dev/null +++ b/website/docs/cli/commands/list/list-stacks.mdx @@ -0,0 +1,46 @@ +--- +title: atmos list stacks +sidebar_label: stacks +sidebar_class_name: command +id: stacks +description: Use this command to list all Stack configurations or a stack of a specified component. +--- +import Screengrab from '@site/src/components/Screengrab' +import Terminal from '@site/src/components/Terminal' + +:::note Purpose +Use this command to list Atmos stacks. +::: + + + +## Usage + +Execute the `list stacks` command like this: + +```shell +atmos list stacks +``` + +To view all stacks for a provided component, execute the `list stacks` command like this: + +```shell +atmos list stacks -c +``` + +:::tip +Run `atmos list stacks --help` to see all the available options +::: + +## Examples + +```shell +atmos list stacks +atmos list stacks -c vpc +``` + +## Flags + +| Flag | Description | Alias | Required | +|------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------|----------| +| `--component` | Atmos component | `-c` | no | diff --git a/website/docs/cli/commands/list/usage.mdx b/website/docs/cli/commands/list/usage.mdx new file mode 100644 index 000000000..95776da44 --- /dev/null +++ b/website/docs/cli/commands/list/usage.mdx @@ -0,0 +1,18 @@ +--- +title: atmos list +sidebar_label: list +sidebar_class_name: command +description: "List Atmos Stacks and Components" +--- +import Screengrab from '@site/src/components/Screengrab' +import DocCardList from '@theme/DocCardList'; + +:::note Purpose +Use these subcommands to validate Atmos configurations. +::: + + + +## Subcommands + + diff --git a/website/docs/cli/commands/pro/_category_.json b/website/docs/cli/commands/pro/_category_.json index 23a7e15c1..03b4abd65 100644 --- a/website/docs/cli/commands/pro/_category_.json +++ b/website/docs/cli/commands/pro/_category_.json @@ -1,6 +1,6 @@ { "label": "pro", - "position": 5, + "position": 7, "className": "command", "collapsible": true, "collapsed": true, diff --git a/website/docs/cli/commands/terraform/_category_.json b/website/docs/cli/commands/terraform/_category_.json index 6a2bc28ed..0991cb0b6 100644 --- a/website/docs/cli/commands/terraform/_category_.json +++ b/website/docs/cli/commands/terraform/_category_.json @@ -1,6 +1,6 @@ { "label": "terraform", - "position": 6, + "position": 8, "className": "command", "collapsible": true, "collapsed": true, diff --git a/website/docs/cli/commands/validate/_category_.json b/website/docs/cli/commands/validate/_category_.json index c375f5cfb..7a049b4a4 100644 --- a/website/docs/cli/commands/validate/_category_.json +++ b/website/docs/cli/commands/validate/_category_.json @@ -1,6 +1,6 @@ { "label": "validate", - "position": 7, + "position": 9, "className": "command", "collapsible": true, "collapsed": true, diff --git a/website/docs/cli/commands/vendor/_category_.json b/website/docs/cli/commands/vendor/_category_.json index 099960a5a..4ccaa9352 100644 --- a/website/docs/cli/commands/vendor/_category_.json +++ b/website/docs/cli/commands/vendor/_category_.json @@ -1,6 +1,6 @@ { "label": "vendor", - "position": 8, + "position": 10, "className": "command", "collapsible": true, "collapsed": true, diff --git a/website/docs/core-concepts/custom-commands/custom-commands.mdx b/website/docs/core-concepts/custom-commands/custom-commands.mdx index 63425f5ed..471376ab5 100644 --- a/website/docs/core-concepts/custom-commands/custom-commands.mdx +++ b/website/docs/core-concepts/custom-commands/custom-commands.mdx @@ -147,66 +147,6 @@ commands: - atmos terraform apply {{ .Arguments.component }} -s {{ .Flags.stack }} -auto-approve ``` -### List Atmos Stacks and Components - -```yaml -# Custom CLI commands -commands: - - name: list - description: Execute 'atmos list' commands - # subcommands - commands: - - name: stacks - description: | - List all Atmos stacks. - steps: - - > - atmos describe stacks --process-templates=false --sections none | grep -e "^\S" | sed s/://g - - name: components - description: | - List all Atmos components in all stacks or in a single stack. - - Example usage: - atmos list components - atmos list components -s plat-ue2-dev - atmos list components --stack plat-uw2-prod - atmos list components -s plat-ue2-dev --type abstract - atmos list components -s plat-ue2-dev -t enabled - atmos list components -s plat-ue2-dev -t disabled - flags: - - name: stack - shorthand: s - description: Name of the stack - required: false - - name: type - shorthand: t - description: Component types - abstract, enabled, or disabled - required: false - steps: - - > - {{ if .Flags.stack }} - {{ if eq .Flags.type "enabled" }} - atmos describe stacks --stack {{ .Flags.stack }} --format json | jq '.[].components.terraform | to_entries[] | select(.value.vars.enabled == true)' | jq -r .key - {{ else if eq .Flags.type "disabled" }} - atmos describe stacks --stack {{ .Flags.stack }} --format json | jq '.[].components.terraform | to_entries[] | select(.value.vars.enabled == false)' | jq -r .key - {{ else if eq .Flags.type "abstract" }} - atmos describe stacks --stack {{ .Flags.stack }} --format json | jq '.[].components.terraform | to_entries[] | select(.value.metadata.type == "abstract")' | jq -r .key - {{ else }} - atmos describe stacks --stack {{ .Flags.stack }} --format json --sections none | jq ".[].components.terraform" | jq -s add | jq -r "keys[]" - {{ end }} - {{ else }} - {{ if eq .Flags.type "enabled" }} - atmos describe stacks --format json | jq '.[].components.terraform | to_entries[] | select(.value.vars.enabled == true)' | jq -r '[.key]' | jq -s 'add' | jq 'unique | sort' | jq -r "values[]" - {{ else if eq .Flags.type "disabled" }} - atmos describe stacks --format json | jq '.[].components.terraform | to_entries[] | select(.value.vars.enabled == false)' | jq -r '[.key]' | jq -s 'add' | jq 'unique | sort' | jq -r "values[]" - {{ else if eq .Flags.type "abstract" }} - atmos describe stacks --format json | jq '.[].components.terraform | to_entries[] | select(.value.metadata.type == "abstract")' | jq -r '[.key]' | jq -s 'add' | jq 'unique | sort' | jq -r "values[]" - {{ else }} - atmos describe stacks --format json --sections none | jq ".[].components.terraform" | jq -s add | jq -r "keys[]" - {{ end }} - {{ end }} -``` - ### Show Component Info ```yaml