From 06ccdd0ade184a214c261931558d1bad07985a8c Mon Sep 17 00:00:00 2001 From: Ringo Hoffmann Date: Thu, 5 Dec 2024 15:59:34 +0100 Subject: [PATCH] add parameter for terraform/tofu executable --- cmd/root.go | 25 +++++++++++++++++++++++++ cmd/util.go | 9 ++++++--- cmd/util_test.go | 4 ++++ 3 files changed, 35 insertions(+), 3 deletions(-) diff --git a/cmd/root.go b/cmd/root.go index 86e1ef9..455d562 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -4,7 +4,9 @@ Copyright © 2023 Takafumi Miyanaga miya.org.0309@gmai.com package cmd import ( + "fmt" "os" + "os/exec" "github.com/spf13/cobra" ) @@ -18,11 +20,34 @@ You can interactivity select resource to ( plan | appply | destroy ) with target `, } +func init() { + executable := os.Getenv("TFTARGET_EXECUTABLE") + if executable == "" { + if existsInPath("terraform") { + executable = "terraform" + } else if existsInPath("tofu") { + executable = "tofu" + } else { + fmt.Println("Error: no terraform executable found in PATH") + os.Exit(1) + } + } + rootCmd.PersistentFlags().StringP("executable", "e", executable, "The name or path of the terraform executable") +} + +// existsInPath returns true if name is available in any of the paths listed +// in the PATH variable. +func existsInPath(name string) bool { + _, err := exec.LookPath(name) + return err == nil +} + // Execute adds all child commands to the root command and sets flags appropriately. // This is called by main.main(). It only needs to happen once to the rootCmd. func Execute() { s.Suffix = " loading ..." s.Color("green") + err := rootCmd.Execute() if err != nil { os.Exit(1) diff --git a/cmd/util.go b/cmd/util.go index 4ce4520..051c040 100644 --- a/cmd/util.go +++ b/cmd/util.go @@ -24,10 +24,12 @@ func executePlan(cmd *cobra.Command, option string) ([]string, error) { if err := validateFlagValue(action, validValues); action != "" && err != nil { return nil, err } + + executable, _ := cmd.Flags().GetString("executable") p, _ := cmd.Flags().GetInt("parallel") - planCmd := exec.Command("terraform", "plan", "-no-color", fmt.Sprintf("--parallelism=%d", p)) + planCmd := exec.Command(executable, "plan", "-no-color", fmt.Sprintf("--parallelism=%d", p)) if option != "" { - planCmd = exec.Command("terraform", "plan", option, "-no-color", fmt.Sprintf("--parallelism=%d", p)) + planCmd = exec.Command(executable, "plan", option, "-no-color", fmt.Sprintf("--parallelism=%d", p)) } out, err := planCmd.CombinedOutput() @@ -103,7 +105,8 @@ func slice2String(slice []string) string { func genTargetCmd(cmd *cobra.Command, action, target string) bytes.Buffer { var buf bytes.Buffer - buf.WriteString("terraform " + action + " -target=" + target) + executable, _ := cmd.Flags().GetString("executable") + buf.WriteString(executable + " " + action + " -target=" + target) p, _ := cmd.Flags().GetInt("parallel") buf.WriteString(fmt.Sprintf(" --parallelism=%d", p)) return buf diff --git a/cmd/util_test.go b/cmd/util_test.go index 698115d..c72d57f 100644 --- a/cmd/util_test.go +++ b/cmd/util_test.go @@ -210,6 +210,10 @@ func Test_genTargetCmd(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { + // The --executable flag is a persistent flag set by the root command, but because the default value of it + // is not passed to the command because it was not executed through the root command, the flag is set here + // as flag with the expected test value set as default value. + tt.cmd.Flags().String("executable", "terraform", "") got := genTargetCmd(tt.cmd, tt.action, tt.input) if diff := cmp.Diff(got.String(), tt.want); diff != "" { t.Errorf("genTargetCmd (-got +want):%s", diff)