diff options
Diffstat (limited to 'Omni/Task.hs')
| -rw-r--r-- | Omni/Task.hs | 70 |
1 files changed, 62 insertions, 8 deletions
diff --git a/Omni/Task.hs b/Omni/Task.hs index 5e0595b..bf262ab 100644 --- a/Omni/Task.hs +++ b/Omni/Task.hs @@ -45,6 +45,7 @@ Usage: task create <title> [options] task edit <id> [options] task delete <id> [--json] + task comment <id> <message> [--json] task list [options] task ready [--json] task show <id> [--json] @@ -63,6 +64,7 @@ Commands: create Create a new task or epic edit Edit an existing task delete Delete a task + comment Add a comment to a task list List all tasks ready Show ready tasks (not blocked) show Show detailed task information @@ -100,6 +102,7 @@ Arguments: <title> Task title <id> Task ID <status> Task status (draft, open, in-progress, review, approved, done) + <message> Comment message <file> JSONL file to import |] @@ -259,6 +262,13 @@ move' args if isJsonMode args then outputSuccess ("Deleted task " <> tid) else putStrLn <| "Deleted task: " <> T.unpack tid + | args `Cli.has` Cli.command "comment" = do + tid <- getArgText args "id" + message <- getArgText args "message" + updatedTask <- addComment tid message + if isJsonMode args + then outputJson updatedTask + else putStrLn <| "Added comment to task: " <> T.unpack tid | args `Cli.has` Cli.command "list" = do maybeType <- case Cli.getArg args (Cli.longOption "type") of Nothing -> pure Nothing @@ -539,9 +549,10 @@ unitTests = taskStatus = Open, taskPriority = P2, taskDependencies = [], + taskDescription = "Child 3", + taskComments = [], taskCreatedAt = taskCreatedAt child1, - taskUpdatedAt = taskUpdatedAt child1, - taskDescription = "Child 3" + taskUpdatedAt = taskUpdatedAt child1 } saveTask child3 @@ -601,7 +612,7 @@ unitTests = Test.unit "can create task with lowercase ID" <| do -- This verifies that lowercase IDs are accepted and not rejected let lowerId = "t-lowercase" - let task = Task lowerId "Lower" WorkTask Nothing Nothing Open P2 [] "Lower description" (read "2025-01-01 00:00:00 UTC") (read "2025-01-01 00:00:00 UTC") + let task = Task lowerId "Lower" WorkTask Nothing Nothing Open P2 [] "Lower description" [] (read "2025-01-01 00:00:00 UTC") (read "2025-01-01 00:00:00 UTC") saveTask task tasks <- loadTasks case findTask lowerId tasks of @@ -609,7 +620,7 @@ unitTests = Nothing -> Test.assertFailure "Should find task with lowercase ID", Test.unit "generateId produces valid ID" <| do tid <- generateId - let task = Task tid "Auto" WorkTask Nothing Nothing Open P2 [] "Auto description" (read "2025-01-01 00:00:00 UTC") (read "2025-01-01 00:00:00 UTC") + let task = Task tid "Auto" WorkTask Nothing Nothing Open P2 [] "Auto description" [] (read "2025-01-01 00:00:00 UTC") (read "2025-01-01 00:00:00 UTC") saveTask task tasks <- loadTasks case findTask tid tasks of @@ -633,7 +644,7 @@ unitTests = Test.unit "lowercase ID does not clash with existing uppercase ID" <| do -- Setup: Create task with Uppercase ID let upperId = "t-UPPER" - let task1 = Task upperId "Upper Task" WorkTask Nothing Nothing Open P2 [] "Upper description" (read "2025-01-01 00:00:00 UTC") (read "2025-01-01 00:00:00 UTC") + let task1 = Task upperId "Upper Task" WorkTask Nothing Nothing Open P2 [] "Upper description" [] (read "2025-01-01 00:00:00 UTC") (read "2025-01-01 00:00:00 UTC") saveTask task1 -- Action: Try to create task with Lowercase ID (same letters) @@ -644,7 +655,7 @@ unitTests = -- treating them as the same is dangerous. let lowerId = "t-upper" - let task2 = Task lowerId "Lower Task" WorkTask Nothing Nothing Open P2 [] "Lower description" (read "2025-01-01 00:00:01 UTC") (read "2025-01-01 00:00:01 UTC") + let task2 = Task lowerId "Lower Task" WorkTask Nothing Nothing Open P2 [] "Lower description" [] (read "2025-01-01 00:00:01 UTC") (read "2025-01-01 00:00:01 UTC") saveTask task2 tasks <- loadTasks @@ -684,7 +695,35 @@ unitTests = Test.unit "FromHttpApiData Status: valid values parse correctly" <| do (parseQueryParam "Open" :: Either Text Status) Test.@?= Right Open (parseQueryParam "InProgress" :: Either Text Status) Test.@?= Right InProgress - (parseQueryParam "Done" :: Either Text Status) Test.@?= Right Done + (parseQueryParam "Done" :: Either Text Status) Test.@?= Right Done, + Test.unit "can add comment to task" <| do + task <- createTask "Task with comment" WorkTask Nothing Nothing P2 [] "Description" + updatedTask <- addComment (taskId task) "This is a test comment" + length (taskComments updatedTask) Test.@?= 1 + case taskComments updatedTask of + (c : _) -> commentText c Test.@?= "This is a test comment" + [] -> Test.assertFailure "Expected at least one comment", + Test.unit "can add multiple comments to task" <| do + task <- createTask "Task with comments" WorkTask Nothing Nothing P2 [] "Description" + _ <- addComment (taskId task) "First comment" + updatedTask <- addComment (taskId task) "Second comment" + length (taskComments updatedTask) Test.@?= 2 + case taskComments updatedTask of + (c1 : c2 : _) -> do + commentText c1 Test.@?= "First comment" + commentText c2 Test.@?= "Second comment" + _ -> Test.assertFailure "Expected at least two comments", + Test.unit "comments are persisted" <| do + task <- createTask "Persistent comments" WorkTask Nothing Nothing P2 [] "Description" + _ <- addComment (taskId task) "Persisted comment" + tasks <- loadTasks + case findTask (taskId task) tasks of + Nothing -> Test.assertFailure "Could not reload task" + Just reloaded -> do + length (taskComments reloaded) Test.@?= 1 + case taskComments reloaded of + (c : _) -> commentText c Test.@?= "Persisted comment" + [] -> Test.assertFailure "Expected at least one comment" ] -- | Test CLI argument parsing to ensure docopt string matches actual usage @@ -918,5 +957,20 @@ cliTests = args `Cli.has` Cli.command "create" Test.@?= True args `Cli.has` Cli.longOption "json" Test.@?= True Cli.getArg args (Cli.longOption "priority") Test.@?= Just "1" - Cli.getArg args (Cli.longOption "namespace") Test.@?= Just "Omni/Task" + Cli.getArg args (Cli.longOption "namespace") Test.@?= Just "Omni/Task", + Test.unit "comment command" <| do + let result = Docopt.parseArgs help ["comment", "t-abc123", "This is a comment"] + case result of + Left err -> Test.assertFailure <| "Failed to parse 'comment': " <> show err + Right args -> do + args `Cli.has` Cli.command "comment" Test.@?= True + Cli.getArg args (Cli.argument "id") Test.@?= Just "t-abc123" + Cli.getArg args (Cli.argument "message") Test.@?= Just "This is a comment", + Test.unit "comment with --json flag" <| do + let result = Docopt.parseArgs help ["comment", "t-abc123", "Test comment", "--json"] + case result of + Left err -> Test.assertFailure <| "Failed to parse 'comment --json': " <> show err + Right args -> do + args `Cli.has` Cli.command "comment" Test.@?= True + args `Cli.has` Cli.longOption "json" Test.@?= True ] |
