Skip to content

Commit

Permalink
Add help for terraform
Browse files Browse the repository at this point in the history
  • Loading branch information
samtholiya committed Dec 19, 2024
1 parent 922ba49 commit b4b103a
Show file tree
Hide file tree
Showing 8 changed files with 534 additions and 130 deletions.
19 changes: 13 additions & 6 deletions cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -138,18 +138,25 @@ func init() {
func initConfig() {
styles := boa.DefaultStyles()
b := boa.New(boa.WithStyles(styles))

oldUsageFunc := RootCmd.UsageFunc()
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")
if err != nil {
u.LogErrorAndExit(schema.CliConfiguration{}, err)
if command.Use != "terraform" {
err := tuiUtils.PrintStyledText("ATMOS")
if err != nil {
u.LogErrorAndExit(schema.CliConfiguration{}, err)
}
}
// TODO: find a better way to do this if possible
if command.Use == "terraform" {
oldUsageFunc(command)
return
} else {
b.HelpFunc(command, strings)
}

b.HelpFunc(command, strings)
command.Usage()
})
}
Expand Down
91 changes: 60 additions & 31 deletions cmd/terraform.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@ import (
"github.com/spf13/cobra"

e "github.com/cloudposse/atmos/internal/exec"
"github.com/cloudposse/atmos/internal/tui/templates"
"github.com/cloudposse/atmos/pkg/schema"
u "github.com/cloudposse/atmos/pkg/utils"
cc "github.com/ivanpirog/coloredcobra"
)

// terraformCmd represents the base command for all terraform sub-commands
Expand All @@ -16,42 +18,69 @@ var terraformCmd = &cobra.Command{
Short: "Execute Terraform commands",
Long: `This command executes Terraform commands`,
FParseErrWhitelist: struct{ UnknownFlags bool }{UnknownFlags: true},
Run: func(cmd *cobra.Command, args []string) {
// Check Atmos configuration
//checkAtmosConfig()

var argsAfterDoubleDash []string
var finalArgs = args

doubleDashIndex := lo.IndexOf(args, "--")
if doubleDashIndex > 0 {
finalArgs = lo.Slice(args, 0, doubleDashIndex)
argsAfterDoubleDash = lo.Slice(args, doubleDashIndex+1, len(args))
}
info, err := e.ProcessCommandLineArgs("terraform", cmd, finalArgs, argsAfterDoubleDash)
if err != nil {
u.LogErrorAndExit(schema.CliConfiguration{}, err)
}

// Exit on help
if info.NeedHelp {
// Check for the latest Atmos release on GitHub and print update message
CheckForAtmosUpdateAndPrintMessage(cliConfig)
return
}
// Check Atmos configuration
checkAtmosConfig()

err = e.ExecuteTerraform(info)
if err != nil {
u.LogErrorAndExit(schema.CliConfiguration{}, err)
}
},
Run: terraformRun,
}

func terraformRun(cmd *cobra.Command, args []string) {
// Check Atmos configuration
//checkAtmosConfig()

var argsAfterDoubleDash []string
var finalArgs = args

doubleDashIndex := lo.IndexOf(args, "--")
if doubleDashIndex > 0 {
finalArgs = lo.Slice(args, 0, doubleDashIndex)
argsAfterDoubleDash = lo.Slice(args, doubleDashIndex+1, len(args))
}
info, err := e.ProcessCommandLineArgs("terraform", cmd, finalArgs, argsAfterDoubleDash)
if err != nil {
u.LogErrorAndExit(schema.CliConfiguration{}, err)
}

// Exit on help
if info.NeedHelp {
// Check for the latest Atmos release on GitHub and print update message
template := templates.GenerateFromBaseTemplate(cmd.Use, []templates.HelpTemplateSections{
templates.LongDescription,
templates.Usage,
templates.Aliases,
templates.Examples,
templates.AvailableCommands,
templates.Flags,
templates.GlobalFlags,
templates.NativeCommands,
templates.Footer,
})

cmd.SetUsageTemplate(template)
cc.Init(&cc.Config{
RootCmd: cmd,
Headings: cc.HiCyan + cc.Bold + cc.Underline,
Commands: cc.HiGreen + cc.Bold,
Example: cc.Italic,
ExecName: cc.Bold,
Flags: cc.Bold,
})

cmd.Help()
CheckForAtmosUpdateAndPrintMessage(cliConfig)
return
}
// Check Atmos configuration
checkAtmosConfig()

err = e.ExecuteTerraform(info)
if err != nil {
u.LogErrorAndExit(schema.CliConfiguration{}, err)
}

}

func init() {
// https://github.com/spf13/cobra/issues/739
terraformCmd.DisableFlagParsing = true
terraformCmd.PersistentFlags().StringP("stack", "s", "", "atmos terraform <terraform_command> <component> -s <stack>")
attachTerraformCommands(terraformCmd)
RootCmd.AddCommand(terraformCmd)
}
1 change: 1 addition & 0 deletions cmd/terraform_generate.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ var terraformGenerateCmd = &cobra.Command{
Short: "Execute 'terraform generate' commands",
Long: "This command generates configurations for terraform components",
FParseErrWhitelist: struct{ UnknownFlags bool }{UnknownFlags: false},
Run: terraformRun,
}

func init() {
Expand Down
238 changes: 238 additions & 0 deletions cmd/terraform_native_commands.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,238 @@
package cmd

import (
"github.com/spf13/cobra"
)

// getTerraformCommands returns an array of statically defined Terraform commands with flags
func getTerraformCommands() []*cobra.Command {
// List of Terraform commands
return []*cobra.Command{
{
Use: "plan",
Short: "Show changes required by the current configuration",
Long: "Generate an execution plan, which shows what actions Terraform will take to reach the desired state of the configuration.",
Annotations: map[string]string{
"nativeCommand": "true",
},
},
{
Use: "apply",
Short: "Apply changes to infrastructure",
Long: "Apply the changes required to reach the desired state of the configuration. This will prompt for confirmation before making changes.",
Annotations: map[string]string{
"nativeCommand": "true",
},
},
{
Use: "workspace",
Short: "Manage Terraform workspaces",
Long: "Create, list, select, or delete Terraform workspaces, which allow for separate states within the same configuration.",
Annotations: map[string]string{
"nativeCommand": "true",
},
},
{
Use: "clean",
Short: "Clean up resources",
Long: "Remove unused or outdated resources to keep the infrastructure clean and reduce costs.",
Run: terraformRun,
},
{
Use: "deploy",
Short: "Deploy the specified infrastructure using Terraform",
Long: `Deploy the specified infrastructure by running the Terraform plan and apply commands.
This command automates the deployment process, integrates configuration, and ensures streamlined execution.`,
Run: terraformRun,
},
{
Use: "shell",
Short: "Configures an 'atmos' environment and starts a shell for native Terraform commands.",
Long: "command configures an environment for an 'atmos' component in a stack and starts a new shell allowing executing all native terraform commands inside the shell without using atmos-specific arguments and flag",
Run: terraformRun,
},
{
Use: "version",
Short: "Show the current Terraform version",
Long: "Displays the current version of Terraform installed on the system.",
Annotations: map[string]string{
"nativeCommand": "true",
},
},
{
Use: "varfile",
Short: "Load variables from a file",
Long: "Load variable definitions from a specified file and use them in the configuration.",
Run: terraformRun,
Annotations: map[string]string{
"nativeCommand": "true",
},
},
{
Use: "write varfile",
Short: "Write variables to a file",
Long: "Write the variables used in the configuration to a specified file for later use or modification.",
Annotations: map[string]string{
"nativeCommand": "true",
},
},
{
Use: "destroy",
Short: "Destroy previously-created infrastructure",
Long: "Destroy all the infrastructure managed by Terraform, removing resources as defined in the state file.",
Annotations: map[string]string{
"nativeCommand": "true",
},
},
{
Use: "refresh",
Short: "Update the state to match remote systems",
Long: "Refresh the Terraform state, reconciling the local state with the actual infrastructure state.",
Annotations: map[string]string{
"nativeCommand": "true",
},
},
{
Use: "init",
Short: "Prepare your working directory for other commands",
Long: "Initialize the working directory containing Terraform configuration files. It will download necessary provider plugins and set up the backend.",
Annotations: map[string]string{
"nativeCommand": "true",
},
},
{
Use: "validate",
Short: "Check whether the configuration is valid",
Annotations: map[string]string{
"nativeCommand": "true",
},
},
{
Use: "console",
Short: "Try Terraform expressions at an interactive command prompt",
Annotations: map[string]string{
"nativeCommand": "true",
},
},
{
Use: "fmt",
Short: "Reformat your configuration in the standard style",
Annotations: map[string]string{
"nativeCommand": "true",
},
},
{
Use: "force-unlock",
Short: "Release a stuck lock on the current workspace",
Annotations: map[string]string{
"nativeCommand": "true",
},
},
{
Use: "get",
Short: "Install or upgrade remote Terraform modules",
Annotations: map[string]string{
"nativeCommand": "true",
},
},
{
Use: "graph",
Short: "Generate a Graphviz graph of the steps in an operation",
Annotations: map[string]string{
"nativeCommand": "true",
},
},
{
Use: "import",
Short: "Associate existing infrastructure with a Terraform resource",
Annotations: map[string]string{
"nativeCommand": "true",
},
},
{
Use: "login",
Short: "Obtain and save credentials for a remote host",
Annotations: map[string]string{
"nativeCommand": "true",
},
},
{
Use: "logout",
Short: "Remove locally-stored credentials for a remote host",
Annotations: map[string]string{
"nativeCommand": "true",
},
},
{
Use: "metadata",
Short: "Metadata related commands",
Annotations: map[string]string{
"nativeCommand": "true",
},
},
{
Use: "modules",
Short: "Show all declared modules in a working directory",
Annotations: map[string]string{
"nativeCommand": "true",
},
},
{
Use: "output",
Short: "Show output values from your root module",
Annotations: map[string]string{
"nativeCommand": "true",
},
},
{
Use: "providers",
Short: "Show the providers required for this configuration",
Annotations: map[string]string{
"nativeCommand": "true",
},
},
{
Use: "show",
Short: "Show the current state or a saved plan",
Annotations: map[string]string{
"nativeCommand": "true",
},
},
{
Use: "state",
Short: "Advanced state management",
Annotations: map[string]string{
"nativeCommand": "true",
},
},
{
Use: "taint",
Short: "Mark a resource instance as not fully functional",
Annotations: map[string]string{
"nativeCommand": "true",
},
},
{
Use: "test",
Short: "Execute integration tests for Terraform modules",
Annotations: map[string]string{
"nativeCommand": "true",
},
},
{
Use: "untaint",
Short: "Remove the 'tainted' state from a resource instance",
Annotations: map[string]string{
"nativeCommand": "true",
},
},
}
}

// attachTerraformCommands attaches static Terraform commands to a provided parent command
func attachTerraformCommands(parentCmd *cobra.Command) {
commands := getTerraformCommands()
for _, cmd := range commands {
parentCmd.AddCommand(cmd)
}
}
Loading

0 comments on commit b4b103a

Please sign in to comment.