Merge pull request #37 from LazyBachelor/LPM-85

LPM-85 Coding Task
This commit is contained in:
Robin Olsen
2026-03-04 08:51:36 -08:00
committed by GitHub
4 changed files with 164 additions and 47 deletions

View File

@@ -2,37 +2,80 @@ package tasks
import (
"context"
"fmt"
"os"
"strings"
"github.com/LazyBachelor/LazyPM/internal/models"
"github.com/LazyBachelor/LazyPM/internal/utils/check"
"github.com/charmbracelet/huh"
)
const codingDescription = `You are tasked with writing a simple function.
const codingDescription = `You are tasked with doing a chore in the codebase.
This task will test your ability to write clean, working code.
This task will test your ability to read and understand instructions, change text, and save it to a file.
The MongoDB Driver dependency in the file is outdated and needs to be updated to the latest version.
This is a common task for developers, and it requires attention to detail and the ability to follow instructions carefully.
Your task:
1. Review the requirements below
2. Write a function that takes two integers and returns their sum
3. The function should be named "Add"
4. The function should be part of the "coding" package
5. Save your code to the code.txt file
1. Assign this Issue to yourself as "Me" and mark it as "In Progress"
2. 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".
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".`
Requirements:
- Function name: Add
- Parameters: two integers
- Return value: integer (sum of the two inputs)
- Package: coding`
var textFileDescription = `
Please upgrade the MongoDB Driver dependency in the go.mod file to the latest version.
It should be v1.17.9. After you are done, save the file and mark the task as completed.
############################################################`
var textFileContent = codingDescription + `
Please write your code below this line!
############################################################
var code = `
require (
charm.land/lipgloss/v2 v2.0.0-beta.3.0.20251106193318-19329a3e8410
github.com/go-git/go-git/v6 v6.0.0-20260222090600-424e9964d3a3
github.com/muesli/reflow v0.3.0
github.com/steveyegge/beads v0.49.6
go.mongodb.org/mongo-driver v1.17.8
go.mongodb.org/mongo-driver/v2 v2.5.0
)
require (
github.com/c-bata/go-prompt v0.2.6
github.com/charmbracelet/bubbles v0.21.1
github.com/charmbracelet/bubbletea v1.3.10
github.com/charmbracelet/fang v0.4.4
github.com/charmbracelet/huh v0.8.0
github.com/charmbracelet/lipgloss v1.1.1-0.20250404203927-76690c660834
github.com/spf13/cobra v1.10.2
golang.org/x/term v0.40.0
)
require (
github.com/NYTimes/gziphandler v1.1.1
github.com/a-h/templ v0.3.977
github.com/donseba/go-htmx v1.12.1
github.com/go-chi/chi/v5 v5.2.5
github.com/go-playground/form/v4 v4.3.0
github.com/go-playground/validator/v10 v10.30.1
github.com/rs/cors v1.11.1
)
tool (
github.com/a-h/templ/cmd/templ
github.com/haatos/goshipit/cmd/gsi
)
`
var textFileContent = codingDescription + textFileDescription + "\n" + code
type CodingTask struct {
done bool
app *App
done bool
setupIssue *Issue
app *App
}
func NewCodingTask(app *App) *CodingTask {
@@ -48,35 +91,11 @@ func (t *CodingTask) Details() TaskDetails {
}
func (t *CodingTask) Questions(interfaceType InterfaceType) (questions Questions) {
return BaseQuestions(interfaceType).
With(
ReplQuestion(interfaceType,
huh.NewConfirm().Key("repl_experience").Title("Question only for REPL interface")),
).
With(
WebQuestion(interfaceType,
huh.NewInput().Key("web_feedback").Title("Question only for Web interface")),
).
With(
TUIQuestion(interfaceType,
huh.NewConfirm().Key("tui_experience").Title("Question only for TUI interface")),
).
With(
Question(
huh.NewConfirm().Key("final_confirmation").Title("One last question for all interfaces!")),
)
return BaseQuestions(interfaceType)
}
func (t *CodingTask) QuestionnaireKeys(interfaceType InterfaceType) []string {
keys := []string{"task_completed", "task_difficulty", "final_confirmation"}
switch interfaceType {
case InterfaceTypeREPL:
keys = append(keys, "repl_experience")
case InterfaceTypeWeb:
keys = append(keys, "web_feedback")
case InterfaceTypeTUI:
keys = append(keys, "tui_experience")
}
keys := []string{"task_completed", "task_difficulty"}
return keys
}
@@ -85,6 +104,17 @@ 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
}
@@ -92,8 +122,87 @@ func (t *CodingTask) Setup(ctx context.Context) error {
return nil
}
var codeTaskInProgress = false
func (t *CodingTask) Validate(ctx context.Context) ValidationFeedback {
expect := check.NewExpector()
expect.Assert(true, "This task is always valid")
issues, err := FetchIssues(ctx, t.app, t.setupIssue)
if err != nil {
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
}
issue := issues[0]
expect.Assert(len(issues) < 2,
"Multiple issues were created instead of one. Delete the extra issues and try again.")
expect.NotEmptyString(issue.Title,
"Issue title should not be empty")
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.NotEmptyString(issue.Description,
"Issue description should not be empty")
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.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
} else {
expect.Fail("Issue should be marked as In Progress when work starts")
}
if _, err := os.Stat("./code.txt"); os.IsNotExist(err) {
expect.Fail("The code.txt file should exist on the desktop.")
return expect.ValidationFeedback
}
fileContent, err := os.ReadFile("./code.txt")
if err != nil {
expect.Fail("Error reading code.txt file: " + err.Error())
return expect.ValidationFeedback
}
code, ok := strings.CutPrefix(string(fileContent), codingDescription+textFileDescription+"\n")
if !ok {
expect.Fail("The content of code.txt does not match the expected format.")
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.")
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")
}
return expect.Complete()
}

View File

@@ -25,6 +25,13 @@ func runStatusCmd(cmd *cobra.Command, args []string) error {
return nil
}
cmd.Print(app.CurrentFeedback.Message)
cmd.Println(app.CurrentFeedback.Message)
for _, check := range app.CurrentFeedback.Checks {
if check.Valid {
cmd.Printf("✅ %s\n", check.Message)
} else {
cmd.Printf("❌ %s\n", check.Message)
}
}
return nil
}

View File

@@ -129,6 +129,7 @@ func (r *REPL) watchValidation() {
r.app.CurrentFeedback = &ValidationFeedback{
Success: feedback.Success,
Message: feedback.Message,
Checks: feedback.Checks,
}
}
if feedback.Success {

View File

@@ -69,7 +69,7 @@ func (m TaskModel) View() string {
style.TextStyle.Render("Terminal too small."))
}
boxWidth := min(m.width-10, 80)
boxWidth := min(m.width-10, 120)
detailsText := fmt.Sprintf("Time to complete: %s | Difficulty: %s", m.TimeToComplete, m.Difficulty)