commands/mr/checkout/mr_checkout.go (105 lines of code) (raw):
package checkout
import (
"fmt"
"strings"
"github.com/MakeNowJust/heredoc/v2"
"github.com/spf13/cobra"
gitlab "gitlab.com/gitlab-org/api/client-go"
"gitlab.com/gitlab-org/cli/api"
"gitlab.com/gitlab-org/cli/commands/cmdutils"
"gitlab.com/gitlab-org/cli/commands/mr/mrutils"
"gitlab.com/gitlab-org/cli/pkg/git"
)
type mrCheckoutConfig struct {
branch string
track bool
upstream string
}
var mrCheckoutCfg mrCheckoutConfig
func NewCmdCheckout(f *cmdutils.Factory) *cobra.Command {
mrCheckoutCmd := &cobra.Command{
Use: "checkout [<id> | <branch>]",
Short: "Check out an open merge request.",
Long: ``,
Example: heredoc.Doc(`
- glab mr checkout 1
- glab mr checkout branch
- glab mr checkout 12 --branch todo-fix
- glab mr checkout new-feature --set-upstream-to=upstream/main
Uses the checked-out branch
- glab mr checkout
`),
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
var err error
var upstream string
if mrCheckoutCfg.upstream != "" {
upstream = mrCheckoutCfg.upstream
if val := strings.Split(mrCheckoutCfg.upstream, "/"); len(val) > 1 {
// Verify that we have the remote set
repo, err := f.Remotes()
if err != nil {
return err
}
_, err = repo.FindByName(val[0])
if err != nil {
return err
}
}
}
apiClient, err := f.HttpClient()
if err != nil {
return err
}
mr, _, err := mrutils.MRFromArgs(f, args, "any")
if err != nil {
return err
}
if mrCheckoutCfg.branch == "" {
mrCheckoutCfg.branch = mr.SourceBranch
}
var mrRef string
var mrProject *gitlab.Project
mrProject, err = api.GetProject(apiClient, mr.SourceProjectID)
if err != nil {
// If we don't have access to the source project, let's try the target project
mrProject, err = api.GetProject(apiClient, mr.TargetProjectID)
if err != nil {
return err
} else {
// We found the target project, let's find the ref another way
mrRef = fmt.Sprintf("refs/merge-requests/%d/head", mr.IID)
}
} else {
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
var gr git.StandardGitCommand
if err := git.CheckoutBranch(mrCheckoutCfg.branch, gr); err != nil {
return err
}
// Check out the branch
if upstream != "" {
if err := git.RunCmd([]string{"branch", "--set-upstream-to", upstream}); err != nil {
return err
}
}
return nil
},
}
mrCheckoutCmd.Flags().StringVarP(&mrCheckoutCfg.branch, "branch", "b", "", "Check out merge request with name <branch>.")
mrCheckoutCmd.Flags().BoolVarP(&mrCheckoutCfg.track, "track", "t", true, "Set checked out branch to track the 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
}