tea pr checkout: fetch via ssh if available (#192)

improved logging

try to use local branch before creating pulls/<PR>

useful for checking out your own PRs

reorder imports

refactor pulls checkout

isolated "gitea API to local git cfg" aspect

work around go-git limitation

As we cant manage multiple remote URLs properly, we just set the correct
URL protocol ahead of time.

This logic won't apply for already existing HTTPS remotes, these
should be deleted before using `tea pr checkout`.

use SSH if user has key in gitea

Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: Norwin Roosen <git@nroo.de>
Reviewed-on: https://gitea.com/gitea/tea/pulls/192
Reviewed-by: 6543 <6543@noreply.gitea.io>
Reviewed-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-Authored-By: Norwin <noerw@noreply.gitea.io>
Co-Committed-By: Norwin <noerw@noreply.gitea.io>
This commit is contained in:
Norwin 2020-11-07 15:00:03 +08:00 committed by 6543
parent 33468630e6
commit 355fd7aa53

View File

@ -13,6 +13,7 @@ import (
local_git "code.gitea.io/tea/modules/git" local_git "code.gitea.io/tea/modules/git"
"code.gitea.io/tea/modules/utils" "code.gitea.io/tea/modules/utils"
"code.gitea.io/sdk/gitea"
"github.com/go-git/go-git/v5" "github.com/go-git/go-git/v5"
"github.com/urfave/cli/v2" "github.com/urfave/cli/v2"
) )
@ -32,40 +33,33 @@ func runPullsCheckout(ctx *cli.Context) error {
if ctx.Args().Len() != 1 { if ctx.Args().Len() != 1 {
log.Fatal("Must specify a PR index") log.Fatal("Must specify a PR index")
} }
// fetch PR source-repo & -branch from gitea
idx, err := utils.ArgToIndex(ctx.Args().First()) idx, err := utils.ArgToIndex(ctx.Args().First())
if err != nil { if err != nil {
return err return err
} }
pr, _, err := login.Client().GetPullRequest(owner, repo, idx)
localRepo, err := local_git.RepoForWorkdir()
if err != nil { if err != nil {
return err return err
} }
remoteURL := pr.Head.Repository.CloneURL
remoteBranchName := pr.Head.Ref
// open local git repo localBranchName, remoteBranchName, newRemoteName, remoteURL, err :=
localRepo, err := local_git.RepoForWorkdir() gitConfigForPR(localRepo, login, owner, repo, idx)
if err != nil { if err != nil {
return nil return err
} }
// verify related remote is in local repo, otherwise add it // verify related remote is in local repo, otherwise add it
newRemoteName := fmt.Sprintf("pulls/%v", pr.Head.Repository.Owner.UserName)
localRemote, err := localRepo.GetOrCreateRemote(remoteURL, newRemoteName) localRemote, err := localRepo.GetOrCreateRemote(remoteURL, newRemoteName)
if err != nil { if err != nil {
return err return err
} }
localRemoteName := localRemote.Config().Name localRemoteName := localRemote.Config().Name
localBranchName := fmt.Sprintf("pulls/%v-%v", idx, remoteBranchName)
// fetch remote // get auth & fetch remote
fmt.Printf("Fetching PR %v (head %s:%s) from remote '%s'\n", fmt.Printf("Fetching PR %v (head %s:%s) from remote '%s'\n",
idx, remoteURL, remoteBranchName, localRemoteName) idx, remoteURL, remoteBranchName, localRemoteName)
url, err := local_git.ParseURL(remoteURL)
url, err := local_git.ParseURL(localRemote.Config().URLs[0])
if err != nil { if err != nil {
return err return err
} }
@ -73,7 +67,6 @@ func runPullsCheckout(ctx *cli.Context) error {
if err != nil { if err != nil {
return err return err
} }
err = localRemote.Fetch(&git.FetchOptions{Auth: auth}) err = localRemote.Fetch(&git.FetchOptions{Auth: auth})
if err == git.NoErrAlreadyUpToDate { if err == git.NoErrAlreadyUpToDate {
fmt.Println(err) fmt.Println(err)
@ -85,13 +78,38 @@ func runPullsCheckout(ctx *cli.Context) error {
fmt.Printf("Creating branch '%s'\n", localBranchName) fmt.Printf("Creating branch '%s'\n", localBranchName)
err = localRepo.TeaCreateBranch(localBranchName, remoteBranchName, localRemoteName) err = localRepo.TeaCreateBranch(localBranchName, remoteBranchName, localRemoteName)
if err == git.ErrBranchExists { if err == git.ErrBranchExists {
fmt.Println(err) fmt.Println("There may be changes since you last checked out, run `git pull` to get them.")
} else if err != nil { } else if err != nil {
return err return err
} }
fmt.Printf("Checking out PR %v\n", idx) return localRepo.TeaCheckout(localBranchName)
err = localRepo.TeaCheckout(localBranchName) }
return err func gitConfigForPR(repo *local_git.TeaRepo, login *config.Login, owner, repoName string, idx int64) (localBranch, remoteBranch, remoteName, remoteURL string, err error) {
// fetch PR source-repo & -branch from gitea
pr, _, err := login.Client().GetPullRequest(owner, repoName, idx)
if err != nil {
return
}
// test if we can pull via SSH, and configure git remote accordingly
remoteURL = pr.Head.Repository.CloneURL
keys, _, err := login.Client().ListMyPublicKeys(gitea.ListPublicKeysOptions{})
if err != nil {
return
}
if len(keys) != 0 {
remoteURL = pr.Head.Repository.SSHURL
}
// try to find a matching existing branch, otherwise return branch in pulls/ namespace
localBranch = fmt.Sprintf("pulls/%v-%v", idx, pr.Head.Ref)
if b, _ := repo.TeaFindBranchBySha(pr.Head.Sha, remoteURL); b != nil {
localBranch = b.Name
}
remoteBranch = pr.Head.Ref
remoteName = fmt.Sprintf("pulls/%v", pr.Head.Repository.Owner.UserName)
return
} }