Skip to content

Add source project key to migration reports#483

Merged
okorach-sonar merged 1 commit into
release-1-1from
fix/issue-448-source-project-key
Jul 10, 2026
Merged

Add source project key to migration reports#483
okorach-sonar merged 1 commit into
release-1-1from
fix/issue-448-source-project-key

Conversation

@okorach-sonar

Copy link
Copy Markdown
Contributor

Summary

  • Adds the source project key beneath the project name in the Projects section's Name column (PDF + Markdown), styled like the target project key already is in the Details column, with a line break between name and key.
  • Applies to both the actual (migration_summary) and predictive (predictive_migration_summary) reports, since both share the same rendering pipeline.
  • Threads the source key through every bucket a project can land in: Succeeded, Skipped, Failed (via a name-based lookup against generateProjectMappings, since the analysis-report ledger backing Failed rows has no key field), and Partial/NearPerfect (carried over from the matching Succeeded/config-failure entry).

Test plan

  • go build ./..., go vet ./..., go test ./... all pass
  • New unit tests: EntityItem.SourceKey propagation across Succeeded/Skipped/Failed/Partial buckets, drawNameCell PDF rendering (bold/regular font split, border pattern parity with drawWrappedCell), and Markdown Name-cell rendering (Name<br>**KEY**)
  • Manually rendered a sample PDF and Markdown report and visually confirmed the key renders correctly under the name for every outcome bucket, with non-Projects sections unaffected

Fixes #448

🤖 Generated with Claude Code

Only the source project name was shown in the Projects section's Name
column, making it hard to identify projects that share a name across
servers/orgs. Adds the source key on its own line, styled like the
target key already is in the Details column, in both the actual and
predictive PDF/Markdown reports.

Fixes #448

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@okorach-sonar
okorach-sonar requested a review from a team as a code owner July 10, 2026 13:00
Comment on lines +822 to +836
func attachFailedSourceKeys(items []EntityItem, store *common.DataStore, def sectionDef) {
if def.SourceKeyField == "" || len(items) == 0 {
return
}
mapped, err := store.ReadAll(def.InputTask)
if err != nil {
return
}
keyByName := make(map[string]string, len(mapped))
for _, item := range mapped {
name := jsonStr(item, def.NameField)
if name == "" {
continue
}
keyByName[name] = jsonStr(item, def.SourceKeyField)

@gitar-bot gitar-bot Bot Jul 10, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Edge Case: Failed source-key lookup collides on duplicate project names

attachFailedSourceKeys builds keyByName keyed solely on the project name (def.NameField) and then assigns items[i].SourceKey by name match. Unlike the Succeeded/Skipped paths (which read the source key directly from the same record), Failed rows are matched purely by name. Project names are not guaranteed unique — the same name can exist across different organizations, or even be reused — so the map silently overwrites earlier entries (last-write-wins). When two projects share a name but have different source keys, a failed row can be annotated with the wrong source key, which is misleading in a migration audit report. Consider disambiguating the lookup by including the organization (the analysis ReportRow carries Organization, and generateProjectMappings rows carry sonarcloud_org_key/sonarqube_org_key), or otherwise handling the collision case rather than blindly overwriting.

Key the lookup by organization + name so projects that share a name across organizations are not conflated.:

keyByName := make(map[string]string, len(mapped))
for _, item := range mapped {
	name := jsonStr(item, def.NameField)
	if name == "" {
		continue
	}
	org := jsonStr(item, "sonarcloud_org_key")
	keyByName[org+"\x00"+name] = jsonStr(item, def.SourceKeyField)
}
for i := range items {
	if key, ok := keyByName[items[i].Organization+"\x00"+items[i].Name]; ok {
		items[i].SourceKey = key
	}
}

Was this helpful? React with 👍 / 👎

@gitar-bot

gitar-bot Bot commented Jul 10, 2026

Copy link
Copy Markdown
Code Review 👍 Approved with suggestions 0 resolved / 1 findings

Migration reports now display source project keys beneath project names for improved traceability across all outcome buckets. Note that the lookup mechanism for failed migrations relies on project names and may encounter collisions if duplicate names exist.

💡 Edge Case: Failed source-key lookup collides on duplicate project names

📄 go/internal/report/summary/collect.go:822-836

attachFailedSourceKeys builds keyByName keyed solely on the project name (def.NameField) and then assigns items[i].SourceKey by name match. Unlike the Succeeded/Skipped paths (which read the source key directly from the same record), Failed rows are matched purely by name. Project names are not guaranteed unique — the same name can exist across different organizations, or even be reused — so the map silently overwrites earlier entries (last-write-wins). When two projects share a name but have different source keys, a failed row can be annotated with the wrong source key, which is misleading in a migration audit report. Consider disambiguating the lookup by including the organization (the analysis ReportRow carries Organization, and generateProjectMappings rows carry sonarcloud_org_key/sonarqube_org_key), or otherwise handling the collision case rather than blindly overwriting.

Key the lookup by organization + name so projects that share a name across organizations are not conflated.
keyByName := make(map[string]string, len(mapped))
for _, item := range mapped {
	name := jsonStr(item, def.NameField)
	if name == "" {
		continue
	}
	org := jsonStr(item, "sonarcloud_org_key")
	keyByName[org+"\x00"+name] = jsonStr(item, def.SourceKeyField)
}
for i := range items {
	if key, ok := keyByName[items[i].Organization+"\x00"+items[i].Name]; ok {
		items[i].SourceKey = key
	}
}
🤖 Prompt for agents
Code Review: Migration reports now display source project keys beneath project names for improved traceability across all outcome buckets. Note that the lookup mechanism for failed migrations relies on project names and may encounter collisions if duplicate names exist.

1. 💡 Edge Case: Failed source-key lookup collides on duplicate project names
   Files: go/internal/report/summary/collect.go:822-836

   `attachFailedSourceKeys` builds `keyByName` keyed solely on the project name (`def.NameField`) and then assigns `items[i].SourceKey` by name match. Unlike the Succeeded/Skipped paths (which read the source key directly from the same record), Failed rows are matched purely by name. Project names are not guaranteed unique — the same name can exist across different organizations, or even be reused — so the map silently overwrites earlier entries (last-write-wins). When two projects share a name but have different source keys, a failed row can be annotated with the wrong source key, which is misleading in a migration audit report. Consider disambiguating the lookup by including the organization (the analysis `ReportRow` carries `Organization`, and `generateProjectMappings` rows carry `sonarcloud_org_key`/`sonarqube_org_key`), or otherwise handling the collision case rather than blindly overwriting.

   Fix (Key the lookup by organization + name so projects that share a name across organizations are not conflated.):
   keyByName := make(map[string]string, len(mapped))
   for _, item := range mapped {
   	name := jsonStr(item, def.NameField)
   	if name == "" {
   		continue
   	}
   	org := jsonStr(item, "sonarcloud_org_key")
   	keyByName[org+"\x00"+name] = jsonStr(item, def.SourceKeyField)
   }
   for i := range items {
   	if key, ok := keyByName[items[i].Organization+"\x00"+items[i].Name]; ok {
   		items[i].SourceKey = key
   	}
   }

Options

Auto-apply is off → Gitar will not commit updates to this branch.
Display: compact → Showing less information.

Comment with these commands to change the behavior for this request:

Auto-apply Compact
gitar auto-apply:on         
gitar display:verbose         

Was this helpful? React with 👍 / 👎 | Gitar

@sonarqubecloud

Copy link
Copy Markdown

@okorach-sonar
okorach-sonar merged commit 209e527 into release-1-1 Jul 10, 2026
9 checks passed
@okorach-sonar
okorach-sonar deleted the fix/issue-448-source-project-key branch July 10, 2026 13:09
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.

2 participants