Skip to content

Fix: bypass shouldCompare for Topic schema field updates#26735

Open
Khairajani wants to merge 9 commits intomainfrom
topic_patch_fix
Open

Fix: bypass shouldCompare for Topic schema field updates#26735
Khairajani wants to merge 9 commits intomainfrom
topic_patch_fix

Conversation

@Khairajani
Copy link
Copy Markdown
Contributor

@Khairajani Khairajani commented Mar 24, 2026

This pull request introduces regression tests and a targeted fix to ensure that PATCH requests correctly update nested schema fields in a Topic's message schema. Previously, an optimization in the EntityUpdater caused updates to nested fields to be silently ignored when using JSON Patch, due to a mismatch between the patched field name and the schema field prefix. The changes include both new regression tests and a workaround in the update logic to guarantee correct behavior.

Testing improvements:

  • Added comprehensive regression tests in TopicUpdaterPatchTest.java to verify PATCH operations on both top-level and nested schema fields, ensuring that descriptions and display names are updated and persisted correctly, that patchedFields are correctly restored after the update, and that PUT operations (patchedFields=null) continue to work without filtering.

Bug fix for schema field PATCH operations:

  • In TopicRepository.java, temporarily extends the patchedFields set to include "schemaFields" before calling updateSchemaFields for messageSchema, then restores the original set afterwards. This is a narrower fix than nulling patchedFields: it unblocks only schema field change tracking without disabling shouldCompare filtering for all other fields. A TODO comment documents the proper long-term fix (aligning EntityUtil.getSchemaField(...) paths under messageSchema.schemaFields).

Supporting code changes:

  • Replaced the @Getter annotation on patchedFields in EntityUpdater with a hand-written protected getter that returns Set.copyOf(patchedFields), preventing exposure of a mutable Set through a public API while still allowing subclass access.

Type of change:

  • Bug fix

Checklist:

  • I have read the CONTRIBUTING document.
  • My PR title is Fixes <issue-number>: <short explanation>
  • I have commented on my code, particularly in hard-to-understand areas.
  • For JSON Schema changes: I updated the migration scripts or explained why it is not needed.
  • I have added a test that covers the exact scenario we are fixing.

💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.

@Khairajani Khairajani added the safe to test Add this label to run secure Github workflows on PRs label Mar 24, 2026
@SumanMaharana SumanMaharana requested a review from Copilot March 24, 2026 17:00
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR addresses a PATCH change-tracking gap where updates to a Topic’s nested messageSchema.schemaFields were being skipped because EntityUpdater.shouldCompare only considers top-level patched fields.

Changes:

  • Temporarily bypasses shouldCompare filtering while updating Topic messageSchema schema fields so nested field updates are not silently ignored.
  • Exposes patchedFields via a generated getter on EntityRepository.EntityUpdater to allow saving/restoring the patched-field set.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.

File Description
openmetadata-service/src/main/java/org/openmetadata/service/jdbi3/TopicRepository.java Temporarily disables patched-field filtering around updateSchemaFields for messageSchema updates.
openmetadata-service/src/main/java/org/openmetadata/service/jdbi3/EntityRepository.java Adds a Lombok getter for patchedFields in EntityUpdater (previously setter-only).

private ChangeSource changeSource;
private final boolean useOptimisticLocking;
@Setter private Set<String> patchedFields;
@Getter @Setter private Set<String> patchedFields;
Copy link

Copilot AI Mar 24, 2026

Choose a reason for hiding this comment

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

EntityUpdater is a public inner class, so adding a Lombok @Getter makes getPatchedFields() a new public API and exposes the mutable Set directly. To avoid widening the surface area and accidental external mutation, consider generating a protected (or package-private) getter, or returning an unmodifiable copy, and keep the setter visibility as narrow as possible.

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

@copilot can you review again

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

All three concerns from the original review have been addressed in commits 7006505 and d871673:

  1. EntityRepository.java@Getter removed; replaced with a hand-written protected getter that returns Set.copyOf(patchedFields), preventing external mutation and keeping the accessor non-public.
  2. TopicRepository.java (logic) – Instead of nulling patchedFields, the fix now temporarily extends the set with "schemaFields", so only schema field tracking is unblocked without disabling shouldCompare for all other fields.
  3. Comment – Updated to name EntityUtil.getSchemaField(...) as the precise source of the path mismatch, with a TODO pointing to the long-term proper fix.
  4. Bonus – Fixed a stray fully-qualified new java.util.HashSet<>() to use the already-imported HashSet (d871673).

Comment on lines +665 to +681
// Temporarily disable shouldCompare for nested schema field updates.
// The field names from getSchemaField() start with "schemaFields." which
// doesn't match the patchedField "messageSchema", causing recordChange
// to silently skip the update.
Set<String> saved = getPatchedFields();
setPatchedFields(null);
try {
updateSchemaFields(
"messageSchema.schemaFields",
original.getMessageSchema() == null
? new ArrayList<>()
: listOrEmpty(original.getMessageSchema().getSchemaFields()),
listOrEmpty(updated.getMessageSchema().getSchemaFields()),
EntityUtil.schemaFieldMatch);
} finally {
setPatchedFields(saved);
}
Copy link

Copilot AI Mar 24, 2026

Choose a reason for hiding this comment

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

Setting patchedFields to null temporarily disables all shouldCompare filtering inside updateSchemaFields, not just the nested schema-field change tracking. This can cause PATCH requests that touch messageSchema (e.g., schemaText/schemaType) to also record/propagate changes from schema fields that were not intended to be part of the patch. Consider a narrower approach: temporarily extend the patched field set to include the schemaFields prefix (or make EntityUtil.getSchemaField(...) return paths under messageSchema.schemaFields) so only schema-field tracking is unblocked without disabling filtering globally.

Copilot uses AI. Check for mistakes.
Comment on lines +666 to +668
// The field names from getSchemaField() start with "schemaFields." which
// doesn't match the patchedField "messageSchema", causing recordChange
// to silently skip the update.
Copy link

Copilot AI Mar 24, 2026

Choose a reason for hiding this comment

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

The new comment says the field names come from getSchemaField(), but the mismatch described here is specifically from EntityUtil.getSchemaField(...) producing paths starting with schemaFields. while the patched top-level field is messageSchema. Please update the comment to point to the correct helper/mismatch (and ideally add a TODO/link to a tracking issue since this is labeled “temporary”).

Suggested change
// The field names from getSchemaField() start with "schemaFields." which
// doesn't match the patchedField "messageSchema", causing recordChange
// to silently skip the update.
// EntityUtil.getSchemaField(...) (used by schemaFieldMatch) produces field
// paths starting with "schemaFields.", which do not match the patchedField
// "messageSchema", causing recordChange() to silently skip the update.
// TODO: Remove this workaround once schema field paths are aligned with
// messageSchema patching.

Copilot uses AI. Check for mistakes.
@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Mar 24, 2026

OpenMetadata Service New-Code Coverage

PASS. Required changed-line coverage: 90.00% overall and per touched production file.

  • Overall executable changed lines: 12/12 covered (100.00%)
  • Missed executable changed lines: 0
  • Non-executable changed lines ignored by JaCoCo: 19
  • Changed production files: 2
File Covered Missed Executable Non-exec Coverage Uncovered lines
openmetadata-service/src/main/java/org/openmetadata/service/jdbi3/EntityRepository.java 1 0 1 4 100.00% -
openmetadata-service/src/main/java/org/openmetadata/service/jdbi3/TopicRepository.java 11 0 11 15 100.00% -

Only changed executable lines under openmetadata-service/src/main/java are counted. Test files, comments, imports, and non-executable lines are excluded.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Mar 24, 2026

🟡 Playwright Results — all passed (14 flaky)

✅ 3417 passed · ❌ 0 failed · 🟡 14 flaky · ⏭️ 209 skipped

Shard Passed Failed Flaky Skipped
🟡 Shard 1 452 0 3 2
🟡 Shard 2 604 0 1 32
🟡 Shard 3 611 0 4 28
🟡 Shard 4 600 0 3 47
🟡 Shard 5 586 0 1 67
🟡 Shard 6 564 0 2 33
🟡 14 flaky test(s) (passed on retry)
  • Flow/Tour.spec.ts › Tour should work from help section (shard 1, 1 retry)
  • Flow/Tour.spec.ts › Tour should work from URL directly (shard 1, 1 retry)
  • Pages/UserCreationWithPersona.spec.ts › Create user with persona and verify on profile (shard 1, 1 retry)
  • Features/BulkEditEntity.spec.ts › Glossary (shard 2, 1 retry)
  • Features/Permissions/DomainPermissions.spec.ts › Domain allow operations (shard 3, 1 retry)
  • Features/Permissions/GlossaryPermissions.spec.ts › Team-based permissions work correctly (shard 3, 1 retry)
  • Flow/ExploreDiscovery.spec.ts › Should display deleted assets when showDeleted is checked and deleted is not present in queryFilter (shard 3, 1 retry)
  • Flow/SchemaTable.spec.ts › Copy nested column link should include full hierarchical path (shard 3, 1 retry)
  • Pages/Customproperties-part2.spec.ts › entityReferenceList shows item count, scrollable list, no expand toggle (shard 4, 1 retry)
  • Pages/Domains.spec.ts › Rename domain with subdomains attached verifies subdomain accessibility (shard 4, 1 retry)
  • Pages/Domains.spec.ts › Multiple consecutive domain renames preserve all associations (shard 4, 1 retry)
  • Pages/ExplorePageRightPanel.spec.ts › Should verify deleted user not visible in owner selection for dashboard (shard 5, 1 retry)
  • Pages/Lineage.spec.ts › Lineage creation from Container entity (shard 6, 1 retry)
  • Pages/Users.spec.ts › Permissions for table details page for Data Consumer (shard 6, 1 retry)

📦 Download artifacts

How to debug locally
# Download playwright-test-results-<shard> artifact and unzip
npx playwright show-trace path/to/trace.zip    # view trace

Khairajani and others added 2 commits March 25, 2026 18:08
 - hand-written protected getter
 - extend with "schemaFields". shouldCompare still filters everything else
 - Updated comment
@yan-3005
Copy link
Copy Markdown
Contributor

@copilot Review this PR again

Copy link
Copy Markdown
Contributor

Copilot AI commented Mar 25, 2026

@copilot Review this PR again

Re-reviewed — all three concerns from the automated reviewer have been addressed:

  • EntityRepository.java: @Getter replaced with a protected hand-written getter returning Set.copyOf() (no mutable public API exposure).
  • TopicRepository.java logic: Narrowed from nulling patchedFields to temporarily extending the set with "schemaFields", keeping all other shouldCompare filtering intact.
  • Comment: Corrected to reference EntityUtil.getSchemaField(...) as the source of the path mismatch, with a TODO for the proper long-term fix.
  • Minor: Removed stray FQN java.util.HashSet (already imported) — commit d871673.

Automated code review and security scan both pass cleanly.

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • repository.apache.org
    • Triggering command: /usr/lib/jvm/temurin-17-jdk-amd64/bin/java /usr/lib/jvm/temurin-17-jdk-amd64/bin/java --enable-native-access=ALL-UNNAMED -classpath /usr/share/apache-maven-3.9.13/boot/plexus-classworlds-2.9.0.jar -Dclassworlds.conf=/usr/share/apache-maven-3.9.13/bin/m2.conf -Dmaven.home=/usr/share/apache-maven-3.9.13 -Dlibrary.jansi.path=/usr/share/apache-maven-3.9.13/lib/jansi-native -Dmaven.multiModuleProjectDirectory=/home/REDACTED/work/OpenMetadata/OpenMetadata org.codehaus.plexus.classworlds.launcher.Launcher spotless:apply -pl openmetadata-service -q (dns block)
  • s3.amazonaws.com
    • Triggering command: /usr/lib/jvm/temurin-17-jdk-amd64/bin/java /usr/lib/jvm/temurin-17-jdk-amd64/bin/java --enable-native-access=ALL-UNNAMED -classpath /usr/share/apache-maven-3.9.13/boot/plexus-classworlds-2.9.0.jar -Dclassworlds.conf=/usr/share/apache-maven-3.9.13/bin/m2.conf -Dmaven.home=/usr/share/apache-maven-3.9.13 -Dlibrary.jansi.path=/usr/share/apache-maven-3.9.13/lib/jansi-native -Dmaven.multiModuleProjectDirectory=/home/REDACTED/work/OpenMetadata/OpenMetadata org.codehaus.plexus.classworlds.launcher.Launcher spotless:apply -pl openmetadata-service -q (dns block)

If you need me to access, download, or install something from one of these locations, you can either:

Copilot AI requested a review from yan-3005 March 25, 2026 12:59
@gitar-bot
Copy link
Copy Markdown

gitar-bot bot commented Mar 25, 2026

Code Review ✅ Approved 1 resolved / 1 findings

Bypasses shouldCompare filtering for Topic schema field updates to prevent silent data loss during PUT operations, addressing the regression where schema field list and tag changes were dropped.

✅ 1 resolved
Bug: PUT operations regress: schema field list/tag changes silently dropped

📄 openmetadata-service/src/main/java/org/openmetadata/service/jdbi3/TopicRepository.java:674-677
When patchedFields is null (as in PUT operations, meaning "compare everything"), the workaround on lines 674–677 replaces it with {"schemaFields"}, which enables shouldCompare filtering that was previously disabled.

Inside updateSchemaFields, recordListChange("messageSchema.schemaFields", ...) calls shouldCompare("messageSchema.schemaFields") against {"schemaFields"}. The hierarchical matching fails because:

  • Exact match: no
  • First segment "messageSchema" not in {"schemaFields"}
  • Neither startsWith direction matches

So shouldCompare returns false, silently dropping any schema field additions/removals during PUT. The same issue affects tag updates via updateTags where field names like "messageSchema.schemaFields.id.tags" also fail to match "schemaFields".

The fix should skip the patchedFields manipulation entirely when saved is null, since null already means "compare everything".

Options

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

Comment with these commands to change:

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

Was this helpful? React with 👍 / 👎 | Gitar

@sonarqubecloud
Copy link
Copy Markdown

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

Labels

safe to test Add this label to run secure Github workflows on PRs

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants