From b0c76b056574351c39c03a5ae655fdbe236e2389 Mon Sep 17 00:00:00 2001 From: Robin Olsen Date: Thu, 19 Mar 2026 15:21:30 +0100 Subject: [PATCH] remove setup issues and simplify validaiton --- cmd/pm/tasks/backlogRefinement.go | 20 ++------ cmd/pm/tasks/base.go | 11 ++-- cmd/pm/tasks/codingTask.go | 75 ++++++---------------------- cmd/pm/tasks/createIssue.go | 20 ++------ cmd/pm/tasks/dependencyManagement.go | 31 +++--------- cmd/pm/tasks/gitTask.go | 36 ++++++------- cmd/pm/tasks/issueReviewCleanup.go | 43 +++++++--------- cmd/pm/tasks/priorityManagement.go | 36 ++----------- cmd/pm/tasks/sprintPlanning.go | 30 +++-------- internal/commands/issues/update.go | 8 +++ 10 files changed, 91 insertions(+), 219 deletions(-) diff --git a/cmd/pm/tasks/backlogRefinement.go b/cmd/pm/tasks/backlogRefinement.go index f04201f..30e66ae 100644 --- a/cmd/pm/tasks/backlogRefinement.go +++ b/cmd/pm/tasks/backlogRefinement.go @@ -23,9 +23,8 @@ The product backlog has become cluttered with old and unclear issues. You need t Focus on making the backlog a reliable source of upcoming work.` type BacklogRefinementTask struct { - done bool - app *App - setupIssue *Issue + done bool + app *App } func NewBacklogRefinementTask(app *App) *BacklogRefinementTask { @@ -115,24 +114,15 @@ func (t *BacklogRefinementTask) Setup(ctx context.Context) error { Build(), } - if err := t.app.Issues.CreateIssues(ctx, refinementIssues, ""); err != nil { - return err - } - - t.setupIssue = NewIssueBuilder(). - WithTitle("Backlog Refinement Session"). - WithDescription(backlogRefinementDescription). - Build() - - return t.app.Issues.CreateIssue(ctx, t.setupIssue, "") + return t.app.Issues.CreateIssues(ctx, refinementIssues, "") } func (t *BacklogRefinementTask) Validate(ctx context.Context) ValidationFeedback { expect := check.NewExpector() - issues, err := FetchIssues(ctx, t.app, t.setupIssue) + issues, err := FetchIssues(ctx, t.app) if err != nil { - return expect.ValidationFeedback + return expect.Fatal("Could not fetch issues") } var closedDuplicate *models.Issue diff --git a/cmd/pm/tasks/base.go b/cmd/pm/tasks/base.go index d634629..93f359f 100644 --- a/cmd/pm/tasks/base.go +++ b/cmd/pm/tasks/base.go @@ -168,9 +168,8 @@ func TUIQuestion(interfaceType InterfaceType, fields ...huh.Field) *huh.Group { return huh.NewGroup(fields...) } -// FetchIssues retrieves all issues from the app and returns those that are relevant for validation, -// excluding the setup issue. It also updates the setup issue with the latest data from the app. -func FetchIssues(ctx context.Context, app *App, setupIssue *Issue) ([]*Issue, error) { +// FetchIssues retrieves all issues from the app and returns those that are relevant for validation +func FetchIssues(ctx context.Context, app *App) ([]*Issue, error) { issues, err := app.Issues.SearchIssues(ctx, "", models.IssueFilter{}) if err != nil { return nil, err @@ -178,11 +177,7 @@ func FetchIssues(ctx context.Context, app *App, setupIssue *Issue) ([]*Issue, er var relevantIssues []*Issue for _, issue := range issues { - if issue.ID != setupIssue.ID { - relevantIssues = append(relevantIssues, issue) - } else { - *setupIssue = *issue - } + relevantIssues = append(relevantIssues, issue) } return relevantIssues, nil diff --git a/cmd/pm/tasks/codingTask.go b/cmd/pm/tasks/codingTask.go index 18d313a..12d5e34 100644 --- a/cmd/pm/tasks/codingTask.go +++ b/cmd/pm/tasks/codingTask.go @@ -6,7 +6,6 @@ import ( "strings" "charm.land/huh/v2" - "github.com/LazyBachelor/LazyPM/internal/models" "github.com/LazyBachelor/LazyPM/internal/utils/check" ) @@ -18,15 +17,10 @@ The MongoDB Driver dependency in the file is outdated and needs to be updated to This is a common task for developers, and it requires attention to detail and the ability to follow instructions carefully. Your task: -1. Create a New Issue and give it these details: - - Title: "Upgrade MongoDB Driver Dependency" - - Description: "We need to upgrade the MongoDB Driver dependency to the latest version." - - Status: "In Progress" - - Issue Type: "Chore" -2. Assign the issue to yourself as "Me". -3. A file will appear in the current directory named "code.txt". +1. Assingn the given issue to yourself as 'Me'. +2. A file will appear in the current directory named "code.txt". Open it and follow the instructions inside. And save the file after you are done. -4. When you are done, mark this and the issue you made as "Closed".` +3. When you are done, mark this and the issue you made as "Closed".` var textFileDescription = ` @@ -76,9 +70,9 @@ tool ( var textFileContent = codingDescription + textFileDescription + "\n" + code type CodingTask struct { - done bool - setupIssue *Issue - app *App + done bool + app *App + issue *Issue } func NewCodingTask(app *App) *CodingTask { @@ -124,60 +118,27 @@ func (t *CodingTask) Setup(ctx context.Context) error { return err } - t.setupIssue = NewIssueBuilder(). - WithTitle("Coding Task - Upgrade MongoDB Driver"). - WithDescription(codingDescription). - WithStatus(models.StatusOpen). - WithIssueType(models.TypeTask). - Build() - - if err := t.app.Issues.CreateIssue(ctx, t.setupIssue, "LazyPM"); err != nil { - return err - } - if err := os.WriteFile("./code.txt", []byte(textFileContent), 0644); err != nil { return err } - return nil -} + t.issue = NewIssueBuilder(). + WithTitle("Upgrade MongoDB Driver"). + WithDescription(codingDescription). + Build() -var codingTaskInProgress = false + return t.app.Issues.CreateIssue(ctx, t.issue, "") +} func (t *CodingTask) Validate(ctx context.Context) ValidationFeedback { expect := check.NewExpector() - issues, err := FetchIssues(ctx, t.app, t.setupIssue) + issue, err := t.app.Issues.GetIssue(ctx, t.issue.ID) if err != nil { - return expect.ValidationFeedback + return expect.Fatal("Could not fetch issues") } - if len(issues) == 0 { - expect.Fail("No new issues created") - return expect.ValidationFeedback - } else { - expect.Pass("An issue was created") - } - - issue := issues[0] - - expect.Assert(len(issues) < 2, "Multiple issues were created instead of one") - - expect.NotEmptyAndEqual(issue.Title, "Upgrade MongoDB Driver Dependency", "Issue title") - - expect.NotEmptyAndEqual(issue.Description, - "We need to upgrade the MongoDB Driver dependency to the latest version.", "Issue description") - - expect.NotEmptyAndEqual(issue.Assignee, "Me", "Issue Assignee") - - expect.Equal(issue.IssueType, models.TypeChore, "Issue type") - - if issue.Status == models.StatusInProgress || codingTaskInProgress { - codingTaskInProgress = true - } else { - expect.Fail("The issue should be marked as In Progress while working on the task.") - return expect.ValidationFeedback - } + expect.Equal(issue.Assignee, "Me", "Issue Assignee") if _, err := os.Stat("./code.txt"); os.IsNotExist(err) { expect.Fail("The code.txt file should exist on the desktop.") @@ -196,11 +157,7 @@ func (t *CodingTask) Validate(ctx context.Context) ValidationFeedback { return expect.ValidationFeedback } - expect.Assert(strings.Contains(code, "go.mongodb.org/mongo-driver v1.17.9"), - "The MongoDB Driver dependency should be updated to version v1.17.9 in the file.") - - expect.Assert(codingTaskInProgress && issue.Status == models.StatusClosed, - "The issue should be marked as Closed after completing the task.") + expect.Contains(code, "go.mongodb.org/mongo-driver v1.17.9", "MongoDB Driver version") return expect.Complete() } diff --git a/cmd/pm/tasks/createIssue.go b/cmd/pm/tasks/createIssue.go index c34dc8e..4893e8d 100644 --- a/cmd/pm/tasks/createIssue.go +++ b/cmd/pm/tasks/createIssue.go @@ -2,7 +2,6 @@ package tasks import ( "context" - "fmt" "charm.land/huh/v2" "github.com/LazyBachelor/LazyPM/internal/models" @@ -69,37 +68,28 @@ func (t *CreateIssueTask) Setup(ctx context.Context) error { return err } - t.setupIssue = NewIssueBuilder(). - WithTitle("Create a New Issue"). - WithDescription(description). - Build() - - return t.app.Issues.CreateIssue(ctx, t.setupIssue, "") + return nil } func (t *CreateIssueTask) Validate(ctx context.Context) ValidationFeedback { expect := check.NewExpector() - issues, err := FetchIssues(ctx, t.app, t.setupIssue) + issues, err := FetchIssues(ctx, t.app) if err != nil { - return expect.ValidationFeedback + return expect.Fatal("Could not fetch issues") } if len(issues) == 0 { - expect.Fail("No new issues created") + expect.Fail("No issues were created") return expect.ValidationFeedback } issue := issues[0] - expect.Assert(len(issues) < 2, "Multiple issues were created instead of one") - expect.NotEmptyAndEqual(issue.Title, "My first Issue", "Issue title") expect.NotEmptyAndEqual(issue.Description, "I need to do some coding", "Issue description") expect.NotEmptyAndEqual(issue.Assignee, "Me", "Issue assignee") - - expect.Assert(issue.Status == models.StatusInProgress, - fmt.Sprintf("Issue status should be 'In Progress', but was '%s'", issue.Status)) + expect.Equal(issue.Status, models.StatusInProgress, "Issue status") return expect.Complete() } diff --git a/cmd/pm/tasks/dependencyManagement.go b/cmd/pm/tasks/dependencyManagement.go index d1c6a4a..798d2e9 100644 --- a/cmd/pm/tasks/dependencyManagement.go +++ b/cmd/pm/tasks/dependencyManagement.go @@ -11,8 +11,9 @@ import ( const dependencyManagementDescription = `You are tasked with managing issue dependencies. -Several issues in your project have dependencies on other issues. You need to: +Several issues in your project have dependencies on other issues. +You need to: 1. Find the 4 issues that mention dependencies in their detail description. For example: "Depends on Issue '123'". Set their status to "blocked". 2. Find the 2 foundational issues that are mentioned by the other issues. 3. Set priority of the 2 foundational issues to 3 (high). @@ -22,10 +23,9 @@ Several issues in your project have dependencies on other issues. You need to: Resolving dependencies in the right order is critical for efficient team workflow.` type DependencyManagementTask struct { - done bool - app *App - setupIssue *Issue - depIssues []*Issue + done bool + app *App + depIssues []*Issue } func NewDependencyManagementTask(app *App) *DependencyManagementTask { @@ -115,23 +115,13 @@ func (t *DependencyManagementTask) Setup(ctx context.Context) error { Build(), } - if err := t.app.Issues.CreateIssues(ctx, t.depIssues, ""); err != nil { - return err - } - - t.setupIssue = NewIssueBuilder(). - WithTitle("Dependency Management"). - WithDescription(dependencyManagementDescription). - Build() - - return t.app.Issues.CreateIssue(ctx, t.setupIssue, "") + return t.app.Issues.CreateIssues(ctx, t.depIssues, "") } func (t *DependencyManagementTask) Validate(ctx context.Context) ValidationFeedback { expect := check.NewExpector() - taskIssue := t.setupIssue - issues, err := FetchIssues(ctx, t.app, t.setupIssue) + issues, err := FetchIssues(ctx, t.app) if err != nil { return expect.Fatal("Could not fetch issues") } @@ -157,12 +147,5 @@ func (t *DependencyManagementTask) Validate(ctx context.Context) ValidationFeedb } - if !expect.Valid() { - return expect.ValidationFeedback - } - - expect.Equal(taskIssue.Status, models.StatusClosed, - fmt.Sprintf("%s", taskIssue.Title)) - return expect.Complete() } diff --git a/cmd/pm/tasks/gitTask.go b/cmd/pm/tasks/gitTask.go index 40be4f6..3ce4f54 100644 --- a/cmd/pm/tasks/gitTask.go +++ b/cmd/pm/tasks/gitTask.go @@ -14,12 +14,14 @@ import ( const gitTaskDescription = `You are tasked with performing a Git operation. -This task will test your ability to use Git effectively within a project management workflow. Your goal is to modify a file in a Git repository and commit the change. +This task will test your ability to use Git effectively within a project management workflow. +Your goal is to modify a file in a Git repository and commit the change. Your task: -1. Set the Issue status to "In Progress" when you are ready to start. -2. A folder called "task" is created in the project directory when you start this task. Open it. -3. Inside the folder you will find README.md. Edit this file and add something to it (e.g. your name, a short note, or a new line). The file must be different from its original content. +1. Assign the given issue to yourself as 'Me'. +2. A folder called "task" is created in the project directory when you start this task. +3. Inside the folder you will find README.md. Edit this file and add something to it. + The file must be different from its original content. 4. Commit your change: - Open a terminal and change into the task folder. - Run "git add ." to stage the changes. @@ -102,7 +104,7 @@ func (t *GitTask) Setup(ctx context.Context) error { _ = os.WriteFile("./task/.gitattributes", []byte("* text=auto\n"), 0o644) t.setupIssue = NewIssueBuilder(). - WithTitle("Git Task Setup Issue"). + WithTitle("Upgrade the codebase"). WithDescription(gitTaskDescription). WithIssueType(models.TypeTask). Build() @@ -117,19 +119,14 @@ func (t *GitTask) Setup(ctx context.Context) error { func (t *GitTask) Validate(ctx context.Context) ValidationFeedback { expect := check.NewExpector() - issues, err := FetchIssues(ctx, t.app, t.setupIssue) + issue, err := t.app.Issues.GetIssue(ctx, t.setupIssue.ID) if err != nil { - return expect.ValidationFeedback + return expect.Fatal("Could not fetch issue") } - _ = issues + expect.Equal(issue.Assignee, "Me", "Issue Assignee") - issue := t.setupIssue - - if issue.Status == models.StatusInProgress || gitTaskInProgress { - gitTaskInProgress = true - } else { - expect.Fail("The issue should be marked as In Progress while working on the Git task.") + if !expect.Valid() { return expect.ValidationFeedback } @@ -175,16 +172,19 @@ func (t *GitTask) Validate(ctx context.Context) ValidationFeedback { } expect.Assert(readmeContent != gitTaskReadmeContent, - "You should modify README.md content before committing (make appropriate changes to complete the task).") + "You should modify README.md content before committing") if wt, err := t.repo.Worktree(); err == nil { if status, err := wt.Status(); err == nil { - expect.Assert(status.IsClean(), "The working tree should be clean after committing (no unstaged changes).") + expect.Assert(status.IsClean(), "The working tree should be clean after committing") } } - expect.Assert(gitTaskInProgress && issue.Status == models.StatusClosed, - "The issue should be marked as Closed after completing the Git task.") + if !expect.Valid() { + return expect.ValidationFeedback + } + + expect.Equal(issue.Status, models.StatusClosed, "Issue Status") return expect.Complete() } diff --git a/cmd/pm/tasks/issueReviewCleanup.go b/cmd/pm/tasks/issueReviewCleanup.go index 69241e4..194d760 100644 --- a/cmd/pm/tasks/issueReviewCleanup.go +++ b/cmd/pm/tasks/issueReviewCleanup.go @@ -12,12 +12,12 @@ const issueReviewCleanupDescription = `You are responsible for reviewing and mai Using the system, complete the following steps: 1. Add a comment to two issues -2. Delete this cleanup task issue ("Issue Review and Cleanup Task") from the issue list — do not delete the other project issues` +2. Delete the issue titled "Delete this issue"` type IssueReviewCleanupTask struct { - done bool - app *App - setupIssue *models.Issue + done bool + app *App + reviewIssues []*models.Issue } func NewIssueReviewCleanupTask(app *App) *IssueReviewCleanupTask { @@ -49,10 +49,10 @@ func (t *IssueReviewCleanupTask) Setup(ctx context.Context) error { return err } - reviewIssues := []*models.Issue{ + t.reviewIssues = []*models.Issue{ models.NewIssueBuilder(). - WithTitle("Fix login page layout"). - WithDescription("The login form is misaligned on smaller screens. Needs responsive CSS adjustments."). + WithTitle("Delete this issue"). + WithDescription(""). WithPriority(2). WithStatus(models.StatusOpen). WithIssueType(models.TypeTask). @@ -87,22 +87,13 @@ func (t *IssueReviewCleanupTask) Setup(ctx context.Context) error { Build(), } - if err := t.app.Issues.CreateIssues(ctx, reviewIssues, ""); err != nil { - return err - } - - t.setupIssue = models.NewBaseIssue(). - WithTitle("Issue Review and Cleanup Task"). - WithDescription(issueReviewCleanupDescription). - Build() - - return t.app.Issues.CreateIssue(ctx, t.setupIssue, "") + return t.app.Issues.CreateIssues(ctx, t.reviewIssues, "") } func (t *IssueReviewCleanupTask) Validate(ctx context.Context) ValidationFeedback { expect := check.NewExpector() - issues, err := FetchIssues(ctx, t.app, t.setupIssue) + issues, err := FetchIssues(ctx, t.app) if err != nil { return expect.Fatal("Could not fetch issues") } @@ -123,16 +114,18 @@ func (t *IssueReviewCleanupTask) Validate(ctx context.Context) ValidationFeedbac } expect.Equal(commentsInIssues, 2, "Comments on issues") + expect.Equal(len(issues), len(t.reviewIssues)-1, "Remaining issues after cleanup") - // Fetching the setup issue as as FetchIssues only updates the setup issue if it exists, - // we can check if it was deleted by seeing if it can be fetched again - if t.setupIssue, err = t.app.Issues.GetIssue(ctx, t.setupIssue.ID); t.setupIssue != nil { - expect.Fail("Setup issue still exists") - } else { - expect.Pass("Setup issue deleted") + issue, err := t.app.Issues.GetIssue(ctx, t.reviewIssues[0].ID) + if err != nil { + return expect.Fatal("Deleted issue should not be found") } - expect.Equal(len(issues), 5, "Number of remaining issues") + if issue != nil { + expect.Fail("The issue titled 'Delete this issue' should have been deleted.") + } else { + expect.Pass("Issue deleted successfully") + } return expect.Complete() } diff --git a/cmd/pm/tasks/priorityManagement.go b/cmd/pm/tasks/priorityManagement.go index 2bb729b..338bd6e 100644 --- a/cmd/pm/tasks/priorityManagement.go +++ b/cmd/pm/tasks/priorityManagement.go @@ -17,16 +17,14 @@ The database is not working properly and users are not able to connect and acces You need to rebalance the current sprint priorities: -1. Assign the task Issue you are currently reading to yourself as "Me" and set status to "In Progress". -2. A new issue has appeared in the list that needs urgent attention. Change the database related issue's priority to 4 (critical). -3. Set the priority of the feature and chore issues in the list to 1 (low). -4. Change this issue status to "Closed". +1. A new issue has appeared in the list that needs urgent attention. + Change the database related issue's priority to 4 (critical). +2. Set the priority of the feature and chore issues in the list to 1 (low). ` type PriorityManagementTask struct { done bool app *App - setupIssue *Issue priorityIssues []*models.Issue isInProgress bool } @@ -111,38 +109,17 @@ func (t *PriorityManagementTask) Setup(ctx context.Context) error { Build(), } - if err := t.app.Issues.CreateIssues(ctx, t.priorityIssues, ""); err != nil { - return err - } - - t.setupIssue = NewIssueBuilder(). - WithTitle("Priority Rebalancing"). - WithDescription(priorityManagementDescription). - Build() - - return t.app.Issues.CreateIssue(ctx, t.setupIssue, "") + return t.app.Issues.CreateIssues(ctx, t.priorityIssues, "") } func (t *PriorityManagementTask) Validate(ctx context.Context) ValidationFeedback { expect := check.NewExpector() - issues, err := FetchIssues(ctx, t.app, t.setupIssue) + issues, err := FetchIssues(ctx, t.app) if err != nil { return expect.Fatal("Failed to fetch issues for validation") } - expect.NotEmptyAndEqual(t.setupIssue.Assignee, "Me", - fmt.Sprintf("%s assignee", t.setupIssue.Title)) - - if t.setupIssue.Status != models.StatusClosed { - expect.Equal(t.setupIssue.Status, models.StatusInProgress, - fmt.Sprintf("%s status", t.setupIssue.Title)) - } - - if !expect.Valid() { - return expect.ValidationFeedback - } - for _, issue := range issues { if issue.Title == t.priorityIssues[0].Title { expect.Equal(issue.Priority, 4, @@ -153,8 +130,5 @@ func (t *PriorityManagementTask) Validate(ctx context.Context) ValidationFeedbac } } - expect.Equal(t.setupIssue.Status, models.StatusClosed, - fmt.Sprintf("%s status", t.setupIssue.Title)) - return expect.Complete() } diff --git a/cmd/pm/tasks/sprintPlanning.go b/cmd/pm/tasks/sprintPlanning.go index 68330ca..7d4c87b 100644 --- a/cmd/pm/tasks/sprintPlanning.go +++ b/cmd/pm/tasks/sprintPlanning.go @@ -23,9 +23,8 @@ Your task: The goal is to create a realistic sprint plan that delivers value while respecting team capacity.` type SprintPlanningTask struct { - done bool - app *App - setupIssue *Issue + done bool + app *App } func NewSprintPlanningTask(app *App) *SprintPlanningTask { @@ -109,35 +108,21 @@ func (t *SprintPlanningTask) Setup(ctx context.Context) error { Build(), } - if err := t.app.Issues.CreateIssues(ctx, backlogIssues, ""); err != nil { - return err - } - - t.setupIssue = NewIssueBuilder(). - WithTitle("Sprint Planning - Week 1"). - WithDescription(sprintPlanningDescription). - Build() - - return t.app.Issues.CreateIssue(ctx, t.setupIssue, "") + return t.app.Issues.CreateIssues(ctx, backlogIssues, "") } func (t *SprintPlanningTask) Validate(ctx context.Context) ValidationFeedback { expect := check.NewExpector() - issues, err := FetchIssues(ctx, t.app, t.setupIssue) + issues, err := FetchIssues(ctx, t.app) if err != nil { return expect.ValidationFeedback } - if len(issues) == 0 { - expect.Fail("No backlog issues found to plan a sprint with.") - return expect.ValidationFeedback - } - // Sort by priority ascending (0 is highest priority). sorted := make([]*models.Issue, len(issues)) copy(sorted, issues) - for i := 0; i < len(sorted); i++ { + for i := range sorted { for j := i + 1; j < len(sorted); j++ { if sorted[j].Priority < sorted[i].Priority { sorted[i], sorted[j] = sorted[j], sorted[i] @@ -145,10 +130,7 @@ func (t *SprintPlanningTask) Validate(ctx context.Context) ValidationFeedback { } } - topN := 5 - if len(sorted) < topN { - topN = len(sorted) - } + topN := min(len(sorted), 5) top := sorted[:topN] var plannedCount int diff --git a/internal/commands/issues/update.go b/internal/commands/issues/update.go index 29a6b29..3c2bb7a 100644 --- a/internal/commands/issues/update.go +++ b/internal/commands/issues/update.go @@ -6,6 +6,7 @@ import ( "github.com/LazyBachelor/LazyPM/internal/models" "github.com/LazyBachelor/LazyPM/internal/utils/shellcomp" "github.com/spf13/cobra" + "github.com/spf13/pflag" ) var updateFlags Flags @@ -52,6 +53,13 @@ func runUpdateCmd(cmd *cobra.Command, args []string) error { cmd.Printf("Updated issue to:\n%s", models.IssueString(*updatedIssue)) + updateFlags = Flags{} + + cmd.Flags().VisitAll(func(f *pflag.Flag) { + f.Changed = false + _ = f.Value.Set(f.DefValue) + }) + return nil }