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

Remove default configuration and add fallback configuration #142

Merged
merged 2 commits into from
Oct 24, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion pkg/api/client_options.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ func optionsNeedResolution(opts ClientOptions) bool {
}

func resolveOptions(opts ClientOptions) (ClientOptions, error) {
cfg, _ := config.Read()
cfg, _ := config.Read(nil)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's kind of a shame with this pattern that we end up passing nil around everywhere. Oh well.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed. Open to better suggestions if you have them.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The only reasonable one I have is using variadic functional opts. Everything else is a much bigger change than I think we would want to tackle.

if opts.Host == "" {
opts.Host, _ = auth.DefaultHost()
}
Expand Down
2 changes: 1 addition & 1 deletion pkg/api/http_client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -247,7 +247,7 @@ func defaultHeaders() http.Header {
func stubConfig(t *testing.T, cfgStr string) {
t.Helper()
old := config.Read
config.Read = func() (*config.Config, error) {
config.Read = func(_ *config.Config) (*config.Config, error) {
return config.ReadFromString(cfgStr), nil
}
t.Cleanup(func() {
Expand Down
6 changes: 3 additions & 3 deletions pkg/auth/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ func TokenForHost(host string) (string, string) {
// file as fallback, but does not support reading the token from system keyring. Most consumers
// should use TokenForHost.
func TokenFromEnvOrConfig(host string) (string, string) {
cfg, _ := config.Read()
cfg, _ := config.Read(nil)
return tokenForHost(cfg, host)
}

Expand Down Expand Up @@ -105,7 +105,7 @@ func tokenFromGh(path string, host string) (string, string) {
// or from the configuration file.
// Returns an empty string slice if no hosts are found.
func KnownHosts() []string {
cfg, _ := config.Read()
cfg, _ := config.Read(nil)
return knownHosts(cfg)
}

Expand All @@ -131,7 +131,7 @@ func knownHosts(cfg *config.Config) []string {
// configuration file.
// Returns "github.com", "default" if no viable host is found.
func DefaultHost() (string, string) {
cfg, _ := config.Read()
cfg, _ := config.Read(nil)
return defaultHost(cfg)
}

Expand Down
2 changes: 1 addition & 1 deletion pkg/browser/browser.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ func resolveLauncher() string {
if ghBrowser := os.Getenv("GH_BROWSER"); ghBrowser != "" {
return ghBrowser
}
cfg, err := config.Read()
cfg, err := config.Read(nil)
if err == nil {
if cfgBrowser, _ := cfg.Get([]string{"browser"}); cfgBrowser != "" {
return cfgBrowser
Expand Down
2 changes: 1 addition & 1 deletion pkg/browser/browser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ func TestResolveLauncher(t *testing.T) {
}
if tt.config != nil {
old := config.Read
config.Read = func() (*config.Config, error) {
config.Read = func(_ *config.Config) (*config.Config, error) {
return tt.config, nil
}
defer func() { config.Read = old }()
Expand Down
43 changes: 17 additions & 26 deletions pkg/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -119,18 +119,23 @@ func (c *Config) Set(keys []string, value string) {
m.SetEntry(keys[len(keys)-1], yamlmap.StringValue(value))
}

func (c *Config) deepCopy() *Config {
return ReadFromString(c.entries.String())
}

// Read gh configuration files from the local file system and
// return a Config.
var Read = func() (*Config, error) {
// returns a Config. A copy of the fallback configuration will
// be returned when there are no configuration files to load.
// If there are no configuration files and no fallback configuration
// an empty configuration will be returned.
var Read = func(fallback *Config) (*Config, error) {
once.Do(func() {
cfg, loadErr = load(generalConfigFile(), hostsConfigFile())
cfg, loadErr = load(generalConfigFile(), hostsConfigFile(), fallback)
})
return cfg, loadErr
}

// ReadFromString takes a yaml string and returns a Config.
// Note: This is only used for testing, and should not be
// relied upon in production.
func ReadFromString(str string) *Config {
m, _ := mapFromString(str)
if m == nil {
Expand Down Expand Up @@ -174,7 +179,7 @@ func Write(c *Config) error {
return nil
}

func load(generalFilePath, hostsFilePath string) (*Config, error) {
func load(generalFilePath, hostsFilePath string, fallback *Config) (*Config, error) {
generalMap, err := mapFromFile(generalFilePath)
if err != nil && !os.IsNotExist(err) {
if errors.Is(err, yamlmap.ErrInvalidYaml) ||
Expand All @@ -184,8 +189,8 @@ func load(generalFilePath, hostsFilePath string) (*Config, error) {
return nil, err
}

if generalMap == nil || generalMap.Empty() {
generalMap, _ = mapFromString(defaultGeneralEntries)
if generalMap == nil {
generalMap = yamlmap.MapValue()
}

hostsMap, err := mapFromFile(hostsFilePath)
Expand All @@ -201,6 +206,10 @@ func load(generalFilePath, hostsFilePath string) (*Config, error) {
generalMap.AddEntry("hosts", hostsMap)
}

if generalMap.Empty() && fallback != nil {
return fallback.deepCopy(), nil
}

return &Config{entries: generalMap}, nil
}

Expand Down Expand Up @@ -302,21 +311,3 @@ func writeFile(filename string, data []byte) (writeErr error) {
_, writeErr = file.Write(data)
return
}

var defaultGeneralEntries = `
# What protocol to use when performing git operations. Supported values: ssh, https
git_protocol: https
# What editor gh should run when creating issues, pull requests, etc. If blank, will refer to environment.
editor:
# When to interactively prompt. This is a global config that cannot be overridden by hostname. Supported values: enabled, disabled
prompt: enabled
# A pager program to send command output to, e.g. "less". Set the value to "cat" to disable the pager.
pager:
# Aliases allow you to create nicknames for gh commands
aliases:
co: pr checkout
# The path to a unix socket through which send HTTP connections. If blank, HTTP traffic will be handled by net/http.DefaultTransport.
http_unix_socket:
# What web browser gh should use when opening URLs. If blank, will refer to environment.
browser:
`
Loading
Loading