- Added SprintCmd to issues command group - taskLoop hide survey related commands when in repl - Updated coding task instructions for clarity - Removed redundant SprintCmd registration - Improved REPL command handling for better user experience avoiding a chash if users type pm - Enhanced task UI to display additional information
321 lines
7.7 KiB
Go
321 lines
7.7 KiB
Go
package issues
|
|
|
|
import (
|
|
"fmt"
|
|
"strconv"
|
|
|
|
"github.com/LazyBachelor/LazyPM/internal/models"
|
|
"github.com/spf13/cobra"
|
|
)
|
|
|
|
// sprintFlags holds the flag values for sprint commands
|
|
type sprintFlags struct {
|
|
sprintNum int
|
|
issueID string
|
|
}
|
|
|
|
var sprintCmdFlags sprintFlags
|
|
|
|
// SprintCmd represents the sprint management command
|
|
var SprintCmd = &cobra.Command{
|
|
Use: "sprint",
|
|
Short: "Manage sprints",
|
|
Long: `Manage sprints - create, list, add/remove issues, and view sprint contents.`,
|
|
}
|
|
|
|
// SprintListCmd lists all sprints
|
|
var SprintListCmd = &cobra.Command{
|
|
Use: "list",
|
|
Short: "List all sprints",
|
|
Long: `List all sprints in the project.`,
|
|
Aliases: []string{"ls"},
|
|
RunE: runSprintListCmd,
|
|
}
|
|
|
|
// SprintCreateCmd creates a new sprint
|
|
var SprintCreateCmd = &cobra.Command{
|
|
Use: "create",
|
|
Short: "Create a new sprint",
|
|
Long: `Create a new sprint for organizing issues.`,
|
|
Aliases: []string{"new"},
|
|
RunE: runSprintCreateCmd,
|
|
}
|
|
|
|
// SprintIssuesCmd lists issues in a sprint
|
|
var SprintIssuesCmd = &cobra.Command{
|
|
Use: "issues [sprint-num]",
|
|
Short: "List issues in a sprint",
|
|
Long: `List all issues assigned to a specific sprint. Use 'backlog' or omit to view the backlog.`,
|
|
Aliases: []string{"show", "view"},
|
|
Args: cobra.MaximumNArgs(1),
|
|
RunE: runSprintIssuesCmd,
|
|
}
|
|
|
|
// SprintAddCmd adds an issue to a sprint
|
|
var SprintAddCmd = &cobra.Command{
|
|
Use: "add [issue-id] [sprint-num]",
|
|
Short: "Add an issue to a sprint",
|
|
Long: `Add an issue to a sprint. If sprint-num is omitted, adds to backlog.`,
|
|
Args: cobra.RangeArgs(1, 2),
|
|
RunE: runSprintAddCmd,
|
|
|
|
ValidArgsFunction: completeIssues,
|
|
}
|
|
|
|
// SprintRemoveCmd removes an issue from a sprint
|
|
var SprintRemoveCmd = &cobra.Command{
|
|
Use: "remove [issue-id] [sprint-num]",
|
|
Short: "Remove an issue from a sprint",
|
|
Long: `Remove an issue from a sprint. If sprint-num is omitted, removes from backlog.`,
|
|
Aliases: []string{"rm"},
|
|
Args: cobra.RangeArgs(1, 2),
|
|
RunE: runSprintRemoveCmd,
|
|
|
|
ValidArgsFunction: completeIssues,
|
|
}
|
|
|
|
// SprintBacklogCmd shows the backlog sprint
|
|
var SprintBacklogCmd = &cobra.Command{
|
|
Use: "backlog",
|
|
Short: "Show backlog issues",
|
|
Long: `Show all issues in the backlog sprint.`,
|
|
RunE: runSprintBacklogCmd,
|
|
}
|
|
|
|
// SprintDeleteCmd deletes a sprint
|
|
var SprintDeleteCmd = &cobra.Command{
|
|
Use: "delete [sprint-num]",
|
|
Short: "Delete a sprint",
|
|
Long: `Delete a sprint by its number. Issues in the sprint will not be deleted.`,
|
|
Aliases: []string{"del"},
|
|
Args: cobra.MaximumNArgs(1),
|
|
RunE: runSprintDeleteCmd,
|
|
}
|
|
|
|
func runSprintListCmd(cmd *cobra.Command, args []string) error {
|
|
app := AppFromContext(cmd.Context())
|
|
|
|
sprints, err := app.Issues.GetSprints(cmd.Context())
|
|
if err != nil {
|
|
return fmt.Errorf("failed to get sprints: %w", err)
|
|
}
|
|
|
|
if len(sprints) == 0 {
|
|
cmd.Println("No sprints found.")
|
|
return nil
|
|
}
|
|
|
|
backlogNum, _ := app.Issues.GetBacklogSprint(cmd.Context())
|
|
|
|
cmd.Println("Sprints:")
|
|
for _, sprintNum := range sprints {
|
|
label := ""
|
|
if sprintNum == backlogNum {
|
|
label = " (backlog)"
|
|
}
|
|
cmd.Printf(" Sprint %d%s\n", sprintNum, label)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func runSprintCreateCmd(cmd *cobra.Command, args []string) error {
|
|
app := AppFromContext(cmd.Context())
|
|
|
|
sprintNum, err := app.Issues.AddSprint(cmd.Context())
|
|
if err != nil {
|
|
return fmt.Errorf("failed to create sprint: %w", err)
|
|
}
|
|
|
|
cmd.Printf("Created sprint %d\n", sprintNum)
|
|
return nil
|
|
}
|
|
|
|
func runSprintIssuesCmd(cmd *cobra.Command, args []string) error {
|
|
app := AppFromContext(cmd.Context())
|
|
ctx := cmd.Context()
|
|
|
|
var sprintNum int
|
|
var isBacklog bool
|
|
var err error
|
|
|
|
if len(args) == 0 || args[0] == "backlog" {
|
|
sprintNum, err = app.Issues.GetBacklogSprint(ctx)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to get backlog sprint: %w", err)
|
|
}
|
|
isBacklog = true
|
|
} else {
|
|
sprintNum, err = strconv.Atoi(args[0])
|
|
if err != nil {
|
|
return fmt.Errorf("invalid sprint number: %s", args[0])
|
|
}
|
|
isBacklog = false
|
|
}
|
|
|
|
var issues []*models.Issue
|
|
if isBacklog {
|
|
issues, err = app.Issues.GetIssuesNotInAnySprint(ctx)
|
|
} else {
|
|
issues, err = app.Issues.GetIssuesBySprint(ctx, sprintNum)
|
|
}
|
|
if err != nil {
|
|
return fmt.Errorf("failed to get issues in sprint %d: %w", sprintNum, err)
|
|
}
|
|
|
|
if isBacklog {
|
|
cmd.Printf("Backlog (%d issues):\n", len(issues))
|
|
} else {
|
|
cmd.Printf("Sprint %d (%d issues):\n", sprintNum, len(issues))
|
|
}
|
|
|
|
if len(issues) == 0 {
|
|
cmd.Println(" No issues in this sprint.")
|
|
return nil
|
|
}
|
|
|
|
issuesList := models.IssuesPtrToIssues(issues)
|
|
models.PrintIssues(issuesList)
|
|
|
|
return nil
|
|
}
|
|
|
|
func runSprintAddCmd(cmd *cobra.Command, args []string) error {
|
|
app := AppFromContext(cmd.Context())
|
|
ctx := cmd.Context()
|
|
|
|
issueID := args[0]
|
|
|
|
var sprintNum int
|
|
var err error
|
|
|
|
if len(args) == 1 {
|
|
sprintNum, err = app.Issues.GetBacklogSprint(ctx)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to get backlog sprint: %w", err)
|
|
}
|
|
} else {
|
|
sprintNum, err = strconv.Atoi(args[1])
|
|
if err != nil {
|
|
return fmt.Errorf("invalid sprint number: %s", args[1])
|
|
}
|
|
}
|
|
|
|
err = app.Issues.AddIssueToSprint(ctx, issueID, sprintNum)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to add issue to sprint: %w", err)
|
|
}
|
|
|
|
backlogNum, _ := app.Issues.GetBacklogSprint(ctx)
|
|
|
|
if sprintNum == backlogNum {
|
|
cmd.Printf("Added issue %s to backlog\n", issueID)
|
|
} else {
|
|
cmd.Printf("Added issue %s to sprint %d\n", issueID, sprintNum)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func runSprintRemoveCmd(cmd *cobra.Command, args []string) error {
|
|
app := AppFromContext(cmd.Context())
|
|
ctx := cmd.Context()
|
|
|
|
issueID := args[0]
|
|
|
|
var sprintNum int
|
|
var err error
|
|
|
|
if len(args) == 1 {
|
|
sprintNum, err = app.Issues.GetBacklogSprint(ctx)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to get backlog sprint: %w", err)
|
|
}
|
|
} else {
|
|
sprintNum, err = strconv.Atoi(args[1])
|
|
if err != nil {
|
|
return fmt.Errorf("invalid sprint number: %s", args[1])
|
|
}
|
|
}
|
|
|
|
err = app.Issues.RemoveIssueFromSprint(ctx, issueID, sprintNum)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to remove issue from sprint: %w", err)
|
|
}
|
|
|
|
backlogNum, _ := app.Issues.GetBacklogSprint(ctx)
|
|
|
|
if sprintNum == backlogNum {
|
|
cmd.Printf("Removed issue %s from backlog\n", issueID)
|
|
} else {
|
|
cmd.Printf("Removed issue %s from sprint %d\n", issueID, sprintNum)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func runSprintBacklogCmd(cmd *cobra.Command, args []string) error {
|
|
app := AppFromContext(cmd.Context())
|
|
ctx := cmd.Context()
|
|
|
|
issues, err := app.Issues.GetIssuesNotInAnySprint(ctx)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to get backlog issues: %w", err)
|
|
}
|
|
|
|
cmd.Printf("Backlog (%d issues):\n", len(issues))
|
|
|
|
if len(issues) == 0 {
|
|
cmd.Println(" No issues in backlog.")
|
|
return nil
|
|
}
|
|
|
|
issuesList := models.IssuesPtrToIssues(issues)
|
|
models.PrintIssues(issuesList)
|
|
|
|
return nil
|
|
}
|
|
|
|
func runSprintDeleteCmd(cmd *cobra.Command, args []string) error {
|
|
app := AppFromContext(cmd.Context())
|
|
ctx := cmd.Context()
|
|
|
|
var sprintNum int
|
|
var err error
|
|
|
|
if len(args) == 0 {
|
|
sprintNum, err = app.Issues.GetBacklogSprint(ctx)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to get backlog sprint: %w", err)
|
|
}
|
|
} else {
|
|
sprintNum, err = strconv.Atoi(args[0])
|
|
if err != nil {
|
|
return fmt.Errorf("invalid sprint number: %s", args[0])
|
|
}
|
|
}
|
|
|
|
backlogNum, _ := app.Issues.GetBacklogSprint(ctx)
|
|
if sprintNum == backlogNum {
|
|
return fmt.Errorf("cannot delete the backlog sprint")
|
|
}
|
|
|
|
err = app.Issues.RemoveSprint(ctx, sprintNum)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to delete sprint: %w", err)
|
|
}
|
|
|
|
cmd.Printf("Deleted sprint %d\n", sprintNum)
|
|
return nil
|
|
}
|
|
|
|
func init() {
|
|
SprintCmd.AddCommand(SprintListCmd)
|
|
SprintCmd.AddCommand(SprintBacklogCmd)
|
|
SprintCmd.AddCommand(SprintCreateCmd)
|
|
SprintCmd.AddCommand(SprintIssuesCmd)
|
|
SprintCmd.AddCommand(SprintAddCmd)
|
|
SprintCmd.AddCommand(SprintRemoveCmd)
|
|
SprintCmd.AddCommand(SprintDeleteCmd)
|
|
}
|