Skip to content

fix: Skip stale Press Role resources during sync#6558

Open
saurabh6790 wants to merge 1 commit into
frappe:developfrom
saurabh6790:fix-sync_press_role
Open

fix: Skip stale Press Role resources during sync#6558
saurabh6790 wants to merge 1 commit into
frappe:developfrom
saurabh6790:fix-sync_press_role

Conversation

@saurabh6790

Copy link
Copy Markdown
Member

Problem

The decouple_press_role_resources patch fails with a ValidationError when a Press Role Resource references a document that is no longer owned by the team. This happens when:

A site, bench, or server has been archived (renamed to {name}.archived)
A document has been transferred to another team (team switch)
A document has been deleted entirely
In all these cases, validate_document_name throws because the current document owner doesn't match the team on the resource being created.

  File "/home/frappe/frappe-bench/apps/frappe/frappe/migrate.py", line 248, in run
    self.run_schema_updates()
  File "/home/frappe/frappe-bench/apps/frappe/frappe/migrate.py", line 53, in wrapper
    raise e
  File "/home/frappe/frappe-bench/apps/frappe/frappe/migrate.py", line 45, in wrapper
    ret = method(*args, **kwargs)
  File "/home/frappe/frappe-bench/apps/frappe/frappe/migrate.py", line 125, in run_schema_updates
    frappe.modules.patch_handler.run_all(
  File "/home/frappe/frappe-bench/apps/frappe/frappe/modules/patch_handler.py", line 76, in run_all
    run_patch(patch)
  File "/home/frappe/frappe-bench/apps/frappe/frappe/modules/patch_handler.py", line 62, in run_patch
    if not run_single(patchmodule=patch):
  File "/home/frappe/frappe-bench/apps/frappe/frappe/modules/patch_handler.py", line 152, in run_single
    return execute_patch(patchmodule, method, methodargs)
  File "/home/frappe/frappe-bench/apps/frappe/frappe/modules/patch_handler.py", line 188, in execute_patch
    _patch()
  File "/home/frappe/frappe-bench/apps/press/press/patches/v0_8_0/decouple_press_role_resources.py", line 12, in execute
    sync_press_role(press_role_doc)
  File "/home/frappe/frappe-bench/apps/press/press/press/doctype/team_member_resource/team_member_resource.py", line 145, in sync_press_role
    frappe.get_doc(document).insert(ignore_permissions=True)
  File "/home/frappe/frappe-bench/apps/frappe/frappe/model/document.py", line 123, in wrapper
    return func(self, *args, **kwargs)
  File "/home/frappe/frappe-bench/apps/frappe/frappe/model/document.py", line 412, in insert
    self.run_before_save_methods()
  File "/home/frappe/frappe-bench/apps/frappe/frappe/model/document.py", line 1280, in run_before_save_methods
    self.run_method("validate")
  File "/home/frappe/frappe-bench/apps/frappe/frappe/model/document.py", line 1128, in run_method
    out = Document.hook(fn)(self, *args, **kwargs)
  File "/home/frappe/frappe-bench/apps/frappe/frappe/model/document.py", line 1516, in composer
    return composed(self, method, *args, **kwargs)
  File "/home/frappe/frappe-bench/apps/frappe/frappe/model/document.py", line 1494, in runner
    add_to_return_value(self, fn(self, *args, **kwargs))
  File "/home/frappe/frappe-bench/apps/frappe/frappe/model/document.py", line 1125, in fn
    return method_object(*args, **kwargs)
  File "/home/frappe/frappe-bench/apps/press/press/press/doctype/team_member_resource/team_member_resource.py", line 54, in validate
    self.validate_document_name()
  File "/home/frappe/frappe-bench/apps/press/press/press/doctype/team_member_resource/team_member_resource.py", line 77, in validate_document_name
    frappe.throw(
  File "/home/frappe/frappe-bench/apps/frappe/frappe/utils/messages.py", line 145, in throw
    msgprint(
  File "/home/frappe/frappe-bench/apps/frappe/frappe/utils/messages.py", line 106, in msgprint
    _raise_exception()
  File "/home/frappe/frappe-bench/apps/frappe/frappe/utils/messages.py", line 57, in _raise_exception
    raise exc
frappe.exceptions.ValidationError: Document ****.frappe.cloud.archived is not associated with team ******@*****.com

Fix

In sync_press_role, check the document's current team before attempting to insert a Team Member Resource entry. If the document no longer belongs to the team (or doesn't exist), skip it silently.

This check is type-agnostic and covers all three permitted document types: Site, Release Group, and Server.

@saurabh6790 saurabh6790 requested a review from ssiyad as a code owner May 29, 2026 11:13
@greptile-apps

greptile-apps Bot commented May 29, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR fixes a ValidationError crash in the decouple_press_role_resources migration patch by skipping Press Role Resources whose referenced document no longer belongs to the target team (archived, transferred, or deleted documents).

  • A frappe.db.get_value ownership check is inserted before each Team Member Resource insert in sync_press_role, and the resource is silently skipped when the current document team doesn't match. The fix correctly handles all three stale-data scenarios (archived name, team transfer, deletion) since get_value returns None for missing documents, and None != team evaluates to True.
  • The same guard now runs on every live Press Role save (not only during the migration), adding an extra DB query per resource per user inside an already-nested loop; for teams with many members and many resources this could be noticeable, though in typical usage it should be acceptable.

Confidence Score: 4/5

Safe to merge — the fix correctly resolves the migration crash and handles all documented stale-data cases without introducing new correctness risks.

The ownership check is logically sound: frappe.db.get_value returns None for missing/renamed documents, and None != team correctly triggers the skip. The only concern is that the same function is a live hook on Press Role saves, and the new per-resource get_value call compounds an already-N+1 inner loop — but this is a quality concern rather than a correctness defect.

press/press/doctype/team_member_resource/team_member_resource.py — specifically the sync_press_role loop, which now has two DB queries per resource per user on every Press Role save.

Important Files Changed

Filename Overview
press/press/doctype/team_member_resource/team_member_resource.py Adds a stale-resource guard in sync_press_role that checks document ownership via frappe.db.get_value before inserting; logically correct but introduces an additional per-resource DB query in an already N+1 inner loop that runs on every Press Role save.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[sync_press_role triggered\non Press Role save / patch] --> B[Delete all Team Member Resources\nfor the team]
    B --> C[For each team member user]
    C --> D[Query Press Role Resources\nfor user in team]
    D --> E[For each resource]
    E --> F{NEW: frappe.db.get_value\ndocument_type, document_name, 'team'}
    F -->|document_team != team\nor doc not found| G[Skip - stale resource\narchived / transferred / deleted]
    F -->|document_team == team| H{frappe.db.exists\nTeam Member Resource}
    H -->|exists| I[Skip - duplicate]
    H -->|not exists| J[frappe.get_doc.insert\nignore_permissions=True]
    E --> K{More resources?}
    K -->|Yes| E
    K -->|No| C
    G --> K
    I --> K
    J --> K
Loading

Reviews (1): Last reviewed commit: "fix: Skip stale Press Role resources dur..." | Re-trigger Greptile

Comment on lines 133 to +137
for resource in resources:
# Skip stale resources whose document has been transferred or archived.
document_team = frappe.db.get_value(resource.document_type, resource.document_name, "team")
if document_team != team:
continue

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.

P2 N+1 query inside inner loop on a live hook path

frappe.db.get_value is issued for every resource entry in the inner loop, which already runs once per user. Because sync_press_role fires as a hook on every Press Role save (not only during the migration patch), a team with many users and many resources will generate a large number of individual SELECT queries on each save. The existing frappe.db.exists call at line 148 compounds the same pattern. Consider collecting all unique (document_type, document_name) pairs from resources before the loop and resolving their teams in per-type batches (one frappe.db.get_all per distinct document_type), then look up results from a local dict during the iteration.

@codecov

codecov Bot commented May 29, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 0% with 3 lines in your changes missing coverage. Please review.
✅ Project coverage is 50.14%. Comparing base (02d381c) to head (a04bfc9).
⚠️ Report is 9 commits behind head on develop.

Files with missing lines Patch % Lines
...ctype/team_member_resource/team_member_resource.py 0.00% 3 Missing ⚠️

❌ Your patch check has failed because the patch coverage (0.00%) is below the target coverage (75.00%). You can increase the patch coverage or adjust the target coverage.

Additional details and impacted files
@@             Coverage Diff             @@
##           develop    #6558      +/-   ##
===========================================
+ Coverage    50.11%   50.14%   +0.03%     
===========================================
  Files          954      954              
  Lines        78895    78917      +22     
  Branches       369      369              
===========================================
+ Hits         39537    39573      +36     
+ Misses       39332    39318      -14     
  Partials        26       26              
Flag Coverage Δ
dashboard 61.01% <ø> (+<0.01%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

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.

1 participant