Skip to content

Commit

Permalink
Extend init command to guess the user's username for private repos
Browse files Browse the repository at this point in the history
  • Loading branch information
twpayne committed Sep 10, 2021
1 parent 933f141 commit 63610a4
Show file tree
Hide file tree
Showing 2 changed files with 110 additions and 76 deletions.
88 changes: 52 additions & 36 deletions internal/cmd/initcmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,49 +38,58 @@ type initCmdConfig struct {
}

var dotfilesRepoGuesses = []struct {
rx *regexp.Regexp
httpGuessRepl string
sshGuessRepl string
rx *regexp.Regexp
httpRepoGuessRepl string
httpUsernameGuessRepl string
sshRepoGuessRepl string
}{
{
rx: regexp.MustCompile(`\A([-0-9A-Za-z]+)\z`),
httpGuessRepl: "https://github.com/$1/dotfiles.git",
sshGuessRepl: "[email protected]:$1/dotfiles.git",
rx: regexp.MustCompile(`\A([-0-9A-Za-z]+)\z`),
httpRepoGuessRepl: "https://github.com/$1/dotfiles.git",
httpUsernameGuessRepl: "$1",
sshRepoGuessRepl: "[email protected]:$1/dotfiles.git",
},
{
rx: regexp.MustCompile(`\A([-0-9A-Za-z]+/[-0-9A-Za-z]+\.git)\z`),
httpGuessRepl: "https://github.com/$1",
sshGuessRepl: "[email protected]:$1",
rx: regexp.MustCompile(`\A([-0-9A-Za-z]+)/([-0-9A-Za-z]+)(\.git)?\z`),
httpRepoGuessRepl: "https://github.com/$1/$2.git",
httpUsernameGuessRepl: "$1",
sshRepoGuessRepl: "[email protected]:$1/$2.git",
},
{
rx: regexp.MustCompile(`\A([-0-9A-Za-z]+/[-0-9A-Za-z]+)\z`),
httpGuessRepl: "https://github.com/$1.git",
sshGuessRepl: "[email protected]:$1.git",
rx: regexp.MustCompile(`\A([-.0-9A-Za-z]+)/([-0-9A-Za-z]+)\z`),
httpRepoGuessRepl: "https://$1/$2/dotfiles.git",
httpUsernameGuessRepl: "$2",
sshRepoGuessRepl: "git@$1:$2/dotfiles.git",
},
{
rx: regexp.MustCompile(`\A([-.0-9A-Za-z]+)/([-0-9A-Za-z]+)\z`),
httpGuessRepl: "https://$1/$2/dotfiles.git",
sshGuessRepl: "git@$1:$2/dotfiles.git",
rx: regexp.MustCompile(`\A([-0-9A-Za-z]+)/([-0-9A-Za-z]+)/([-.0-9A-Za-z]+)\z`),
httpRepoGuessRepl: "https://$1/$2/$3.git",
httpUsernameGuessRepl: "$2",
sshRepoGuessRepl: "git@$1:$2/$3.git",
},
{
rx: regexp.MustCompile(`\A([-.0-9A-Za-z]+)/([-0-9A-Za-z]+/[-0-9A-Za-z]+)\z`),
httpGuessRepl: "https://$1/$2.git",
sshGuessRepl: "git@$1:$2.git",
rx: regexp.MustCompile(`\A([-.0-9A-Za-z]+)/([-0-9A-Za-z]+)/([-0-9A-Za-z]+)(\.git)?\z`),
httpRepoGuessRepl: "https://$1/$2/$3.git",
httpUsernameGuessRepl: "$2",
sshRepoGuessRepl: "git@$1:$2/$3.git",
},
{
rx: regexp.MustCompile(`\A([-.0-9A-Za-z]+)/([-0-9A-Za-z]+/[-0-9A-Za-z]+\.git)\z`),
httpGuessRepl: "https://$1/$2",
sshGuessRepl: "git@$1:$2",
rx: regexp.MustCompile(`\A(https?://)([-.0-9A-Za-z]+)/([-0-9A-Za-z]+)/([-0-9A-Za-z]+)(\.git)?\z`),
httpRepoGuessRepl: "$1$2/$3/$4.git",
httpUsernameGuessRepl: "$3",
sshRepoGuessRepl: "git@$2:$3/$4.git",
},
{
rx: regexp.MustCompile(`\Asr\.ht/(~[-0-9A-Za-z]+)\z`),
httpGuessRepl: "https://git.sr.ht/$1/dotfiles",
sshGuessRepl: "[email protected]:$1/dotfiles",
rx: regexp.MustCompile(`\Asr\.ht/~([-0-9A-Za-z]+)\z`),
httpRepoGuessRepl: "https://git.sr.ht/~$1/dotfiles",
httpUsernameGuessRepl: "$1",
sshRepoGuessRepl: "[email protected]:~$1/dotfiles",
},
{
rx: regexp.MustCompile(`\Asr\.ht/(~[-0-9A-Za-z]+/[-0-9A-Za-z]+)\z`),
httpGuessRepl: "https://git.sr.ht/$1",
sshGuessRepl: "[email protected]:$1",
rx: regexp.MustCompile(`\Asr\.ht/~([-0-9A-Za-z]+)/([-0-9A-Za-z]+)\z`),
httpRepoGuessRepl: "https://git.sr.ht/~$1/$2",
httpUsernameGuessRepl: "$1",
sshRepoGuessRepl: "[email protected]:~$1/$2",
},
}

Expand Down Expand Up @@ -144,7 +153,7 @@ func (c *Config) runInitCmd(cmd *cobra.Command, args []string) error {
return err
}
} else {
dotfilesRepoURL := guessDotfilesRepoURL(args[0], c.init.ssh)
username, dotfilesRepoURL := guessDotfilesRepoURL(args[0], c.init.ssh)
if useBuiltinGit {
var referenceName plumbing.ReferenceName
if c.init.branch != "" {
Expand All @@ -160,9 +169,12 @@ func (c *Config) runInitCmd(cmd *cobra.Command, args []string) error {
_, err = git.PlainClone(string(rawSourceDir), isBare, &cloneOptions)
if errors.Is(err, transport.ErrAuthenticationRequired) {
var basicAuth http.BasicAuth
if basicAuth.Username, err = c.readLine("Username? "); err != nil {
if basicAuth.Username, err = c.readLine(fmt.Sprintf("Username [default %q]? ", username)); err != nil {
return err
}
if basicAuth.Username == "" {
basicAuth.Username = username
}
if basicAuth.Password, err = c.readPassword("Password? "); err != nil {
return err
}
Expand Down Expand Up @@ -358,18 +370,22 @@ func (c *Config) writeToStdout(args ...string) string {
return ""
}

// guessDotfilesRepoURL guesses the user's dotfile repo from arg.
func guessDotfilesRepoURL(arg string, ssh bool) string {
// guessDotfilesRepoURL guesses the user's username and dotfile repo from arg.
func guessDotfilesRepoURL(arg string, ssh bool) (username, repo string) {
for _, dotfileRepoGuess := range dotfilesRepoGuesses {
if !dotfileRepoGuess.rx.MatchString(arg) {
continue
}
switch {
case ssh && dotfileRepoGuess.sshGuessRepl != "":
return dotfileRepoGuess.rx.ReplaceAllString(arg, dotfileRepoGuess.sshGuessRepl)
case !ssh && dotfileRepoGuess.httpGuessRepl != "":
return dotfileRepoGuess.rx.ReplaceAllString(arg, dotfileRepoGuess.httpGuessRepl)
case ssh && dotfileRepoGuess.sshRepoGuessRepl != "":
repo = dotfileRepoGuess.rx.ReplaceAllString(arg, dotfileRepoGuess.sshRepoGuessRepl)
return
case !ssh && dotfileRepoGuess.httpRepoGuessRepl != "":
username = dotfileRepoGuess.rx.ReplaceAllString(arg, dotfileRepoGuess.httpUsernameGuessRepl)
repo = dotfileRepoGuess.rx.ReplaceAllString(arg, dotfileRepoGuess.httpRepoGuessRepl)
return
}
}
return arg
repo = arg
return
}
98 changes: 58 additions & 40 deletions internal/cmd/initcmd_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,69 +8,87 @@ import (

func TestGuessDotfilesRepoURL(t *testing.T) {
for _, tc := range []struct {
arg string
expectedHTTPSURL string
expectedSSHURL string
arg string
expectedHTTPRepoURL string
expectedHTTPUsername string
expectedSSHRepoURL string
}{
{
arg: "[email protected]:user/dotfiles.git",
arg: "[email protected]:user/dotfiles.git",
expectedHTTPRepoURL: "[email protected]:user/dotfiles.git",
expectedSSHRepoURL: "[email protected]:user/dotfiles.git",
},
{
arg: "gitlab.com/user",
expectedHTTPSURL: "https://gitlab.com/user/dotfiles.git",
expectedSSHURL: "[email protected]:user/dotfiles.git",
arg: "gitlab.com/user",
expectedHTTPRepoURL: "https://gitlab.com/user/dotfiles.git",
expectedHTTPUsername: "user",
expectedSSHRepoURL: "[email protected]:user/dotfiles.git",
},
{
arg: "gitlab.com/user/dots",
expectedHTTPSURL: "https://gitlab.com/user/dots.git",
expectedSSHURL: "[email protected]:user/dots.git",
arg: "gitlab.com/user/dots",
expectedHTTPRepoURL: "https://gitlab.com/user/dots.git",
expectedHTTPUsername: "user",
expectedSSHRepoURL: "[email protected]:user/dots.git",
},
{
arg: "gitlab.com/user/dots.git",
expectedHTTPSURL: "https://gitlab.com/user/dots.git",
expectedSSHURL: "[email protected]:user/dots.git",
arg: "gitlab.com/user/dots.git",
expectedHTTPRepoURL: "https://gitlab.com/user/dots.git",
expectedHTTPUsername: "user",
expectedSSHRepoURL: "[email protected]:user/dots.git",
},
{
arg: "https://gitlab.com/user/dots.git",
expectedHTTPSURL: "https://gitlab.com/user/dots.git",
arg: "http://gitlab.com/user/dots.git",
expectedHTTPRepoURL: "http://gitlab.com/user/dots.git",
expectedHTTPUsername: "user",
expectedSSHRepoURL: "[email protected]:user/dots.git",
},
{
arg: "sr.ht/~user",
expectedHTTPSURL: "https://git.sr.ht/~user/dotfiles",
expectedSSHURL: "[email protected]:~user/dotfiles",
arg: "https://gitlab.com/user/dots.git",
expectedHTTPRepoURL: "https://gitlab.com/user/dots.git",
expectedHTTPUsername: "user",
expectedSSHRepoURL: "[email protected]:user/dots.git",
},
{
arg: "sr.ht/~user/dots",
expectedHTTPSURL: "https://git.sr.ht/~user/dots",
expectedSSHURL: "[email protected]:~user/dots",
arg: "sr.ht/~user",
expectedHTTPRepoURL: "https://git.sr.ht/~user/dotfiles",
expectedHTTPUsername: "user",
expectedSSHRepoURL: "[email protected]:~user/dotfiles",
},
{
arg: "user",
expectedHTTPSURL: "https://github.com/user/dotfiles.git",
expectedSSHURL: "[email protected]:user/dotfiles.git",
arg: "sr.ht/~user/dots",
expectedHTTPRepoURL: "https://git.sr.ht/~user/dots",
expectedHTTPUsername: "user",
expectedSSHRepoURL: "[email protected]:~user/dots",
},
{
arg: "user/dots",
expectedHTTPSURL: "https://github.com/user/dots.git",
expectedSSHURL: "[email protected]:user/dots.git",
arg: "user",
expectedHTTPRepoURL: "https://github.com/user/dotfiles.git",
expectedHTTPUsername: "user",
expectedSSHRepoURL: "[email protected]:user/dotfiles.git",
},
{
arg: "user/dots.git",
expectedHTTPSURL: "https://github.com/user/dots.git",
expectedSSHURL: "[email protected]:user/dots.git",
arg: "user/dots",
expectedHTTPRepoURL: "https://github.com/user/dots.git",
expectedHTTPUsername: "user",
expectedSSHRepoURL: "[email protected]:user/dots.git",
},
{
arg: "user/dots.git",
expectedHTTPRepoURL: "https://github.com/user/dots.git",
expectedHTTPUsername: "user",
expectedSSHRepoURL: "[email protected]:user/dots.git",
},
} {
t.Run(tc.arg, func(t *testing.T) {
expectedHTTPSURL := tc.expectedHTTPSURL
if expectedHTTPSURL == "" {
expectedHTTPSURL = tc.arg
}
assert.Equal(t, expectedHTTPSURL, guessDotfilesRepoURL(tc.arg, false))
expectedSSHURL := tc.expectedSSHURL
if tc.expectedSSHURL == "" {
expectedSSHURL = tc.arg
}
assert.Equal(t, expectedSSHURL, guessDotfilesRepoURL(tc.arg, true))
ssh := false
actualHTTPUsername, actualHTTPRepoURL := guessDotfilesRepoURL(tc.arg, ssh)
assert.Equal(t, tc.expectedHTTPUsername, actualHTTPUsername, "HTTPUsername")
assert.Equal(t, tc.expectedHTTPRepoURL, actualHTTPRepoURL, "HTTPRepoURL")

ssh = true
actualSSHUsername, actualSSHRepoURL := guessDotfilesRepoURL(tc.arg, ssh)
assert.Equal(t, "", actualSSHUsername, "SSHUsername")
assert.Equal(t, tc.expectedSSHRepoURL, actualSSHRepoURL, "SSHRepoURL")
})
}
}

0 comments on commit 63610a4

Please sign in to comment.