421 lines
8.9 KiB
Markdown
421 lines
8.9 KiB
Markdown
# 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 |