Generated with the help of an LLM.
Problem/Motivation
In #3532950: Support importing default content in JSON format, \Drupal\Core\DefaultContent\Finder was updated to discover and import default content entities defined in JSON format in addition to YAML. To do so, Finder scans the recipe's content/ directory for both *.yml and *.json files.
When default content includes file entities, the physical file payloads associated with the entities are stored inside content/file/{filename} alongside the entity definition file (as exported by \Drupal\Core\DefaultContent\Exporter::exportToFile() and \Drupal\file\EventSubscriber\DefaultContentSubscriber).
If the physical file payload is a JSON document (such as an OpenAPI / OAS specification file like petstore.json, a GeoJSON file, or a JSON schema fixture), Finder::__construct() encounters the .json file during directory traversal and assumes it is an exported Drupal content entity. Because the document is a raw JSON asset and not a normalized default content export, it lacks a _meta.uuid key, causing Finder to throw an ImportException:
In Finder.php line 57: /path/to/recipe/content/file/petstore.json does not have a UUID.
This regression prevents recipes containing default file entities with .json assets from being applied.
Steps to reproduce
- Create a recipe containing default content for a
fileentity whose physical asset is a.jsonfile (e.g.content/file/petstore.jsonaccompanyingcontent/file/{uuid}.yml). - Apply the recipe via
recipe:apply,drush recipe, or within a test usingRecipeTestTrait::applyRecipe(). - Observe the failure:
ImportException: .../content/file/petstore.json does not have a UUID.
Proposed resolution
In \Drupal\Core\DefaultContent\Finder::__construct(), do not require every discovered .json or .yml file to be a content entity. If a decoded file is not an array or does not contain _meta, it represents a non-entity file asset (or unrelated file) and should be skipped by Finder:
foreach ($finder as $file) { $decoded = (match ($file->getExtension()) { Yaml::getFileExtension() => Yaml::decode(...), Json::getFileExtension() => Json::decode(...), })($file->getContents()); // Physical file attachments or non-entity files do not have default content metadata. if (!is_array($decoded) || !isset($decoded['_meta'])) { continue; } $decoded['_meta']['path'] = $file->getPathname(); $uuid = $decoded['_meta']['uuid'] ?? throw new ImportException($decoded['_meta']['path'] . ' does not have a UUID.'); $files[$uuid] = $decoded;
Files that do define _meta but lack a uuid will continue to throw an ImportException, preserving existing validation coverage in \Drupal\Tests\Core\DefaultContent\FinderTest::testExceptionIfNoUuid().
Remaining tasks
- Create a merge request.
- Add unit and functional test coverage for recipes with default content file entities attaching
.jsonfiles. - Review and commit.
User interface changes
None.
Introduced terminology
None.
API changes
\Drupal\Core\DefaultContent\Finder ignores files without _meta rather than throwing an ImportException.
Data model changes
None.
Release notes snippet
Issue fork drupal-3633775
Show commands
Start within a Git clone of the project using the version control instructions.
Or, if you do not have SSH keys set up on git.drupalcode.org:
Comments
Comment #2
phenaproximaI think that silently skipping items that don't have
_metais a good solution here, and should be very simple to implement and test; all we'd need to do is add two new files (one JSON and one YAML) to an existing fixture.Comment #4
phenaproximaWith the new fixture files, the tests fail exactly as you would expect: https://git.drupalcode.org/project/drupal/-/jobs/13186426/viewer#L14374
Excerpted:
Comment #5
phenaproximaComment #6
phenaproximaCurrent test failure is almost certainly a random. I'd rerun but don't have permissions for that.
Comment #7
mxr576Thanks for the quick fix, tested the change, RTBC++
Also merged the latest main in a hope that the flaky test got resolved there already.