From 1bff97b4344f54afb5a91e12a7db3579a45aa6a8 Mon Sep 17 00:00:00 2001 From: NightStar Date: Tue, 28 Jul 2026 16:08:05 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20provider=20cmd=20=E2=80=94=20list,=20us?= =?UTF-8?q?e,=20add=20with=20interactive=20key=20input?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- cmd/ry/main.go | 1 + internal/cmd/provider.go | 94 ++++++++++++++++++++++++++++++++++++++++ internal/cmd/root.go | 5 +++ 3 files changed, 100 insertions(+) create mode 100644 internal/cmd/provider.go diff --git a/cmd/ry/main.go b/cmd/ry/main.go index 135e353..7b998ac 100644 --- a/cmd/ry/main.go +++ b/cmd/ry/main.go @@ -5,6 +5,7 @@ import ( "os" "git.yoresee.cc/nightstar/ry/internal/cmd" + _ "git.yoresee.cc/nightstar/ry/internal/provider/rainyun" ) func main() { diff --git a/internal/cmd/provider.go b/internal/cmd/provider.go new file mode 100644 index 0000000..0e7118b --- /dev/null +++ b/internal/cmd/provider.go @@ -0,0 +1,94 @@ +package cmd + +import ( + "fmt" + + "git.yoresee.cc/nightstar/ry/internal/config" + "git.yoresee.cc/nightstar/ry/internal/provider" + + "github.com/spf13/cobra" +) + +var providerCmd = &cobra.Command{ + Use: "provider", + Short: "Manage cloud providers", +} + +var providerListCmd = &cobra.Command{ + Use: "list", + Short: "List configured providers", + Annotations: map[string]string{"skipProvider": "true"}, + RunE: func(cmd *cobra.Command, args []string) error { + // show all registered providers, mark current with * + current := "" + if cfg != nil { + current = cfg.CurrentProvider + } + for _, name := range provider.List() { + marker := " " + if name == current { + marker = "*" + } + fmt.Printf("%s %s\n", marker, name) + } + return nil + }, +} + +var providerUseCmd = &cobra.Command{ + Use: "use ", + Short: "Switch the current cloud provider", + Annotations: map[string]string{"skipProvider": "true"}, + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + name := args[0] + if _, ok := cfg.Providers[name]; !ok { + return fmt.Errorf("provider %q not configured — run 'ry provider add %s' first", name, name) + } + cfg.CurrentProvider = name + if err := config.Save(cfgPath, cfg); err != nil { + return fmt.Errorf("save config: %w", err) + } + fmt.Printf("Switched to provider %q\n", name) + return nil + }, +} + +var providerAddCmd = &cobra.Command{ + Use: "add ", + Short: "Add a new cloud provider", + Annotations: map[string]string{"skipProvider": "true"}, + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + name := args[0] + fmt.Printf("Adding provider %q...\n", name) + fmt.Print("Enter API Key: ") + var apiKey string + fmt.Scanln(&apiKey) + if apiKey == "" { + return fmt.Errorf("API Key is required") + } + if cfg.Providers == nil { + cfg.Providers = make(map[string]config.ProviderConfig) + } + cfg.Providers[name] = config.ProviderConfig{APIKey: apiKey} + if cfg.CurrentProvider == "" { + cfg.CurrentProvider = name + } + if err := config.Save(cfgPath, cfg); err != nil { + return fmt.Errorf("save config: %w", err) + } + fmt.Printf("Provider %q added successfully\n", name) + if cfg.CurrentProvider == name { + fmt.Printf("Set as current provider\n") + } + return nil + }, +} + +func init() { + providerCmd.AddCommand(providerListCmd) + providerCmd.AddCommand(providerUseCmd) + providerCmd.AddCommand(providerAddCmd) + rootCmd.AddCommand(providerCmd) +} diff --git a/internal/cmd/root.go b/internal/cmd/root.go index 2d0d804..e301a19 100644 --- a/internal/cmd/root.go +++ b/internal/cmd/root.go @@ -38,6 +38,11 @@ Use "ry [command] --help" for more information about a command.`, return fmt.Errorf("load config: %w", err) } + // provider subcommands don't need an initialized provider + if cmd.Annotations != nil && cmd.Annotations["skipProvider"] == "true" { + return nil + } + providerName := cfg.CurrentProvider if flagProvider != "" { providerName = flagProvider