Skip to content

Commit 58adb50

Browse files
committed
feat: update plan commands
1 parent 05883ce commit 58adb50

File tree

1 file changed

+63
-52
lines changed

1 file changed

+63
-52
lines changed

internal/terraform/plan.go

Lines changed: 63 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1,107 +1,118 @@
11
package terraform
22

33
import (
4+
"bytes"
45
"context"
5-
"fmt"
66
"os"
77

88
"github.com/clouddrove/smurf/internal/ai"
99
"github.com/hashicorp/terraform-exec/tfexec"
1010
)
1111

12-
func Plan(
13-
vars []string,
14-
varFiles []string,
15-
dir string,
16-
destroy bool,
17-
targets []string,
18-
refresh bool,
19-
state string,
20-
out string,
21-
jsonOutput bool,
22-
pushToCloud bool,
23-
useAI bool,
24-
) error {
25-
12+
// Plan runs 'terraform plan' and outputs the plan to the console.
13+
// It allows setting variables either via command-line arguments or variable files.
14+
// The function provides user feedback through spinners and colored messages,
15+
// and handles any errors that occur during the planning process.
16+
func Plan(vars []string, varFiles []string,
17+
dir string, destroy bool,
18+
targets []string, refresh bool,
19+
state string, out string,
20+
useAI bool) error {
2621
tf, err := GetTerraform(dir)
2722
if err != nil {
28-
Error("Failed to initialize Terraform: %v", err)
23+
Error("Failed to initialize Terraform client: %v", err)
2924
ai.AIExplainError(useAI, err.Error())
3025
return err
3126
}
3227

33-
tf.SetStdout(os.Stdout)
28+
var outputBuffer bytes.Buffer
29+
customWriter := &CustomColorWriter{
30+
Buffer: &outputBuffer,
31+
Writer: os.Stdout,
32+
}
33+
34+
tf.SetStdout(customWriter)
3435
tf.SetStderr(os.Stderr)
3536

37+
// Start planning process
38+
Info("Starting infrastructure planning in directory: %s", dir)
39+
3640
planOptions := []tfexec.PlanOption{}
3741

42+
// Handle state file
3843
if state != "" {
44+
Info("Using custom state file: %s", state)
3945
planOptions = append(planOptions, tfexec.State(state))
4046
}
4147

48+
// Handle output plan file
4249
if out != "" {
50+
Info("Saving execution plan to: %s", out)
4351
planOptions = append(planOptions, tfexec.Out(out))
4452
}
4553

46-
for _, v := range vars {
47-
planOptions = append(planOptions, tfexec.Var(v))
54+
// Apply variables
55+
if len(vars) > 0 {
56+
for _, v := range vars {
57+
Info("Applying variable: %s", v)
58+
planOptions = append(planOptions, tfexec.Var(v))
59+
}
4860
}
4961

50-
for _, vf := range varFiles {
51-
planOptions = append(planOptions, tfexec.VarFile(vf))
62+
// Apply variable files
63+
if len(varFiles) > 0 {
64+
for _, vf := range varFiles {
65+
Info("Loading variable file: %s", vf)
66+
planOptions = append(planOptions, tfexec.VarFile(vf))
67+
}
5268
}
5369

54-
for _, target := range targets {
55-
planOptions = append(planOptions, tfexec.Target(target))
70+
// Handle targets
71+
if len(targets) > 0 {
72+
Info("Targeting %d resource(s)...", len(targets))
73+
for _, target := range targets {
74+
Info("Using target: %s", target)
75+
planOptions = append(planOptions, tfexec.Target(target))
76+
}
5677
}
5778

79+
// Destroy flag support
5880
if destroy {
81+
Warn("Planning for destruction of infrastructure resources...")
5982
planOptions = append(planOptions, tfexec.Destroy(true))
6083
}
6184

85+
// Refresh flag support
6286
if !refresh {
87+
Info("Skipping state refresh...")
6388
planOptions = append(planOptions, tfexec.Refresh(false))
6489
}
6590

66-
// Execute plan
91+
// Execute Terraform plan and get the hasChanges boolean
6792
hasChanges, err := tf.Plan(context.Background(), planOptions...)
93+
6894
if err != nil {
6995
ai.AIExplainError(useAI, err.Error())
7096
return err
7197
}
7298

99+
// Check if there are any changes
73100
if !hasChanges {
74-
Success("✔ No changes. Infrastructure is up-to-date.")
75-
return nil
76-
}
77-
78-
Success("Plan completed successfully.")
101+
Success("\nNo changes. Your infrastructure matches the configuration.")
79102

80-
// -----------------------------
81-
// JSON Output Section
82-
// -----------------------------
83-
if jsonOutput {
84-
85-
if out == "" {
86-
return fmt.Errorf("JSON output requires --out plan file")
87-
}
88-
89-
Info("Generating JSON plan output...")
90-
91-
planJSON, err := tf.ShowPlanFileRaw(context.Background(), out)
92-
if err != nil {
93-
return err
94-
}
95-
96-
jsonFile := "plan.json"
97-
98-
// FIXED HERE 👇
99-
err = os.WriteFile(jsonFile, []byte(planJSON), 0644)
100-
if err != nil {
101-
return err
103+
if out != "" {
104+
Info("Note: Plan file was saved even though no changes detected: %s", out)
102105
}
106+
return nil
107+
}
103108

104-
Success("JSON plan saved to %s", jsonFile)
109+
// Changes detected
110+
if out != "" {
111+
Success("Terraform plan saved to: %s", out)
112+
Info("To apply this plan, run: smurf stf apply %s", out)
113+
} else {
114+
Success("Terraform plan executed successfully. Review the changes above before applying.")
115+
Warn("Note: No plan file was saved. To save and apply later, use: smurf stf plan --out=plan.tfplan")
105116
}
106117

107118
return nil

0 commit comments

Comments
 (0)