From b0ff6ea7afabdb5bfa46ef3dbb6d5339e082726e Mon Sep 17 00:00:00 2001 From: Pierre-Yves Ritschard Date: Sat, 29 Oct 2022 19:20:20 +0200 Subject: [PATCH] allow overriding base url in profiles For APIs deployed for several environments (development, staging, production), it can be useful to share most of the configuration but to allow configuration of the URL base. --- cli/apiconfig.go | 21 ++++++++++++++++++--- cli/cli.go | 25 +++++++++++++++++++++++-- cli/interactive.go | 10 ++++++++++ cli/request.go | 18 ++++++++++++++---- 4 files changed, 65 insertions(+), 9 deletions(-) diff --git a/cli/apiconfig.go b/cli/apiconfig.go index 96f76a6..5e069ab 100644 --- a/cli/apiconfig.go +++ b/cli/apiconfig.go @@ -32,6 +32,7 @@ type TLSConfig struct { // APIProfile contains account-specific API information type APIProfile struct { + Base string `json:"base",omitempty` Headers map[string]string `json:"headers,omitempty"` Query map[string]string `json:"query,omitempty"` Auth *APIAuth `json:"auth"` @@ -189,9 +190,23 @@ func initAPIConfig() { func findAPI(uri string) (string, *APIConfig) { for name, config := range configs { - if strings.HasPrefix(uri, config.Base) { - // TODO: find the longest matching base? - return name, config + profile := viper.GetString("rsh-profile") + if profile != "default" { + if config.Profiles[profile] == nil { + continue + } + if config.Profiles[profile].Base != "" { + if strings.HasPrefix(uri, config.Profiles[profile].Base) { + return name, config + } + } else if strings.HasPrefix(uri, config.Base) { + return name, config + } + } else { + if strings.HasPrefix(uri, config.Base) { + // TODO: find the longest matching base? + return name, config + } } } diff --git a/cli/cli.go b/cli/cli.go index 13906b1..5344356 100644 --- a/cli/cli.go +++ b/cli/cli.go @@ -116,7 +116,17 @@ func completeCurrentConfig(cmd *cobra.Command, args []string, toComplete string, for _, cmd := range Root.Commands() { if cmd.Use == currentConfig.name { // This is the matching command. Load the URL and check each operation. - api, _ := Load(currentConfig.Base, cmd) + currentBase := currentConfig.Base + currentProfile := currentConfig.Profiles[viper.GetString("rsh-profile")] + if currentProfile == nil { + if viper.GetString("rsh-profile") != "default" { + panic("Invalid profile " + viper.GetString("rsh-profile")) + } + } + if currentProfile != nil && currentProfile.Base != "" { + currentBase = currentProfile.Base + } + api, _ := Load(currentBase, cmd) for _, op := range api.Operations { if op.Method != method { // We only care about operations which match the currently selected @@ -679,6 +689,7 @@ func Run() { if headers, _ := GlobalFlags.GetStringSlice("rsh-header"); len(headers) > 0 { viper.Set("rsh-header", headers) } + profile, _ := GlobalFlags.GetString("rsh-profile") // Now that global flags are parsed we can enable verbose mode if requested. if viper.GetBool("rsh-verbose") { @@ -704,7 +715,17 @@ func Run() { currentConfig = cfg for _, cmd := range Root.Commands() { if cmd.Use == apiName { - if _, err := Load(cfg.Base, cmd); err != nil { + currentBase := cfg.Base + currentProfile := cfg.Profiles[profile] + if currentProfile == nil { + if profile != "default" { + panic("Invalid profile " + profile) + } + } + if currentProfile != nil && currentProfile.Base != "" { + currentBase = currentProfile.Base + } + if _, err := Load(currentBase, cmd); err != nil { panic(err) } loaded = true diff --git a/cli/interactive.go b/cli/interactive.go index c3ac832..eb8f732 100644 --- a/cli/interactive.go +++ b/cli/interactive.go @@ -241,6 +241,11 @@ func askEditProfile(a asker, name string, profile *APIProfile) { options = append(options, "Delete query param "+k) } + options = append(options, "Add custom base URL") + if profile.Base != "" { + options = append(options, "Remove custom base URL") + } + options = append(options, "Setup auth", "Finished with profile") choice := a.askSelect("Select option for profile `"+name+"`", options, nil, "") @@ -275,6 +280,11 @@ func askEditProfile(a asker, name string, profile *APIProfile) { profile.Auth = &APIAuth{} } askAuth(a, profile.Auth) + case choice == "Add custom base URL": + url := a.askInput("Base URL", "", true, "") + profile.Base = url + case choice == "Remove custom base URL": + profile.Base = "" case choice == "Finished with profile": return } diff --git a/cli/request.go b/cli/request.go index 5d0be72..50893dd 100644 --- a/cli/request.go +++ b/cli/request.go @@ -26,9 +26,20 @@ func fixAddress(addr string) string { // the base URL for that API. parts := strings.Split(addr, "/") c := configs[parts[0]] - if c != nil && c.Base != "" { - parts[0] = c.Base - return strings.Join(parts, "/") + if c != nil { + p := c.Profiles[viper.GetString("rsh-profile")] + if p == nil { + if viper.GetString("rsh-profile") != "default" { + panic("Invalid profile " + viper.GetString("rsh-profile")) + } + } + if p != nil && p.Base != "" { + parts[0] = p.Base + return strings.Join(parts, "/") + } else if c.Base != "" { + parts[0] = c.Base + return strings.Join(parts, "/") + } } // Local traffic defaults to HTTP, everything else uses TLS. @@ -82,7 +93,6 @@ func MakeRequest(req *http.Request, options ...requestOption) (*http.Response, e if viper.GetString("rsh-profile") != "default" { panic("Invalid profile " + viper.GetString("rsh-profile")) } - profile = &APIProfile{} }