From d517ece317e16c52d460d03529219aff256247fc Mon Sep 17 00:00:00 2001 From: Diogo Ribeiro Date: Tue, 3 Jun 2025 23:17:38 +0100 Subject: [PATCH] feat: warn on overdue todos --- action.yml | 5 +++++ src/ActionMain.ts | 8 +++++++- src/core/report.ts | 16 ++++++++++++++++ tests/overdueDetection.test.ts | 25 +++++++++++++++++++++++++ 4 files changed, 53 insertions(+), 1 deletion(-) create mode 100644 tests/overdueDetection.test.ts diff --git a/action.yml b/action.yml index 8d6dd81..626407c 100644 --- a/action.yml +++ b/action.yml @@ -17,6 +17,11 @@ inputs: description: Use structured tag extraction with @assignee, #module, and key=value default: 'false' + warn-overdue: + required: false + description: Emit warnings for TODOs with due dates in the past + default: 'false' + issue-title-template: required: false description: Optional path to custom issue title template diff --git a/src/ActionMain.ts b/src/ActionMain.ts index cc4bb8c..8601111 100644 --- a/src/ActionMain.ts +++ b/src/ActionMain.ts @@ -7,7 +7,7 @@ import { extractTodosFromDir } from './parser/extractTodosFromDir'; import { extractTodosWithStructuredTagsFromDir } from './parser/extractTodosWithStructuredTagsFromDir'; // 👈 novo import { TodoItem } from './parser/types'; import { getExistingIssueTitles, createIssueIfNeeded } from './core/issueManager'; -import { generateMarkdownReport } from './core/report'; +import { generateMarkdownReport, warnOverdueTodos } from './core/report'; import { limitTodos, todoKey } from './core/todoUtils'; import { generateChangelogFromTodos } from './core/changelog'; @@ -30,6 +30,8 @@ async function run(): Promise { const useStructured = core.getInput('structured') === 'true'; + const warnOverdue = core.getInput('warn-overdue') === 'true'; + const todos: TodoItem[] = useStructured ? extractTodosWithStructuredTagsFromDir(workspace) : extractTodosFromDir(workspace); @@ -48,6 +50,10 @@ async function run(): Promise { return true; }); + if (warnOverdue) { + warnOverdueTodos(uniqueTodos); + } + const issueLimit = parseInt(core.getInput('limit') || '5', 10); const todosToCreate = limitTodos(uniqueTodos, issueLimit); diff --git a/src/core/report.ts b/src/core/report.ts index dceb6f7..b30f6c0 100644 --- a/src/core/report.ts +++ b/src/core/report.ts @@ -2,6 +2,7 @@ import fs from 'fs'; import path from 'path'; import { TodoItem } from '../parser/types'; import { todoKey } from './todoUtils'; +import * as core from '@actions/core'; const PRIORITY_ORDER = ['high', 'medium', 'low']; @@ -13,6 +14,21 @@ function getDue(todo: TodoItem): string { return todo.metadata?.due ?? ''; } +export function findOverdueTodos(todos: TodoItem[]): TodoItem[] { + const today = new Date().toISOString().split('T')[0]; + return todos.filter(t => { + const due = t.metadata?.due; + return typeof due === 'string' && due < today; + }); +} + +export function warnOverdueTodos(todos: TodoItem[]): void { + const overdue = findOverdueTodos(todos); + for (const todo of overdue) { + core.warning(`\u23F0 Overdue TODO (${todo.metadata!.due}): ${todo.text} (${todo.file}:${todo.line})`); + } +} + function sortTodos(a: TodoItem, b: TodoItem): number { const pa = getPriority(a); const pb = getPriority(b); diff --git a/tests/overdueDetection.test.ts b/tests/overdueDetection.test.ts new file mode 100644 index 0000000..6245a77 --- /dev/null +++ b/tests/overdueDetection.test.ts @@ -0,0 +1,25 @@ +import { describe, it, expect } from 'vitest'; +import { findOverdueTodos } from '../src/core/report'; +import { TodoItem } from '../src/parser/types'; + +function format(date: Date) { + return date.toISOString().split('T')[0]; +} + +describe('findOverdueTodos', () => { + it('detects todos with past due dates', () => { + const yesterday = format(new Date(Date.now() - 86400000)); + const today = format(new Date()); + const tomorrow = format(new Date(Date.now() + 86400000)); + const todos: TodoItem[] = [ + { tag: 'TODO', text: 'past', file: 'a.ts', line: 1, metadata: { due: yesterday } }, + { tag: 'TODO', text: 'today', file: 'b.ts', line: 2, metadata: { due: today } }, + { tag: 'TODO', text: 'future', file: 'c.ts', line: 3, metadata: { due: tomorrow } }, + { tag: 'TODO', text: 'none', file: 'd.ts', line: 4 } + ]; + + const result = findOverdueTodos(todos); + expect(result.length).toBe(1); + expect(result[0].text).toBe('past'); + }); +});