Skip to content

Merge V7.12.0.5 into main#8043

Draft
acwhite211 wants to merge 39 commits intomainfrom
v7_12_0_5
Draft

Merge V7.12.0.5 into main#8043
acwhite211 wants to merge 39 commits intomainfrom
v7_12_0_5

Conversation

@acwhite211
Copy link
Copy Markdown
Member

@acwhite211 acwhite211 commented Apr 28, 2026

Merge the PRs added in the v7_12_0_5 branch into main.

Checklist

  • Self-review the PR after opening it to make sure the changes look good and
    self-explanatory (or properly documented)
  • Add relevant issue to release milestone
  • Add pr to documentation list

Testing instructions

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 28, 2026

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 38bc94f0-3949-4dc4-98dd-c8f905b5e655

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

This PR refactors migration utilities to improve determinism and maintainability, updates FormParse column definition selection to include OS-specific fallback behavior, normalizes delete-blocker serialization for many-to-many relationships, and makes permissions policy JSON serialization deterministic.

Changes

Cohort / File(s) Summary
FormParse Column Definitions
specifyweb/frontend/js_src/lib/components/FormParse/index.ts, specifyweb/frontend/js_src/lib/components/FormParse/__tests__/index.test.ts
Added explicit OS fallback behavior: tries Linux-specific column definition first, then generic, then first available. Includes unit tests for precedence rules.
Delete Blocker Serialization
specifyweb/backend/delete_blockers/views.py, specifyweb/specify/tests/test_delete_blockers.py
Routes many-to-many blockers through normalization function that resolves through models and rewrites payloads using related model names and relationship logical names. Adds comprehensive test coverage including cascade collection from parent models.
Permissions Determinism
specifyweb/frontend/js_src/lib/components/Permissions/index.ts
Sorts both outer policy entries and inner action collections before JSON serialization for fully deterministic output.
Data Model Utilities
specifyweb/specify/models_utils/load_datamodel.py
Introduces Table._all_fields helper method to centralize field/relationship iteration with configurable filtering; updates all_fields property to delegate to this helper.
Migration Utilities Refactor
specifyweb/specify/migration_utils/update_schema_config.py, specifyweb/specify/migration_utils/sp7_schemaconfig.py, specifyweb/specify/migration_utils/tectonic_ranks.py, specifyweb/specify/migration_utils/default_cots.py
Type-safe schema config defaults via new TableDefaults/FieldDefaults typed dicts; deterministic locale container resolution; conditional picklist item creation; removes redundant loan/gift agent functions; refactors tectonic rank creation to avoid overwrites; removes MIGRATION_0038_UPDATE_FIELDS constant.
Migration Orchestration
specifyweb/specify/management/commands/run_key_migration_functions.py, specifyweb/specify/migrations/0039_agent_fields_for_loan_and_gift.py
Disables unsuitable startup migration functions with in-code comments; removes calls to deleted update_loan_and_gift_agents and revert_loan_and_gift_agents functions.
API & Formatting
specifyweb/specify/api/crud.py
Minor newline formatting fix at file end.

Possibly related PRs

  • specify/specify7#8028: Directly modifies the same FormParse column definition logic and unit tests for OS-specific precedence.
  • specify/specify7#8039: Related migration utility refactoring in update_schema_config.py and run_key_migration_functions.py for deterministic locale/schema-config handling.

Suggested reviewers

  • grantfitzsimmons
🚥 Pre-merge checks | ✅ 4 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Automatic Tests ⚠️ Warning PR includes comprehensive tests for delete blockers and FormParse, but significant backend changes lack automatic test coverage, and review comments identify actual functional bugs in untested code. Add unit tests for untested modules (tectonic_ranks.py, update_schema_config.py, default_cots.py, load_datamodel.py, Permissions) and address identified bugs with regression tests.
Testing Instructions ⚠️ Warning Testing instructions are vague and insufficient for the scope of changes affecting 10+ components without specific test cases or validation steps. Enhance testing instructions by listing required unit tests, providing manual testing scenarios, clarifying migration validation, and addressing outstanding review comments.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Merge V7.12.0.5 into main' accurately describes the PR's primary objective: merging a release branch into the main branch.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch v7_12_0_5

Tip

💬 Introducing Slack Agent: The best way for teams to turn conversations into code.

Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get started


Comment @coderabbitai help to get the list of available commands and usage tips.

Also, define a helper on Table to fetch/filter fields
…alecontaineritem

Duplicate items and strings would be created everytime the function is run.
The cause of this is the same as #7988.
There's no easy way to differentiate schema config items for
which these should be applied.
I suppose the BEST method might be to be exact: only updating
Containers/Items/Strings that exactly match the previous values
expected with the migrations they aim to fix/resolve
@melton-jason
Copy link
Copy Markdown
Contributor

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 29, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
specifyweb/specify/tests/test_delete_blockers.py (1)

165-329: ⚠️ Potential issue | 🟠 Major

Please remove the duplicated module block appended at the end.

The entire test module is repeated from Line 165 onward, including imports and class redefinitions. This shadows earlier class bindings and makes the test file brittle/confusing. Keep a single copy of the module content.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@specifyweb/specify/tests/test_delete_blockers.py` around lines 165 - 329, The
file contains a duplicated module block (duplicate imports and repeated
definitions of TestDeleteBlockers, TestDeleteBlockersCascade, helper _url and
tests) appended after the original content; remove the entire second copy so
only one definition of helpers (_url, _get_blockers, _assertSame,
_assertContains) and the test classes TestDeleteBlockers and
TestDeleteBlockersCascade remain, ensuring references to
_collect_delete_blockers, GeographyTree, and model usages (e.g. Spexportschema,
Spexportschemamapping) are preserved from the first occurrence.
specifyweb/specify/migration_utils/default_cots.py (1)

71-86: ⚠️ Potential issue | 🟠 Major

Backfill the default COG items on reruns.

Picklistitem.get_or_create(...) was already idempotent, so moving the item loop under picklist_created means fix_cots can no longer heal an existing SystemCOGTypes picklist that is missing one or more default rows. This turns a safe rerun path into a partial no-op.

Suggested fix
-        if picklist_created:
-            for cog_type in DEFAULT_COG_TYPES:
-                Picklistitem.objects.using(using).get_or_create(
-                    title=cog_type,
-                    value=cog_type,
-                    picklist=cog_type_picklist
-                )
+        for cog_type in DEFAULT_COG_TYPES:
+            Picklistitem.objects.using(using).get_or_create(
+                title=cog_type,
+                value=cog_type,
+                picklist=cog_type_picklist
+            )
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@specifyweb/specify/migration_utils/default_cots.py` around lines 71 - 86, The
code currently only seeds DEFAULT_COG_TYPES into the Picklist when
picklist_created is True, which prevents healing missing Picklistitem rows on
reruns; update the logic in the function (e.g., fix_cots in default_cots.py) so
that after obtaining cog_type_picklist via
Picklist.objects.using(using).get_or_create(...) you always iterate
DEFAULT_COG_TYPES and call Picklistitem.objects.using(using).get_or_create(...)
for each cog_type (using cog_type_picklist as the picklist argument) rather than
restricting that loop to the picklist_created branch, ensuring idempotent
backfill of missing items.
🧹 Nitpick comments (2)
specifyweb/backend/delete_blockers/views.py (1)

45-49: Optional cleanup: remove the temporary nested list + flatten() roundtrip.

You can return the serialized list directly for simpler and clearer code.

Proposed simplification
-    return flatten([
-        [
-            _serialize_delete_blocker(field, sub_objs)
-        ] for field, sub_objs in collector.delete_blockers
-    ])
+    return [
+        _serialize_delete_blocker(field, sub_objs)
+        for field, sub_objs in collector.delete_blockers
+    ]
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@specifyweb/backend/delete_blockers/views.py` around lines 45 - 49, The
current return builds a temporary nested list and then flattens it; simplify by
returning a flat list comprehension directly instead of wrapping each item in
its own list and calling flatten — replace the expression that returns
flatten([... for field, sub_objs in collector.delete_blockers]) with a direct
comprehension that calls _serialize_delete_blocker(field, sub_objs) for each
(referencing collector.delete_blockers and _serialize_delete_blocker) so the
function returns the serialized list without the unnecessary nested-list +
flatten roundtrip.
specifyweb/specify/models_utils/load_datamodel.py (1)

152-174: Consider making this iterator public.

update_schema_config.py now depends on table._all_fields(...) directly, so this is effectively part of the external Table API now. Renaming it to a public method like iter_all_fields(...) would make that contract explicit and reduce future refactor breakage.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@specifyweb/specify/models_utils/load_datamodel.py` around lines 152 - 174,
The iterator method _all_fields is being used externally so make it an explicit
public API by adding a new method iter_all_fields(self, exclude_fields=False,
exclude_relationships=False, exclude_id_field=False,
exclude_virtual_fields=True) that implements the same yield logic and update the
all_fields property to call iter_all_fields(); then keep _all_fields as a thin
compatibility wrapper that calls iter_all_fields (or vice versa) and update any
internal call sites to use iter_all_fields to avoid future breakage while
preserving backward compatibility.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@specifyweb/specify/migration_utils/tectonic_ranks.py`:
- Around line 115-126: The current lookup for tectonic_tree_def_item only
filters by treedef and parent=None and can pick a wrong parentless row; update
the initial query on TectonicUnitTreeDefItem (the tectonic_tree_def_item
assignment) to include rankid=0 (i.e., filter by treedef=tectonic_tree_def,
parent=None, rankid=0) so it matches the same root invariant used in the
get_or_create path; ensure the get_or_create call for TectonicUnitTreeDefItem
also uses rankid=0 as a lookup key (not just a value) so both retrieval and
creation use the same unique identifying fields.

In `@specifyweb/specify/migration_utils/update_schema_config.py`:
- Around line 1963-1969: The loop currently calls
update_table_field_schema_config_with_defaults which only applies ishidden when
creating new Splocalecontaineritem rows; change the call (or the function) to
ensure existing Splocalecontaineritem rows are updated to set ishidden=True for
the targeted fields. Concretely, modify
update_table_field_schema_config_with_defaults (or add a small wrapper) so that
for each (table, field_name) it queries Splocalecontaineritem for the matching
table/field/discipline and if a row exists performs a direct update (e.g., set
ishidden=True and save or use queryset.update), otherwise create with the
default; keep references to MIGRATION_0038_FIELDS, Discipline.objects.all(),
update_table_field_schema_config_with_defaults and Splocalecontaineritem when
implementing the change.

---

Outside diff comments:
In `@specifyweb/specify/migration_utils/default_cots.py`:
- Around line 71-86: The code currently only seeds DEFAULT_COG_TYPES into the
Picklist when picklist_created is True, which prevents healing missing
Picklistitem rows on reruns; update the logic in the function (e.g., fix_cots in
default_cots.py) so that after obtaining cog_type_picklist via
Picklist.objects.using(using).get_or_create(...) you always iterate
DEFAULT_COG_TYPES and call Picklistitem.objects.using(using).get_or_create(...)
for each cog_type (using cog_type_picklist as the picklist argument) rather than
restricting that loop to the picklist_created branch, ensuring idempotent
backfill of missing items.

In `@specifyweb/specify/tests/test_delete_blockers.py`:
- Around line 165-329: The file contains a duplicated module block (duplicate
imports and repeated definitions of TestDeleteBlockers,
TestDeleteBlockersCascade, helper _url and tests) appended after the original
content; remove the entire second copy so only one definition of helpers (_url,
_get_blockers, _assertSame, _assertContains) and the test classes
TestDeleteBlockers and TestDeleteBlockersCascade remain, ensuring references to
_collect_delete_blockers, GeographyTree, and model usages (e.g. Spexportschema,
Spexportschemamapping) are preserved from the first occurrence.

---

Nitpick comments:
In `@specifyweb/backend/delete_blockers/views.py`:
- Around line 45-49: The current return builds a temporary nested list and then
flattens it; simplify by returning a flat list comprehension directly instead of
wrapping each item in its own list and calling flatten — replace the expression
that returns flatten([... for field, sub_objs in collector.delete_blockers])
with a direct comprehension that calls _serialize_delete_blocker(field,
sub_objs) for each (referencing collector.delete_blockers and
_serialize_delete_blocker) so the function returns the serialized list without
the unnecessary nested-list + flatten roundtrip.

In `@specifyweb/specify/models_utils/load_datamodel.py`:
- Around line 152-174: The iterator method _all_fields is being used externally
so make it an explicit public API by adding a new method iter_all_fields(self,
exclude_fields=False, exclude_relationships=False, exclude_id_field=False,
exclude_virtual_fields=True) that implements the same yield logic and update the
all_fields property to call iter_all_fields(); then keep _all_fields as a thin
compatibility wrapper that calls iter_all_fields (or vice versa) and update any
internal call sites to use iter_all_fields to avoid future breakage while
preserving backward compatibility.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 0711e959-159f-42a0-9232-05dbdd5b23fa

📥 Commits

Reviewing files that changed from the base of the PR and between b4b1602 and 888aca8.

📒 Files selected for processing (13)
  • specifyweb/backend/delete_blockers/views.py
  • specifyweb/frontend/js_src/lib/components/FormParse/__tests__/index.test.ts
  • specifyweb/frontend/js_src/lib/components/FormParse/index.ts
  • specifyweb/frontend/js_src/lib/components/Permissions/index.ts
  • specifyweb/specify/api/crud.py
  • specifyweb/specify/management/commands/run_key_migration_functions.py
  • specifyweb/specify/migration_utils/default_cots.py
  • specifyweb/specify/migration_utils/sp7_schemaconfig.py
  • specifyweb/specify/migration_utils/tectonic_ranks.py
  • specifyweb/specify/migration_utils/update_schema_config.py
  • specifyweb/specify/migrations/0039_agent_fields_for_loan_and_gift.py
  • specifyweb/specify/models_utils/load_datamodel.py
  • specifyweb/specify/tests/test_delete_blockers.py
💤 Files with no reviewable changes (2)
  • specifyweb/specify/migrations/0039_agent_fields_for_loan_and_gift.py
  • specifyweb/specify/migration_utils/sp7_schemaconfig.py

Comment thread specifyweb/specify/migration_utils/tectonic_ranks.py Outdated
Comment thread specifyweb/specify/migration_utils/update_schema_config.py
@github-project-automation github-project-automation Bot moved this from 📋Back Log to Dev Attention Needed in General Tester Board Apr 29, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Dev Attention Needed

Development

Successfully merging this pull request may close these issues.

2 participants