@@ -12,13 +12,23 @@ import (
1212var configureCmd = & cobra.Command {
1313 Use : "configure" ,
1414 Short : "Configure API endpoint and authentication token" ,
15- Long : "Set up the connection to your Cipi server API. Credentials are stored in ~/.cipi/config.json" ,
15+ Long : "Set up the connection to your Cipi server API. Credentials are stored per profile in ~/.cipi/config.json" ,
1616 RunE : func (cmd * cobra.Command , args []string ) error {
17+ profile , _ := cmd .Flags ().GetString ("profile" )
1718 endpoint , _ := cmd .Flags ().GetString ("endpoint" )
1819 token , _ := cmd .Flags ().GetString ("token" )
1920
21+ if profile == "" {
22+ profile = "default"
23+ }
24+
2025 fmt .Println ()
2126
27+ if err := config .ValidateProfileName (profile ); err != nil {
28+ output .Error ("%s" , err )
29+ return err
30+ }
31+
2232 if endpoint == "" {
2333 endpoint = output .ReadInput ("Cipi API endpoint (e.g. https://api.example.com)" )
2434 }
@@ -37,48 +47,195 @@ var configureCmd = &cobra.Command{
3747 endpoint = "https://" + endpoint
3848 }
3949
40- cfg := & config.Config {
50+ cfg := & config.Profile {
4151 Endpoint : endpoint ,
4252 Token : token ,
4353 }
4454
45- if err := config .Save ( cfg ); err != nil {
55+ if err := config .SaveProfile ( profile , cfg ); err != nil {
4656 output .Error ("Failed to save configuration: %s" , err )
4757 return err
4858 }
4959
50- output .Success ("Configuration saved to %s" , config .Path ())
60+ output .Success ("Profile %q saved to %s" , profile , config .Path ())
5161 fmt .Println ()
5262 return nil
5363 },
5464}
5565
5666var configureShowCmd = & cobra.Command {
57- Use : "show" ,
58- Short : "Show current configuration" ,
67+ Use : "show [profile]" ,
68+ Short : "Show configuration for one or all profiles" ,
69+ Args : cobra .MaximumNArgs (1 ),
5970 RunE : func (cmd * cobra.Command , args []string ) error {
60- cfg , err := config .Load ()
61- if err != nil {
62- output .Error ("%s" , err )
63- return err
71+ if len (args ) == 1 {
72+ return showProfile (args [0 ])
73+ }
74+ return showAllProfiles ()
75+ },
76+ }
77+
78+ var configureListCmd = & cobra.Command {
79+ Use : "list" ,
80+ Short : "List configured profiles" ,
81+ RunE : func (cmd * cobra.Command , args []string ) error {
82+ return listProfiles ()
83+ },
84+ }
85+
86+ var configureDeleteCmd = & cobra.Command {
87+ Use : "delete <profile>" ,
88+ Short : "Delete a profile" ,
89+ Args : cobra .ExactArgs (1 ),
90+ RunE : func (cmd * cobra.Command , args []string ) error {
91+ yes , _ := cmd .Flags ().GetBool ("yes" )
92+ return deleteProfile (args [0 ], yes )
93+ },
94+ }
95+
96+ var configureDefaultCmd = & cobra.Command {
97+ Use : "default <profile>" ,
98+ Short : "Set the default profile for commands without a profile prefix" ,
99+ Args : cobra .ExactArgs (1 ),
100+ RunE : func (cmd * cobra.Command , args []string ) error {
101+ return setDefaultProfile (args [0 ])
102+ },
103+ }
104+
105+ func listProfiles () error {
106+ names , defaultProfile , err := config .ListProfiles ()
107+ if err != nil {
108+ output .Error ("%s" , err )
109+ return err
110+ }
111+
112+ if jsonFlag {
113+ output .PrintJSON (map [string ]interface {}{
114+ "profiles" : names ,
115+ "default" : defaultProfile ,
116+ "path" : config .Path (),
117+ })
118+ return nil
119+ }
120+
121+ output .Header ("Profiles" )
122+ output .KeyValue (nil , "Config file" , config .Path ())
123+ if defaultProfile != "" {
124+ output .KeyValue (nil , "Default" , defaultProfile )
125+ }
126+ fmt .Println ()
127+ if len (names ) == 0 {
128+ output .Warn ("No profiles configured" )
129+ return nil
130+ }
131+ for _ , name := range names {
132+ marker := ""
133+ if name == defaultProfile {
134+ marker = " (default)"
64135 }
136+ fmt .Printf (" %s%s\n " , name , marker )
137+ }
138+ fmt .Println ()
139+ return nil
140+ }
65141
66- if jsonFlag {
67- output .PrintJSON (map [string ]string {
68- "endpoint" : cfg .Endpoint ,
69- "token" : maskToken (cfg .Token ),
70- "path" : config .Path (),
71- })
142+ func deleteProfile (name string , yes bool ) error {
143+ if ! yes {
144+ if ! output .Confirm (fmt .Sprintf ("Delete profile %q?" , name )) {
145+ output .Warn ("Cancelled" )
72146 return nil
73147 }
148+ }
74149
75- output .Header ("Configuration" )
76- output .KeyValue (nil , "Config file" , config .Path ())
77- output .KeyValue (nil , "Endpoint" , cfg .Endpoint )
78- output .KeyValue (nil , "Token" , maskToken (cfg .Token ))
79- fmt .Println ()
150+ if err := config .DeleteProfile (name ); err != nil {
151+ output .Error ("%s" , err )
152+ return err
153+ }
154+
155+ output .Success ("Profile %q deleted" , name )
156+ return nil
157+ }
158+
159+ func setDefaultProfile (name string ) error {
160+ if err := config .SetDefaultProfile (name ); err != nil {
161+ output .Error ("%s" , err )
162+ return err
163+ }
164+ output .Success ("Default profile set to %q" , name )
165+ return nil
166+ }
167+
168+ func showProfile (name string ) error {
169+ profile , err := config .GetProfile (name )
170+ if err != nil {
171+ output .Error ("%s" , err )
172+ return err
173+ }
174+
175+ if jsonFlag {
176+ output .PrintJSON (map [string ]string {
177+ "profile" : name ,
178+ "endpoint" : profile .Endpoint ,
179+ "token" : maskToken (profile .Token ),
180+ "path" : config .Path (),
181+ })
80182 return nil
81- },
183+ }
184+
185+ output .Header ("Configuration" )
186+ output .KeyValue (nil , "Profile" , name )
187+ output .KeyValue (nil , "Config file" , config .Path ())
188+ output .KeyValue (nil , "Endpoint" , profile .Endpoint )
189+ output .KeyValue (nil , "Token" , maskToken (profile .Token ))
190+ fmt .Println ()
191+ return nil
192+ }
193+
194+ func showAllProfiles () error {
195+ names , defaultProfile , err := config .ListProfiles ()
196+ if err != nil {
197+ output .Error ("%s" , err )
198+ return err
199+ }
200+
201+ if jsonFlag {
202+ profiles := make (map [string ]map [string ]string , len (names ))
203+ for _ , name := range names {
204+ profile , err := config .GetProfile (name )
205+ if err != nil {
206+ return err
207+ }
208+ profiles [name ] = map [string ]string {
209+ "endpoint" : profile .Endpoint ,
210+ "token" : maskToken (profile .Token ),
211+ }
212+ }
213+ output .PrintJSON (map [string ]interface {}{
214+ "profiles" : profiles ,
215+ "default" : defaultProfile ,
216+ "path" : config .Path (),
217+ })
218+ return nil
219+ }
220+
221+ output .Header ("Configuration" )
222+ output .KeyValue (nil , "Config file" , config .Path ())
223+ if defaultProfile != "" {
224+ output .KeyValue (nil , "Default" , defaultProfile )
225+ }
226+ fmt .Println ()
227+
228+ for _ , name := range names {
229+ profile , err := config .GetProfile (name )
230+ if err != nil {
231+ return err
232+ }
233+ output .Header (name )
234+ output .KeyValue (nil , "Endpoint" , profile .Endpoint )
235+ output .KeyValue (nil , "Token" , maskToken (profile .Token ))
236+ fmt .Println ()
237+ }
238+ return nil
82239}
83240
84241func maskToken (token string ) string {
@@ -89,8 +246,10 @@ func maskToken(token string) string {
89246}
90247
91248func init () {
249+ configureCmd .Flags ().String ("profile" , "default" , "Profile name (e.g. prod, staging)" )
92250 configureCmd .Flags ().String ("endpoint" , "" , "Cipi API endpoint URL" )
93251 configureCmd .Flags ().String ("token" , "" , "API authentication token" )
94- configureCmd .AddCommand (configureShowCmd )
252+ configureDeleteCmd .Flags ().BoolP ("yes" , "y" , false , "Skip confirmation" )
253+ configureCmd .AddCommand (configureShowCmd , configureListCmd , configureDeleteCmd , configureDefaultCmd )
95254 rootCmd .AddCommand (configureCmd )
96255}
0 commit comments