🐞 fix: Error cleanup, add test harness
This commit is contained in:
@@ -19,10 +19,11 @@ declare(strict_types=1);
|
||||
namespace IronKanban\Repository;
|
||||
|
||||
use IronKanban\Domain\Task;
|
||||
use IronKanban\Markdown\FrontMatterDocument;
|
||||
use IronKanban\Markdown\FrontMatterParser;
|
||||
use IronKanban\Support\FileLock;
|
||||
use IronKanban\Support\IdGenerator;
|
||||
use IronKanban\Support\Paths;
|
||||
use IronKanban\Support\TaskMapper;
|
||||
use RuntimeException;
|
||||
|
||||
/**
|
||||
@@ -40,10 +41,14 @@ class TaskRepository {
|
||||
*
|
||||
* @param Paths $paths The paths helper
|
||||
* @param FrontMatterParser $frontMatterParser The front matter parser
|
||||
* @param TaskMapper $taskMapper The task mapper
|
||||
* @param IdGenerator $idGenerator The ID generator
|
||||
*/
|
||||
public function __construct(
|
||||
private readonly Paths $paths,
|
||||
private readonly FrontMatterParser $frontMatterParser
|
||||
private readonly FrontMatterParser $frontMatterParser,
|
||||
private readonly TaskMapper $taskMapper,
|
||||
private readonly IdGenerator $idGenerator
|
||||
) {
|
||||
}
|
||||
|
||||
@@ -69,7 +74,14 @@ class TaskRepository {
|
||||
continue;
|
||||
}
|
||||
|
||||
$tasks[] = $this->_mapFileToTask($projectId, $filePath);
|
||||
$fileName = basename($filePath);
|
||||
$document = $this->frontMatterParser->parseFile($filePath);
|
||||
|
||||
$tasks[] = $this->taskMapper->fromDocument(
|
||||
$projectId,
|
||||
$fileName,
|
||||
$document
|
||||
);
|
||||
}
|
||||
|
||||
usort(
|
||||
@@ -96,13 +108,13 @@ class TaskRepository {
|
||||
* @throws RuntimeException If task not found
|
||||
*/
|
||||
public function get(string $projectId, string $taskId): Task {
|
||||
$filePath = $this->paths->getTaskFilePath($projectId, $taskId);
|
||||
|
||||
if (!is_file($filePath)) {
|
||||
throw new RuntimeException("Task not found: {$taskId}");
|
||||
foreach ($this->getAll($projectId) as $task) {
|
||||
if ($task->id === $taskId) {
|
||||
return $task;
|
||||
}
|
||||
}
|
||||
|
||||
return $this->_mapFileToTask($projectId, $filePath);
|
||||
throw new RuntimeException("Task not found: {$taskId}");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -115,12 +127,13 @@ class TaskRepository {
|
||||
public function save(Task $task): void {
|
||||
$this->paths->ensureTasksPath($task->projectId);
|
||||
|
||||
$filePath = $this->paths->getTaskFilePath($task->projectId, $task->id);
|
||||
$filePath = $this->paths->getTaskFilePath($task->projectId, $task->fileName);
|
||||
$lockPath = $filePath . '.lock';
|
||||
|
||||
FileLock::run(
|
||||
$lockPath, function () use ($task, $filePath): void {
|
||||
$document = $this->_mapTaskToDocument($task);
|
||||
$lockPath,
|
||||
function () use ($task, $filePath): void {
|
||||
$document = $this->taskMapper->toDocument($task);
|
||||
$contents = $this->frontMatterParser->dump($document);
|
||||
|
||||
$this->_atomicWrite($filePath, $contents);
|
||||
@@ -139,38 +152,45 @@ class TaskRepository {
|
||||
*/
|
||||
public function create(array $data): Task {
|
||||
$projectId = $this->_requireString($data, 'projectId');
|
||||
$title = $this->_requireString($data, 'title');
|
||||
$body = (string) ($data['body'] ?? '');
|
||||
$column = $this->_normalizeColumn((string) ($data['column'] ?? 'backlog'));
|
||||
$priority = (string) ($data['priority'] ?? 'normal');
|
||||
$title = $this->_requireString($data, 'title');
|
||||
$body = (string) ($data['body'] ?? '');
|
||||
$column = $this->taskMapper->normalizeColumn(
|
||||
(string) ($data['column'] ?? 'backlog')
|
||||
);
|
||||
$priority = (string) ($data['priority'] ?? 'normal');
|
||||
$completed = (bool) ($data['completed'] ?? false);
|
||||
$isActive = (bool) ($data['isActive'] ?? true);
|
||||
$order = isset($data['order']) ? (int) $data['order'] : 100;
|
||||
$now = gmdate('c');
|
||||
$isActive = (bool) ($data['isActive'] ?? true);
|
||||
$order = isset($data['order']) ? (int) $data['order'] : 100;
|
||||
$now = gmdate('c');
|
||||
|
||||
$taskId = $this->_generateTaskId();
|
||||
$taskId = $this->idGenerator->generateTaskId();
|
||||
$fileName = $this->idGenerator->generateTaskFileName($taskId);
|
||||
|
||||
$meta = [
|
||||
'id' => $taskId,
|
||||
'type' => 'task',
|
||||
'title' => $title,
|
||||
'project_id' => $projectId,
|
||||
'column' => $column,
|
||||
'order' => $order,
|
||||
'completed' => $completed,
|
||||
'priority' => $priority,
|
||||
'is_active' => $isActive,
|
||||
'created' => $now,
|
||||
'updated' => $now,
|
||||
'tags' => [],
|
||||
'id' => $taskId,
|
||||
'type' => 'task',
|
||||
'title' => $title,
|
||||
'project_id' => $projectId,
|
||||
'column' => $column,
|
||||
'order' => $order,
|
||||
'completed' => $completed,
|
||||
'priority' => $priority,
|
||||
'is_active' => $isActive,
|
||||
'created' => $now,
|
||||
'updated' => $now,
|
||||
'tags' => [],
|
||||
];
|
||||
|
||||
if (isset($data['status'])) {
|
||||
$meta['status'] = (string) $data['status'];
|
||||
if (array_key_exists('status', $data)) {
|
||||
$meta['status'] = $data['status'];
|
||||
}
|
||||
|
||||
if (isset($data['statusNote'])) {
|
||||
$meta['status_note'] = (string) $data['statusNote'];
|
||||
if (array_key_exists('statusNote', $data)) {
|
||||
$meta['status_note'] = $data['statusNote'];
|
||||
}
|
||||
|
||||
if (array_key_exists('section', $data)) {
|
||||
$meta['section'] = $data['section'];
|
||||
}
|
||||
|
||||
$task = new Task(
|
||||
@@ -183,6 +203,7 @@ class TaskRepository {
|
||||
priority: $priority,
|
||||
isActive: $isActive,
|
||||
body: $body,
|
||||
fileName: $fileName,
|
||||
meta: $meta
|
||||
);
|
||||
|
||||
@@ -202,15 +223,17 @@ class TaskRepository {
|
||||
* @throws RuntimeException If task not found
|
||||
*/
|
||||
public function delete(string $projectId, string $taskId): void {
|
||||
$filePath = $this->paths->getTaskFilePath($projectId, $taskId);
|
||||
$task = $this->get($projectId, $taskId);
|
||||
$filePath = $this->paths->getTaskFilePath($projectId, $task->fileName);
|
||||
$lockPath = $filePath . '.lock';
|
||||
|
||||
if (!is_file($filePath)) {
|
||||
throw new RuntimeException("Task not found: {$taskId}");
|
||||
}
|
||||
|
||||
FileLock::run(
|
||||
$lockPath, function () use ($filePath): void {
|
||||
$lockPath,
|
||||
function () use ($filePath): void {
|
||||
if (!is_file($filePath)) {
|
||||
throw new RuntimeException("Task file not found: {$filePath}");
|
||||
}
|
||||
|
||||
if (!unlink($filePath)) {
|
||||
throw new RuntimeException(
|
||||
"Unable to delete task file: {$filePath}"
|
||||
|
||||
Reference in New Issue
Block a user