зеркало из https://github.com/mislav/hub.git
Merge pull request #620 from github/gh_yaml
Refactor to `configService` to read & write `Config`
This commit is contained in:
Коммит
254bf7c7e7
|
@ -59,8 +59,8 @@ func transformCloneArgs(args *Args) {
|
||||||
name, owner := parseCloneNameAndOwner(a)
|
name, owner := parseCloneNameAndOwner(a)
|
||||||
var host *github.Host
|
var host *github.Host
|
||||||
if owner == "" {
|
if owner == "" {
|
||||||
configs := github.CurrentConfigs()
|
config := github.CurrentConfig()
|
||||||
h, err := configs.DefaultHost()
|
h, err := config.DefaultHost()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.Check(github.FormatError("cloning repository", err))
|
utils.Check(github.FormatError("cloning repository", err))
|
||||||
}
|
}
|
||||||
|
|
|
@ -73,8 +73,8 @@ func create(command *Command, args *Args) {
|
||||||
newRepoName = args.FirstParam()
|
newRepoName = args.FirstParam()
|
||||||
}
|
}
|
||||||
|
|
||||||
configs := github.CurrentConfigs()
|
config := github.CurrentConfig()
|
||||||
host, err := configs.DefaultHost()
|
host, err := config.DefaultHost()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.Check(github.FormatError("creating repository", err))
|
utils.Check(github.FormatError("creating repository", err))
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,9 +2,10 @@ package commands
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"os"
|
||||||
|
|
||||||
"github.com/github/hub/github"
|
"github.com/github/hub/github"
|
||||||
"github.com/github/hub/utils"
|
"github.com/github/hub/utils"
|
||||||
"os"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var cmdFork = &Command{
|
var cmdFork = &Command{
|
||||||
|
@ -41,8 +42,8 @@ func fork(cmd *Command, args *Args) {
|
||||||
utils.Check(fmt.Errorf("Error: repository under 'origin' remote is not a GitHub project"))
|
utils.Check(fmt.Errorf("Error: repository under 'origin' remote is not a GitHub project"))
|
||||||
}
|
}
|
||||||
|
|
||||||
configs := github.CurrentConfigs()
|
config := github.CurrentConfig()
|
||||||
host, err := configs.PromptForHost(project.Host)
|
host, err := config.PromptForHost(project.Host)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.Check(github.FormatError("forking repository", err))
|
utils.Check(github.FormatError("forking repository", err))
|
||||||
}
|
}
|
||||||
|
|
|
@ -86,7 +86,7 @@ func pullRequest(cmd *Command, args *Args) {
|
||||||
baseProject, err := localRepo.MainProject()
|
baseProject, err := localRepo.MainProject()
|
||||||
utils.Check(err)
|
utils.Check(err)
|
||||||
|
|
||||||
host, err := github.CurrentConfigs().PromptForHost(baseProject.Host)
|
host, err := github.CurrentConfig().PromptForHost(baseProject.Host)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.Check(github.FormatError("creating pull request", err))
|
utils.Check(github.FormatError("creating pull request", err))
|
||||||
}
|
}
|
||||||
|
|
|
@ -69,7 +69,7 @@ func transformRemoteArgs(args *Args) {
|
||||||
isPriavte := parseRemotePrivateFlag(args)
|
isPriavte := parseRemotePrivateFlag(args)
|
||||||
if len(words) == 2 && words[1] == "origin" {
|
if len(words) == 2 && words[1] == "origin" {
|
||||||
// Origin special case triggers default user/repo
|
// Origin special case triggers default user/repo
|
||||||
host, err := github.CurrentConfigs().DefaultHost()
|
host, err := github.CurrentConfig().DefaultHost()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.Check(github.FormatError("adding remote", err))
|
utils.Check(github.FormatError("adding remote", err))
|
||||||
}
|
}
|
||||||
|
|
|
@ -443,7 +443,7 @@ func (client *Client) FindOrCreateToken(user, password, twoFactorCode string) (t
|
||||||
|
|
||||||
func (client *Client) api() (c *octokit.Client, err error) {
|
func (client *Client) api() (c *octokit.Client, err error) {
|
||||||
if client.Host.AccessToken == "" {
|
if client.Host.AccessToken == "" {
|
||||||
host, e := CurrentConfigs().PromptForHost(client.Host.Host)
|
host, e := CurrentConfig().PromptForHost(client.Host.Host)
|
||||||
if e != nil {
|
if e != nil {
|
||||||
err = e
|
err = e
|
||||||
return
|
return
|
||||||
|
|
|
@ -8,7 +8,6 @@ import (
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"github.com/BurntSushi/toml"
|
|
||||||
"github.com/github/hub/utils"
|
"github.com/github/hub/utils"
|
||||||
"github.com/howeyc/gopass"
|
"github.com/howeyc/gopass"
|
||||||
)
|
)
|
||||||
|
@ -24,11 +23,11 @@ type Host struct {
|
||||||
Protocol string `toml:"protocol"`
|
Protocol string `toml:"protocol"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Configs struct {
|
type Config struct {
|
||||||
Hosts []Host `toml:"hosts"`
|
Hosts []Host `toml:"hosts"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Configs) PromptForHost(host string) (h *Host, err error) {
|
func (c *Config) PromptForHost(host string) (h *Host, err error) {
|
||||||
h = c.Find(host)
|
h = c.Find(host)
|
||||||
if h != nil {
|
if h != nil {
|
||||||
return
|
return
|
||||||
|
@ -65,12 +64,12 @@ func (c *Configs) PromptForHost(host string) (h *Host, err error) {
|
||||||
Protocol: "https",
|
Protocol: "https",
|
||||||
}
|
}
|
||||||
c.Hosts = append(c.Hosts, *h)
|
c.Hosts = append(c.Hosts, *h)
|
||||||
err = saveTo(configsFile(), c)
|
err = newConfigService().Save(configsFile(), c)
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Configs) PromptForUser() (user string) {
|
func (c *Config) PromptForUser() (user string) {
|
||||||
user = os.Getenv("GITHUB_USER")
|
user = os.Getenv("GITHUB_USER")
|
||||||
if user != "" {
|
if user != "" {
|
||||||
return
|
return
|
||||||
|
@ -82,7 +81,7 @@ func (c *Configs) PromptForUser() (user string) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Configs) PromptForPassword(host, user string) (pass string) {
|
func (c *Config) PromptForPassword(host, user string) (pass string) {
|
||||||
pass = os.Getenv("GITHUB_PASSWORD")
|
pass = os.Getenv("GITHUB_PASSWORD")
|
||||||
if pass != "" {
|
if pass != "" {
|
||||||
return
|
return
|
||||||
|
@ -98,12 +97,12 @@ func (c *Configs) PromptForPassword(host, user string) (pass string) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Configs) PromptForOTP() string {
|
func (c *Config) PromptForOTP() string {
|
||||||
fmt.Print("two-factor authentication code: ")
|
fmt.Print("two-factor authentication code: ")
|
||||||
return c.scanLine()
|
return c.scanLine()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Configs) scanLine() string {
|
func (c *Config) scanLine() string {
|
||||||
var line string
|
var line string
|
||||||
scanner := bufio.NewScanner(os.Stdin)
|
scanner := bufio.NewScanner(os.Stdin)
|
||||||
if scanner.Scan() {
|
if scanner.Scan() {
|
||||||
|
@ -114,7 +113,7 @@ func (c *Configs) scanLine() string {
|
||||||
return line
|
return line
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Configs) Find(host string) *Host {
|
func (c *Config) Find(host string) *Host {
|
||||||
for _, h := range c.Hosts {
|
for _, h := range c.Hosts {
|
||||||
if h.Host == host {
|
if h.Host == host {
|
||||||
return &h
|
return &h
|
||||||
|
@ -124,61 +123,7 @@ func (c *Configs) Find(host string) *Host {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func saveTo(filename string, v interface{}) error {
|
func (c *Config) selectHost() *Host {
|
||||||
err := os.MkdirAll(filepath.Dir(filename), 0771)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
f, err := os.OpenFile(filename, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0600)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer f.Close()
|
|
||||||
|
|
||||||
enc := toml.NewEncoder(f)
|
|
||||||
return enc.Encode(v)
|
|
||||||
}
|
|
||||||
|
|
||||||
func loadFrom(filename string, c *Configs) (err error) {
|
|
||||||
_, err = toml.DecodeFile(filename, c)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func configsFile() string {
|
|
||||||
configsFile := os.Getenv("GH_CONFIG")
|
|
||||||
if configsFile == "" {
|
|
||||||
configsFile = defaultConfigsFile
|
|
||||||
}
|
|
||||||
|
|
||||||
return configsFile
|
|
||||||
}
|
|
||||||
|
|
||||||
func CurrentConfigs() *Configs {
|
|
||||||
c := &Configs{}
|
|
||||||
|
|
||||||
configFile := configsFile()
|
|
||||||
err := loadFrom(configFile, c)
|
|
||||||
if err != nil {
|
|
||||||
// load from YAML
|
|
||||||
}
|
|
||||||
|
|
||||||
return c
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Configs) DefaultHost() (host *Host, err error) {
|
|
||||||
if GitHubHostEnv != "" {
|
|
||||||
host, err = c.PromptForHost(GitHubHostEnv)
|
|
||||||
} else if len(c.Hosts) > 0 {
|
|
||||||
host = c.selectHost()
|
|
||||||
} else {
|
|
||||||
host, err = c.PromptForHost(DefaultGitHubHost())
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Configs) selectHost() *Host {
|
|
||||||
options := len(c.Hosts)
|
options := len(c.Hosts)
|
||||||
|
|
||||||
if options == 1 {
|
if options == 1 {
|
||||||
|
@ -201,12 +146,40 @@ func (c *Configs) selectHost() *Host {
|
||||||
return &c.Hosts[i-1]
|
return &c.Hosts[i-1]
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Configs) Save() error {
|
func configsFile() string {
|
||||||
return saveTo(configsFile(), c)
|
configsFile := os.Getenv("GH_CONFIG")
|
||||||
|
if configsFile == "" {
|
||||||
|
configsFile = defaultConfigsFile
|
||||||
|
}
|
||||||
|
|
||||||
|
return configsFile
|
||||||
|
}
|
||||||
|
|
||||||
|
func CurrentConfig() *Config {
|
||||||
|
c := &Config{}
|
||||||
|
|
||||||
|
err := newConfigService().Load(configsFile(), c)
|
||||||
|
if err != nil {
|
||||||
|
// load from YAML
|
||||||
|
}
|
||||||
|
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Config) DefaultHost() (host *Host, err error) {
|
||||||
|
if GitHubHostEnv != "" {
|
||||||
|
host, err = c.PromptForHost(GitHubHostEnv)
|
||||||
|
} else if len(c.Hosts) > 0 {
|
||||||
|
host = c.selectHost()
|
||||||
|
} else {
|
||||||
|
host, err = c.PromptForHost(DefaultGitHubHost())
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Public for testing purpose
|
// Public for testing purpose
|
||||||
func CreateTestConfigs(user, token string) *Configs {
|
func CreateTestConfigs(user, token string) *Config {
|
||||||
f, _ := ioutil.TempFile("", "test-config")
|
f, _ := ioutil.TempFile("", "test-config")
|
||||||
defaultConfigsFile = f.Name()
|
defaultConfigsFile = f.Name()
|
||||||
|
|
||||||
|
@ -216,8 +189,11 @@ func CreateTestConfigs(user, token string) *Configs {
|
||||||
Host: GitHubHost,
|
Host: GitHubHost,
|
||||||
}
|
}
|
||||||
|
|
||||||
c := &Configs{Hosts: []Host{host}}
|
c := &Config{Hosts: []Host{host}}
|
||||||
saveTo(f.Name(), c)
|
err := newConfigService().Save(f.Name(), c)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
return c
|
return c
|
||||||
}
|
}
|
|
@ -0,0 +1,19 @@
|
||||||
|
package github
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
|
||||||
|
"github.com/BurntSushi/toml"
|
||||||
|
)
|
||||||
|
|
||||||
|
type configDecoder interface {
|
||||||
|
Decode(r io.Reader, v interface{}) error
|
||||||
|
}
|
||||||
|
|
||||||
|
type tomlConfigDecoder struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *tomlConfigDecoder) Decode(r io.Reader, v interface{}) error {
|
||||||
|
_, err := toml.DecodeReader(r, v)
|
||||||
|
return err
|
||||||
|
}
|
|
@ -0,0 +1,19 @@
|
||||||
|
package github
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
|
||||||
|
"github.com/BurntSushi/toml"
|
||||||
|
)
|
||||||
|
|
||||||
|
type configEncoder interface {
|
||||||
|
Encode(w io.Writer, v interface{}) error
|
||||||
|
}
|
||||||
|
|
||||||
|
type tomlConfigEncoder struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *tomlConfigEncoder) Encode(w io.Writer, v interface{}) error {
|
||||||
|
enc := toml.NewEncoder(w)
|
||||||
|
return enc.Encode(v)
|
||||||
|
}
|
|
@ -0,0 +1,43 @@
|
||||||
|
package github
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
)
|
||||||
|
|
||||||
|
func newConfigService() *configService {
|
||||||
|
return &configService{
|
||||||
|
Encoder: &tomlConfigEncoder{},
|
||||||
|
Decoder: &tomlConfigDecoder{},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type configService struct {
|
||||||
|
Encoder configEncoder
|
||||||
|
Decoder configDecoder
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *configService) Save(filename string, c *Config) error {
|
||||||
|
err := os.MkdirAll(filepath.Dir(filename), 0771)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
w, err := os.OpenFile(filename, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0600)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer w.Close()
|
||||||
|
|
||||||
|
return s.Encoder.Encode(w, c)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *configService) Load(filename string, c *Config) error {
|
||||||
|
r, err := os.Open(filename)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer r.Close()
|
||||||
|
|
||||||
|
return s.Decoder.Decode(r, c)
|
||||||
|
}
|
|
@ -10,12 +10,12 @@ import (
|
||||||
"github.com/github/hub/fixtures"
|
"github.com/github/hub/fixtures"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestConfigs_loadFrom(t *testing.T) {
|
func TestConfigService_Load(t *testing.T) {
|
||||||
testConfigs := fixtures.SetupTestConfigs()
|
testConfig := fixtures.SetupTestConfigs()
|
||||||
defer testConfigs.TearDown()
|
defer testConfig.TearDown()
|
||||||
|
|
||||||
cc := &Configs{}
|
cc := &Config{}
|
||||||
err := loadFrom(testConfigs.Path, cc)
|
err := newConfigService().Load(testConfig.Path, cc)
|
||||||
assert.Equal(t, nil, err)
|
assert.Equal(t, nil, err)
|
||||||
|
|
||||||
assert.Equal(t, 1, len(cc.Hosts))
|
assert.Equal(t, 1, len(cc.Hosts))
|
||||||
|
@ -26,7 +26,7 @@ func TestConfigs_loadFrom(t *testing.T) {
|
||||||
assert.Equal(t, "http", host.Protocol)
|
assert.Equal(t, "http", host.Protocol)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestConfigs_saveTo(t *testing.T) {
|
func TestConfigService_Save(t *testing.T) {
|
||||||
file, _ := ioutil.TempFile("", "test-gh-config-")
|
file, _ := ioutil.TempFile("", "test-gh-config-")
|
||||||
defer os.RemoveAll(file.Name())
|
defer os.RemoveAll(file.Name())
|
||||||
|
|
||||||
|
@ -36,9 +36,9 @@ func TestConfigs_saveTo(t *testing.T) {
|
||||||
AccessToken: "123",
|
AccessToken: "123",
|
||||||
Protocol: "https",
|
Protocol: "https",
|
||||||
}
|
}
|
||||||
c := Configs{Hosts: []Host{host}}
|
c := Config{Hosts: []Host{host}}
|
||||||
|
|
||||||
err := saveTo(file.Name(), &c)
|
err := newConfigService().Save(file.Name(), &c)
|
||||||
assert.Equal(t, nil, err)
|
assert.Equal(t, nil, err)
|
||||||
|
|
||||||
b, _ := ioutil.ReadFile(file.Name())
|
b, _ := ioutil.ReadFile(file.Name())
|
|
@ -151,7 +151,7 @@ func newProject(owner, name, host, protocol string) *Project {
|
||||||
protocol = ""
|
protocol = ""
|
||||||
}
|
}
|
||||||
if protocol == "" {
|
if protocol == "" {
|
||||||
h := CurrentConfigs().Find(host)
|
h := CurrentConfig().Find(host)
|
||||||
if h != nil {
|
if h != nil {
|
||||||
protocol = h.Protocol
|
protocol = h.Protocol
|
||||||
}
|
}
|
||||||
|
@ -161,7 +161,7 @@ func newProject(owner, name, host, protocol string) *Project {
|
||||||
}
|
}
|
||||||
|
|
||||||
if owner == "" {
|
if owner == "" {
|
||||||
h := CurrentConfigs().Find(host)
|
h := CurrentConfig().Find(host)
|
||||||
if h != nil {
|
if h != nil {
|
||||||
owner = h.User
|
owner = h.User
|
||||||
}
|
}
|
||||||
|
|
Загрузка…
Ссылка в новой задаче