X Tutup
Skip to content

Commit fd7b87f

Browse files
committed
Allow writing host-specific keys in a blank config
1 parent f42c9d4 commit fd7b87f

File tree

5 files changed

+84
-36
lines changed

5 files changed

+84
-36
lines changed

internal/config/config_file.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"io/ioutil"
88
"os"
99
"path"
10+
"path/filepath"
1011

1112
"github.com/mitchellh/go-homedir"
1213
"gopkg.in/yaml.v3"
@@ -49,7 +50,12 @@ var ReadConfigFile = func(fn string) ([]byte, error) {
4950
}
5051

5152
var WriteConfigFile = func(fn string, data []byte) error {
52-
cfgFile, err := os.OpenFile(ConfigFile(), os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0600) // cargo coded from setup
53+
err := os.MkdirAll(filepath.Dir(fn), 0771)
54+
if err != nil {
55+
return err
56+
}
57+
58+
cfgFile, err := os.OpenFile(fn, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0600) // cargo coded from setup
5359
if err != nil {
5460
return err
5561
}

internal/config/config_file_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ hosts:
6363
config, err := ParseConfig("config.yml")
6464
eq(t, err, nil)
6565
_, err = config.Get("github.com", "user")
66-
eq(t, err, errors.New(`could not find config entry for "github.com"`))
66+
eq(t, err, &NotFoundError{errors.New(`could not find config entry for "github.com"`)})
6767
}
6868

6969
func Test_migrateConfig(t *testing.T) {

internal/config/config_setup.go

Lines changed: 6 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,10 @@ import (
55
"fmt"
66
"io"
77
"os"
8-
"path/filepath"
98
"strings"
109

1110
"github.com/cli/cli/api"
1211
"github.com/cli/cli/auth"
13-
"gopkg.in/yaml.v3"
1412
)
1513

1614
const (
@@ -76,44 +74,20 @@ func setupConfigFile(filename string) (Config, error) {
7674
return nil, err
7775
}
7876

79-
// TODO this sucks. It precludes us laying out a nice config with comments and such.
80-
type yamlConfig struct {
81-
Hosts map[string]map[string]string
82-
}
83-
84-
yamlHosts := map[string]map[string]string{}
85-
yamlHosts[oauthHost] = map[string]string{}
86-
yamlHosts[oauthHost]["user"] = userLogin
87-
yamlHosts[oauthHost]["oauth_token"] = token
88-
89-
defaultConfig := yamlConfig{
90-
Hosts: yamlHosts,
91-
}
92-
93-
err = os.MkdirAll(filepath.Dir(filename), 0771)
77+
cfg := NewBlankConfig()
78+
err = cfg.Set(oauthHost, "user", userLogin)
9479
if err != nil {
9580
return nil, err
9681
}
97-
98-
cfgFile, err := os.OpenFile(filename, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0600)
82+
err = cfg.Set(oauthHost, "oauth_token", token)
9983
if err != nil {
10084
return nil, err
10185
}
102-
defer cfgFile.Close()
10386

104-
yamlData, err := yaml.Marshal(defaultConfig)
105-
if err != nil {
106-
return nil, err
107-
}
108-
_, err = cfgFile.Write(yamlData)
109-
if err != nil {
110-
return nil, err
87+
if err = cfg.Write(); err == nil {
88+
AuthFlowComplete()
11189
}
112-
113-
AuthFlowComplete()
114-
115-
// TODO cleaner error handling? this "should" always work given that we /just/ wrote the file...
116-
return ParseConfig(filename)
90+
return cfg, err
11791
}
11892

11993
func getViewer(token string) (string, error) {

internal/config/config_type.go

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,13 @@ func NewConfig(root *yaml.Node) Config {
8888
}
8989
}
9090

91+
func NewBlankConfig() Config {
92+
return NewConfig(&yaml.Node{
93+
Kind: yaml.DocumentNode,
94+
Content: []*yaml.Node{{Kind: yaml.MappingNode}},
95+
})
96+
}
97+
9198
// This type implements a Config interface and represents a config file on disk.
9299
type fileConfig struct {
93100
ConfigMap
@@ -136,7 +143,10 @@ func (c *fileConfig) Set(hostname, key, value string) error {
136143
return c.SetStringValue(key, value)
137144
} else {
138145
hostCfg, err := c.configForHost(hostname)
139-
if err != nil {
146+
var notFound *NotFoundError
147+
if errors.As(err, &notFound) {
148+
hostCfg = c.makeConfigForHost(hostname)
149+
} else if err != nil {
140150
return err
141151
}
142152
return hostCfg.SetStringValue(key, value)
@@ -154,7 +164,7 @@ func (c *fileConfig) configForHost(hostname string) (*HostConfig, error) {
154164
return hc, nil
155165
}
156166
}
157-
return nil, fmt.Errorf("could not find config entry for %q", hostname)
167+
return nil, &NotFoundError{fmt.Errorf("could not find config entry for %q", hostname)}
158168
}
159169

160170
func (c *fileConfig) Write() error {
@@ -186,6 +196,35 @@ func (c *fileConfig) hostEntries() ([]*HostConfig, error) {
186196
return hostConfigs, nil
187197
}
188198

199+
func (c *fileConfig) makeConfigForHost(hostname string) *HostConfig {
200+
hostRoot := &yaml.Node{Kind: yaml.MappingNode}
201+
hostCfg := &HostConfig{
202+
Host: hostname,
203+
ConfigMap: ConfigMap{Root: hostRoot},
204+
}
205+
206+
var notFound *NotFoundError
207+
_, hostsEntry, err := c.FindEntry("hosts")
208+
if errors.As(err, &notFound) {
209+
hostsEntry = &yaml.Node{Kind: yaml.MappingNode}
210+
c.Root.Content = append(c.Root.Content,
211+
&yaml.Node{
212+
Kind: yaml.ScalarNode,
213+
Value: "hosts",
214+
}, hostsEntry)
215+
} else if err != nil {
216+
panic(err)
217+
}
218+
219+
hostsEntry.Content = append(hostsEntry.Content,
220+
&yaml.Node{
221+
Kind: yaml.ScalarNode,
222+
Value: hostname,
223+
}, hostRoot)
224+
225+
return hostCfg
226+
}
227+
189228
func (c *fileConfig) parseHosts(hostsEntry *yaml.Node) ([]*HostConfig, error) {
190229
hostConfigs := []*HostConfig{}
191230

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package config
2+
3+
import (
4+
"bytes"
5+
"testing"
6+
7+
"github.com/stretchr/testify/assert"
8+
)
9+
10+
func Test_fileConfig_Set(t *testing.T) {
11+
cb := bytes.Buffer{}
12+
StubWriteConfig(&cb, nil)
13+
14+
c := NewBlankConfig()
15+
assert.NoError(t, c.Set("", "editor", "nano"))
16+
assert.NoError(t, c.Set("github.com", "git_protocol", "ssh"))
17+
assert.NoError(t, c.Set("example.com", "editor", "vim"))
18+
assert.NoError(t, c.Set("github.com", "user", "hubot"))
19+
assert.NoError(t, c.Write())
20+
21+
assert.Equal(t, `editor: nano
22+
hosts:
23+
github.com:
24+
git_protocol: ssh
25+
user: hubot
26+
example.com:
27+
editor: vim
28+
`, cb.String())
29+
}

0 commit comments

Comments
 (0)
X Tutup