Problem/Motivation
\Drupal\Core\Recipe\Recipe has a TODO about improving the validation of the contents and structure of recipe.yml files. Let's beef that up.
Proposed resolution
PHP-TUF uses Symfony's Validator component to set up a tree of constraints to validate the data of incoming JSON files. An example of this: https://github.com/php-tuf/php-tuf/blob/main/src/Metadata/TargetsMetadat...
Let's do something similar here.
Remaining tasks
Implement it and add unit tests to prove that all constraints are exercised.
As discussed in #3413824: Warn Recipe developers if a module being installed does not have a corresponding config import declaration, one of the most important things to validate is that every module listed in the modules section of a recipe also has a corresponding entry in the config:import section, specifying whether to import some, all, or none of the module's config.
Validate that config actions should have valid config name in case of wildcard config actions. See - https://git.drupalcode.org/project/distributions_recipes/-/merge_request...
Issue fork distributions_recipes-3400672
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 #3
phenaproximaComment #5
wim leersFirst: WOW! 🤩
Second: it doesn't quite work perfectly yet:
… so we'll need to adjust what you have in there so far. But it's a superb start!
The beauty of this approach is that we can reuse the very same validation constraints that we're already using for config 👍
Validation expanded to confirm this works
For example, the values underinstallshould not just be non-empty strings. They should conform to what Drupal considers valid extension names. For that, #3324150: Add validation constraints to config_entity.dependencies added theExtensionNameconstraint 😄This was wrong, because due to #3311111: Support modern syntax for defining module dependencies, syntax like
drupal:forumare supported, to allow specifying eitherdrupal:forumorforum:forum.recipes✅ TheExtensionNameconstraint can be used for the values under this key — done 👍name✅ Matched the constraints used fortype: labelin Drupal coreIts now back to the same set of failures as before I started contributing. I'll let @phenaproxima figure out how to deal with the remaining things 🤓
Importance for recipe authoring to get precise feedback
Since the DX of authoring a new recipe is essentially 100% manual YAML construction today, and it will be for a good while to come, I think it's crucial that we have test coverage proving that every small mistake a recipe author might make is in fact caught by validation.
I just pushed a first test case for this.
Prior art/pattern to copy to thoroughly test this?
I have some prior art/experience with this very problem, because I faced the same challenge for CKEditor 5 plugin definitions. However, that one is far more complicated because it needs to mock modules. Since validating a recipe happens entirely outside the context of a running Drupal site, it'll be far simpler here. What matters IMHO is to not have dozens of
recipe.ymlfiles in the codebase, because that'll be chaotic very quickly. I think it'd be easier to have them defined in the test provider itself.See
\Drupal\Tests\ckeditor5\Kernel\CKEditor5PluginManagerTest::providerTestInvalidPluginDefinitions()for an example. (Although the value is arguably less here, since there's only a YAML file for each test case, whereas for CKEditor 5 you'd need the entire module directory structure +*.info.ymlfile.)@alexpott: would you prefer actual YAML files on disk, like in the first test case I added, or would you prefer the approach taken in CKEditor 5?
Comment #6
thejimbirch commentedAre you talking about managing recipe.yml files in different places or in the
core/tests/fixtures/recipesfolder?I like the idea of having actual recipes in there to provide examples in the code base, not just in documentation places.
Comment #7
wim leersYes, correct recipes make sense to have actual Recipe YAML files.
In this case, we're working to detect invalid Recipe YAML files. Those I'd argue should have actual YAML files on disk. 😊
Comment #8
wim leersOh and this actually resolved
in
\Drupal\Core\Recipe\ConfigConfigurator::__construct()too! 🤩Comment #9
wim leersBefore going much further here, I'd like to get feedback from @alexpott.
Comment #10
borisson_I really like that we are reusing the symfony validator to ensure that everything is correct, I think the approach here is good. We will of course need more/better tests.
Comment #11
wim leersComment #12
phenaproximaComment #13
wim leers@phenaproxima++ for #12.
This is crucial for recipe creators's usability/DX (whichever you want to call it).
Comment #14
narendrarOne issue which I found while working on #3417835: Convert the Standard install profile into a set of recipes is adding wrong key to
configin recipe.yml. I think currently config expects config:import or/and config:actions and any other key supposeconfig:installdoes nothing. So should we validate that config should not have any other key except 2 defined?Comment #15
wim leersYes, we should. Any and every guardrail we can add that would make a problem explicit (rather than the infrastructure silently accepting it and needing a debugger to figure out) is worth adding 👍
Comment #16
narendrarIn continuation to #14, recipes keys are name, description, type, recipes, install, config and content and defining any other key should give validation error.
Comment #17
wim leers#16: the MR already has validation for all those 😄 (and #14's suggestion too btw) — we just need to finish what @phenaproxima started! 🤞
Comment #18
narendrar@Wim Leers, I tried to add the validation constraint, but it is not getting triggered. I think something is not correct in
Comment #19
wim leersThat's totally possible! What did stepping through the execution with a debugger reveal?
Comment #20
narendrarI added
ConfigImportKeyExistsConstraintto 'install' and it is working now 😬. Not sure if this is the correct place though.If this seems correct then we might expand ConfigImportKeyExistsConstraint to validate other things like whether to import some, all, or none of the module's config.
TBH, I don't know if recipes support config:import none.
Comment #21
phenaproximaI think this is blocked by #3421197: It is impossible for recipes to depend on recipes outside of their own directory.
Without that issue, we cannot validate that recipes depend on other recipes that actually exist, which I think is a critically important guard rail we should implement.
Comment #22
narendrarComment #23
wim leersI think there's plenty of things that can continue here? #3421197: It is impossible for recipes to depend on recipes outside of their own directory may block commit of this issue, but there's lots of work we can already do here! 😊
Comment #24
wim leersThis is definitely moving in the right direction 👍 Did another review round to keep this going 😊
Comment #25
wim leersThis is definitely going in the right direction — the only thing still missing here is more test cases! 👍
Comment #26
narendrarComment #27
wim leersThis is now looking very close! 😄
Several follow-ups have been identified — let's get those created and let's make this MR point to them. 50% of the remaining work is creating those follow-ups, 50% are for small remarks.
Comment #28
wim leers#3421197: It is impossible for recipes to depend on recipes outside of their own directory landed!
Comment #29
wim leersThere's a few threads from my feedback 2 days ago that are not yet addressed, but then again @phenaproxima is working on it as we speak! 😄
It's VERY exciting to see that this is unblocked and nearly ready 🤩
Comment #30
phenaproximaI think all feedback is addressed; some threads have been left open for Wim to sign off on.
Comment #31
phenaproximaComment #32
wim leersLooks wonderful! We can nitpick exact validation messages, but I'd rather not do that here, and do it later, when Recipes is further along. Right now, this is a HUGE improvement over the status quo, and will help authors of future recipes enormously! 👏🤩
A few follow-ups have already been created (thanks @phenaproxima):
Comment #33
alexpottLeft a big comment about
:: validateExtensionHasImportEntry()- I think the best way forward is to move that part of the validation to a follow-up.Comment #34
narendrarComment #35
wim leersThat now extracted into #3424603: Validate that extension listed in the config.import section of recipe.yml has option to bypass all config of that extension 👍
Comment #36
alexpottCommitted and pushed fa6b83c3727 to 11.x and e902f1c4937 to 10.2.x. Thanks!
Comment #42
wim leersEh … what's going on here? 😨
Comment #43
alexpottThis broke 10.2.x so I reverted and created 10.3.x :) so this is on 10.3.x and 11.x and 10.2.x is now stuck in time. I should have opened 10.3.x when core did.