func ensureTargetBranchExists(branch, remote string) error { task := fmt.Sprintf("Check whether branch '%v' exists", branch) // In case the branch exists locally, we are done. localExists, err := git.LocalBranchExists(branch) if err != nil { return errs.NewError(task, err) } if localExists { return nil } // Otherwise try to create a tracking branch. remoteExists, err := git.RemoteBranchExists(branch, remote) if err != nil { return errs.NewError(task, err) } if remoteExists { return errs.Wrap(task, git.CreateTrackingBranch(branch, remote)) } // We have failed! return &git.ErrRefNotFound{branch} }
func SetForBranch(ver *Version, branch string) (act action.Action, err error) { var mainTask = fmt.Sprintf("Bump version to %v for branch '%v'", ver, branch) // Make sure the repository is clean (don't check untracked files). task := "Make sure the repository is clean" if err := git.EnsureCleanWorkingTree(false); err != nil { return nil, errs.NewError(task, err) } // Remember the current branch. currentBranch, err := gitutil.CurrentBranch() if err != nil { return nil, err } // Remember the current position of the target branch. task = fmt.Sprintf("Remember the position of branch '%v'", branch) originalPosition, err := git.Hexsha("refs/heads/" + branch) if err != nil { return nil, errs.NewError(task, err) } // Checkout the target branch. task = fmt.Sprintf("Checkout branch '%v'", branch) if err := git.Checkout(branch); err != nil { return nil, errs.NewError(task, err) } defer func() { // Checkout the original branch on return. task := fmt.Sprintf("Checkout branch '%v'", currentBranch) if ex := git.Checkout(currentBranch); ex != nil { if err == nil { err = ex } else { errs.LogError(task, ex) } } }() // Set the project version to the desired value. if err := Set(ver); err != nil { if ex, ok := err.(*scripts.ErrNotFound); ok { return nil, fmt.Errorf( "custom SalsaFlow script '%v' not found on branch '%v'", ex.ScriptName(), branch) } return nil, err } // Commit changes. _, err = git.RunCommand("commit", "-a", "-m", fmt.Sprintf("Bump version to %v", ver), "-m", fmt.Sprintf("Story-Id: %v", git.StoryIdUnassignedTagValue)) if err != nil { task := "Reset the working tree to the original state" if err := git.Reset("--hard"); err != nil { errs.LogError(task, err) } return nil, err } return action.ActionFunc(func() (err error) { // On rollback, reset the target branch to the original position. log.Rollback(mainTask) task := fmt.Sprintf("Reset branch '%v' to the original position", branch) // Get the current branch name. currentBranch, err := gitutil.CurrentBranch() if err != nil { return errs.NewError(task, err) } // Use SetBranch in case we are not on the branch to be modified. if branch != currentBranch { return errs.Wrap(task, git.SetBranch(branch, originalPosition)) } // Otherwise use git reset --hard since currentBranch == branch. return errs.Wrap(task, git.Reset("--hard", originalPosition)) }), nil }
func runMain() (err error) { tracker, err := modules.GetIssueTracker() if err != nil { return err } // Fetch stories from the issue tracker. task := "Fetch stories from the issue tracker" log.Run(task) stories, err := tracker.StartableStories() if err != nil { return errs.NewError(task, err) } if len(stories) == 0 { return errs.NewError(task, errors.New("no startable stories found")) } // Filter out the stories that are not relevant, // i.e. not owned by the current user or assigned to someone else. task = "Fetch the current user record from the issue tracker" user, err := tracker.CurrentUser() if err != nil { return errs.NewError(task, err) } var filteredStories []common.Story StoryLoop: for _, story := range stories { assignees := story.Assignees() // Include the story in case there is no assignee set yet. if len(assignees) == 0 { filteredStories = append(filteredStories, story) continue StoryLoop } // Include the story in case the current user is assigned. for _, assignee := range assignees { if assignee.Id() == user.Id() { filteredStories = append(filteredStories, story) continue StoryLoop } } } stories = filteredStories // Prompt the user to select a story. story, err := dialog( "\nYou can start working on one of the following stories:", stories) if err != nil { switch err { case prompt.ErrNoStories: return errors.New("no startable stories found") case prompt.ErrCanceled: prompt.PanicCancel() default: return err } } fmt.Println() // Create the story branch, optionally. if flagNoBranch { log.Log("Not creating any feature branch") } else { var act action.Action act, err = createBranch() if err != nil { return err } // Roll back on error. defer action.RollbackTaskOnError(&err, task, act) } // Add the current user to the list of story assignees. task = "Amend the list of story assignees" log.Run(task) originalAssignees := story.Assignees() if err := story.AddAssignee(user); err != nil { return errs.NewError(task, err) } defer action.RollbackTaskOnError(&err, task, action.ActionFunc(func() error { task := "Reset the list of story assignees" if err := story.SetAssignees(originalAssignees); err != nil { return errs.NewError(task, err) } return nil })) // Start the selected story. No need to roll back. task = "Start the selected story" log.Run(task) return errs.Wrap(task, story.Start()) }