Problem/Motivation
\Drupal\Core\Recipe\ConfigConfigurator does:
if ($active_data = $active_configuration->read($config_name)) {
// @todo https://www.drupal.org/i/3439714 Investigate if there is any
// generic code in core for this.
unset($active_data['uuid'], $active_data['_core']);
if (empty($active_data['dependencies'])) {
unset($active_data['dependencies']);
}
$recipe_data = $recipe_storage->read($config_name);
if (empty($recipe_data['dependencies'])) {
unset($recipe_data['dependencies']);
}
// Ensure we don't get a false mismatch due to differing key order.
// @todo When https://www.drupal.org/project/drupal/issues/3230826 is
// fixed in core, use that API instead to sort the config data.
self::recursiveSortByKey($active_data);
self::recursiveSortByKey($recipe_data);
if ($active_data !== $recipe_data) {
throw new RecipePreExistingConfigException($config_name, sprintf("The configuration '%s' exists already and does not match the recipe's configuration", $config_name));
}
But that means that if:
- the recipe data contains a UUID (which is not a best practice, but it's also not forbidden, and sometimes, there may be a good reason for it)
- the active data's UUID matches but has been removed
that Recipes will WRONGLY throw this exception!
Steps to reproduce
Proposed resolution
diff --git a/core/lib/Drupal/Core/Recipe/ConfigConfigurator.php b/core/lib/Drupal/Core/Recipe/ConfigConfigurator.php
index ad837d5dc35..bb0f240ae9c 100644
--- a/core/lib/Drupal/Core/Recipe/ConfigConfigurator.php
+++ b/core/lib/Drupal/Core/Recipe/ConfigConfigurator.php
@@ -43,15 +43,18 @@ public function __construct(public readonly array $config, string $recipe_direct
// active storage.
foreach ($strict_list as $config_name) {
if ($active_data = $active_configuration->read($config_name)) {
+ $recipe_data = $recipe_storage->read($config_name);
// @todo https://www.drupal.org/i/3439714 Investigate if there is any
// generic code in core for this.
- unset($active_data['uuid'], $active_data['_core']);
+ unset($active_data['_core']);
+ if (empty($recipe_data['dependencies'])) {
+ unset($recipe_data['dependencies']);
+ }
if (empty($active_data['dependencies'])) {
unset($active_data['dependencies']);
}
- $recipe_data = $recipe_storage->read($config_name);
- if (empty($recipe_data['dependencies'])) {
- unset($recipe_data['dependencies']);
+ if (!array_key_exists('uuid', $recipe_data)) {
+ unset($active_data['uuid']);
}
// Ensure we don't get a false mismatch due to differing key order.
// @todo When https://www.drupal.org/project/drupal/issues/3230826 is
Remaining tasks
User interface changes
Introduced terminology
API changes
Data model changes
Release notes snippet
Recipes that install configuration with a predefined UUID (which is not recommended except in rare cases) will no longer incorrectly trigger RecipePreExistingConfigException.
Comments
Comment #2
wim leersRelated, but not the same: #3480248: Drupal does not recognize when the config is identical.
Comment #3
wim leersComment #4
mxr576Comment #5
smustgrave commentedDon't see anything to review?
Comment #6
wim leersFYI this would allow XB's test recipes to become more reliable:
… which should also make things for Drupal CMS a more predictable.
And I can't imagine us being the only ones affected, so bumping priority 😇
Comment #7
phenaproximaComment #8
wim leersHow did I end up reporting this?
See #3532130-11: `/xb/api/v0/config/component` crashes when `article` node type does not exist due to hardcoded assumption in `GeneratedFieldExplicitInputUxComponentSourceBase::getClientSideInfo()` for what prompted me to add
strict: falseto XB's test site recipe and also prompted the creation of this issue.The 3 commits before that comment show what had to change.
The problem IIRC is that the recipe system when
strict: true(the default), the comparison of the UUID stored intests/fixtures/recipes/test_site/config/experience_builder.component.js.xb_test_code_components_using_imports.ymlfails to match the active one.Comment #9
phenaproximaIs there any reason we shouldn't just unconditionally remove the
uuidand_corekeys from the incoming recipe data?The recipe system assumes those keys aren't there, but that's not a safe assumption -- lots of people make that mistake. We definitely do not want to have those keys be considered in the comparison.
We could remove those keys from the recipe data during the comparison, but if the recipe data still has those keys, they'll get imported anyway...which could be bad. Config UUIDs are expected to be unique per-site, and allowing them to be imported as-is would break that.
I think what needs to happen here is that
RecipeConfigStorageWrappershould always remove those keys from any config it reads in. Either that, or theFileStorageobject created by\Drupal\Core\Recipe\ConfigConfigurator::getConfigStorage()needs to do it.Comment #10
phenaproximaWim, can you elaborate on this bit? It's not forbidden but that might just be an oversight on our part. What are some good reasons for a recipe to include config UUIDs?
Comment #11
thejimbirch commentedWhat are the rare cases where you would want/need the UUID in a config?
Comment #12
wim leers#9++
What I meant is that config exported as default config into a module is (AFAIK) supposed to NOT have a UUID — default config in modules is supposed to get random UUIDs generated — because all that should matter is the config entity ID (a machine name), not the UUID.
See XB's
\Drupal\experience_builder\Entity\XbAssetLibraryTrait::getJsPath()— where it needs to generate a predictable file name based on the config entity UUID.Lots has changed/been improved/hardened in XB itself and in Drupal core 11.2 — this issue was created before #3492722: Update XB to require Drupal 11.2 landed, so first double-checking whether this is truly still needed. Although … #9 will definitely remain true 😇, but then it probably would only be .
Doing that double-checking in #3542282: [upstream] Update all of XB's (test) recipes use `strict: true`…
Comment #13
wim leersSetting
strict: truestill causes the recipe to fail (but now on a different piece of config). Quoting #3542282-3: [upstream] Update all of XB's (test) recipes use `strict: true`:(That's the test results for https://git.drupalcode.org/project/experience_builder/-/merge_requests/1...)
Comment #14
wim leersUpdate for #13: the urgency is gone as of https://git.drupalcode.org/project/canvas/-/merge_requests/83#note_590187 — #3532265: Remove the `canvas_dev_standard` module, instead recommend using XB's `test_site` recipe for development seems to have somehow been causing this.
Which IMHO makes this not major, because that was relatively atypical. But it does point out a weakness in the recipe system, so "minor" seems inappropriate too.