add tea pulls [checkout | clean] commands (#93 #97 #107) (#105)

Merge branch 'master' into issue-97/pulls-clean

vendor terminal dependency

pull/push: provide authentication method

automatically select an AuthMethod according to the
remote url type. If required, credentials are prompted for

login: store username & optional keyfile

refactor

refactor GetRemote

Merge branch 'master' into issue-97/pulls-clean

adress code review

add --ignore-sha flag

When set, the local branch is not matched against the remote sha,
but the remote branch name. This makes the command more flexible
with diverging branches.

add missing error check

fix branch-not-found case

Merge branch 'master' into issue-97/pulls-clean

use directory namespaces for branches & remotes

fix TeaCreateBranch()

improve method of TeaFindBranch()

now only checking .git/refs instead of looking up .git/config which may
not list the branch

add `tea pulls clean`

fixes #97

add copyright to new files

make linter happy

refactor: use new git functions for old code

add `tea pulls checkout`

Co-authored-by: Norwin Roosen <git@nroo.de>
Co-authored-by: Norwin <git@nroo.de>
Reviewed-on: https://gitea.com/gitea/tea/pulls/105
Reviewed-by: 6543 <6543@noreply.gitea.io>
Reviewed-by: Lunny Xiao <xiaolunwen@gmail.com>
This commit is contained in:
Norwin
2020-04-19 03:09:03 +00:00
committed by Lunny Xiao
parent 81fa4e78ff
commit 4cda7e0299
23 changed files with 2050 additions and 92 deletions

117
modules/git/auth.go Normal file
View File

@ -0,0 +1,117 @@
// Copyright 2020 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package git
import (
"bufio"
"fmt"
"io/ioutil"
"net/url"
"os"
"os/user"
"path/filepath"
"strings"
"golang.org/x/crypto/ssh"
"golang.org/x/crypto/ssh/terminal"
git_transport "gopkg.in/src-d/go-git.v4/plumbing/transport"
gogit_http "gopkg.in/src-d/go-git.v4/plumbing/transport/http"
gogit_ssh "gopkg.in/src-d/go-git.v4/plumbing/transport/ssh"
)
// GetAuthForURL returns the appropriate AuthMethod to be used in Push() / Pull()
// operations depending on the protocol, and prompts the user for credentials if
// necessary.
func GetAuthForURL(remoteURL *url.URL, httpUser, keyFile string) (auth git_transport.AuthMethod, err error) {
user := remoteURL.User.Username()
switch remoteURL.Scheme {
case "https":
if httpUser != "" {
user = httpUser
}
if user == "" {
user, err = promptUser(remoteURL.Host)
if err != nil {
return nil, err
}
}
pass, isSet := remoteURL.User.Password()
if !isSet {
pass, err = promptPass(remoteURL.Host)
if err != nil {
return nil, err
}
}
auth = &gogit_http.BasicAuth{Password: pass, Username: user}
case "ssh":
// try to select right key via ssh-agent. if it fails, try to read a key manually
auth, err = gogit_ssh.DefaultAuthBuilder(user)
if err != nil {
signer, err := readSSHPrivKey(keyFile)
if err != nil {
return nil, err
}
auth = &gogit_ssh.PublicKeys{User: user, Signer: signer}
}
default:
return nil, fmt.Errorf("don't know how to handle url scheme %v", remoteURL.Scheme)
}
return auth, nil
}
func readSSHPrivKey(keyFile string) (sig ssh.Signer, err error) {
if keyFile != "" {
keyFile, err = absPathWithExpansion(keyFile)
} else {
keyFile, err = absPathWithExpansion("~/.ssh/id_rsa")
}
if err != nil {
return nil, err
}
sshKey, err := ioutil.ReadFile(keyFile)
if err != nil {
return nil, err
}
sig, err = ssh.ParsePrivateKey(sshKey)
if err != nil {
pass, err := promptPass(keyFile)
sig, err = ssh.ParsePrivateKeyWithPassphrase(sshKey, []byte(pass))
if err != nil {
return nil, err
}
}
return sig, err
}
func promptUser(domain string) (string, error) {
reader := bufio.NewReader(os.Stdin)
fmt.Printf("%s username: ", domain)
username, err := reader.ReadString('\n')
return strings.TrimSpace(username), err
}
func promptPass(domain string) (string, error) {
fmt.Printf("%s password: ", domain)
pass, err := terminal.ReadPassword(0)
return string(pass), err
}
func absPathWithExpansion(p string) (string, error) {
u, err := user.Current()
if err != nil {
return "", err
}
if p == "~" {
return u.HomeDir, nil
} else if strings.HasPrefix(p, "~/") {
return filepath.Join(u.HomeDir, p[2:]), nil
} else {
return filepath.Abs(p)
}
}