Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DO NOT MERGE: Fix Terraform help printing log twice and causing error #798

Closed
wants to merge 16 commits into from
Closed
2 changes: 1 addition & 1 deletion cmd/cmd_utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -394,7 +394,7 @@ func printMessageForMissingAtmosConfig(cliConfig schema.CliConfiguration) {
c2 := color.New(color.FgGreen)

fmt.Println()
err := tuiUtils.PrintStyledText("ATMOS")
err := tuiUtils.PrintAtmosLogo()
if err != nil {
u.LogErrorAndExit(cliConfig, err)
}
Expand Down
55 changes: 30 additions & 25 deletions cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,38 +26,40 @@ var RootCmd = &cobra.Command{
Use: "atmos",
Short: "Universal Tool for DevOps and Cloud Automation",
Long: `Atmos is a universal tool for DevOps and cloud automation used for provisioning, managing and orchestrating workflows across various toolchains`,
PersistentPreRun: func(cmd *cobra.Command, args []string) {
// Determine if the command is a help command or if the help flag is set
isHelpCommand := cmd.Name() == "help"
helpFlag := cmd.Flags().Changed("help")

isHelpRequested := isHelpCommand || helpFlag

if isHelpRequested {
// Do not silence usage or errors when help is invoked
cmd.SilenceUsage = false
cmd.SilenceErrors = false
} else {
cmd.SilenceUsage = true
cmd.SilenceErrors = true
}
},
Run: func(cmd *cobra.Command, args []string) {
// Check Atmos configuration
checkAtmosConfig()

// Print a styled Atmos logo to the terminal
fmt.Println()
err := tuiUtils.PrintStyledText("ATMOS")
// Print the Atmos logo
err := tuiUtils.PrintAtmosLogo()
if err != nil {
u.LogErrorAndExit(schema.CliConfiguration{}, err)
return
}

err = e.ExecuteAtmosCmd()
if err != nil {
u.LogErrorAndExit(schema.CliConfiguration{}, err)
}
},
PersistentPreRun: func(cmd *cobra.Command, args []string) {
// Determine if the command is a help command or if the help flag is set
isHelpCommand := cmd.Name() == "help"
helpFlag := cmd.Flags().Changed("help")

isHelpRequested := isHelpCommand || helpFlag

if isHelpRequested {
// Do not silence usage or errors when help is invoked
cmd.Root().SilenceUsage = false
cmd.Root().SilenceErrors = false
} else {
// For non-help commands, we want to control the error output
cmd.Root().SilenceUsage = true
// Only silence errors for unknown commands
cmd.Root().SilenceErrors = cmd.Parent() == nil
}
},
}

// Execute adds all child commands to the root command and sets flags appropriately.
Expand All @@ -80,11 +82,15 @@ func Execute() error {
// This custom help function will call the original help function and then display the bordered message.
RootCmd.SetHelpFunc(customHelpMessageToUpgradeToAtmosLatestRelease)

// Set custom error handling to prevent duplicate messages
RootCmd.SilenceErrors = true
RootCmd.SilenceUsage = true

// Check if the `help` flag is passed and print a styled Atmos logo to the terminal before printing the help
err := RootCmd.ParseFlags(os.Args)
if err != nil && errors.Is(err, pflag.ErrHelp) {
fmt.Println()
err = tuiUtils.PrintStyledText("ATMOS")
if err != nil && errors.Is(err, pflag.ErrHelp) ||
(len(os.Args) > 1 && (os.Args[len(os.Args)-1] == "help" || os.Args[len(os.Args)-1] == "--help")) {
err = tuiUtils.PrintAtmosLogo()
if err != nil {
u.LogErrorAndExit(schema.CliConfiguration{}, err)
}
Expand Down Expand Up @@ -140,9 +146,8 @@ func initConfig() {
RootCmd.SetUsageFunc(b.UsageFunc)

RootCmd.SetHelpFunc(func(command *cobra.Command, strings []string) {
// Print a styled Atmos logo to the terminal
fmt.Println()
err := tuiUtils.PrintStyledText("ATMOS")
// Print the Atmos logo
err := tuiUtils.PrintAtmosLogo()
if err != nil {
u.LogErrorAndExit(schema.CliConfiguration{}, err)
}
Expand Down
9 changes: 9 additions & 0 deletions cmd/terraform.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,15 @@ var terraformCmd = &cobra.Command{
Long: `This command executes Terraform commands`,
FParseErrWhitelist: struct{ UnknownFlags bool }{UnknownFlags: true},
Run: func(cmd *cobra.Command, args []string) {
// Check if help is requested
if cmd.Flags().Changed("help") || (len(args) > 0 && args[0] == "help") {
err := e.ExecuteTerraformCmd(cmd, args, nil)
if err != nil {
u.LogErrorAndExit(schema.CliConfiguration{}, err)
}
return
}

// Check Atmos configuration
checkAtmosConfig()

Expand Down
5 changes: 2 additions & 3 deletions cmd/version.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,8 @@ var versionCmd = &cobra.Command{
Long: `This command prints the CLI version`,
Example: "atmos version",
Run: func(cmd *cobra.Command, args []string) {
// Print a styled Atmos logo to the terminal
fmt.Println()
err := tuiUtils.PrintStyledText("ATMOS")
// Print the Atmos logo
err := tuiUtils.PrintAtmosLogo()
if err != nil {
u.LogErrorAndExit(schema.CliConfiguration{}, err)
}
Expand Down
3 changes: 1 addition & 2 deletions internal/exec/helmfile.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,7 @@ func ExecuteHelmfile(info schema.ConfigAndStacksInfo) error {

// If the user just types `atmos helmfile`, print Atmos logo and show helmfile help
if info.SubCommand == "" {
fmt.Println()
err = tuiUtils.PrintStyledText("ATMOS")
err = tuiUtils.PrintAtmosLogo()
if err != nil {
return err
}
Expand Down
37 changes: 22 additions & 15 deletions internal/exec/terraform.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import (
"github.com/pkg/errors"
"github.com/spf13/cobra"

tuiUtils "github.com/cloudposse/atmos/internal/tui/utils"
cfg "github.com/cloudposse/atmos/pkg/config"
"github.com/cloudposse/atmos/pkg/schema"
u "github.com/cloudposse/atmos/pkg/utils"
Expand All @@ -36,19 +35,9 @@ func ExecuteTerraformCmd(cmd *cobra.Command, args []string, additionalArgsAndFla

// ExecuteTerraform executes terraform commands
func ExecuteTerraform(info schema.ConfigAndStacksInfo) error {
cliConfig, err := cfg.InitCliConfig(info, true)
if err != nil {
return err
}

if info.NeedHelp {
return nil
}

// If the user just types `atmos terraform`, print Atmos logo and show terraform help
if info.SubCommand == "" {
fmt.Println()
err = tuiUtils.PrintStyledText("ATMOS")
// For help commands and empty subcommand, we don't need to process stacks
if info.NeedHelp || info.SubCommand == cfg.HelpFlag1 || info.SubCommand == cfg.HelpFlag2 || info.SubCommand == "" {
cliConfig, err := cfg.InitCliConfig(info, false)
if err != nil {
return err
}
Expand All @@ -57,11 +46,29 @@ func ExecuteTerraform(info schema.ConfigAndStacksInfo) error {
if err != nil {
return err
}

fmt.Println()
return nil
}

// For all other commands, we need to process stacks
cliConfig, err := cfg.InitCliConfig(info, true)
if err != nil {
return err
}

info, err = ProcessStacks(cliConfig, info, true, true)
if err != nil {
return err
}

if info.ComponentFromArg == "" {
return errors.New("component must be specified")
}

if len(info.Stack) < 1 {
return errors.New("stack must be specified")
}

shouldProcessStacks := true
shouldCheckStack := true
// Skip stack processing when cleaning with --everything or --force flags to allow
Expand Down
20 changes: 15 additions & 5 deletions internal/exec/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ var (
cfg.PlanFileFlag,
cfg.HelpFlag1,
cfg.HelpFlag2,
cfg.HelpFlag3,
cfg.WorkflowDirFlag,
cfg.JsonSchemaDirFlag,
cfg.OpaDirFlag,
Expand Down Expand Up @@ -221,10 +222,6 @@ func processCommandLineArgs(

// Check if `-h` or `--help` flags are specified
if argsAndFlagsInfo.NeedHelp {
err = processHelp(schema.CliConfiguration{}, componentType, argsAndFlagsInfo.SubCommand)
if err != nil {
return configAndStacksInfo, err
}
return configAndStacksInfo, nil
}

Expand Down Expand Up @@ -285,6 +282,16 @@ func ProcessStacks(

configAndStacksInfo.StackFromArg = configAndStacksInfo.Stack

// Initialize component section maps
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Cerebrovinny why this is needed? Did it cause issues w/o this?
If needed, please add more info in the comment

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

processHelp func is not used anymore?

Copy link
Collaborator Author

@Cerebrovinny Cerebrovinny Nov 23, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ProcessComponentConfig is causing it to display nil pointer dereference errors in tests when we process the stack
so we need to initialize it first before accessing.

configAndStacksInfo.ComponentSection = make(map[string]any)
configAndStacksInfo.ComponentVarsSection = make(map[string]any)
configAndStacksInfo.ComponentSettingsSection = make(map[string]any)
configAndStacksInfo.ComponentOverridesSection = make(map[string]any)
configAndStacksInfo.ComponentProvidersSection = make(map[string]any)
configAndStacksInfo.ComponentEnvSection = make(map[string]any)
configAndStacksInfo.ComponentBackendSection = make(map[string]any)
configAndStacksInfo.ComponentMetadataSection = make(map[string]any)

stacksMap, rawStackConfigs, err := FindStacksMap(cliConfig, false)
if err != nil {
return configAndStacksInfo, err
Expand Down Expand Up @@ -979,8 +986,11 @@ func processArgsAndFlags(componentType string, inputArgsAndFlags []string) (sche
info.SkipInit = true
}

if arg == cfg.HelpFlag1 || arg == cfg.HelpFlag2 {
if arg == cfg.HelpFlag1 || arg == cfg.HelpFlag2 || arg == cfg.HelpFlag3 {
info.NeedHelp = true
// For help commands, we don't need a component or stack
info.ComponentFromArg = ""
return info, nil
}

for _, f := range commonFlags {
Expand Down
15 changes: 15 additions & 0 deletions internal/tui/utils/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ package utils

import (
"bytes"
"fmt"
"os"
"sync"

"github.com/alecthomas/chroma/quick"
"github.com/arsham/figurine/figurine"
Expand All @@ -19,6 +21,9 @@ func HighlightCode(code string, language string, syntaxTheme string) (string, er
return buf.String(), nil
}

// logoOnce ensures the ATMOS logo is printed exactly once
var logoOnce sync.Once

// PrintStyledText prints a styled text to the terminal
func PrintStyledText(text string) error {
// Check if the terminal supports colors
Expand All @@ -27,3 +32,13 @@ func PrintStyledText(text string) error {
}
return nil
}

// logoOnce ensures thread-safe single execution of logo display
func PrintAtmosLogo() error {
var err error
logoOnce.Do(func() {
fmt.Println()
err = PrintStyledText("ATMOS")
})
return err
}
Cerebrovinny marked this conversation as resolved.
Show resolved Hide resolved
1 change: 1 addition & 0 deletions pkg/config/const.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ const (

HelpFlag1 = "-h"
HelpFlag2 = "--help"
HelpFlag3 = "-help"

ComponentVendorConfigFileName = "component.yaml"
AtmosVendorConfigFileName = "vendor"
Expand Down
Loading