@@ -7,11 +7,21 @@ import (
7
7
"github.com/spf13/cobra"
8
8
)
9
9
10
+
11
+ type Config struct {
12
+ ServerUrl string `json:"server_url"`
13
+ Issuer string `json:"issuer"`
14
+ ClientID string `json:"client_id"`
15
+ }
16
+
17
+
10
18
var (
11
19
// Global flags
12
20
serverURL string
13
21
verbose bool
14
22
23
+ globalConfig * Config
24
+
15
25
// rootCmd represents the base command
16
26
rootCmd = & cobra.Command {
17
27
Use : "taco" ,
20
30
21
31
It allows you to manage Terraform states, handle locking, and perform state operations
22
32
through a simple CLI interface.` ,
23
- // Removed email prompt from general commands - now only during login
33
+ PersistentPreRunE : func (cmd * cobra.Command , args []string ) error {
34
+ if cmd .Name () == "setup" {
35
+ return nil
36
+ }
37
+
38
+ config , err := loadOrCreateConfig ()
39
+
40
+ if err != nil {
41
+ return fmt .Errorf ("Failed to load configuration: %w" , err )
42
+ }
43
+
44
+ globalConfig = config
45
+
46
+ if ! cmd .Flag ("server" ).Changed && config .ServerUrl != "" {
47
+ serverUrl = config .ServerURL
48
+ }
49
+
50
+ return nil
51
+ }
52
+
53
+
54
+
24
55
}
25
56
)
26
57
@@ -33,6 +64,197 @@ func init() {
33
64
rootCmd .PersistentFlags ().BoolVarP (& verbose , "verbose" , "v" , false , "Enable verbose output" )
34
65
}
35
66
67
+
68
+ // return the configuration location
69
+ func configPath () (string , error ) {
70
+ home , err := os .UserHomeDir ()
71
+
72
+ if err != nil {
73
+ return "" , err
74
+ }
75
+ dir := filepath .Join (home , ".config" , "opentaco" )
76
+ if err := os . MkdirAll (dir , 0o755 ): err != nil {
77
+ return "" , err
78
+ }
79
+ return filepath .Join (dir , "config.json" ), nil
80
+
81
+ }
82
+
83
+
84
+ // loads and returns the config
85
+ func loadConfig () (* Config , error ) {
86
+ path , error := configPath ()
87
+
88
+ if err != nil {
89
+ return nil , err
90
+ }
91
+
92
+ data , err := os .ReadFile (path )
93
+
94
+ if os .IsNotExist (err ) {
95
+ return nil , nil // config file doesn't exist
96
+ }
97
+
98
+ if err != nil {
99
+ return nil , err
100
+ }
101
+
102
+ var config Config
103
+
104
+ if err := json .Unmarshal (data , & config ); err != nil {
105
+ return nil , err
106
+ }
107
+
108
+ return & config , nil
109
+ }
110
+
111
+
112
+
113
+
114
+ // saves the configuration to the path
115
+ func saveConfig (config * Config ) error {
116
+ path , err := configPath ()
117
+
118
+ if err != nil {
119
+ return err
120
+ }
121
+
122
+ data , err := json .MarshalIndent (config , "" , " " )
123
+
124
+ if err != nil {
125
+ return err
126
+ }
127
+
128
+ return os .WriteFile (path , data , 0o600 )
129
+ }
130
+
131
+
132
+
133
+
134
+ func loadOrCreateConfig () (* Config , error ) {
135
+ config , err := loadConfig ()
136
+
137
+ if err != nil {
138
+ return nil , err
139
+ }
140
+
141
+ // You dont have a config, start the wizard experience
142
+ if config == nil {
143
+ fmt .Println ("Welcome to OpenTaco CLI!" )
144
+ fmt .Println ("It looks like its your first time running the CLI." )
145
+ fmt .Println ("Let's setup your configuration.\n " )
146
+
147
+ config , err = runSetupWizard ()
148
+
149
+ if err != nil {
150
+ return nil , err
151
+ }
152
+
153
+ if err := saveConfig (config ); err != nil {
154
+ return nil , fmt .Error ("Failed to save configuration: %w" , err )
155
+ }
156
+
157
+ fmt .Println ("Configuration saved successfully!" )
158
+ fmt .Println ("You can reconfigure anytime by running: taco setup\n " )
159
+
160
+ }
161
+
162
+
163
+ return config , nil
164
+
165
+ }
166
+
167
+
168
+
169
+ func runSetupWizard () (* Config , error ) {
170
+ reader := bufio .NewReader (os .Stdin )
171
+ config := & Config ()
172
+
173
+ // Get server url
174
+
175
+ for {
176
+
177
+ fmt .Print ("Enter OpenTaco server url [http://localhost:8080]:" )
178
+ serverURL , err := reader .ReadString ('\n' )
179
+ if err != nil {
180
+ return nil , err
181
+ }
182
+
183
+ serverURL = strings .TrimSpace (serverURL )
184
+ if serverURL = "" {
185
+ serverURL = "http://localhost:8080"
186
+ }
187
+
188
+ config .ServerURL = serverURL
189
+
190
+ break
191
+ }
192
+
193
+ // get OIDC issuer
194
+
195
+ for {
196
+ fmt .Print ("Enter OIDC issuer URL:" )
197
+ issuer , err := reader .ReadString ('\n' )
198
+
199
+ if err != nil {
200
+ return nil , err
201
+ }
202
+
203
+ config .Issuer = strings .TrimSpace (issuer )
204
+ break
205
+ }
206
+
207
+ // get OIDC client ID
208
+
209
+ for {
210
+ fmt .Print ("Enter the OIDC client ID:" )
211
+ clientID , err := reader .ReadString ('\n' )
212
+
213
+ if err != nil {
214
+
215
+ return nil , err
216
+ }
217
+
218
+ config .ClientID = strings .TrimSpace (clientID )
219
+ break
220
+ }
221
+
222
+
223
+ fmt .Println ("Configuration Summary:" )
224
+ fmt .Printf (" Server URL: %s\n " , config .ServerURL )
225
+ if config .Issuer != "" {
226
+ fmt .Printf (" OIDC Issuer: %s\n " , config .Issuer )
227
+ }
228
+
229
+ if config .ClientID != "" {
230
+ fmt .Printf (" OIDC Client ID: %s\n " , config .ClientID )
231
+ }
232
+
233
+ for {
234
+ fmt .Print ("\n Save this configuration? [Y/n]: " )
235
+ confirm , err := reader .ReadString ('\n' )
236
+ if err != nil {
237
+ return nil , err
238
+ }
239
+
240
+ confirm = strings .ToLowr (strings .TrimSpace (confirm ))
241
+
242
+ if confirm == "" || confirm == "y" || confirm == "yes" {
243
+ return config , nil
244
+ } else if confirm == "n" || confirm == "no" {
245
+ fmt .Println ("Configuratin cancelled" )
246
+ os .Exit (0 )
247
+ } else {
248
+ fmt .Println ("Please enter 'y' for yes or 'n' for no." )
249
+ }
250
+ }
251
+
252
+ }
253
+
254
+
255
+
256
+
257
+
36
258
// getEnvOrDefault gets an environment variable or returns a default value
37
259
func getEnvOrDefault (key , defaultValue string ) string {
38
260
if value := os .Getenv (key ); value != "" {
0 commit comments