From 9b4492cb9726430edf0fc94f1fb790fd3892dd9f Mon Sep 17 00:00:00 2001 From: Thomas Scott Date: Wed, 17 Dec 2025 11:48:49 +0000 Subject: [PATCH] Intiial commit Signed-off-by: Thomas Scott --- FIX_SUMMARY.md | 421 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 421 insertions(+) create mode 100644 FIX_SUMMARY.md diff --git a/FIX_SUMMARY.md b/FIX_SUMMARY.md new file mode 100644 index 0000000..60828e6 --- /dev/null +++ b/FIX_SUMMARY.md @@ -0,0 +1,421 @@ +# Bug Fixes Summary + +## Overview + +This document summarizes the recent bug fixes for bidirectional sync issues between Redmine and Gitea. + +--- + +## Fix #1: Label to Field Mapping (Gitea → Redmine) + +### Problem + +When syncing from Gitea to Redmine: +- Gitea uses **labels** for tracker types ("bug", "feature") and priorities ("High Priority", etc.) +- Redmine uses **fields**: `tracker_id` and `priority_id` +- Previously, all Gitea issues were created in Redmine as "Bug" with "Normal" priority, regardless of labels + +### Solution + +Added reverse mapping to parse Gitea labels and convert them to Redmine field IDs: + +**Tracker Mapping:** +```javascript +giteaToRedmine: { + "bug": 1, // Bug tracker + "feature": 2, // Feature tracker + "support": 3, // Support tracker +} +``` + +**Priority Mapping:** +```javascript +giteaToRedmine: { + "Low Priority": 1, + "Normal Priority": 2, + "High Priority": 3, + "Urgent": 4, + "Immediate": 5, +} +``` + +**New Utility Functions:** +- `extractTrackerFromLabels(labels)` - Scans labels for tracker types +- `extractPriorityFromLabels(labels)` - Scans labels for priority levels +- Falls back to defaults if no matching labels found + +### Testing + +```bash +# 1. Create issue in Gitea with labels: +# - "feature" +# - "High Priority" + +# 2. Check Redmine: +# - Tracker: Feature +# - Priority: High +``` + +--- + +## Fix #2: Redmine Comments Not Syncing to Gitea + +### Problem + +- Adding notes/journals in Redmine didn't create comments in Gitea +- Gitea → Redmine comment sync worked fine +- Issue was one-directional + +### Root Cause + +The Redmine → Gitea sync only processed journals when creating NEW issues, not when updating existing ones. + +### Solution + +Modified the webhook handler to always process journals: + +**Before:** +```javascript +if (giteaIssue) { + // Update issue + await GiteaAPI.updateIssue(...); + // ❌ Journals not processed here +} else { + // Create issue + await GiteaAPI.createIssue(...); + // ✅ Journals only processed for new issues +} +``` + +**After:** +```javascript +if (giteaIssue) { + // Update issue + await GiteaAPI.updateIssue(...); + + // ✅ ALWAYS process journals + if (payload.journal) { + await SyncUtilities.processJournals(...); + } +} +``` + +### Improvements + +1. **Better logging** for journal processing +2. **Safer author extraction** - handles both `journal.user.login` and `journal.author.login` +3. **Debug messages** to trace journal skipping decisions +4. **Change tracking** - field changes are included in Gitea comments + +### Testing + +```bash +# 1. Create issue in Redmine +# 2. Sync creates Gitea issue +# 3. Add note in Redmine with text: "This is a test comment" +# 4. Check Gitea issue - should see comment: + +[Redmine Journal #14] +**admin** commented: + +This is a test comment + +**Changes:** +- status_id: 1 → 2 +- due_date: (none) → 2025-12-19 +``` + +--- + +## Fix #3: Date Format Issues (422 Errors) + +### Problem + +**Gitea → Redmine:** +- Gitea sends: `2025-12-19T00:00:00Z` (ISO 8601) +- Redmine expects: `2025-12-19` (date only) +- Result: 422 validation error + +**Redmine → Gitea:** +- Redmine sends: `2025-12-19` +- Gitea expects: `2025-12-19T00:00:00Z` (ISO 8601) +- Previously could cause issues + +### Solution + +**For Gitea → Redmine:** +```javascript +// Extract date portion only +if (issue.due_date) { + const dueDate = new Date(issue.due_date); + if (!isNaN(dueDate.getTime())) { + issueData.due_date = dueDate.toISOString().split('T')[0]; + // Result: "2025-12-19" + } +} +``` + +**For Redmine → Gitea:** +```javascript +// Convert to full ISO format +if (issue.due_date) { + const dueDate = new Date(issue.due_date); + if (!isNaN(dueDate.getTime())) { + issueData.due_date = dueDate.toISOString(); + // Result: "2025-12-19T00:00:00.000Z" + } +} +``` + +**Safety Features:** +- Date validation before sending +- Try-catch blocks for invalid dates +- Warning logs for malformed dates +- Graceful fallback (omit field if invalid) + +--- + +## Fix #4: Label Handling (422 Errors) + +### Problem + +**Redmine → Gitea:** +- Labels were included in issue create/update payload +- Gitea expects label IDs as numbers: `[1, 2, 3]` +- We were sending label objects: `[{name: "bug"}, {name: "feature"}]` +- Result: 422 validation error + +### Solution + +**Two-step process:** + +1. **Create/update issue WITHOUT labels** +2. **Set labels separately using label IDs** + +```javascript +// Step 1: Create/update issue +await GiteaAPI.updateIssue(owner, repo, number, { + title: "...", + body: "...", + state: "open", + // ❌ NO labels here +}); + +// Step 2: Set labels separately +await GiteaAPI.setIssueLabels(owner, repo, number, ["bug", "High Priority"]); +``` + +**Label ID Resolution:** +```javascript +static async setIssueLabels(owner, repo, number, labelNames) { + // Get all repository labels + const allLabels = await this.getLabels(owner, repo); + + // Map names to IDs + const labelIds = []; + for (const labelName of labelNames) { + const label = allLabels.find(l => l.name === labelName); + if (label) { + labelIds.push(label.id); + } + } + + // Send IDs to Gitea + if (labelIds.length > 0) { + await giteaClient.put(`/api/v1/repos/${owner}/${repo}/issues/${number}/labels`, + { labels: labelIds } + ); + } +} +``` + +--- + +## Fix #5: Enhanced Error Logging + +### Problem + +422 errors showed no details about what validation failed. + +### Solution + +Added detailed error logging for all 422 responses: + +```javascript +catch (err) { + logger.error(`Sync failed: ${err.message}`); + + // ✅ NEW: Show validation details + if (err.response?.status === 422) { + logger.error(`Validation error details: ${JSON.stringify(err.response.data)}`); + } + + if (CONFIG.logging.verbose) { + logger.error(err.stack); + } +} +``` + +**Example Output:** +``` +[ERROR] Gitea to Redmine sync failed: Request failed with status code 422 +[ERROR] Validation error details: {"errors":["Due date is not a valid date"]} +``` + +This makes debugging much easier! + +--- + +## Deployment + +### Update Your Server + +```bash +# 1. Pull latest changes +cd ~/redmine-gitea-sync +git pull + +# 2. Restart PM2 +pm2 restart redmine-gitea-sync + +# 3. Watch logs to verify +pm2 logs redmine-gitea-sync +``` + +### Verify Fixes + +**Test Label Mapping:** +```bash +# Create Gitea issue with labels "feature" and "High Priority" +# Check Redmine - should show Feature tracker with High priority +``` + +**Test Comment Sync:** +```bash +# Add note in Redmine +# Check Gitea - comment should appear +``` + +**Test Dates:** +```bash +# Create issue with due date in either platform +# Should sync without 422 errors +``` + +--- + +## Configuration + +No configuration changes required. All fixes work automatically with existing settings. + +### Optional: Enable Debug Logging + +To see detailed sync information: + +```javascript +// In ecosystem.config.cjs +env: { + LOG_LEVEL: 'debug', + LOG_VERBOSE: 'true', +} +``` + +Then: +```bash +pm2 restart redmine-gitea-sync --update-env +pm2 logs redmine-gitea-sync +``` + +--- + +## Known Limitations + +### Tracker/Priority Mapping + +- Only works for standard tracker IDs (1=Bug, 2=Feature, 3=Support) +- Custom Redmine trackers require manual mapping in code +- Custom priorities require manual mapping in code + +### Comment Sync + +- Only text notes sync (file attachments not yet supported) +- Very long comments may be truncated by platform limits +- Formatting differences between Markdown (Gitea) and Textile (Redmine) + +### Labels + +- Label colors are auto-generated (not synced) +- Category labels use prefix: `category:name` +- If label doesn't exist in Gitea, it's created automatically + +--- + +## Troubleshooting + +### Still Getting 422 Errors? + +```bash +# Enable verbose logging +pm2 start ecosystem.config.cjs --env development + +# Watch logs for validation details +pm2 logs redmine-gitea-sync + +# Look for: "Validation error details: {...}" +``` + +### Comments Still Not Syncing? + +```bash +# Check if journal has content +pm2 logs redmine-gitea-sync | grep "journal" + +# Should see: +# "Synced Redmine journal #X to Gitea comment" + +# If you see "Skipping journal - empty notes": +# - Add actual text to Redmine notes +# - Empty journals (only field changes) won't sync +``` + +### Labels Not Mapping? + +```bash +# Verify label names match exactly: +# - "bug" (not "Bug" or "BUG") +# - "High Priority" (not "high priority" or "HighPriority") + +# Check Gitea labels: +curl -H "Authorization: token TOKEN" \ + https://gitea.example.com/api/v1/repos/OWNER/REPO/labels +``` + +--- + +## Version History + +**v2.0.1** (Current) +- ✅ Fixed label to field mapping (Gitea → Redmine) +- ✅ Fixed Redmine comment sync to Gitea +- ✅ Fixed date format issues (both directions) +- ✅ Fixed label handling (Redmine → Gitea) +- ✅ Added detailed error logging +- ✅ Improved journal processing with better logging + +**v2.0.0** +- Initial comprehensive rewrite +- PM2 support +- Basic bidirectional sync +- Label and milestone support + +--- + +## Support + +If you encounter issues after applying these fixes: + +1. Check [TROUBLESHOOTING.md](TROUBLESHOOTING.md) +2. Enable debug logging +3. Collect logs: `pm2 logs redmine-gitea-sync --lines 100` +4. Check server status: `curl http://localhost:3002/status` +5. Report with detailed logs and steps to reproduce \ No newline at end of file