feat(mr/checkout): Track by default without adding extra remotes

This commit is contained in:
Jan Tojnar 2023-05-31 18:34:04 +00:00 committed by Gary Holtz
parent b4c5bba711
commit 9a450081b9
3 changed files with 63 additions and 39 deletions

View File

@ -1,7 +1,6 @@
package checkout
import (
"errors"
"fmt"
"strings"
@ -28,7 +27,7 @@ func NewCmdCheckout(f *cmdutils.Factory) *cobra.Command {
Long: ``,
Example: heredoc.Doc(`
glab mr checkout 1
glab mr checkout branch --track
glab mr checkout branch
glab mr checkout 12 --branch todo-fix
glab mr checkout new-feature --set-upstream-to=upstream/main
glab mr checkout # use checked out branch
@ -39,11 +38,6 @@ func NewCmdCheckout(f *cmdutils.Factory) *cobra.Command {
var upstream string
if mrCheckoutCfg.upstream != "" {
// Make sure we don't have the mutually exclusive flags --track and --set-upstream-to
if mrCheckoutCfg.track {
return &cmdutils.FlagError{Err: errors.New("--track and --set-upstream-to are mutually exclusive")}
}
upstream = mrCheckoutCfg.upstream
if val := strings.Split(mrCheckoutCfg.upstream, "/"); len(val) > 1 {
@ -64,7 +58,7 @@ func NewCmdCheckout(f *cmdutils.Factory) *cobra.Command {
return err
}
mr, repo, err := mrutils.MRFromArgs(f, args, "any")
mr, _, err := mrutils.MRFromArgs(f, args, "any")
if err != nil {
return err
}
@ -72,40 +66,32 @@ func NewCmdCheckout(f *cmdutils.Factory) *cobra.Command {
if mrCheckoutCfg.branch == "" {
mrCheckoutCfg.branch = mr.SourceBranch
}
fetchToRef := mrCheckoutCfg.branch
if mrCheckoutCfg.track {
if _, err := git.Config("remote." + mr.Author.Username + ".url"); err != nil {
mrProject, err := api.GetProject(apiClient, mr.SourceProjectID)
if err != nil {
return err
}
if _, err := git.AddRemote(mr.Author.Username, mrProject.SSHURLToRepo); err != nil {
return err
}
}
fetchToRef = fmt.Sprintf("refs/remotes/%s/%s", mr.Author.Username, mr.SourceBranch)
}
remotes, err := f.Remotes()
mrProject, err := api.GetProject(apiClient, mr.SourceProjectID)
if err != nil {
fmt.Println(err)
}
repoRemote, err := remotes.FindByRepo(repo.RepoOwner(), repo.RepoName())
if err != nil {
fmt.Println(err)
}
mrRef := fmt.Sprintf("refs/merge-requests/%d/head", mr.IID)
fetchRefSpec := fmt.Sprintf("%s:%s", mrRef, fetchToRef)
if err := git.RunCmd([]string{"fetch", repoRemote.Name, fetchRefSpec}); err != nil {
return err
}
if mrCheckoutCfg.track {
if err := git.RunCmd([]string{"branch", "--track", mrCheckoutCfg.branch, fetchToRef}); err != nil {
mrRef := fmt.Sprintf("refs/heads/%s", mr.SourceBranch)
fetchRefSpec := fmt.Sprintf("%s:%s", mrRef, mrCheckoutCfg.branch)
if err := git.RunCmd([]string{"fetch", mrProject.SSHURLToRepo, fetchRefSpec}); err != nil {
return err
}
// .remote is needed for `git pull` to work
// .pushRemote is needed for `git push` to work, if user has set `remote.pushDefault`.
// see https://git-scm.com/docs/git-config#Documentation/git-config.txt-branchltnamegtremote
if err := git.RunCmd([]string{"config", fmt.Sprintf("branch.%s.remote", mrCheckoutCfg.branch), mrProject.SSHURLToRepo}); err != nil {
return err
}
if mr.AllowCollaboration {
if err := git.RunCmd([]string{"config", fmt.Sprintf("branch.%s.pushRemote", mrCheckoutCfg.branch), mrProject.SSHURLToRepo}); err != nil {
return err
}
}
if err := git.RunCmd([]string{"config", fmt.Sprintf("branch.%s.merge", mrCheckoutCfg.branch), mrRef}); err != nil {
return err
}
// Check out branch
if err := git.CheckoutBranch(mrCheckoutCfg.branch); err != nil {
@ -122,7 +108,8 @@ func NewCmdCheckout(f *cmdutils.Factory) *cobra.Command {
},
}
mrCheckoutCmd.Flags().StringVarP(&mrCheckoutCfg.branch, "branch", "b", "", "checkout merge request with <branch> name")
mrCheckoutCmd.Flags().BoolVarP(&mrCheckoutCfg.track, "track", "t", false, "set checked out branch to track remote branch, adds remote if needed")
mrCheckoutCmd.Flags().BoolVarP(&mrCheckoutCfg.track, "track", "t", true, "set checked out branch to track remote branch")
_ = mrCheckoutCmd.Flags().MarkDeprecated("track", "Now enabled by default")
mrCheckoutCmd.Flags().StringVarP(&mrCheckoutCfg.upstream, "set-upstream-to", "u", "", "set tracking of checked out branch to [REMOTE/]BRANCH")
return mrCheckoutCmd
}

View File

@ -86,15 +86,28 @@ func TestMrCheckout(t *testing.T) {
"id": 123,
"iid": 123,
"project_id": 3,
"source_project_id": 3,
"title": "test mr title",
"description": "test mr description",
"allow_collaboration": false,
"state": "opened",
"source_branch":"feat-new-mr"
}`,
},
{
http.MethodGet,
"/api/v4/projects/3",
http.StatusOK,
`{
"id": 3,
"ssh_url_to_repo": "git@gitlab.com:OWNER/REPO.git"
}`,
},
},
shelloutStubs: []string{
"HEAD branch: master\n",
"\n",
"\n",
heredoc.Doc(`
deadbeef HEAD
deadb00f refs/remotes/upstream/feat-new-mr
@ -102,7 +115,12 @@ func TestMrCheckout(t *testing.T) {
`),
},
expectedShellouts: []string{"git fetch upstream refs/merge-requests/123/head:feat-new-mr", "git checkout feat-new-mr"},
expectedShellouts: []string{
"git fetch git@gitlab.com:OWNER/REPO.git refs/heads/feat-new-mr:feat-new-mr",
"git config branch.feat-new-mr.remote git@gitlab.com:OWNER/REPO.git",
"git config branch.feat-new-mr.merge refs/heads/feat-new-mr",
"git checkout feat-new-mr",
},
},
{
name: "when a valid MR is checked out using MR id and specifying branch",
@ -117,15 +135,29 @@ func TestMrCheckout(t *testing.T) {
"id": 123,
"iid": 123,
"project_id": 3,
"source_project_id": 4,
"title": "test mr title",
"description": "test mr description",
"allow_collaboration": true,
"state": "opened",
"source_branch":"feat-new-mr"
}`,
},
{
http.MethodGet,
"/api/v4/projects/4",
http.StatusOK,
`{
"id": 3,
"ssh_url_to_repo": "git@gitlab.com:FORK_OWNER/REPO.git"
}`,
},
},
shelloutStubs: []string{
"HEAD branch: master\n",
"\n",
"\n",
"\n",
heredoc.Doc(`
deadbeef HEAD
deadb00f refs/remotes/upstream/feat-new-mr
@ -133,7 +165,13 @@ func TestMrCheckout(t *testing.T) {
`),
},
expectedShellouts: []string{"git fetch upstream refs/merge-requests/123/head:foo", "git checkout foo"},
expectedShellouts: []string{
"git fetch git@gitlab.com:FORK_OWNER/REPO.git refs/heads/feat-new-mr:foo",
"git config branch.foo.remote git@gitlab.com:FORK_OWNER/REPO.git",
"git config branch.foo.pushRemote git@gitlab.com:FORK_OWNER/REPO.git",
"git config branch.foo.merge refs/heads/feat-new-mr",
"git checkout foo",
},
},
}

View File

@ -21,7 +21,7 @@ glab mr checkout [<id> | <branch>] [flags]
```plaintext
glab mr checkout 1
glab mr checkout branch --track
glab mr checkout branch
glab mr checkout 12 --branch todo-fix
glab mr checkout new-feature --set-upstream-to=upstream/main
glab mr checkout # use checked out branch
@ -33,7 +33,6 @@ glab mr checkout # use checked out branch
```plaintext
-b, --branch string checkout merge request with <branch> name
-u, --set-upstream-to string set tracking of checked out branch to [REMOTE/]BRANCH
-t, --track set checked out branch to track remote branch, adds remote if needed
```
## Options inherited from parent commands