diff --git a/README.md b/README.md index b391467..eeecb1f 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,11 @@ _zit_ chooses a git identity based on: 2. repository owner 3. repository name -… as defined in the configuration file: +… as defined in the configuration file. + +2 types of configuration files are supported: + +**Jsonnet** ```jsonnet local User(name, email) = { name: name, email: email }; @@ -36,6 +40,31 @@ local user = { } ``` +**YAML** + +```yaml +users: + work: &work_user + name: John Doe + email: john.doe@corp.com + personal: + github_user: &personal_github_user + name: JD42 + email: JD42@users.noreply.github.com + gitlab_user: &personal_gitlab_user + name: JD42 + email: 786972-JD42@users.noreply.gitlab.com + +hosts: + github.com: + default: *personal_github_user + overrides: + - owner: corp + user: *work_user + gitlab.com: + default: *personal_gitlab_user +``` + ## Setup There are 2 ways to set up a configuration file: @@ -45,6 +74,8 @@ There are 2 ways to set up a configuration file: ```bash export ZIT_CONFIG=~/.zit-config.jsonnet +# or +export ZIT_CONFIG=~/.zit-config.yaml ``` If the environment variable is set up, it will be chosen over the config at the diff --git a/config/config.go b/config/config.go index 4d1c42b..1325560 100644 --- a/config/config.go +++ b/config/config.go @@ -31,16 +31,6 @@ func (err *ErrConfigNotFound) Error() string { // HostMap TODO type HostMap map[string]Config -// Get TODO -func (hm *HostMap) Get(host string) (*Config, error) { - conf, ok := (*hm)[host] - if !ok { - return nil, fmt.Errorf("cannot find config for host %q", host) - } - - return &conf, nil -} - // Config TODO type Config struct { Default *User `json:"default"` @@ -49,19 +39,19 @@ type Config struct { // User TODO type User struct { - Name string `json:"name"` - Email string `json:"email"` + Name string `json:"name" yaml:"name"` + Email string `json:"email" yaml:"email"` } // Override TODO type Override struct { - Owner string `json:"owner"` - Repo string `json:"repo,omitempty"` - User User `json:"user"` + Owner string `json:"owner" yaml:"owner"` + Repo string `json:"repo,omitempty" yaml:"repo"` + User User `json:"user" yaml:"user"` } // ReadHostMap TODO -func ReadHostMap(filename string, r io.Reader) (*HostMap, error) { +func readHostMap(filename string, r io.Reader) (*HostMap, error) { buf := new(bytes.Buffer) buf.ReadFrom(r) confStr := buf.String() @@ -114,3 +104,18 @@ func LocateConfFile() (string, error) { return confPath, nil } + +// --- + +func toV2(hostMap *HostMap) *ConfigV2 { + configV2 := ConfigV2{ + Hosts: map[string]HostV2{}, + } + for host, hostConfig := range *hostMap { + configV2.Hosts[host] = HostV2{ + Default: hostConfig.Default, + Overrides: hostConfig.Overrides, + } + } + return &configV2 +} diff --git a/config/config_v2.go b/config/config_v2.go new file mode 100644 index 0000000..3251af0 --- /dev/null +++ b/config/config_v2.go @@ -0,0 +1,22 @@ +package config + +import "fmt" + +type ConfigV2 struct { + Hosts map[string]HostV2 `yaml:"hosts"` +} + +type HostV2 struct { + Default *User `yaml:"default"` + Overrides []Override `yaml:"overrides"` +} + +// Get TODO +func (c *ConfigV2) Get(host string) (*HostV2, error) { + hostConf, ok := (*&c.Hosts)[host] + if !ok { + return nil, fmt.Errorf("cannot find config for host %q", host) + } + + return &hostConf, nil +} diff --git a/config/load.go b/config/load.go new file mode 100644 index 0000000..ce41b6a --- /dev/null +++ b/config/load.go @@ -0,0 +1,38 @@ +package config + +import ( + "bytes" + "fmt" + "os" + "strings" +) + +func Load(filename string) (*ConfigV2, error) { + isYaml := strings.HasSuffix(filename, ".yaml") + isJsonnet := strings.HasSuffix(filename, ".jsonnet") + + if !isYaml && !isJsonnet { + return nil, fmt.Errorf("unsupported config format") + } + + r, err := os.Open(filename) + if err != nil { + return nil, err + } + + if isYaml { + buf := new(bytes.Buffer) + buf.ReadFrom(r) + confStr := buf.String() + return parseYaml(confStr) + } else if isJsonnet { + hostMap, err := readHostMap(filename, r) + if err != nil { + return nil, err + } + configV2 := toV2(hostMap) + return configV2, nil + } else { + return nil, fmt.Errorf("something went horribly wrong") + } +} diff --git a/config/yaml.go b/config/yaml.go new file mode 100644 index 0000000..ad7721e --- /dev/null +++ b/config/yaml.go @@ -0,0 +1,13 @@ +package config + +import ( + "gopkg.in/yaml.v2" +) + +func parseYaml(s string) (*ConfigV2, error) { + var config ConfigV2 + if err := yaml.Unmarshal([]byte(s), &config); err != nil { + return nil, err + } + return &config, nil +} diff --git a/config/yaml_test.go b/config/yaml_test.go new file mode 100644 index 0000000..3451b35 --- /dev/null +++ b/config/yaml_test.go @@ -0,0 +1,38 @@ +package config + +import ( + "testing" +) + +func TestParseYaml(t *testing.T) { + + // TODO: improve this test + t.Run("test YAML config parsing", func(t *testing.T) { + s := `users: + work: &work_user + name: John Doe + email: john.doe@corp.com + personal: + github_user: &personal_github_user + name: JD42 + email: JD42@users.noreply.github.com + gitlab_user: &personal_gitlab_user + name: JD42 + email: 786972-JD42@users.noreply.gitlab.com + +hosts: + github.com: + default: *personal_github_user + overrides: + - owner: corp + user: *work_user + + gitlab.com: + default: *personal_gitlab_user` + + _, err := parseYaml(s) + if err != nil { + t.Errorf("%+v", err) + } + }) +} diff --git a/go.mod b/go.mod index 249aad1..890fe64 100644 --- a/go.mod +++ b/go.mod @@ -6,4 +6,5 @@ require ( github.com/google/go-jsonnet v0.17.0 github.com/spf13/cobra v1.1.3 github.com/whilp/git-urls v1.0.0 + gopkg.in/yaml.v2 v2.4.0 ) diff --git a/go.sum b/go.sum index a9a9f51..308d3ee 100644 --- a/go.sum +++ b/go.sum @@ -293,6 +293,7 @@ gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bl gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/identity/identity.go b/identity/identity.go index 740a1a8..784e448 100644 --- a/identity/identity.go +++ b/identity/identity.go @@ -5,11 +5,11 @@ import ( "zit/git" ) -func findBestMatch(conf config.Config, repo git.RepoInfo) (user *config.User) { +func findBestMatch(conf config.HostV2, repo git.RepoInfo) (user *config.User) { if conf.Default != nil { user = &config.User{ - conf.Default.Name, - conf.Default.Email, + Name: conf.Default.Name, + Email: conf.Default.Email, } } @@ -18,8 +18,8 @@ func findBestMatch(conf config.Config, repo git.RepoInfo) (user *config.User) { if override.Repo != "" { if override.Owner == repo.Owner && override.Repo == repo.Name { user = &config.User{ - override.User.Name, - override.User.Email, + Name: override.User.Name, + Email: override.User.Email, } break } else { @@ -29,8 +29,8 @@ func findBestMatch(conf config.Config, repo git.RepoInfo) (user *config.User) { if override.Owner == repo.Owner { user = &config.User{ - override.User.Name, - override.User.Email, + Name: override.User.Name, + Email: override.User.Email, } break } diff --git a/identity/identity_test.go b/identity/identity_test.go index 9c0bfea..f88dd91 100644 --- a/identity/identity_test.go +++ b/identity/identity_test.go @@ -30,7 +30,7 @@ func TestFindBestMatch(t *testing.T) { } t.Run("match default user", func(t *testing.T) { - conf := config.Config{ + conf := config.HostV2{ Default: &defaultUser, Overrides: []config.Override{ { @@ -56,7 +56,7 @@ func TestFindBestMatch(t *testing.T) { }) t.Run("match owner override", func(t *testing.T) { - conf := config.Config{ + conf := config.HostV2{ Default: &defaultUser, Overrides: []config.Override{ { @@ -82,7 +82,7 @@ func TestFindBestMatch(t *testing.T) { }) t.Run("match repo override", func(t *testing.T) { - conf := config.Config{ + conf := config.HostV2{ Default: &defaultUser, Overrides: []config.Override{ { @@ -108,7 +108,7 @@ func TestFindBestMatch(t *testing.T) { }) t.Run("match repo and owner override", func(t *testing.T) { - conf := config.Config{ + conf := config.HostV2{ Default: &defaultUser, Overrides: []config.Override{ { diff --git a/identity/set.go b/identity/set.go index 3199770..754dda3 100644 --- a/identity/set.go +++ b/identity/set.go @@ -22,10 +22,7 @@ var SetCmd = &cobra.Command{ confPath, err := config.LocateConfFile() cli.PrintlnExit(err) - confFile, err := os.Open(confPath) - cli.PrintlnExit(err) - - hostMap, err := config.ReadHostMap(confPath, confFile) + conf, err := config.Load(confPath) cli.PrintlnExit(err) host, err := git.RemoteURL("origin") @@ -47,10 +44,10 @@ defined in the configuration file: repo, err := git.ExtractRepoInfo(host) cli.PrintlnExit(err) - conf, err := hostMap.Get((*repo).Host) + hostConf, err := conf.Get((*repo).Host) cli.PrintlnExit(err) - cred := findBestMatch(*conf, *repo) + cred := findBestMatch(*hostConf, *repo) if cred == nil { cli.PrintlnExit(fmt.Errorf("cannot find a match for host %q", (*repo).Host)) } diff --git a/version/version.txt b/version/version.txt index 9e5bb93..b1d18bc 100644 --- a/version/version.txt +++ b/version/version.txt @@ -1 +1 @@ -v2.2.0+1 +v2.3.0