fix: target issue ends in current source status, not first changelog state (#140)#145
Conversation
…state (#140) When a SonarQube issue had been transitioned multiple times (e.g. OPEN -> FIXED -> OPEN), the migrated issue on SonarCloud ended up in the *first* changed status instead of the current one. Cause: syncIssueStatus replayed every changelog transition in API response order. Each transition was applied via client.transitionIssue, but SonarCloud rejected most of them with state-machine errors (those rejections were swallowed silently). The first transition that SonarCloud accepted from its OPEN starting state stuck, regardless of what came after. Fix: skip the changelog replay entirely. syncIssueStatus now applies a single transition derived from the source issue's current status/resolution (applyFallbackTransition's logic). This is what the user-facing requirement asks for - target issue should reflect the *current* source state, not its history - and avoids the silent rejection problem completely. Also add a 'FIXED' case to getFallbackTransition for SonarQube 2025.x modern lifecycle, where FIXED is a direct status value rather than a resolution. Defense in depth: closed/fixed issues are already filtered upstream by the #133 filter, but the case ensures the fallback is correct if anything ever bypasses it. Applied across all four pipelines (sq-9.9, sq-10.0, sq-10.4, sq-2025) and the shared parallel-issue-sync worker. Removed the now-dead changelog plumbing (changelogMap parameter, embedded extractTransitionsFromChangelog/ mapChangelogDiffToTransition copies) from the worker and parallelSyncIssues signature. The shared apply-pre-filter still fetches changelogs - they're used by hasManualChanges to filter out issues with no manual changes. mapChangelogDiffToTransition and extractTransitionsFromChangelog remain exported from each pipeline's issue-sync module - verify-issue-pair.js still uses them for status-history verification reporting. Tests: replaced five replay-related tests in test/sonarcloud/migrators/migrators.test.js that asserted multi-transition replay (and were already failing on main due to the manual-changes prefilter dropping issues with no user field on the changelog). The replacements add user fields to the changelog fixtures so the prefilter keeps the issues, and assert the new single-transition behavior. Added a regression test covering the exact #140 scenario. Closes #140 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
SummaryFixes What was wrong: When syncing SQ→SC, the code replayed all transitions from the changelog (e.g., confirm, then falsepositive, then reopen). SonarCloud's state machine silently rejects invalid transitions, so the first applicable one succeeded, leaving issues in the wrong final status. The fix: Apply one transition derived from the SQ issue's current status, not its history. An issue in REOPENED status gets transition 'reopen', period. This ensures SC issues end in the state SQ considers current. Scale: ~200 lines deleted across 5 locations (4 pipeline versions + shared worker thread). Changes are mechanical and identical, making them easy to verify for consistency. What reviewers should knowStart here: Test change at line 517–623 in Consistency check: Review changes in any one of the 4 pipeline versions (e.g., sq-10.4) to understand the pattern, then spot-check 1–2 others to verify mechanical equivalence. The worker thread in What was removed:
Known loose end: Docs: CONTRIBUTING.md updated to describe the new single-transition model (lines 250, 255–256).
|
Summary
Closes #140.
When syncing issues from SonarQube to SonarCloud, the migration was replaying every transition recorded in the SQ changelog. SonarCloud's state machine rejects most non-current transitions, so the first applicable transition often won and the SC issue ended up in the wrong status (e.g. `CONFIRMED` instead of `REOPENED`).
This change drops the changelog-replay strategy entirely and applies a single transition derived from the SQ issue's current status. The four pipeline copies (sq-9.9, sq-10.0, sq-10.4, sq-2025) and the worker-thread sync (`parallel-issue-sync.js`) are updated consistently. Net diff: -203 lines.
Code changes
Tests
Docs
Test Coverage
```
syncIssueStatus(scIssue, sqIssue, client) [sq-10.4]
+-- scIssue.status === sqIssue.status ........ TESTED
+-- applyFallbackTransition
+-- getFallbackTransition(sqIssue)
| +-- resolution=FALSE-POSITIVE ........ TESTED
| +-- resolution=WONTFIX ............... TESTED
| +-- status=CONFIRMED ................. TESTED
| +-- status=RESOLVED .................. TESTED
| +-- status=ACCEPTED .................. TESTED
| +-- status=REOPENED .................. TESTED (#140 regression)
| +-- status=FIXED (NEW branch) ........ GAP
| +-- default => null .................. TESTED
+-- transitionIssue success/throws ....... TESTED
#140 regression scenario (changelog ignored, current status wins) — TESTED
parallel-issue-sync worker / sibling pipeline copies — relies on mechanical equivalence to sq-10.4
```
Coverage: ~78% on new `syncIssueStatus` paths. Core regression for #140 is asserted directly.
Pre-Landing Review
1 issue auto-fixed: `docs/CONTRIBUTING.md` had stale references to `preloadedChangelog` / `changelogMap` pass-through. Updated to describe the new single-transition behavior.
Note: `extractTransitionsFromChangelog` and `mapChangelogDiffToTransition` are still exported (and tested) but no longer called by production code. Left in place for this PR; can be cleaned up in a follow-up.
Test plan
🤖 Generated with Claude Code
Note
Medium Risk
Changes core issue status migration logic across all pipelines and the worker-based parallel sync, which can alter final SonarCloud issue states. Risk is mitigated by updated regression tests but could still surface edge-case status mappings in real migrations.
Overview
Fixes issue status syncing so SonarCloud ends in the current SonarQube status by removing changelog-replay transitions and always applying one derived transition in
syncIssueStatus(acrosssq-9.9,sq-10.0,sq-10.4,sq-2025, andparallel-issue-sync.js).Updates the transition mapping to treat SQ status
FIXEDasresolve, removeschangelogMap/preloaded-changelog plumbing from per-issue sync and parallel worker data, and adjusts docs/tests to reflect the single-transition model (including a regression covering #140).Reviewed by Cursor Bugbot for commit 6ac4084. Bugbot is set up for automated code reviews on this repo. Configure here.