remove setup issues and simplify validaiton

This commit is contained in:
Robin Olsen
2026-03-19 15:21:30 +01:00
parent 64a02a6ed5
commit b0c76b0565
10 changed files with 91 additions and 219 deletions

View File

@@ -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

View File

@@ -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

View File

@@ -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()
}

View File

@@ -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()
}

View File

@@ -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()
}

View File

@@ -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()
}

View File

@@ -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()
}

View File

@@ -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()
}

View File

@@ -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