1
0
mirror of https://gitea.com/Sirherobrine23/tea.git synced 2024-07-07 11:35:52 -03:00
tea/cmd/pulls/checkout.go
Norwin 355fd7aa53 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>
2020-11-07 15:00:03 +08:00

116 lines
3.3 KiB
Go

// 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 pulls
import (
"fmt"
"log"
"code.gitea.io/tea/cmd/flags"
"code.gitea.io/tea/modules/config"
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"
)
// CmdPullsCheckout is a command to locally checkout the given PR
var CmdPullsCheckout = cli.Command{
Name: "checkout",
Usage: "Locally check out the given PR",
Description: `Locally check out the given PR`,
Action: runPullsCheckout,
ArgsUsage: "<pull index>",
Flags: flags.AllDefaultFlags,
}
func runPullsCheckout(ctx *cli.Context) error {
login, owner, repo := config.InitCommand(flags.GlobalRepoValue, flags.GlobalLoginValue, flags.GlobalRemoteValue)
if ctx.Args().Len() != 1 {
log.Fatal("Must specify a PR index")
}
idx, err := utils.ArgToIndex(ctx.Args().First())
if err != nil {
return err
}
localRepo, err := local_git.RepoForWorkdir()
if err != nil {
return err
}
localBranchName, remoteBranchName, newRemoteName, remoteURL, err :=
gitConfigForPR(localRepo, login, owner, repo, idx)
if err != nil {
return err
}
// verify related remote is in local repo, otherwise add it
localRemote, err := localRepo.GetOrCreateRemote(remoteURL, newRemoteName)
if err != nil {
return err
}
localRemoteName := localRemote.Config().Name
// 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(remoteURL)
if err != nil {
return err
}
auth, err := local_git.GetAuthForURL(url, login.User, login.SSHKey)
if err != nil {
return err
}
err = localRemote.Fetch(&git.FetchOptions{Auth: auth})
if err == git.NoErrAlreadyUpToDate {
fmt.Println(err)
} else if err != nil {
return err
}
// checkout local branch
fmt.Printf("Creating branch '%s'\n", localBranchName)
err = localRepo.TeaCreateBranch(localBranchName, remoteBranchName, localRemoteName)
if err == git.ErrBranchExists {
fmt.Println("There may be changes since you last checked out, run `git pull` to get them.")
} else if err != nil {
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
}