From 355fd7aa53d5d4036113637443c0e15ab4a75554 Mon Sep 17 00:00:00 2001 From: Norwin Date: Sat, 7 Nov 2020 15:00:03 +0800 Subject: [PATCH] `tea pr checkout`: fetch via ssh if available (#192) improved logging try to use local branch before creating pulls/ 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 Co-authored-by: Norwin Roosen Reviewed-on: https://gitea.com/gitea/tea/pulls/192 Reviewed-by: 6543 <6543@noreply.gitea.io> Reviewed-by: Lunny Xiao Co-Authored-By: Norwin Co-Committed-By: Norwin --- cmd/pulls/checkout.go | 58 ++++++++++++++++++++++++++++--------------- 1 file changed, 38 insertions(+), 20 deletions(-) diff --git a/cmd/pulls/checkout.go b/cmd/pulls/checkout.go index 389df33..d93d429 100644 --- a/cmd/pulls/checkout.go +++ b/cmd/pulls/checkout.go @@ -13,6 +13,7 @@ import ( local_git "code.gitea.io/tea/modules/git" "code.gitea.io/tea/modules/utils" + "code.gitea.io/sdk/gitea" "github.com/go-git/go-git/v5" "github.com/urfave/cli/v2" ) @@ -32,40 +33,33 @@ func runPullsCheckout(ctx *cli.Context) error { if ctx.Args().Len() != 1 { log.Fatal("Must specify a PR index") } - - // fetch PR source-repo & -branch from gitea idx, err := utils.ArgToIndex(ctx.Args().First()) if err != nil { return err } - pr, _, err := login.Client().GetPullRequest(owner, repo, idx) + + localRepo, err := local_git.RepoForWorkdir() if err != nil { return err } - remoteURL := pr.Head.Repository.CloneURL - remoteBranchName := pr.Head.Ref - // open local git repo - localRepo, err := local_git.RepoForWorkdir() + localBranchName, remoteBranchName, newRemoteName, remoteURL, err := + gitConfigForPR(localRepo, login, owner, repo, idx) if err != nil { - return nil + return err } // 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) if err != nil { return err } - 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", idx, remoteURL, remoteBranchName, localRemoteName) - - url, err := local_git.ParseURL(localRemote.Config().URLs[0]) + url, err := local_git.ParseURL(remoteURL) if err != nil { return err } @@ -73,7 +67,6 @@ func runPullsCheckout(ctx *cli.Context) error { if err != nil { return err } - err = localRemote.Fetch(&git.FetchOptions{Auth: auth}) if err == git.NoErrAlreadyUpToDate { fmt.Println(err) @@ -85,13 +78,38 @@ func runPullsCheckout(ctx *cli.Context) error { fmt.Printf("Creating branch '%s'\n", localBranchName) err = localRepo.TeaCreateBranch(localBranchName, remoteBranchName, localRemoteName) 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 { return err } - fmt.Printf("Checking out PR %v\n", idx) - err = localRepo.TeaCheckout(localBranchName) - - return err + return localRepo.TeaCheckout(localBranchName) +} + +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 }