fix: 不正なtasks.yamlで削除せず停止するように修正 (#418)
* test: add regression coverage for invalid tasks.yaml preservation * fix: keep invalid tasks.yaml untouched and fail fast
This commit is contained in:
parent
ac4cb9c8a5
commit
fe0b7237a7
@ -94,18 +94,29 @@ describe('TaskRunner (tasks.yaml)', () => {
|
|||||||
expect(recovered).toBe(0);
|
expect(recovered).toBe(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should recover from corrupted tasks.yaml and allow adding tasks again', () => {
|
it('should preserve corrupted tasks.yaml and throw', () => {
|
||||||
mkdirSync(join(testDir, '.takt'), { recursive: true });
|
mkdirSync(join(testDir, '.takt'), { recursive: true });
|
||||||
writeFileSync(join(testDir, '.takt', 'tasks.yaml'), 'tasks:\n - name: [broken', 'utf-8');
|
writeFileSync(join(testDir, '.takt', 'tasks.yaml'), 'tasks:\n - name: [broken', 'utf-8');
|
||||||
|
|
||||||
expect(() => runner.listTasks()).not.toThrow();
|
const tasksFilePath = join(testDir, '.takt', 'tasks.yaml');
|
||||||
expect(runner.listTasks()).toEqual([]);
|
expect(() => runner.listTasks()).toThrow(/Invalid tasks\.yaml/);
|
||||||
expect(existsSync(join(testDir, '.takt', 'tasks.yaml'))).toBe(false);
|
expect(existsSync(tasksFilePath)).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
const task = runner.addTask('Task after recovery');
|
it('should preserve tasks.yaml and throw when pending record has started_at', () => {
|
||||||
expect(task.name).toContain('task-after-recovery');
|
writeTasksFile(testDir, [{
|
||||||
expect(existsSync(join(testDir, '.takt', 'tasks.yaml'))).toBe(true);
|
name: 'broken-pending-task',
|
||||||
expect(runner.listTasks()).toHaveLength(1);
|
status: 'pending',
|
||||||
|
content: 'Broken pending',
|
||||||
|
created_at: '2026-02-09T00:00:00.000Z',
|
||||||
|
started_at: '2026-02-09T00:01:00.000Z',
|
||||||
|
completed_at: null,
|
||||||
|
owner_pid: null,
|
||||||
|
}]);
|
||||||
|
|
||||||
|
const tasksFilePath = join(testDir, '.takt', 'tasks.yaml');
|
||||||
|
expect(() => runner.claimNextTasks(1)).toThrow();
|
||||||
|
expect(existsSync(tasksFilePath)).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should load pending content from relative content_file', () => {
|
it('should load pending content from relative content_file', () => {
|
||||||
@ -164,7 +175,7 @@ describe('TaskRunner (tasks.yaml)', () => {
|
|||||||
expect(() => runner.listTasks()).toThrow(/Task spec file is missing/i);
|
expect(() => runner.listTasks()).toThrow(/Task spec file is missing/i);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should reset tasks file when both content and content_file are set', () => {
|
it('should preserve tasks file and throw when both content and content_file are set', () => {
|
||||||
writeTasksFile(testDir, [{
|
writeTasksFile(testDir, [{
|
||||||
name: 'task-a',
|
name: 'task-a',
|
||||||
status: 'pending',
|
status: 'pending',
|
||||||
@ -176,8 +187,9 @@ describe('TaskRunner (tasks.yaml)', () => {
|
|||||||
owner_pid: null,
|
owner_pid: null,
|
||||||
}]);
|
}]);
|
||||||
|
|
||||||
expect(runner.listTasks()).toEqual([]);
|
const tasksFilePath = join(testDir, '.takt', 'tasks.yaml');
|
||||||
expect(existsSync(join(testDir, '.takt', 'tasks.yaml'))).toBe(false);
|
expect(() => runner.listTasks()).toThrow(/Invalid tasks\.yaml/);
|
||||||
|
expect(existsSync(tasksFilePath)).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should throw when content_file target is missing', () => {
|
it('should throw when content_file target is missing', () => {
|
||||||
|
|||||||
@ -56,9 +56,11 @@ export class TaskStore {
|
|||||||
const parsed = parseYaml(raw) as unknown;
|
const parsed = parseYaml(raw) as unknown;
|
||||||
return TasksFileSchema.parse(parsed);
|
return TasksFileSchema.parse(parsed);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
log.error('tasks.yaml is broken. Resetting file.', { file: this.tasksFile, error: String(err) });
|
log.error('tasks.yaml is broken. Keeping file untouched.', { file: this.tasksFile, error: String(err) });
|
||||||
fs.unlinkSync(this.tasksFile);
|
const reason = err instanceof Error ? err.message : String(err);
|
||||||
return { tasks: [] };
|
throw new Error(
|
||||||
|
`Invalid tasks.yaml: ${this.tasksFile}. Please fix the file and retry. Cause: ${reason}`,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user