func (release *nextRelease) PromptUserToConfirmStart() (bool, error) { // Collect the issues to be added to the current release. task := "Collect the issues that modified trunk since the last release" log.Run(task) ids, err := releases.ListStoryIdsToBeAssigned(release.tracker) if err != nil { return false, errs.NewError(task, err) } // Fetch the additional issues from JIRA. task = "Fetch the collected issues from JIRA" log.Run(task) issues, err := listStoriesById(newClient(release.tracker.config), ids) if len(issues) == 0 && err != nil { return false, errs.NewError(task, err) } if len(issues) != len(ids) { log.Warn("Some issues were dropped since they were not found in JIRA") } // Drop the issues that were already assigned to the right version. releaseLabel := release.trunkVersion.ReleaseTagString() filteredIssues := make([]*jira.Issue, 0, len(issues)) IssueLoop: for _, issue := range issues { // Add only the parent tasks, i.e. skip sub-tasks. if issue.Fields.Parent != nil { continue } // Add only the issues that have not been assigned to the release yet. for _, label := range issue.Fields.Labels { if label == releaseLabel { continue IssueLoop } } filteredIssues = append(filteredIssues, issue) } issues = filteredIssues // Present the issues to the user. if len(issues) != 0 { fmt.Println("\nThe following issues are going to be added to the release:\n") err := prompt.ListStories(toCommonStories(issues, release.tracker), os.Stdout) if err != nil { return false, err } } // Ask the user to confirm. ok, err := prompt.Confirm( fmt.Sprintf( "\nAre you sure you want to start release %v?", release.trunkVersion.BaseString())) if err == nil { release.additionalIssues = issues } return ok, err }
func (release *nextRelease) PromptUserToConfirmStart() (bool, error) { var ( config = release.tracker.config client = pivotal.NewClient(config.UserToken()) releaseLabel = getReleaseLabel(release.trunkVersion) ) // Collect the commits that modified trunk since the last release. task := "Collect the stories that modified trunk" log.Run(task) ids, err := releases.ListStoryIdsToBeAssigned(release.tracker) if err != nil { return false, errs.NewError(task, err) } // Fetch the collected stories from Pivotal Tracker, if necessary. var additional []*pivotal.Story if len(ids) != 0 { task = "Fetch the collected stories from Pivotal Tracker" log.Run(task) var err error additional, err = listStoriesById(client, config.ProjectId(), ids) if len(additional) == 0 && err != nil { return false, errs.NewError(task, err) } if len(additional) != len(ids) { log.Warn("Some stories were dropped since they were not found in PT") } // Drop the issues that are already assigned to the right release. unassignedStories := make([]*pivotal.Story, 0, len(additional)) for _, story := range additional { if labeled(story, releaseLabel) { continue } unassignedStories = append(unassignedStories, story) } additional = unassignedStories } // Check the Point Me label. task = "Make sure there are no unpointed stories" log.Run(task) pmLabel := config.PointMeLabel() // Fetch the already assigned but unpointed stories. pmStories, err := searchStories(client, config.ProjectId(), "label:\"%v\" AND label:\"%v\"", releaseLabel, pmLabel) if err != nil { return false, errs.NewError(task, err) } // Also add these that are to be added but are unpointed. for _, story := range additional { if labeled(story, pmLabel) { pmStories = append(pmStories, story) } } // In case there are some unpointed stories, stop the release. if len(pmStories) != 0 { fmt.Println("\nThe following stories are still yet to be pointed:\n") err := prompt.ListStories(toCommonStories(pmStories, release.tracker), os.Stdout) if err != nil { return false, err } fmt.Println() return false, errs.NewError(task, errors.New("unpointed stories detected")) } // Print the stories to be added to the release. if len(additional) != 0 { fmt.Println("\nThe following stories are going to be added to the release:\n") err := prompt.ListStories(toCommonStories(additional, release.tracker), os.Stdout) if err != nil { return false, err } } // Ask the user to confirm. ok, err := prompt.Confirm( fmt.Sprintf( "\nAre you sure you want to start release %v?", release.trunkVersion.BaseString())) if err == nil { release.additionalStories = additional } return ok, err }
func (release *nextRelease) PromptUserToConfirmStart() (bool, error) { var ( client = release.client productId = release.tracker.config.ProductId() itemReleaseTag = getItemReleaseTag(release.trunkVersion) ) // Collect the commits that modified trunk since the last release. task := "Collect the stories that modified trunk" log.Run(task) ids, err := releases.ListStoryIdsToBeAssigned(release.tracker) if err != nil { return false, errs.NewError(task, err) } // Get the story ids associated with these commits. numbers := make([]int, 0, len(ids)) for _, id := range ids { number, err := strconv.Atoi(id) if err != nil { return false, errs.NewError(task, fmt.Errorf("invalid item number: %v", id), nil) } numbers = append(numbers, number) } // Fetch the collected items from Sprintly, if necessary. var additional []sprintly.Item if len(numbers) != 0 { var err error // listItemsByNumber lists children as well, so there is no way we can miss a sub-item. additional, err = listItemsByNumber(client, productId, numbers) if err != nil { return false, err } // Drop the issues that are already assigned to the right release. unassignedItems := make([]sprintly.Item, 0, len(additional)) for _, item := range additional { if tagged(&item, itemReleaseTag) { continue } unassignedItems = append(unassignedItems, item) } additional = unassignedItems } // Make sure there are no unrated items. task = "Make sure there are no unrated items" log.Run(task) // Check the additional items and collect the unrated ones. unrated := make([]sprintly.Item, 0) for _, item := range additional { if item.Score == sprintly.ItemScoreUnset { unrated = append(unrated, item) } } // Fetch the items that were assigned manually. assignedItems, err := listItemsByTag(client, productId, []string{itemReleaseTag}) if err != nil { return false, errs.NewError(task, err) } // Check the manually assigned items and collect the unrated ones. for _, item := range assignedItems { if item.Score == sprintly.ItemScoreUnset { unrated = append(unrated, item) } // Also, since the sub-items of the assigned items are returned as well, // they may be missing the release tag, so let's register them to be tagged. if !tagged(&item, itemReleaseTag) { additional = append(additional, item) } } // In case there are some unrated items, abort the release process. if len(unrated) != 0 { fmt.Println("\nThe following items have not been rated yet:\n") err := prompt.ListStories(toCommonStories(unrated), os.Stdout) if err != nil { return false, err } fmt.Println() return false, errs.NewError(task, errors.New("unrated items detected"), nil) } // Print the items to be added to the release. if len(additional) != 0 { fmt.Println("\nThe following items are going to be added to the release:\n") err := prompt.ListStories(toCommonStories(additional), os.Stdout) if err != nil { return false, err } } // Ask the user to confirm. ok, err := prompt.Confirm( fmt.Sprintf("\nAre you sure you want to start release %v?", release.trunkVersion)) if err == nil { release.additionalItems = additional } return ok, err }