Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .yarnrc.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
nodeLinker: node-modules
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ A GitHub Action that scans your codebase for inline TODOs, FIXMEs, and BUG comme
- ✅ Extracts metadata like `priority`, `due`, etc.
- ✅ Automatically labels issues based on type and metadata
- ✅ Creates labels on the fly if they don't exist
- ✅ Supports custom label colors and descriptions via JSON config

---

Expand Down Expand Up @@ -75,8 +76,9 @@ If a label like `priority:high` or `due:2025-06-01` doesn't exist, it will be au
## 📌 Notes

- Max **5 issues** are created per run to avoid rate limiting (configurable via the `limit` input)
- **Duplicate detection** is not yet implemented _(coming soon)_
- All labels are **auto-created with default colors** if missing
- **Duplicate detection** is not yet implemented _(coming soon)_
- All labels are **auto-created with default colors** if missing
- Provide a JSON file via `label-config` to override colors and descriptions

---

Expand Down
4 changes: 4 additions & 0 deletions action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ inputs:
required: false
description: Optional path to custom issue body template

label-config:
required: false
description: Optional path to JSON file with custom label colors and descriptions

llm:
required: false
description: Use LLM to generate issue titles and bodies
Expand Down
6 changes: 6 additions & 0 deletions src/ActionMain.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { extractTodosWithStructuredTagsFromDir } from './parser/extractTodosWith
import { TodoItem } from './parser/types';
import { getExistingIssueTitles, createIssueIfNeeded } from './core/issueManager';
import { generateMarkdownReport, warnOverdueTodos } from './core/report';
import { loadLabelConfig } from './core/labelManager';
import { limitTodos, todoKey } from './core/todoUtils';
import { generateChangelogFromTodos } from './core/changelog';

Expand All @@ -18,6 +19,7 @@ async function run(): Promise<void> {
const generateReport = core.getInput('report') === 'true';
const titleTemplatePath = core.getInput('issue-title-template');
const bodyTemplatePath = core.getInput('issue-body-template');
const labelConfigPath = core.getInput('label-config');
const workspace = process.env.GITHUB_WORKSPACE || '.';

// LLM support
Expand All @@ -29,6 +31,10 @@ async function run(): Promise<void> {

const useStructured = core.getInput('structured') === 'true';

if (labelConfigPath) {
loadLabelConfig(labelConfigPath);
}

const warnOverdue = core.getInput('warn-overdue') === 'true';

const todos: TodoItem[] = useStructured
Expand Down
25 changes: 23 additions & 2 deletions src/core/labelManager.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import * as github from '@actions/github';
import * as core from '@actions/core';
import fs from 'fs';
import { TodoItem } from '../parser/types';
import { classifyTodoText } from './classifier'; // Novo: classificador heurístico ou LLM

Expand All @@ -22,6 +23,24 @@ export const LABEL_COLORS: Record<string, string> = {
doc: '0075ca'
};

export interface LabelDefinition {
color?: string;
description?: string;
}

let CUSTOM_LABEL_CONFIG: Record<string, LabelDefinition> = {};

export function loadLabelConfig(path: string): void {
try {
const raw = fs.readFileSync(path, 'utf8');
CUSTOM_LABEL_CONFIG = JSON.parse(raw);
core.info(`\uD83D\uDCC4 Loaded label config from ${path}`);
} catch (err: any) {
core.warning(`⚠️ Failed to load label config: ${err.message}`);
CUSTOM_LABEL_CONFIG = {};
}
}

// Fallback para labels metadata:priority, due, etc.
export function labelsFromMetadata(metadata?: Record<string, string>): string[] {
if (!metadata) return [];
Expand Down Expand Up @@ -50,13 +69,15 @@ export async function ensureLabelExists(
} catch (err: any) {
if (err.status === 404) {
const base = label.split(':')[0];
const color = LABEL_COLORS[base] || 'cccccc';
const custom = CUSTOM_LABEL_CONFIG[label] || CUSTOM_LABEL_CONFIG[base] || {};
const color = custom.color || LABEL_COLORS[base] || 'cccccc';
const description = custom.description || 'Auto-created by smart-todo-action';
await octokit.rest.issues.createLabel({
owner,
repo,
name: label,
color,
description: 'Auto-created by smart-todo-action'
description
});
core.info(`🏷️ Created label: ${label}`);
} else {
Expand Down
4 changes: 4 additions & 0 deletions tests/fixtures/label-config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"bug": { "color": "ff0000", "description": "Custom bug" },
"priority:high": { "color": "00ff00", "description": "High priority" }
}
22 changes: 21 additions & 1 deletion tests/labelManager.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { describe, it, expect, vi, beforeEach } from 'vitest';
import * as core from '@actions/core';
import { labelsFromMetadata, ensureLabelExists } from '../src/core/labelManager';
import path from 'path';
import { labelsFromMetadata, ensureLabelExists, loadLabelConfig } from '../src/core/labelManager';

const mockOctokit = {
rest: {
Expand Down Expand Up @@ -54,5 +55,24 @@ describe('ensureLabelExists', () => {
description: 'Auto-created by smart-todo-action'
});
});

it('should use custom config for color and description', async () => {
const error = { status: 404 } as any;
octokit.rest.issues.getLabel.mockRejectedValueOnce(error);
octokit.rest.issues.createLabel.mockResolvedValueOnce({});

const cfg = path.join(__dirname, 'fixtures/label-config.json');
loadLabelConfig(cfg);

await ensureLabelExists(octokit, 'test-owner', 'test-repo', 'bug');

expect(octokit.rest.issues.createLabel).toHaveBeenCalledWith({
owner: 'test-owner',
repo: 'test-repo',
name: 'bug',
color: 'ff0000',
description: 'Custom bug'
});
});
});

Loading