Merge remote-tracking branch 'origin/main' into Metrics-and-Logs
This commit is contained in:
@@ -2,6 +2,7 @@ package tasks
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
|
||||
"github.com/LazyBachelor/LazyPM/internal/models"
|
||||
"github.com/LazyBachelor/LazyPM/internal/utils/check"
|
||||
@@ -12,12 +13,12 @@ const backlogRefinementDescription = `You are tasked with backlog refinement.
|
||||
|
||||
The product backlog has become cluttered with old and unclear issues. You need to groom the backlog:
|
||||
|
||||
1. Review all issues in the backlog
|
||||
2. Identify stale or obsolete issues (older items that are no longer relevant)
|
||||
3. Update issue descriptions for clarity where needed
|
||||
4. Close issues that are duplicates or no longer applicable
|
||||
5. Reprioritize issues based on current business value
|
||||
6. Ensure remaining issues are well-defined and actionable
|
||||
1. Go to the backlog.
|
||||
2. Find two issues that got the same name or describe the same problem.
|
||||
3. Open one of these issues.
|
||||
4. Select "Close issue"
|
||||
5. Choose "Duplicate issue" as closing reason.
|
||||
6. Save/close issue.
|
||||
|
||||
Focus on making the backlog a reliable source of upcoming work.`
|
||||
|
||||
@@ -47,60 +48,65 @@ func (t *BacklogRefinementTask) Questions(interfaceType InterfaceType) Questions
|
||||
return BaseQuestions(interfaceType).With(
|
||||
huh.NewGroup(
|
||||
huh.NewSelect[int]().
|
||||
Title("How many issues did you close or update during refinement?").
|
||||
Key("how-many-duplicate-issues").
|
||||
Title("How many duplicate issues did you close during refinement?").
|
||||
Options(
|
||||
huh.NewOption("1-2", 1),
|
||||
huh.NewOption("3-4", 2),
|
||||
huh.NewOption("5+", 3),
|
||||
huh.NewOption("1", 1),
|
||||
huh.NewOption("2", 2),
|
||||
huh.NewOption("3+", 3),
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
func (t *BacklogRefinementTask) QuestionnaireKeys(_ InterfaceType) []string {
|
||||
return []string{"task_completed", "task_difficulty", "how-many-duplicate-issues"}
|
||||
}
|
||||
|
||||
func (t *BacklogRefinementTask) Setup(ctx context.Context) error {
|
||||
if err := ClearIssues(t.app); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
refinementIssues := []*models.Issue{
|
||||
NewIssueBuilder().
|
||||
WithTitle("Old feature request: Fax integration").
|
||||
WithDescription("Allow sending reports via fax. DEPRECATED - nobody uses fax anymore").
|
||||
WithPriority(3).
|
||||
WithStatus(models.StatusOpen).
|
||||
WithIssueType(models.TypeTask).
|
||||
Build(),
|
||||
NewIssueBuilder().
|
||||
WithTitle("User profile page").
|
||||
WithDescription("Create page for users to view profile. DUPLICATE of user-management epic").
|
||||
WithDescription("Create page for users to view and edit their profile").
|
||||
WithPriority(2).
|
||||
WithStatus(models.StatusOpen).
|
||||
WithIssueType(models.TypeTask).
|
||||
Build(),
|
||||
NewIssueBuilder().
|
||||
WithTitle("Mobile app redesign").
|
||||
WithDescription("Redesign mobile interface with modern UI patterns. Still relevant, needs clarity").
|
||||
WithTitle("User profile page").
|
||||
WithDescription("Allow users to view their profile information").
|
||||
WithPriority(2).
|
||||
WithStatus(models.StatusOpen).
|
||||
WithIssueType(models.TypeTask).
|
||||
Build(),
|
||||
NewIssueBuilder().
|
||||
WithTitle("Fix login timeout").
|
||||
WithDescription("Login sometimes times out after 30 seconds").
|
||||
WithPriority(1).
|
||||
WithStatus(models.StatusOpen).
|
||||
WithIssueType(models.TypeTask).
|
||||
WithIssueType(models.TypeBug).
|
||||
Build(),
|
||||
NewIssueBuilder().
|
||||
WithTitle("Legacy data export tool").
|
||||
WithDescription("Tool for exporting data in old format. OBSOLETE - format no longer supported").
|
||||
WithPriority(3).
|
||||
WithTitle("Fix login timeout").
|
||||
WithDescription("Users report login requests timing out").
|
||||
WithPriority(1).
|
||||
WithStatus(models.StatusOpen).
|
||||
WithIssueType(models.TypeTask).
|
||||
WithIssueType(models.TypeBug).
|
||||
Build(),
|
||||
NewIssueBuilder().
|
||||
WithTitle("API v1 documentation").
|
||||
WithDescription("Document old API version. DEPRECATED - migrating to v2").
|
||||
WithPriority(3).
|
||||
WithTitle("Mobile app redesign").
|
||||
WithDescription("Redesign mobile interface with modern UI patterns").
|
||||
WithPriority(2).
|
||||
WithStatus(models.StatusOpen).
|
||||
WithIssueType(models.TypeTask).
|
||||
Build(),
|
||||
NewIssueBuilder().
|
||||
WithTitle("Customer feedback system").
|
||||
WithDescription("Build system for collecting user feedback. HIGH VALUE - prioritize").
|
||||
WithDescription("Build system for collecting user feedback").
|
||||
WithPriority(2).
|
||||
WithStatus(models.StatusOpen).
|
||||
WithIssueType(models.TypeTask).
|
||||
@@ -122,5 +128,22 @@ func (t *BacklogRefinementTask) Setup(ctx context.Context) error {
|
||||
func (t *BacklogRefinementTask) Validate(ctx context.Context) ValidationFeedback {
|
||||
expect := check.NewExpector()
|
||||
|
||||
issues, err := FetchIssues(ctx, t.app, t.setupIssue)
|
||||
if err != nil {
|
||||
return expect.ValidationFeedback
|
||||
}
|
||||
|
||||
var closedDuplicate *models.Issue
|
||||
for _, issue := range issues {
|
||||
if issue.Status == models.StatusClosed &&
|
||||
strings.Contains(strings.ToLower(issue.CloseReason), "duplicate") {
|
||||
closedDuplicate = issue
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
expect.Assert(closedDuplicate != nil,
|
||||
"Expected one duplicate issue to be closed with 'Duplicate issue' as closing reason")
|
||||
|
||||
return expect.Complete()
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ package tasks
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
@@ -18,15 +17,14 @@ 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. Assign this Issue to yourself as "Me" and mark it as "In Progress"
|
||||
2. Create a New Issue and give it these details:
|
||||
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"
|
||||
3. A file will appear in the current directory named "code.txt".
|
||||
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 = `
|
||||
Please upgrade the MongoDB Driver dependency in the go.mod file to the latest version.
|
||||
@@ -122,7 +120,7 @@ func (t *CodingTask) Setup(ctx context.Context) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
var codeTaskInProgress = false
|
||||
var codingTaskInProgress = false
|
||||
|
||||
func (t *CodingTask) Validate(ctx context.Context) ValidationFeedback {
|
||||
expect := check.NewExpector()
|
||||
@@ -132,47 +130,31 @@ func (t *CodingTask) Validate(ctx context.Context) ValidationFeedback {
|
||||
return expect.ValidationFeedback
|
||||
}
|
||||
|
||||
expect.Assert(t.setupIssue.Assignee == "Me",
|
||||
"The original issue should be assigned to 'Me'.")
|
||||
|
||||
expect.Assert(t.setupIssue.Status == models.StatusInProgress,
|
||||
"The original issue should be marked as In Progress before starting work.")
|
||||
|
||||
expect.Assert(len(issues) > 0,
|
||||
"No new issues created. Please create an issue with the specified details.")
|
||||
|
||||
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. Delete the extra issues and try again.")
|
||||
expect.Assert(len(issues) < 2, "Multiple issues were created instead of one")
|
||||
|
||||
expect.NotEmptyString(issue.Title,
|
||||
"Issue title should not be empty")
|
||||
expect.NotEmptyAndEqual(issue.Title, "Upgrade MongoDB Driver Dependency", "Issue title")
|
||||
|
||||
expect.Assert(issue.Title == "Upgrade MongoDB Driver Dependency",
|
||||
fmt.Sprintf("Issue title does not match the expected value 'Upgrade MongoDB Driver Dependency', but was '%s'", issue.Title))
|
||||
expect.NotEmptyAndEqual(issue.Description,
|
||||
"We need to upgrade the MongoDB Driver dependency to the latest version.", "Issue description")
|
||||
|
||||
expect.NotEmptyString(issue.Description,
|
||||
"Issue description should not be empty")
|
||||
expect.NotEmptyAndEqual(issue.Assignee, "Me", "Issue Assignee")
|
||||
|
||||
expect.Assert(issue.Description == "We need to upgrade the MongoDB Driver dependency to the latest version.",
|
||||
fmt.Sprintf("Issue description does not match 'We need to upgrade the MongoDB Driver dependency to the latest version.', but was '%s'", issue.Description))
|
||||
expect.Equal(issue.IssueType, models.TypeChore, "Issue type")
|
||||
|
||||
expect.Assert(issue.IssueType == models.TypeChore,
|
||||
fmt.Sprintf("Issue type should be 'Chore', but was '%s'", issue.IssueType))
|
||||
|
||||
expect.Assert(issue.Assignee == "Me",
|
||||
fmt.Sprintf("Issue should be assigned to 'Me', but was assigned to '%s'", issue.Assignee))
|
||||
|
||||
if issue.Status == models.StatusInProgress || codeTaskInProgress {
|
||||
codeTaskInProgress = true
|
||||
if issue.Status == models.StatusInProgress || codingTaskInProgress {
|
||||
codingTaskInProgress = true
|
||||
} else {
|
||||
expect.Fail("Issue should be marked as In Progress when work starts")
|
||||
expect.Fail("The issue should be marked as In Progress while working on the task.")
|
||||
return expect.ValidationFeedback
|
||||
}
|
||||
|
||||
if _, err := os.Stat("./code.txt"); os.IsNotExist(err) {
|
||||
@@ -195,14 +177,8 @@ func (t *CodingTask) Validate(ctx context.Context) 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.")
|
||||
|
||||
if !codeTaskInProgress {
|
||||
return expect.ValidationFeedback
|
||||
} else if issue.Status != models.StatusClosed {
|
||||
expect.Fail("Issue should be set to Closed once the work is completed")
|
||||
} else {
|
||||
expect.Assert(t.setupIssue.Status == models.StatusClosed,
|
||||
"The original setup issue should be set to Closed once the work is completed")
|
||||
}
|
||||
expect.Assert(codingTaskInProgress && issue.Status == models.StatusClosed,
|
||||
"The issue should be marked as Closed after completing the task.")
|
||||
|
||||
return expect.Complete()
|
||||
}
|
||||
|
||||
@@ -16,8 +16,7 @@ Your task:
|
||||
1. Create a new issue with the title "My first Issue"
|
||||
2. Add this detailed description "I need to do some coding"
|
||||
3. Assign the issue to yourself as "Me"
|
||||
4. Mark the issue as In Progress when you start working on it
|
||||
5. Close the issue once you've completed the work
|
||||
4. Mark the issue as In Progress when you are done.
|
||||
|
||||
Make sure to fill out all the necessary details to help others understand the work item.`
|
||||
|
||||
@@ -43,8 +42,7 @@ func (t *CreateIssueTask) Questions(interfaceType InterfaceType) Questions {
|
||||
return BaseQuestions(interfaceType)
|
||||
}
|
||||
|
||||
func (t *CreateIssueTask) QuestionnaireKeys(interfaceType InterfaceType) []string {
|
||||
_ = interfaceType
|
||||
func (t *CreateIssueTask) QuestionnaireKeys(_ InterfaceType) []string {
|
||||
return []string{"task_completed", "task_difficulty"}
|
||||
}
|
||||
|
||||
@@ -61,8 +59,6 @@ func (t *CreateIssueTask) Setup(ctx context.Context) error {
|
||||
return t.app.Issues.CreateIssue(ctx, t.setupIssue, "")
|
||||
}
|
||||
|
||||
var isInProgress = false
|
||||
|
||||
func (t *CreateIssueTask) Validate(ctx context.Context) ValidationFeedback {
|
||||
expect := check.NewExpector()
|
||||
|
||||
@@ -78,30 +74,14 @@ func (t *CreateIssueTask) Validate(ctx context.Context) ValidationFeedback {
|
||||
|
||||
issue := issues[0]
|
||||
|
||||
expect.Assert(len(issues) < 2, "Multiple issues were created instead of one. Delete the extra issues and try again.")
|
||||
expect.Assert(len(issues) < 2, "Multiple issues were created instead of one")
|
||||
|
||||
expect.NotEmptyString(issue.Title, "Issue title should not be empty")
|
||||
expect.Assert(issue.Title == "My first Issue",
|
||||
fmt.Sprintf("Issue title does not match the expected value 'My first Issue', but was '%s'", issue.Title))
|
||||
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.NotEmptyString(issue.Description, "Issue description should not be empty")
|
||||
expect.Assert(issue.Description == "I need to do some coding",
|
||||
fmt.Sprintf("Issue description does not match the expected value 'I need to do some coding', but was '%s'", issue.Description))
|
||||
|
||||
expect.Assert(issue.Assignee == "Me",
|
||||
fmt.Sprintf("Issue should be assigned to 'Me', but was assigned to '%s'", issue.Assignee))
|
||||
|
||||
if issue.Status == models.StatusInProgress || isInProgress {
|
||||
isInProgress = true
|
||||
} else {
|
||||
expect.Fail("Issue should be marked as in-progress when work starts")
|
||||
}
|
||||
|
||||
if !isInProgress {
|
||||
return expect.ValidationFeedback
|
||||
} else if issue.Status != models.StatusClosed {
|
||||
expect.Fail("Issue should be set to Closed once the work is completed")
|
||||
}
|
||||
expect.Assert(issue.Status == models.StatusInProgress,
|
||||
fmt.Sprintf("Issue status should be 'In Progress', but was '%s'", issue.Status))
|
||||
|
||||
return expect.Complete()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user