Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve configuration system #21

Open
wants to merge 12 commits into
base: main
Choose a base branch
from
34 changes: 22 additions & 12 deletions cmd/commands/auth/login/login.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,33 @@ package login

import (
"fmt"
"path/filepath"

"github.com/craftamap/bb/config"
"github.com/craftamap/bb/util/logging"

"github.com/AlecAivazis/survey/v2"
"github.com/craftamap/bb/cmd/options"
"github.com/logrusorgru/aurora"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)

func Add(authCmd *cobra.Command, globalOpts *options.GlobalOptions) {
func Add(authCmd *cobra.Command, _ *options.GlobalOptions) {
loginCmd := &cobra.Command{
Use: "login",
Run: func(cmd *cobra.Command, args []string) {
oldPw := viper.GetString("password")
Run: func(_ *cobra.Command, _ []string) {
configDirectory, filename := config.GetGlobalConfigurationPath()
path := filepath.Join(configDirectory, filename)
tmpVp, err := config.GetViperForPath(path)
if err != nil {
logging.Error(err)
return
}

oldPw := tmpVp.GetString(config.CONFIG_KEY_AUTH_PASSWORD)

if oldPw != "" {
fmt.Println(aurora.Yellow("::"), aurora.Bold("Warning:"), "You are already logged in as", viper.GetString("username"))
logging.Warning("You are already logged in as ", tmpVp.GetString(config.CONFIG_KEY_AUTH_USERNAME))
cont := false
err := survey.AskOne(&survey.Confirm{Message: "Do you want to overwrite this?"}, &cont)
if err != nil {
Expand All @@ -41,7 +50,7 @@ func Add(authCmd *cobra.Command, globalOpts *options.GlobalOptions) {
Password string
}{}

err := survey.Ask([]*survey.Question{
err = survey.Ask([]*survey.Question{
{
Name: "username",
Prompt: &survey.Input{
Expand All @@ -60,17 +69,18 @@ func Add(authCmd *cobra.Command, globalOpts *options.GlobalOptions) {
logging.Error(err)
return
}

viper.Set("username", answers.Username)
viper.Set("password", answers.Password)

err = viper.WriteConfig()
_, err = config.ValidateAndUpdateEntryWithViper(tmpVp, config.CONFIG_KEY_AUTH_USERNAME, answers.Username)
if err != nil {
logging.Error(err)
return
}
_, err = config.ValidateAndUpdateEntryWithViper(tmpVp, config.CONFIG_KEY_AUTH_PASSWORD, answers.Password)
if err != nil {
logging.Error(err)
return
}

logging.Success(fmt.Sprint("Stored credentials successfully to", viper.ConfigFileUsed()))
logging.Success(fmt.Sprint("Stored credentials successfully to", tmpVp.ConfigFileUsed()))
},
}

Expand Down
220 changes: 220 additions & 0 deletions cmd/commands/config/config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,220 @@
package config

import (
"fmt"
"os"
"path/filepath"
"strings"

"github.com/craftamap/bb/cmd/options"
"github.com/craftamap/bb/config"
"github.com/craftamap/bb/util/logging"
"github.com/spf13/cobra"
)

var (
Local bool
Get bool
GetAll bool
)

func Add(rootCmd *cobra.Command, _ *options.GlobalOptions) {
configCommand := cobra.Command{
Use: "config",
Short: "configure bb",
Long: fmt.Sprintf(`configure bb and change it's behaviour.
bb sources configuration values from multiple sources:
1. The global configuration (usually located at $HOME/.config/bb/configuration.toml)
2. The local configuration (a .bb file in your repository root)
3. Environment variables
4. command-line flags
This command allows you to modify and retrieve the configuration values without editing the configuration values by yourself.

The following keys are supported:
%s`, strings.Join(config.ConfigKeys, ", ")),
PreRunE: func(_ *cobra.Command, _ []string) error {
if Get && GetAll {
logging.Error("--get and --get-all are mutually exclusive")
return fmt.Errorf("") // FIXME: return empty error, so the command fails, but we can use our own method to print out the error message
}
return nil
},
Args: func(cmd *cobra.Command, args []string) error {
if GetAll {
return cobra.ExactArgs(0)(cmd, args)
} else if Get {
return cobra.ExactArgs(1)(cmd, args)
} else {
return cobra.ExactArgs(2)(cmd, args)
}
},
Run: func(_ *cobra.Command, args []string) {
if GetAll {
GetAllValues(args)
} else if Get {
GetValue(args)
} else {
SetValue(args)
}
},
}

configCommand.Flags().BoolVar(&Local, "local", false, "modify or retrieve the local configuration")
configCommand.Flags().BoolVar(&Get, "get", false, "gets a configuration value instead of setting it")
configCommand.Flags().BoolVar(&GetAll, "get-all", false, "prints out all configuration values of the selected configuration")

rootCmd.AddCommand(&configCommand)
}

func GetAllValues(_ []string) {
var configDirectory string
var filename string
if Local {
var err error
configDirectory, filename, err = config.GetLocalConfigurationPath()
if err != nil {
logging.Error(err)
return
}
} else {
configDirectory, filename = config.GetGlobalConfigurationPath()
}
path := filepath.Join(configDirectory, filename)
tmpVp, err := config.GetViperForPath(path)
if err != nil {
logging.Error(err)
return
}
for key, entry := range config.BbConfigurationValidation {
value := tmpVp.Get(key)
if value == nil {
continue
}
if entry.Hidden {
value = "(hidden)"
}

fmt.Printf("%s = %s\n", key, value)
}
}

func SetValue(args []string) {
key := args[0]
inputValue := args[1]

newValue, err := config.BbConfigurationValidation.ValidateEntry(key, inputValue)

if err != nil {
logging.Error(fmt.Sprintf("failed to validate %s: %s", inputValue, err))
return
}

var configDirectory string
var filename string
if Local {
var err error
configDirectory, filename, err = config.GetLocalConfigurationPath()
if err != nil {
logging.Error(err)
return
}
} else {
configDirectory, filename = config.GetGlobalConfigurationPath()
}

// If the directory does not exist, something is off:
// - The global configuration directory get's created in root
// - The local configuration directory is a repository, which always exists
if _, err := os.Stat(configDirectory); os.IsNotExist(err) {
logging.Error(fmt.Sprintf("Expected directory \"%s\", but the directory does not exist", configDirectory))
return
}
path := filepath.Join(configDirectory, filename)
// If the config itself does not exist, it's fine (although weird for global) - we create it now
if _, err := os.Stat(path); os.IsNotExist(err) {
logging.Note(fmt.Sprintf("Creating config file %s", path))
fh, err := os.Create(path)
if err != nil {
logging.Error(fmt.Sprintf("Unable to create file %s", path))
}
fh.Close()
}

logging.Debugf("Config file path: %s", path)

tmpVp, err := config.GetViperForPath(path)
if err != nil {
logging.Error(err)
return
}

isSetAlready := tmpVp.IsSet(key)
oldValue := tmpVp.Get(key)

if isSetAlready {
// Don't print old password values
if config.BbConfigurationValidation[key].Hidden {
oldValue = "(hidden)"
}
logging.Warning(fmt.Sprintf("\"%s\" is already set. This will overwrite the value of \"%s\" from \"%s\" to \"%s\".", key, key, oldValue, newValue))
}

logging.Note(fmt.Sprintf("Setting \"%s\" to \"%s\" in %s", key, newValue, path))
logging.Debugf("%+v", tmpVp.AllSettings())

tmpVp.Set(key, newValue)
logging.Debugf("%+v", tmpVp.AllSettings())

err = config.WriteViper(tmpVp, path)
if err != nil {
logging.Error(err)
return
}

logging.SuccessExclamation(fmt.Sprintf("Successfully updated configuration %s", path))
}

func GetValue(args []string) {
key := args[0]

entry, ok := config.BbConfigurationValidation[key]
if !ok {
logging.Warning(fmt.Sprintf("\"%s\" is not a valid key", key))
return
}

var configDirectory string
var filename string
if Local {
var err error
configDirectory, filename, err = config.GetLocalConfigurationPath()
if err != nil {
logging.Error(err)
return
}
} else {
configDirectory, filename = config.GetGlobalConfigurationPath()
}

path := filepath.Join(configDirectory, filename)
if _, err := os.Stat(path); os.IsNotExist(err) {
logging.Error(fmt.Sprintf("config file %s does not exist yet", path))
return
}

tmpVp, err := config.GetViperForPath(path)
if err != nil {
logging.Error(err)
return
}
value := tmpVp.Get(key)
if value == nil {
logging.Warning(fmt.Sprintf("%s is not set yet.", key))
return
}
if entry.Hidden {
value = "(hidden)"
}

logging.Success(fmt.Sprintf("%s = %s", key, value))
}
5 changes: 3 additions & 2 deletions cmd/commands/pr/sync/sync.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"github.com/cli/cli/utils"
"github.com/cli/safeexec"
"github.com/craftamap/bb/cmd/options"
"github.com/craftamap/bb/config"
"github.com/craftamap/bb/internal/run"
"github.com/craftamap/bb/util/logging"
"github.com/logrusorgru/aurora"
Expand Down Expand Up @@ -38,7 +39,7 @@ func Add(prCmd *cobra.Command, globalOpts *options.GlobalOptions) {
},
PreRunE: func(cmd *cobra.Command, _ []string) error {
// In order to check if the method exists in the config, we need to check here
syncMethodIsSet := viper.IsSet("sync-method")
syncMethodIsSet := viper.IsSet(config.CONFIG_KEY_PR_SYNC_SYNC_METHOD)
if !syncMethodIsSet {
logging.Note(
"You can configure your preferred way of syncing by adding the following line to your configuration: ",
Expand All @@ -48,7 +49,7 @@ func Add(prCmd *cobra.Command, globalOpts *options.GlobalOptions) {
)
}
if syncMethodIsSet && !cmd.Flags().Lookup("method").Changed {
Method = viper.GetString("sync-method")
Method = viper.GetString(config.CONFIG_KEY_PR_SYNC_SYNC_METHOD)
}

if Method != MethodOptionRebase && Method != MethodOptionMerge {
Expand Down
14 changes: 11 additions & 3 deletions cmd/commands/repo/clone/clone.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@ package clone

import (
"fmt"
"path/filepath"
"strings"

"github.com/craftamap/bb/config"
"github.com/craftamap/bb/util/logging"

"github.com/AlecAivazis/survey/v2"
Expand All @@ -24,7 +26,7 @@ func Add(repoCmd *cobra.Command, globalOpts *options.GlobalOptions) {
Run: func(cmd *cobra.Command, args []string) {
c := globalOpts.Client

gitProtocol := viper.GetString("git_protocol")
gitProtocol := viper.GetString(config.CONFIG_KEY_REPO_CLONE_GIT_PROTOCOL)
if gitProtocol == "" || (gitProtocol != "ssh" && gitProtocol != "https") {
err := survey.AskOne(&survey.Select{
Message: "Please select a prefered protocol of cloning repositories",
Expand All @@ -34,8 +36,14 @@ func Add(repoCmd *cobra.Command, globalOpts *options.GlobalOptions) {
logging.Error(err)
return
}
viper.Set("git_protocol", gitProtocol)
viper.WriteConfig()

configDirectory, filename := config.GetGlobalConfigurationPath()
path := filepath.Join(configDirectory, filename)
_, err = config.ValidateAndUpdateEntry(path, config.CONFIG_KEY_REPO_CLONE_GIT_PROTOCOL, gitProtocol)
if err != nil {
logging.Error(err)
return
}
}

if len(args) == 0 {
Expand Down
Loading