mirror of
https://github.com/johndoe6345789/metabuilder.git
synced 2026-04-24 13:54:57 +00:00
Add GitHub Action workflow and TODO monitoring script with comprehensive docs
Co-authored-by: johndoe6345789 <224850594+johndoe6345789@users.noreply.github.com>
This commit is contained in:
162
.github/workflows/todo-to-issues.yml
vendored
Normal file
162
.github/workflows/todo-to-issues.yml
vendored
Normal file
@@ -0,0 +1,162 @@
|
||||
name: TODO to Issues Sync
|
||||
|
||||
# This workflow can be triggered manually to convert TODO items to GitHub issues
|
||||
# or can be run on a schedule to keep issues in sync with TODO files
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
mode:
|
||||
description: 'Execution mode'
|
||||
required: true
|
||||
type: choice
|
||||
options:
|
||||
- dry-run
|
||||
- export-json
|
||||
- create-issues
|
||||
default: 'dry-run'
|
||||
|
||||
filter_priority:
|
||||
description: 'Filter by priority (leave empty for all)'
|
||||
required: false
|
||||
type: choice
|
||||
options:
|
||||
- ''
|
||||
- critical
|
||||
- high
|
||||
- medium
|
||||
- low
|
||||
|
||||
filter_label:
|
||||
description: 'Filter by label (e.g., security, frontend)'
|
||||
required: false
|
||||
type: string
|
||||
|
||||
exclude_checklist:
|
||||
description: 'Exclude checklist items'
|
||||
required: false
|
||||
type: boolean
|
||||
default: true
|
||||
|
||||
limit:
|
||||
description: 'Limit number of issues (0 for no limit)'
|
||||
required: false
|
||||
type: number
|
||||
default: 0
|
||||
|
||||
# Uncomment to run on a schedule (e.g., weekly)
|
||||
# schedule:
|
||||
# - cron: '0 0 * * 0' # Every Sunday at midnight
|
||||
|
||||
jobs:
|
||||
convert-todos:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.11'
|
||||
|
||||
- name: Install GitHub CLI
|
||||
run: |
|
||||
type -p curl >/dev/null || (sudo apt update && sudo apt install curl -y)
|
||||
curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg | sudo dd of=/usr/share/keyrings/githubcli-archive-keyring.gpg \
|
||||
&& sudo chmod go+r /usr/share/keyrings/githubcli-archive-keyring.gpg \
|
||||
&& echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" | sudo tee /etc/apt/sources.list.d/github-cli.list > /dev/null \
|
||||
&& sudo apt update \
|
||||
&& sudo apt install gh -y
|
||||
|
||||
- name: Authenticate GitHub CLI
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
echo "$GH_TOKEN" | gh auth login --with-token
|
||||
gh auth status
|
||||
|
||||
- name: Build command arguments
|
||||
id: args
|
||||
run: |
|
||||
ARGS=""
|
||||
|
||||
# Add mode
|
||||
if [ "${{ inputs.mode }}" = "dry-run" ]; then
|
||||
ARGS="$ARGS --dry-run"
|
||||
elif [ "${{ inputs.mode }}" = "export-json" ]; then
|
||||
ARGS="$ARGS --output todos-export.json"
|
||||
elif [ "${{ inputs.mode }}" = "create-issues" ]; then
|
||||
ARGS="$ARGS --create"
|
||||
fi
|
||||
|
||||
# Add filters
|
||||
if [ -n "${{ inputs.filter_priority }}" ]; then
|
||||
ARGS="$ARGS --filter-priority ${{ inputs.filter_priority }}"
|
||||
fi
|
||||
|
||||
if [ -n "${{ inputs.filter_label }}" ]; then
|
||||
ARGS="$ARGS --filter-label ${{ inputs.filter_label }}"
|
||||
fi
|
||||
|
||||
if [ "${{ inputs.exclude_checklist }}" = "true" ]; then
|
||||
ARGS="$ARGS --exclude-checklist"
|
||||
fi
|
||||
|
||||
# Add limit if specified
|
||||
if [ "${{ inputs.limit }}" != "0" ]; then
|
||||
ARGS="$ARGS --limit ${{ inputs.limit }}"
|
||||
fi
|
||||
|
||||
echo "args=$ARGS" >> $GITHUB_OUTPUT
|
||||
echo "Command arguments: $ARGS"
|
||||
|
||||
- name: Run populate-kanban script
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
python3 tools/project-management/populate-kanban.py ${{ steps.args.outputs.args }}
|
||||
|
||||
- name: Upload JSON export (if applicable)
|
||||
if: inputs.mode == 'export-json'
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: todos-export
|
||||
path: todos-export.json
|
||||
retention-days: 30
|
||||
|
||||
- name: Create summary
|
||||
if: always()
|
||||
run: |
|
||||
echo "## TODO to Issues Conversion" >> $GITHUB_STEP_SUMMARY
|
||||
echo "" >> $GITHUB_STEP_SUMMARY
|
||||
echo "**Mode:** ${{ inputs.mode }}" >> $GITHUB_STEP_SUMMARY
|
||||
|
||||
if [ -n "${{ inputs.filter_priority }}" ]; then
|
||||
echo "**Priority Filter:** ${{ inputs.filter_priority }}" >> $GITHUB_STEP_SUMMARY
|
||||
fi
|
||||
|
||||
if [ -n "${{ inputs.filter_label }}" ]; then
|
||||
echo "**Label Filter:** ${{ inputs.filter_label }}" >> $GITHUB_STEP_SUMMARY
|
||||
fi
|
||||
|
||||
if [ "${{ inputs.exclude_checklist }}" = "true" ]; then
|
||||
echo "**Checklist Items:** Excluded" >> $GITHUB_STEP_SUMMARY
|
||||
fi
|
||||
|
||||
if [ "${{ inputs.limit }}" != "0" ]; then
|
||||
echo "**Limit:** ${{ inputs.limit }} items" >> $GITHUB_STEP_SUMMARY
|
||||
fi
|
||||
|
||||
echo "" >> $GITHUB_STEP_SUMMARY
|
||||
|
||||
if [ "${{ inputs.mode }}" = "export-json" ]; then
|
||||
echo "✅ JSON export created successfully" >> $GITHUB_STEP_SUMMARY
|
||||
echo "Download the artifact from the workflow run page" >> $GITHUB_STEP_SUMMARY
|
||||
elif [ "${{ inputs.mode }}" = "create-issues" ]; then
|
||||
echo "✅ GitHub issues created successfully" >> $GITHUB_STEP_SUMMARY
|
||||
echo "View issues: https://github.com/${{ github.repository }}/issues" >> $GITHUB_STEP_SUMMARY
|
||||
else
|
||||
echo "ℹ️ Dry run completed - no issues created" >> $GITHUB_STEP_SUMMARY
|
||||
fi
|
||||
5
.gitignore
vendored
5
.gitignore
vendored
@@ -88,6 +88,11 @@ lint-output.txt
|
||||
stub-patterns.json
|
||||
complexity-report.json
|
||||
|
||||
# TODO management
|
||||
todos-baseline.json
|
||||
todos-export.json
|
||||
todos*.json
|
||||
|
||||
# Project-specific
|
||||
**/agent-eval-report*
|
||||
vite.config.ts.bak*
|
||||
|
||||
@@ -7,7 +7,9 @@
|
||||
"todos:export-filtered": "python3 tools/project-management/populate-kanban.py --output todos-filtered.json --exclude-checklist",
|
||||
"todos:test": "python3 tools/project-management/test_populate_kanban.py",
|
||||
"todos:create": "python3 tools/project-management/populate-kanban.py --create",
|
||||
"todos:help": "python3 tools/project-management/populate-kanban.py --help"
|
||||
"todos:help": "python3 tools/project-management/populate-kanban.py --help",
|
||||
"todos:check": "python3 tools/project-management/check-new-todos.py",
|
||||
"todos:baseline": "python3 tools/project-management/check-new-todos.py --save-baseline"
|
||||
},
|
||||
"devDependencies": {
|
||||
"prisma": "^7.2.0"
|
||||
|
||||
@@ -2,6 +2,35 @@
|
||||
|
||||
Tools for managing MetaBuilder's GitHub project board and issues.
|
||||
|
||||
## Overview
|
||||
|
||||
This directory contains three main tools:
|
||||
|
||||
1. **populate-kanban.py** - Convert TODO items to GitHub issues
|
||||
2. **check-new-todos.py** - Monitor for new TODO items
|
||||
3. **test_populate_kanban.py** - Unit tests for the conversion script
|
||||
|
||||
## Quick Start
|
||||
|
||||
```bash
|
||||
# From repository root:
|
||||
|
||||
# Preview issues that would be created
|
||||
npm run todos:preview
|
||||
|
||||
# Run tests
|
||||
npm run todos:test
|
||||
|
||||
# Check for new TODOs since baseline
|
||||
npm run todos:check
|
||||
|
||||
# Export to JSON
|
||||
npm run todos:export
|
||||
|
||||
# Create issues on GitHub (requires gh auth)
|
||||
npm run todos:create
|
||||
```
|
||||
|
||||
## populate-kanban.py
|
||||
|
||||
Automatically populate the GitHub project kanban board from TODO markdown files.
|
||||
@@ -310,8 +339,152 @@ From the last full parse:
|
||||
- **Medium priority**: 269 items
|
||||
- **Low priority**: 80 items
|
||||
|
||||
### See Also
|
||||
---
|
||||
|
||||
- [docs/todo/README.md](../../docs/todo/README.md) - TODO system overview
|
||||
- [docs/todo/TODO_STATUS.md](../../docs/todo/TODO_STATUS.md) - Current status
|
||||
- [GitHub Projects](https://github.com/users/johndoe6345789/projects/2) - Target kanban board
|
||||
## check-new-todos.py
|
||||
|
||||
Monitor for new TODO items added since the last baseline.
|
||||
|
||||
### Features
|
||||
|
||||
- **Baseline tracking**: Save current TODO state as baseline
|
||||
- **Change detection**: Identify new and removed TODO items
|
||||
- **Diff reporting**: Show what changed and where
|
||||
- **CI integration**: Exit code indicates if new items found
|
||||
|
||||
### Quick Start
|
||||
|
||||
```bash
|
||||
# Save current state as baseline
|
||||
npm run todos:baseline
|
||||
|
||||
# Check for new items
|
||||
npm run todos:check
|
||||
|
||||
# Or use directly:
|
||||
python3 tools/project-management/check-new-todos.py --save-baseline
|
||||
python3 tools/project-management/check-new-todos.py
|
||||
```
|
||||
|
||||
### Use Cases
|
||||
|
||||
1. **CI/CD Integration**: Fail the build if new TODOs are added
|
||||
2. **PR Reviews**: Detect if a PR adds new TODOs
|
||||
3. **Project Management**: Track TODO growth over time
|
||||
4. **Issue Creation**: Know exactly which items are new
|
||||
|
||||
### Example Output
|
||||
|
||||
```
|
||||
============================================================
|
||||
TODO Items Comparison
|
||||
============================================================
|
||||
Baseline count: 775
|
||||
Current count: 783
|
||||
Net change: +8
|
||||
|
||||
New items: 8
|
||||
Removed items: 0
|
||||
|
||||
============================================================
|
||||
New TODO Items (8)
|
||||
============================================================
|
||||
|
||||
1. Add GraphQL API support
|
||||
File: docs/todo/features/15-API-TODO.md:23
|
||||
Section: API Features
|
||||
Priority: 🟠 High
|
||||
Labels: feature, backend
|
||||
|
||||
2. Implement caching layer
|
||||
File: docs/todo/infrastructure/16-PERFORMANCE-TODO.md:45
|
||||
Section: Optimization
|
||||
Priority: 🟡 Medium
|
||||
Labels: infrastructure, performance
|
||||
|
||||
...
|
||||
|
||||
============================================================
|
||||
💡 Tip: Create issues for these new items:
|
||||
python3 tools/project-management/populate-kanban.py --create --limit 8
|
||||
============================================================
|
||||
```
|
||||
|
||||
### CI/CD Example
|
||||
|
||||
```yaml
|
||||
# .github/workflows/check-todos.yml
|
||||
name: Check for new TODOs
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
paths:
|
||||
- 'docs/todo/**'
|
||||
|
||||
jobs:
|
||||
check-todos:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Check for new TODOs
|
||||
run: |
|
||||
python3 tools/project-management/check-new-todos.py
|
||||
if [ $? -eq 1 ]; then
|
||||
echo "::warning::New TODO items detected. Consider creating issues."
|
||||
fi
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## test_populate_kanban.py
|
||||
|
||||
Comprehensive unit tests for populate-kanban.py.
|
||||
|
||||
### Features
|
||||
|
||||
- **15 test cases** covering all major functionality
|
||||
- **Parser tests**: TODO extraction, context, sections
|
||||
- **Categorization tests**: Labels, priorities, filters
|
||||
- **Edge case handling**: Empty items, long titles, special files
|
||||
|
||||
### Running Tests
|
||||
|
||||
```bash
|
||||
# Run all tests
|
||||
npm run todos:test
|
||||
|
||||
# Or directly
|
||||
python3 tools/project-management/test_populate_kanban.py
|
||||
|
||||
# With pytest (if installed)
|
||||
pytest tools/project-management/test_populate_kanban.py -v
|
||||
```
|
||||
|
||||
### Test Coverage
|
||||
|
||||
- ✅ Parse simple TODO items
|
||||
- ✅ Skip empty/short items
|
||||
- ✅ Extract context from surrounding lines
|
||||
- ✅ Track section headers
|
||||
- ✅ Track line numbers
|
||||
- ✅ Categorize by filename
|
||||
- ✅ Categorize by directory
|
||||
- ✅ Assign priorities from README
|
||||
- ✅ Assign default priorities
|
||||
- ✅ Exclude special files (README, STATUS, SCAN)
|
||||
- ✅ Truncate long titles
|
||||
- ✅ Dry run mode
|
||||
- ✅ Issue creation
|
||||
- ✅ Project board integration
|
||||
- ✅ Filter logic
|
||||
|
||||
---
|
||||
|
||||
## See Also
|
||||
|
||||
- **[docs/guides/TODO_TO_ISSUES.md](../../docs/guides/TODO_TO_ISSUES.md)** - Complete user guide
|
||||
- **[docs/todo/README.md](../../docs/todo/README.md)** - TODO system overview
|
||||
- **[docs/todo/TODO_STATUS.md](../../docs/todo/TODO_STATUS.md)** - Current status
|
||||
- **[KANBAN_READY.md](../../KANBAN_READY.md)** - Implementation summary
|
||||
- **[GitHub Projects](https://github.com/users/johndoe6345789/projects/2)** - Target kanban board
|
||||
- **[.github/workflows/todo-to-issues.yml](../../.github/workflows/todo-to-issues.yml)** - GitHub Action workflow
|
||||
|
||||
166
tools/project-management/check-new-todos.py
Executable file
166
tools/project-management/check-new-todos.py
Executable file
@@ -0,0 +1,166 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Check for new TODO items added since last check.
|
||||
|
||||
This script compares the current TODO items with a baseline and reports new items.
|
||||
Useful for detecting when new TODOs are added that should become GitHub issues.
|
||||
|
||||
Usage:
|
||||
python3 check-new-todos.py [--baseline FILE] [--save-baseline]
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import sys
|
||||
from pathlib import Path
|
||||
from typing import Set, List
|
||||
|
||||
# Import TodoParser from populate-kanban.py
|
||||
import importlib.util
|
||||
script_dir = Path(__file__).parent
|
||||
spec = importlib.util.spec_from_file_location("populate_kanban", script_dir / "populate-kanban.py")
|
||||
populate_kanban = importlib.util.module_from_spec(spec)
|
||||
spec.loader.exec_module(populate_kanban)
|
||||
TodoParser = populate_kanban.TodoParser
|
||||
|
||||
|
||||
def get_todo_signatures(items: List) -> Set[str]:
|
||||
"""Generate unique signatures for TODO items."""
|
||||
signatures = set()
|
||||
for item in items:
|
||||
# Create signature from file, line number, and truncated title
|
||||
sig = f"{item.file}:{item.line_number}:{item.title[:50]}"
|
||||
signatures.add(sig)
|
||||
return signatures
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(
|
||||
description='Check for new TODO items',
|
||||
formatter_class=argparse.RawDescriptionHelpFormatter,
|
||||
epilog=__doc__
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
'--baseline',
|
||||
type=Path,
|
||||
default=Path('todos-baseline.json'),
|
||||
help='Path to baseline file (default: todos-baseline.json)'
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
'--save-baseline',
|
||||
action='store_true',
|
||||
help='Save current TODOs as new baseline'
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
'--todo-dir',
|
||||
type=Path,
|
||||
help='Path to docs/todo directory (default: auto-detect)'
|
||||
)
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
# Auto-detect todo directory if not specified
|
||||
if args.todo_dir is None:
|
||||
repo_root = script_dir.parent.parent
|
||||
args.todo_dir = repo_root / 'docs' / 'todo'
|
||||
|
||||
if not args.todo_dir.exists():
|
||||
print(f"ERROR: TODO directory not found: {args.todo_dir}")
|
||||
sys.exit(1)
|
||||
|
||||
# Parse current TODOs
|
||||
print(f"Parsing TODO files from: {args.todo_dir}")
|
||||
parser_obj = TodoParser(args.todo_dir)
|
||||
current_items = parser_obj.parse_all()
|
||||
current_signatures = get_todo_signatures(current_items)
|
||||
|
||||
print(f"Found {len(current_items)} TODO items")
|
||||
|
||||
# Save baseline if requested
|
||||
if args.save_baseline:
|
||||
baseline_data = {
|
||||
'count': len(current_items),
|
||||
'signatures': list(current_signatures)
|
||||
}
|
||||
with open(args.baseline, 'w', encoding='utf-8') as f:
|
||||
json.dump(baseline_data, f, indent=2)
|
||||
print(f"\n✓ Saved baseline to: {args.baseline}")
|
||||
return
|
||||
|
||||
# Load baseline for comparison
|
||||
if not args.baseline.exists():
|
||||
print(f"\nℹ️ No baseline file found at: {args.baseline}")
|
||||
print("Run with --save-baseline to create initial baseline")
|
||||
sys.exit(0)
|
||||
|
||||
with open(args.baseline, 'r', encoding='utf-8') as f:
|
||||
baseline_data = json.load(f)
|
||||
|
||||
baseline_signatures = set(baseline_data['signatures'])
|
||||
baseline_count = baseline_data['count']
|
||||
|
||||
# Find new items
|
||||
new_signatures = current_signatures - baseline_signatures
|
||||
removed_signatures = baseline_signatures - current_signatures
|
||||
|
||||
print(f"\n{'='*60}")
|
||||
print(f"TODO Items Comparison")
|
||||
print(f"{'='*60}")
|
||||
print(f"Baseline count: {baseline_count}")
|
||||
print(f"Current count: {len(current_items)}")
|
||||
print(f"Net change: {len(current_items) - baseline_count:+d}")
|
||||
print(f"\nNew items: {len(new_signatures)}")
|
||||
print(f"Removed items: {len(removed_signatures)}")
|
||||
|
||||
# Show new items
|
||||
if new_signatures:
|
||||
print(f"\n{'='*60}")
|
||||
print(f"New TODO Items ({len(new_signatures)})")
|
||||
print(f"{'='*60}")
|
||||
|
||||
# Find full details of new items
|
||||
new_items = [
|
||||
item for item in current_items
|
||||
if f"{item.file}:{item.line_number}:{item.title[:50]}" in new_signatures
|
||||
]
|
||||
|
||||
for i, item in enumerate(new_items[:20], 1): # Show first 20
|
||||
print(f"\n{i}. {item.title[:80]}")
|
||||
print(f" File: {item.file}:{item.line_number}")
|
||||
print(f" Section: {item.section}")
|
||||
print(f" Priority: {item.priority}")
|
||||
print(f" Labels: {', '.join(item.labels)}")
|
||||
|
||||
if len(new_items) > 20:
|
||||
print(f"\n... and {len(new_items) - 20} more")
|
||||
|
||||
print(f"\n{'='*60}")
|
||||
print(f"💡 Tip: Create issues for these new items:")
|
||||
print(f" python3 tools/project-management/populate-kanban.py --create --limit {len(new_items)}")
|
||||
print(f"{'='*60}")
|
||||
|
||||
# Show removed items
|
||||
if removed_signatures:
|
||||
print(f"\n{'='*60}")
|
||||
print(f"Removed TODO Items ({len(removed_signatures)})")
|
||||
print(f"{'='*60}")
|
||||
|
||||
for i, sig in enumerate(list(removed_signatures)[:10], 1):
|
||||
print(f"{i}. {sig}")
|
||||
|
||||
if len(removed_signatures) > 10:
|
||||
print(f"... and {len(removed_signatures) - 10} more")
|
||||
|
||||
# Exit with status code based on changes
|
||||
if new_signatures:
|
||||
sys.exit(1) # New items found
|
||||
else:
|
||||
print("\n✓ No new TODO items since baseline")
|
||||
sys.exit(0)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
Reference in New Issue
Block a user