1package cmd
2
3import (
4	"fmt"
5
6	"github.com/git-town/git-town/src/cli"
7	"github.com/git-town/git-town/src/git"
8	"github.com/git-town/git-town/src/prompt"
9	"github.com/git-town/git-town/src/steps"
10
11	"github.com/spf13/cobra"
12)
13
14var promptForParent bool
15
16var hackCmd = &cobra.Command{
17	Use:   "hack <branch>",
18	Short: "Creates a new feature branch off the main development branch",
19	Long: `Creates a new feature branch off the main development branch
20
21Syncs the main branch,
22forks a new feature branch with the given name off the main branch,
23pushes the new feature branch to the remote repository
24(if and only if "new-branch-push-flag" is true),
25and brings over all uncommitted changes to the new feature branch.
26
27See "sync" for information regarding remote upstream.`,
28	Run: func(cmd *cobra.Command, args []string) {
29		config, err := getHackConfig(args, prodRepo)
30		if err != nil {
31			cli.Exit(err)
32		}
33		stepList, err := getAppendStepList(config, prodRepo)
34		if err != nil {
35			cli.Exit(err)
36		}
37		runState := steps.NewRunState("hack", stepList)
38		err = steps.Run(runState, prodRepo, nil)
39		if err != nil {
40			cli.Exit(err)
41		}
42	},
43	Args: cobra.ExactArgs(1),
44	PreRunE: func(cmd *cobra.Command, args []string) error {
45		if err := ValidateIsRepository(prodRepo); err != nil {
46			return err
47		}
48		return validateIsConfigured(prodRepo)
49	},
50}
51
52func getParentBranch(targetBranch string, repo *git.ProdRepo) (string, error) {
53	if promptForParent {
54		parentBranch, err := prompt.AskForBranchParent(targetBranch, repo.Config.GetMainBranch(), repo)
55		if err != nil {
56			return "", err
57		}
58		err = prompt.EnsureKnowsParentBranches([]string{parentBranch}, repo)
59		if err != nil {
60			return "", err
61		}
62		return parentBranch, nil
63	}
64	return repo.Config.GetMainBranch(), nil
65}
66
67func getHackConfig(args []string, repo *git.ProdRepo) (result appendConfig, err error) {
68	result.targetBranch = args[0]
69	result.parentBranch, err = getParentBranch(result.targetBranch, repo)
70	if err != nil {
71		return result, err
72	}
73	result.hasOrigin, err = repo.Silent.HasRemote("origin")
74	if err != nil {
75		return result, err
76	}
77	result.shouldNewBranchPush = repo.Config.ShouldNewBranchPush()
78	result.isOffline = repo.Config.IsOffline()
79	if result.hasOrigin && !repo.Config.IsOffline() {
80		err := repo.Logging.Fetch()
81		if err != nil {
82			return result, err
83		}
84	}
85	hasBranch, err := repo.Silent.HasLocalOrRemoteBranch(result.targetBranch)
86	if err != nil {
87		return result, err
88	}
89	if hasBranch {
90		return result, fmt.Errorf("a branch named %q already exists", result.targetBranch)
91	}
92	return
93}
94
95func init() {
96	hackCmd.Flags().BoolVarP(&promptForParent, "prompt", "p", false, "Prompt for the parent branch")
97	RootCmd.AddCommand(hackCmd)
98}
99