Added fallback to check folder naming convention for task numbers. This catches task-048, task-092, task-093, task-094, etc. Chronicler #69
170 lines
6.0 KiB
JavaScript
170 lines
6.0 KiB
JavaScript
const fetch = (...args) => import('node-fetch').then(({default: fetch}) => fetch(...args));
|
|
|
|
module.exports = async function() {
|
|
const GITEA_API = 'https://git.firefrostgaming.com/api/v1';
|
|
const REPO_OWNER = 'firefrost-gaming';
|
|
const REPO_NAME = 'firefrost-operations-manual';
|
|
const TOKEN = process.env.GITEA_TOKEN || 'e0e330cba1749b01ab505093a160e4423ebbbe36';
|
|
|
|
const tasks = [];
|
|
|
|
try {
|
|
// Get list of task directories
|
|
const response = await fetch(
|
|
`${GITEA_API}/repos/${REPO_OWNER}/${REPO_NAME}/contents/docs/tasks?ref=master`,
|
|
{
|
|
headers: {
|
|
'Authorization': `token ${TOKEN}`,
|
|
'Accept': 'application/json'
|
|
},
|
|
timeout: 30000
|
|
}
|
|
);
|
|
|
|
if (!response.ok) {
|
|
console.error('Failed to fetch task list:', response.status);
|
|
return [];
|
|
}
|
|
|
|
const dirs = await response.json();
|
|
const taskDirs = dirs.filter(d => d.type === 'dir' && d.name !== '_archive');
|
|
|
|
// Fetch each task's README
|
|
for (const dir of taskDirs) {
|
|
try {
|
|
// Try README.md first
|
|
let readmePath = `docs/tasks/${dir.name}/README.md`;
|
|
let readmeResponse = await fetch(
|
|
`${GITEA_API}/repos/${REPO_OWNER}/${REPO_NAME}/contents/${encodeURIComponent(readmePath)}?ref=master`,
|
|
{
|
|
headers: {
|
|
'Authorization': `token ${TOKEN}`,
|
|
'Accept': 'application/json'
|
|
}
|
|
}
|
|
);
|
|
|
|
if (!readmeResponse.ok) {
|
|
// Try to find any .md file
|
|
const filesResponse = await fetch(
|
|
`${GITEA_API}/repos/${REPO_OWNER}/${REPO_NAME}/contents/docs/tasks/${encodeURIComponent(dir.name)}?ref=master`,
|
|
{
|
|
headers: {
|
|
'Authorization': `token ${TOKEN}`,
|
|
'Accept': 'application/json'
|
|
}
|
|
}
|
|
);
|
|
|
|
if (filesResponse.ok) {
|
|
const files = await filesResponse.json();
|
|
const mdFile = files.find(f => f.name.endsWith('.md'));
|
|
if (mdFile) {
|
|
readmePath = `docs/tasks/${dir.name}/${mdFile.name}`;
|
|
readmeResponse = await fetch(
|
|
`${GITEA_API}/repos/${REPO_OWNER}/${REPO_NAME}/contents/${encodeURIComponent(readmePath)}?ref=master`,
|
|
{
|
|
headers: {
|
|
'Authorization': `token ${TOKEN}`,
|
|
'Accept': 'application/json'
|
|
}
|
|
}
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (readmeResponse && readmeResponse.ok) {
|
|
const fileData = await readmeResponse.json();
|
|
const content = Buffer.from(fileData.content, 'base64').toString('utf-8');
|
|
|
|
// Parse YAML frontmatter
|
|
const frontmatterMatch = content.match(/^---\n([\s\S]*?)\n---/);
|
|
if (frontmatterMatch) {
|
|
const frontmatter = {};
|
|
frontmatterMatch[1].split('\n').forEach(line => {
|
|
const match = line.match(/^(\w+):\s*(.+)$/);
|
|
if (match) {
|
|
frontmatter[match[1]] = match[2].trim();
|
|
}
|
|
});
|
|
|
|
// Extract title from first H1
|
|
const titleMatch = content.match(/^#\s+(.+)$/m);
|
|
let title = titleMatch ? titleMatch[1] : dir.name;
|
|
|
|
// Extract task number - check multiple sources
|
|
let taskNumber = null;
|
|
|
|
// 1. Check frontmatter for task_number field
|
|
if (frontmatter.task_number) {
|
|
taskNumber = frontmatter.task_number;
|
|
}
|
|
|
|
// 2. Check folder name (e.g., task-048-n8n-rebuild)
|
|
if (!taskNumber) {
|
|
const folderNumMatch = dir.name.match(/^task-0*(\d+)/);
|
|
if (folderNumMatch) {
|
|
taskNumber = folderNumMatch[1];
|
|
}
|
|
}
|
|
|
|
// 3. Check title for #XX pattern
|
|
if (!taskNumber) {
|
|
const titleNumMatch = title.match(/#(\d+)/);
|
|
if (titleNumMatch) {
|
|
taskNumber = titleNumMatch[1];
|
|
}
|
|
}
|
|
|
|
// 4. Check content for Task ID or Task #XX patterns
|
|
if (!taskNumber) {
|
|
const contentNumMatch = content.match(/\*\*Task ID:\*\*\s*#?(\d+)/i) ||
|
|
content.match(/\*\*Task ID:\*\*\s*FFG-TASK-0*(\d+)/i) ||
|
|
content.match(/^#\s+Task\s+#(\d+)/im);
|
|
if (contentNumMatch) {
|
|
taskNumber = contentNumMatch[1];
|
|
}
|
|
}
|
|
|
|
tasks.push({
|
|
slug: dir.name,
|
|
title: title,
|
|
taskNumber: taskNumber,
|
|
status: frontmatter.status || 'open',
|
|
priority: frontmatter.priority || 'P3',
|
|
owner: frontmatter.owner || 'Michael',
|
|
created: frontmatter.created || '2026-01-01',
|
|
giteaUrl: `https://git.firefrostgaming.com/${REPO_OWNER}/${REPO_NAME}/src/branch/master/docs/tasks/${encodeURIComponent(dir.name)}`
|
|
});
|
|
}
|
|
}
|
|
} catch (err) {
|
|
console.error(`Error processing ${dir.name}:`, err.message);
|
|
}
|
|
}
|
|
|
|
// Sort by priority (P1 first) then by task number (if available) then by title
|
|
tasks.sort((a, b) => {
|
|
if (a.priority !== b.priority) {
|
|
return a.priority.localeCompare(b.priority);
|
|
}
|
|
// Sort by task number if both have one
|
|
if (a.taskNumber && b.taskNumber) {
|
|
return parseInt(a.taskNumber) - parseInt(b.taskNumber);
|
|
}
|
|
// Tasks with numbers come before those without
|
|
if (a.taskNumber && !b.taskNumber) return -1;
|
|
if (!a.taskNumber && b.taskNumber) return 1;
|
|
return a.title.localeCompare(b.title);
|
|
});
|
|
|
|
console.log(`[11ty] Loaded ${tasks.length} tasks from Gitea`);
|
|
return tasks;
|
|
|
|
} catch (err) {
|
|
console.error('[11ty] Error fetching tasks:', err.message);
|
|
return [];
|
|
}
|
|
};
|