fix: handle PluginMissingError while migrating legacy blocks to libraries v2 (#37732)

Unhandled exception while migration legacy xblocks into new library stops the migration process abruptly causing following issues:

* Components not being collected into Collections for successful migrations
* Data being corrupted for already migrated blocks most likely due to incomplete transaction.
This commit is contained in:
Navin Karkera
2025-12-12 22:17:02 +05:30
committed by GitHub
parent e96e6ec684
commit a3cc78a377
2 changed files with 33 additions and 0 deletions

View File

@@ -41,6 +41,7 @@ from openedx_learning.api.authoring_models import (
)
from user_tasks.tasks import UserTask, UserTaskStatus
from xblock.core import XBlock
from xblock.plugin import PluginMissingError
from common.djangoapps.split_modulestore_django.models import SplitModulestoreCourseIndex
from common.djangoapps.util.date_utils import DEFAULT_DATE_TIME_FORMAT, strftime_localized
@@ -1164,6 +1165,9 @@ def _migrate_component(
except libraries_api.IncompatibleTypesError as e:
log.error(f"Error validating block for library {context.target_library_key}: {e}")
return None, str(e)
except PluginMissingError as e:
log.error(f"Block type not supported in {context.target_library_key}: {e}")
return None, f"Invalid block type: {e}"
component = authoring_api.create_component(
context.target_package_id,
component_type=component_type,

View File

@@ -1843,6 +1843,35 @@ class TestMigrateFromModulestore(ModuleStoreTestCase):
f"Not a valid source context key: {invalid_key}. Source key must reference a course or a legacy library."
)
def test_migrate_component_with_fake_block_type(self):
"""
Test _migrate_component with with_fake_block_type
"""
source_key = self.course.id.make_usage_key("fake_block", "test_fake_block")
olx = '<fake_block display_name="Test fake_block"></fake_block>'
context = _MigrationContext(
existing_source_to_target_keys={},
target_package_id=self.learning_package.id,
target_library_key=self.library.library_key,
source_context_key=self.course.id,
content_by_filename={},
composition_level=CompositionLevel.Unit,
repeat_handling_strategy=RepeatHandlingStrategy.Skip,
preserve_url_slugs=True,
created_at=timezone.now(),
created_by=self.user.id,
)
result, reason = _migrate_component(
context=context,
source_key=source_key,
olx=olx,
title="test"
)
self.assertIsNone(result)
self.assertEqual(reason, "Invalid block type: fake_block")
def test_migrate_from_modulestore_nonexistent_modulestore_item(self):
"""
Test migration when modulestore item doesn't exist