Skip to content

Preserve issue creationDate during migration via synthetic SCM change…#125

Merged
joshua-quek-sonarsource merged 1 commit into
mainfrom
feat/preserve-issue-creation-dates-via-changesets
Apr 23, 2026
Merged

Preserve issue creationDate during migration via synthetic SCM change…#125
joshua-quek-sonarsource merged 1 commit into
mainfrom
feat/preserve-issue-creation-dates-via-changesets

Conversation

@okorach-sonar

@okorach-sonar okorach-sonar commented Apr 22, 2026

Copy link
Copy Markdown
Collaborator

…sets

Instead of creating a single stub changeset per file with Date.now(), changeset extraction now uses issue creation dates to build per-line date mappings. The Compute Engine uses SCM blame dates to set issue creationDate, so by encoding the original dates into synthetic changesets, migrated issues retain their original creation timestamps.

Applied across all pipeline versions (sq-9.9, sq-10.0, sq-10.4, sq-2025) for both main branch and branch extraction paths.


Note

Medium Risk
Changes the generated SCM changeset data used during migration so issue creationDate is derived from per-line synthetic blame dates; incorrect mappings could shift timestamps on migrated issues. Scope spans multiple pipeline versions and both main/branch extraction paths.

Overview
Updates changeset extraction across sq-9.9, sq-10.0, sq-10.4, and sq-2025 to derive synthetic SCM blame dates from issue creationDate instead of using a single Date.now() stub per file.

extractChangesets now accepts an issues list, groups issues by file/component, and builds per-line changesetIndexByLine mappings (with a fallback changeset for lines without issues) so migrated issues retain their original creation timestamps.

Reviewed by Cursor Bugbot for commit e3bbbd4. Bugbot is set up for automated code reviews on this repo. Configure here.

…sets

Instead of creating a single stub changeset per file with Date.now(),
changeset extraction now uses issue creation dates to build per-line
date mappings. The Compute Engine uses SCM blame dates to set issue
creationDate, so by encoding the original dates into synthetic
changesets, migrated issues retain their original creation timestamps.

Applied across all pipeline versions (sq-9.9, sq-10.0, sq-10.4, sq-2025)
for both main branch and branch extraction paths.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@sonar-review-alpha

sonar-review-alpha Bot commented Apr 22, 2026

Copy link
Copy Markdown

Summary

This PR enhances issue migration to preserve original creation dates by encoding them into synthetic SCM changesets.

What changed:

  • Changeset builders (buildStubChangeset, createStubChangeset, buildChangeset) now accept an optional fileIssues parameter
  • Instead of creating a single changeset dated Date.now(), the functions build per-line date mappings using issue creation dates
  • Each unique date gets its own changeset; lines are indexed to their corresponding changeset
  • Falls back gracefully to the original single-changeset behavior when no issue dates are available

Why it matters:
The Compute Engine sets migrated issue creationDate based on SCM blame dates. By encoding original issue creation dates into changesets, migrated issues now retain their original timestamps instead of getting the migration date.

Scope:
Applied consistently across all 4 pipeline versions (sq-9.9, sq-10.0, sq-10.4, sq-2025) and both main branch + branch extraction paths. All callers updated to pass issues to extractChangesets().

What reviewers should know

Key files to review:

  1. Changeset builder logic is the core of the change — each pipeline version has a similar pattern:
    • src/pipelines/sq-9.9/sonarqube/extractors/changesets.js (inline buildChangeset)
    • src/pipelines/sq-10.0/sonarqube/extractors/changesets/helpers/build-stub-changeset.js
    • src/pipelines/sq-10.4/sonarqube/extractors/changesets/helpers/extract-changesets.js (inline buildChangeset)
    • src/pipelines/sq-2025/sonarqube/extractors/changesets/helpers/create-stub-changeset.js
  2. Then check caller updates (all in checkpoint/extraction phase files) to see how issues are threaded through.

Non-obvious details:

  • Line numbers in the PR are 1-based (from SonarQube), but changesetIndexByLine array is 0-based — conversion happens at const arrayIdx = line - 1
  • When multiple issues exist on the same line, the earliest creation date wins (important for consistency)
  • Date validation: Number.isNaN() check ensures invalid/unparseable dates are skipped
  • Fallback changeset uses the current timestamp but only if no issues have usable dates

What to watch for:

  • Verify the line number conversion is correct (off-by-one is easy to miss)
  • Check that issuesByComponent Map initialization handles the component key lookup correctly
  • Ensure all 4 pipeline versions apply the same logic (minor code style differences are OK)
  • Confirm all call sites in checkpoint/extraction phases pass ctx.issues or data.issues — spot-check a couple to verify

  • Generate Walkthrough
  • Generate Diagram

🗣️ Give feedback

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit e3bbbd4. Configure here.

restore: (d) => { ctx.duplications = d; } },
{ name: 'extract:changesets', label: 'Step 8: Extracting changesets',
fn: async () => { ctx.changesets = await extractChangesets(extractor.client, ctx.sourceFilesList, ctx.components); return ctx.changesets; },
fn: async () => { ctx.changesets = await extractChangesets(extractor.client, ctx.sourceFilesList, ctx.components, ctx.issues); return ctx.changesets; },

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hotspot issues excluded from changeset date mapping in checkpoint paths

Medium Severity

In all checkpoint-based extraction paths, ctx.issues is passed to extractChangesets before hotspot issues have been merged in. Hotspots are extracted into ctx.hotspotIssues and only merged into ctx.issues after all phases complete (e.g., in extract-all-with-checkpoints.js). This means hotspot creation dates are silently excluded from the synthetic changeset date mappings. Non-checkpoint paths correctly merge hotspots before calling extractChangesets, creating an inconsistency. This affects all four pipeline versions (sq-9.9, sq-10.0, sq-10.4, sq-2025) for both main and branch extraction.

Additional Locations (2)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit e3bbbd4. Configure here.

@sonar-review-alpha sonar-review-alpha Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The logic is correct and the approach is sound. One concern worth discussing before merge: the core buildChangeset algorithm is copy-pasted across all four pipeline versions rather than extracted to src/shared/.

🗣️ Give feedback

return changesets;
}

function buildChangeset(lineCount, fileIssues, fallbackTimestamp) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Logic duplication: The buildChangeset function here is nearly identical to:

  • src/pipelines/sq-10.0/sonarqube/extractors/changesets/helpers/build-stub-changeset.js (buildStubChangeset)
  • src/pipelines/sq-10.4/sonarqube/extractors/changesets/helpers/extract-changesets.js (buildChangeset)
  • src/pipelines/sq-2025/sonarqube/extractors/changesets/helpers/create-stub-changeset.js (createStubChangeset)

The same algorithm (line→date map, dedup, index assignment, bounds check) is copy-pasted four times with only cosmetic naming differences. This logic is not version-specific — it's pure date-encoding math with no SQ API coupling.

Extract it to src/shared/utils/build-issue-changesets.js and import it in each pipeline. A future change (e.g. switching from earliest to latest date, or adding textRange fallback for issues without a line) currently requires four coordinated edits in non-obvious locations.

  • Mark as noise

@joshua-quek-sonarsource
joshua-quek-sonarsource merged commit 9aed877 into main Apr 23, 2026
2 checks passed
@joshua-quek-sonarsource

Copy link
Copy Markdown
Contributor

Hi @okorach I managed to achieve this on my other branch
image

however let me try your fix applied here on your branch

@joshua-quek-sonarsource

Copy link
Copy Markdown
Contributor

will test it on your branch first

@joshua-quek-sonarsource

Copy link
Copy Markdown
Contributor

the algorithm that claude applied on my current feature branch is a bit buggy (still loads 23 other issues into a single day)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants