1package cmd 2 3import ( 4 "errors" 5 "fmt" 6 7 "github.com/git-town/git-town/src/drivers" 8 "github.com/git-town/git-town/src/git" 9 "github.com/git-town/git-town/src/prompt" 10 "github.com/git-town/git-town/src/steps" 11) 12 13// These variables represent command-line flags. 14var ( 15 allFlag, 16 debugFlag, 17 dryRunFlag, 18 globalFlag bool 19 prodRepo = git.NewProdRepo() 20) 21 22// These variables are set at build time. 23var ( 24 version string 25 buildDate string 26) 27 28const dryRunFlagDescription = "Print the commands but don't run them" 29 30func validateIsConfigured(repo *git.ProdRepo) error { 31 err := prompt.EnsureIsConfigured(repo) 32 if err != nil { 33 return err 34 } 35 return repo.RemoveOutdatedConfiguration() 36} 37 38// ValidateIsRepository asserts that the current directory is in a Git repository. 39// If so, it also navigates to the root directory. 40func ValidateIsRepository(repo *git.ProdRepo) error { 41 if repo.Silent.IsRepository() { 42 return repo.NavigateToRootIfNecessary() 43 } 44 return errors.New("this is not a Git repository") 45} 46 47func getAppendStepList(config appendConfig, repo *git.ProdRepo) (result steps.StepList, err error) { 48 for _, branchName := range append(config.ancestorBranches, config.parentBranch) { 49 steps, err := steps.GetSyncBranchSteps(branchName, true, repo) 50 if err != nil { 51 return result, err 52 } 53 result.AppendList(steps) 54 } 55 result.Append(&steps.CreateBranchStep{BranchName: config.targetBranch, StartingPoint: config.parentBranch}) 56 result.Append(&steps.SetParentBranchStep{BranchName: config.targetBranch, ParentBranchName: config.parentBranch}) 57 result.Append(&steps.CheckoutBranchStep{BranchName: config.targetBranch}) 58 if config.hasOrigin && config.shouldNewBranchPush && !config.isOffline { 59 result.Append(&steps.CreateTrackingBranchStep{BranchName: config.targetBranch}) 60 } 61 err = result.Wrap(steps.WrapOptions{RunInGitRoot: true, StashOpenChanges: true}, repo) 62 return result, err 63} 64 65// handleUnfinishedState checks for unfinished state on disk, handles it, and signals whether to continue execution of the originally intended steps. 66func handleUnfinishedState(repo *git.ProdRepo, driver drivers.CodeHostingDriver) (quit bool, err error) { 67 runState, err := steps.LoadPreviousRunState(repo) 68 if err != nil { 69 return false, fmt.Errorf("cannot load previous run state: %w", err) 70 } 71 if runState == nil || !runState.IsUnfinished() { 72 return false, nil 73 } 74 response, err := prompt.AskHowToHandleUnfinishedRunState( 75 runState.Command, 76 runState.UnfinishedDetails.EndBranch, 77 runState.UnfinishedDetails.EndTime, 78 runState.UnfinishedDetails.CanSkip, 79 ) 80 if err != nil { 81 return quit, err 82 } 83 switch response { 84 case prompt.ResponseTypeDiscard: 85 err = steps.DeletePreviousRunState(repo) 86 return false, err 87 case prompt.ResponseTypeContinue: 88 hasConflicts, err := repo.Silent.HasConflicts() 89 if err != nil { 90 return false, err 91 } 92 if hasConflicts { 93 return false, fmt.Errorf("you must resolve the conflicts before continuing") 94 } 95 return true, steps.Run(runState, repo, driver) 96 case prompt.ResponseTypeAbort: 97 abortRunState := runState.CreateAbortRunState() 98 return true, steps.Run(&abortRunState, repo, driver) 99 case prompt.ResponseTypeSkip: 100 skipRunState := runState.CreateSkipRunState() 101 return true, steps.Run(&skipRunState, repo, driver) 102 default: 103 return false, fmt.Errorf("unknown response: %s", response) 104 } 105} 106