CMG-1101: fix delta reference resolution and locale-migrated tracking - #1128
CMG-1101: fix delta reference resolution and locale-migrated tracking#1128chetan-contentstack wants to merge 5 commits into
Conversation
…le-migrated tracking Reference fields (Link/Array Entry) written during a locale-localize restart kept the source CMS entry id instead of the real Contentstack uid, since only the master-locale bulk import resolved references correctly. Threads entry uid-mapper data into the update config so entry-update-script.cjs can resolve them, mirroring the existing asset uid resolution. Also fixes a bug where finishing any locale marked ALL configured locales as migrated, causing not-yet-migrated locales to be silently skipped on later delta restarts. Now only locales actually processed in that run are recorded.
Was reading a literal .id property on the entryId map instead of the dynamic key, so the single-reference branch never took the array path when the mapper legitimately held an array of destination uids.
…k SLA breach SNYK-JS-FASTURI-17675102 (fast-uri) and SNYK-JS-BRACEEXPANSION-17706650 (brace-expansion) crossed the 30-day SLA and were blocking every PR against dev. Bumping the root overrides to the latest patched versions.
umesh-more-cstk
left a comment
There was a problem hiding this comment.
Review summary
Three independent changes here: (a) a delta-migration fix that threads entry uid-mapper data into the entry-update script so reference fields resolve to real Contentstack uids, (b) a change to how migrated_locales is recorded, and (c) a root-level dependency override bump. The delta reference-resolution work is sound and well tested — I traced the premise end-to-end and it holds: removeEntriesFromDatabase snapshots the on-disk transformed entries before the CLI import, and createRefrence (contentful.service.ts:1584) writes the source cms id into { uid, _content_type_uid }, so this update path really was writing source-side uids onto localized entries. Wiring order is also correct — writeUidMapping/writePerLocaleEntryUidMapping run inside runCli before enrichConfigWithEntryMapping is called at migration.service.ts:1265.
Blocking
- runCli.service.ts:373 —
recordMigratedLocalesstill runs before the localize/update CLI that actually writes those locales, and that CLI swallows every failure. Same premature-marking class of bug this PR is fixing, just via a different trigger. - package.json:49-50 — the Snyk bump only touches the root project; the three deployables still pin the vulnerable versions.
Non-blocking
- entry-update.utils.ts:328 —
data?.entryis read as flat, but the sibling reader incontentMapper.service.tsexplicitly handles a nested-per-content-type shape. - runCli.service.ts:369 — a new locale whose entries are all newly created never lands in
updated-entries.json, so it is never recorded as migrated. - entry-update-script.cjs:13 —
isReferenceArrayis all-or-nothing; one unresolved element disables resolution for the whole field. - entry-update-script.cjs:149 — resolution is top-level only (group/modular-block/JSON-RTE-embedded references still keep source uids).
- contentful.service.ts:439 — the typo fix is correct but the branch it fixes is unreachable, so net behaviour is unchanged.
Verified good
enrichConfigWithEntryMappingmirrorsenrichConfigWithAssetMappingexactly (try/catch, empty-mapping default, non-throwing on a malformed config) and never blocks the main flow.extractLocalesFromUpdateConfig's__-prefix skip correctly excludes__assetMapping__/__entryMapping__/__assetUpdates__, and it was verified that those keys are written afterrunClireads the file — so the skip is belt-and-braces, not load-bearing.- Locale-code direction is consistent on both sides:
updated-entries.jsonkeys carry the destination code (removeEntriesFromDatabaseuses the on-disk locale dir name), which is whatmigrated_locales/isFullMigrationForLocalecompare against. - New unit tests are genuinely good — they cover the full fallback precedence chain, the back-compat identity path with no mapping supplied, and malformed/absent config files.
Out-of-diff notes (can't be anchored inline)
api/src/services/updateEntryCli.service.ts:240-249— thecatchonly logs; a failed entry-update CLI run is indistinguishable from success to the caller. This is what makes finding #1 a silent data problem rather than a retryable one.api/src/services/contentMapper.service.ts:2206-2233—getEntryUidMap/flattenNestedUidMap, the existing precedent for readinguid-mapper.json'sentrykey (handles nested shape and anentryUidvariant). Relevant to finding #3.api/src/utils/entry-update.utils.ts:188-190—if (!csEntryUid) continue;is why brand-new entries never reachentriesToUpdate. Relevant to finding #4.- Lockfile evidence for finding #2:
api/package-lock.jsonfast-uri 3.1.2 / brace-expansion 5.0.6;ui/package-lock.jsonbrace-expansion 5.0.6;upload-api/package-lock.jsonfast-uri 3.1.2 / brace-expansion 5.0.7. Rootpackage.jsondeclares noworkspaces, and its only deps are husky + validate-branch-name. - Process note: I could not read the PR description / PR-type / Affected-Areas checkboxes (the GitHub API is SAML-SSO blocked for my token), so I could not check the diff against the stated scope. Flagging on content alone: the dependency bump commit (
cb7c1ef1) is unrelated to the delta and Contentful fixes in the same branch and would be easier to review — and to revert — on its own.
|
Follow-up to my review above — the SAML-SSO block on my token is resolved, so I could finally read the PR description and check the diff against the stated scope. Retracting the "could not check" caveat at the end of that review; here is the actual result. The three functional bullets under What changed? match the diff accurately, and Affected Areas →
None of this changes the technical findings above — the two blockers and five non-blocking items stand as written. |
Root package.json has no workspaces, so root overrides don't reach api/ui/upload-api installs. Adding the same pins to each sub-project's package.json and regenerating their lockfiles so Snyk stops flagging the transitive vulnerabilities.
…le-migrated tracking Address review comments on #1128: - Move iteration 2+ recordMigratedLocales out of runCli into migration.service.ts, after utilsUpdateCli.updateEntryCli resolves. Recording pre-update meant a silent update-CLI failure would still flag the locales as migrated, permanently skipping them on later restarts — same class of bug this PR fixes. - Union in Object.keys(uid-mapper.entryByLocale) so brand-new-entries-only locales (no rows in updated-entries.json because they had no prior csEntryUid) are also recorded as migrated. - Extract flattenNestedUidMap into uid-mapper.utils.js and reuse it in both contentMapper.service and entry-update.utils. entry-update.utils.enrichConfigWithEntryMapping now handles the nested per-content-type shape (and the entryUid variant) instead of assuming a flat map. - entry-update-script.isReferenceArray: switch from .every() to .some(), and pass non-reference items through in resolveReferenceField. Producers legitimately emit mixed arrays (raw Contentful Link objects for unresolved refs, [undefined] from the single-ref fallback) — one such item no longer disables resolution for the whole field.
🔗 Jira Tickets
Parent story: CMG-789 — Delta Migration | v1.0.0 | Update Feature Implementation
📋 PR Type
📝 Description
What changed?
__entryMapping__and remaps Link(Entry) uids inentry-update-script.cjs.updated-entries.json.contentful.service.ts:439:Array?.isArray(entryId?.id)→Array.isArray(entryId?.[id]).Why?
Reproduced with the bundled
contentful-export.json/-v2.json/-v3.json: on iteration 2 the destination reference field went empty and the newly-added locale had zero entries.🧩 Affected Areas
api— Node.js backenduiupload-apidocker/docker-compose🧪 How to Test
Use the three bundled fixtures.
contentful-export.json(1 locale, 2 refs). Confirm both refs resolve in destination.contentful-export-v2.json(addsen-IN, updates one entry's title). On Map Entry, select the changed entry. After migration, confirm refs still resolve inen-USanden-INis populated.contentful-export-v3.json(addsen-GB, addsrelatedArticlesref). Confirm bothauthorandrelatedArticlesresolve in all three locales.cd api && npm testpasses.📸 Screenshots / Recordings
authorref empty in destination after re-mappingen-INlocale has 0 entriesen-INpopulated for every entryrelatedArticlesempty across locales🔗 Related PRs / Dependencies
✅ Author Checklist
bugfix/cmg-1101-delta-ref-locale.env/example.envupdated — N/Anpm testinapi/)README.md/ docs updated — N/A👀 Reviewer Notes
api/src/andapi/tests/.