Skip to content

Commit c979b41

Browse files
committed
feat(cli): add ConfigCommand helper for config init/list
Replaces ~50 lines of identical boilerplate in every raystack CLI: rootCmd.AddCommand(cli.ConfigCommand("frontier", &Config{})) Adds "config init" (creates config file with defaults) and "config list" (shows current config as JSON). Uses config.WithAppConfig for standard file location (~/.config/raystack/<app>.yml).
1 parent b3cfd31 commit c979b41

3 files changed

Lines changed: 76 additions & 6 deletions

File tree

cli/cli.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ type cliContext struct {
3838
//
3939
// The developer owns the root command — Init only adds features to it.
4040
func Init(rootCmd *cobra.Command, opts ...Option) {
41-
cfg := &config{}
41+
cfg := &initConfig{}
4242
for _, opt := range opts {
4343
opt(cfg)
4444
}

cli/config_cmd.go

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
package cli
2+
3+
import (
4+
"fmt"
5+
6+
"github.com/raystack/salt/config"
7+
"github.com/spf13/cobra"
8+
)
9+
10+
// ConfigCommand returns a "config" command with "init" and "list" subcommands
11+
// for managing client-side CLI configuration.
12+
//
13+
// The appName is used to determine the config file location
14+
// (~/.config/raystack/<appName>.yml). The defaultCfg is a pointer to a struct
15+
// with default values used when initializing a new config file.
16+
//
17+
// Usage:
18+
//
19+
// rootCmd.AddCommand(cli.ConfigCommand("frontier", &Config{}))
20+
func ConfigCommand(appName string, defaultCfg interface{}) *cobra.Command {
21+
cmd := &cobra.Command{
22+
Use: "config <command>",
23+
Short: "Manage client configuration",
24+
Example: fmt.Sprintf(" $ %s config init\n $ %s config list", appName, appName),
25+
}
26+
27+
cmd.AddCommand(configInitCmd(appName, defaultCfg))
28+
cmd.AddCommand(configListCmd(appName))
29+
30+
return cmd
31+
}
32+
33+
func configInitCmd(appName string, defaultCfg interface{}) *cobra.Command {
34+
return &cobra.Command{
35+
Use: "init",
36+
Short: "Initialize a new configuration file",
37+
Example: fmt.Sprintf(" $ %s config init", appName),
38+
Annotations: map[string]string{
39+
"group": "core",
40+
},
41+
RunE: func(cmd *cobra.Command, _ []string) error {
42+
loader := config.NewLoader(config.WithAppConfig(appName))
43+
if err := loader.Init(defaultCfg); err != nil {
44+
return err
45+
}
46+
Output(cmd).Success("config initialized")
47+
return nil
48+
},
49+
}
50+
}
51+
52+
func configListCmd(appName string) *cobra.Command {
53+
return &cobra.Command{
54+
Use: "list",
55+
Short: "List current configuration",
56+
Example: fmt.Sprintf(" $ %s config list", appName),
57+
Annotations: map[string]string{
58+
"group": "core",
59+
},
60+
RunE: func(cmd *cobra.Command, _ []string) error {
61+
loader := config.NewLoader(config.WithAppConfig(appName))
62+
data, err := loader.View()
63+
if err != nil {
64+
return fmt.Errorf("failed to load config: %w", err)
65+
}
66+
Output(cmd).Println(data)
67+
return nil
68+
},
69+
}
70+
}

cli/option.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,31 +2,31 @@ package cli
22

33
import "github.com/raystack/salt/cli/commander"
44

5-
type config struct {
5+
type initConfig struct {
66
version string
77
repo string
88
topics []commander.HelpTopic
99
hooks []commander.HookBehavior
1010
}
1111

1212
// Option configures cli.Init.
13-
type Option func(*config)
13+
type Option func(*initConfig)
1414

1515
// Version enables a version command with update checking.
1616
// The repo should be in "owner/repo" format (e.g. "raystack/frontier").
1717
func Version(ver, repo string) Option {
18-
return func(c *config) {
18+
return func(c *initConfig) {
1919
c.version = ver
2020
c.repo = repo
2121
}
2222
}
2323

2424
// Topics adds help topics to the CLI.
2525
func Topics(topics ...commander.HelpTopic) Option {
26-
return func(c *config) { c.topics = append(c.topics, topics...) }
26+
return func(c *initConfig) { c.topics = append(c.topics, topics...) }
2727
}
2828

2929
// Hooks adds hook behaviors applied to commands.
3030
func Hooks(hooks ...commander.HookBehavior) Option {
31-
return func(c *config) { c.hooks = append(c.hooks, hooks...) }
31+
return func(c *initConfig) { c.hooks = append(c.hooks, hooks...) }
3232
}

0 commit comments

Comments
 (0)