diff --git a/cmd/pulls.go b/cmd/pulls.go index c9afcb4..f10954f 100644 --- a/cmd/pulls.go +++ b/cmd/pulls.go @@ -341,13 +341,20 @@ func runPullsCreate(ctx *cli.Context) error { repo, _, err := login.Client().GetRepo(ownerArg, repoArg) if err != nil { - log.Fatal(err) + log.Fatal("could not fetch repo meta: ", err) } // open local git repo localRepo, err := local_git.RepoForWorkdir() if err != nil { - log.Fatal(err) + log.Fatal("could not open local repo: ", err) + } + + // push if possible + log.Println("git push") + err = localRepo.Push(&git.PushOptions{}) + if err != nil && err != git.NoErrAlreadyUpToDate { + log.Printf("Error occurred during 'git push':\n%s\n", err.Error()) } base := ctx.String("base") @@ -359,10 +366,35 @@ func runPullsCreate(ctx *cli.Context) error { head := ctx.String("head") // default is current one if len(head) == 0 { - head, err = localRepo.TeaGetCurrentBranchName() + headBranch, err := localRepo.Head() if err != nil { log.Fatal(err) } + sha := headBranch.Hash().String() + + remote, err := localRepo.TeaFindBranchRemote("", sha) + if err != nil { + return err + } + + if remote == nil { + // if no remote branch is found for the local hash, we abort: + // user has probably not configured a remote for the local branch, + // or local branch does not represent remote state. + log.Fatal("no matching remote found for this branch. try git push -u ") + } + + branchName, err := localRepo.TeaGetCurrentBranchName() + if err != nil { + log.Fatal(err) + } + + url, err := local_git.ParseURL(remote.Config().URLs[0]) + if err != nil { + log.Fatal(err) + } + owner, _ := getOwnerAndRepo(strings.TrimLeft(url.Path, "/"), "") + head = fmt.Sprintf("%s:%s", owner, branchName) } title := ctx.String("title") @@ -382,12 +414,6 @@ func runPullsCreate(ctx *cli.Context) error { return nil } - // push if possible - err = localRepo.Push(&git.PushOptions{}) - if err != nil { - fmt.Printf("Error occurred during 'git push':\n%s\n", err.Error()) - } - pr, _, err := client.CreatePullRequest(ownerArg, repoArg, gitea.CreatePullRequestOption{ Head: head, Base: base, @@ -396,7 +422,7 @@ func runPullsCreate(ctx *cli.Context) error { }) if err != nil { - log.Fatal(err) + log.Fatal("could not create PR: ", err) } in := fmt.Sprintf("# #%d %s (%s)\n%s created %s\n\n%s\n", pr.Index, diff --git a/modules/git/branch.go b/modules/git/branch.go index 8732cd3..042a18b 100644 --- a/modules/git/branch.go +++ b/modules/git/branch.go @@ -176,6 +176,48 @@ func (r TeaRepo) TeaFindBranchByName(branchName, repoURL string) (b *git_config. return b, b.Validate() } +// TeaFindBranchRemote gives the first remote that has a branch with the same name or sha, +// depending on what is passed in. +// This function is needed, as git does not always define branches in .git/config with remote entries. +func (r TeaRepo) TeaFindBranchRemote(branchName, hash string) (*git.Remote, error) { + remotes, err := r.Remotes() + if err != nil { + return nil, err + } + + switch { + case len(remotes) == 0: + return nil, nil + case len(remotes) == 1: + return remotes[0], nil + } + + // check if the given remote has our branch (.git/refs/remotes//*) + iter, err := r.References() + if err != nil { + return nil, err + } + defer iter.Close() + + var match *git.Remote + err = iter.ForEach(func(ref *git_plumbing.Reference) error { + if ref.Name().IsRemote() { + names := strings.SplitN(ref.Name().Short(), "/", 2) + remote := names[0] + branch := names[1] + hashMatch := hash != "" && hash == ref.Hash().String() + nameMatch := branchName != "" && branchName == branch + if hashMatch || nameMatch { + match, err = r.Remote(remote) + return err + } + } + return nil + }) + + return match, err +} + // TeaGetCurrentBranchName return the name of the branch witch is currently active func (r TeaRepo) TeaGetCurrentBranchName() (string, error) { localHead, err := r.Head()