Problem/Motivation
This is best described by referring to this documentation clarification issue I just opened: #3560169: Clarify that "config.import.mymodule: *" imports all optional configuration without checking dependencies
The current documentation states:
For a given module or theme, you have two options. First, you can use a * wildcard to install all configuration the module provides, just as would happen when the extension is installed "normally" (not via a recipe).
This is not accurate, because using a * wildcard will install ALL of the module's configuration, including entities in config/optional and it will NOT filter out optional configuration that has unmet dependencies, which is how it "normally" works.
Steps to reproduce
Attempt to apply a recipe that installs a module with optional configuration that has unmet dependencies, using the config.import.[module].* wildcard syntax.
Proposed resolution
Can we make this work the same as it "normally" works when installing extensions? Can it install all of the module's configuration, and filter out optional config with missing dependencies?
Remaining tasks
TBD
User interface changes
None.
Introduced terminology
None.
API changes
None.
Data model changes
None.
Release notes snippet
None.
Comments
Comment #2
m.stentaI postponed #3560169: Clarify that "config.import.mymodule: *" imports all optional configuration without checking dependencies pending this discussion... since doing this would remove the need to make that change.
Comment #3
phenaproximaThis has been asked for many times, and I have generally pushed back on it. @alexpott may also be able to provide clarification.
This is a tricky area because the way optional configuration works goes directly against the intrinsic goals and guardrails of a recipe.
A recipe needs to be, above all, predictable. Recipes can be applied to a site at any point in its lifecycle, and be composed into huge, complicated clusters and stacks. Both of these things mean that a recipe has to be predictable. You need to know exactly what it will do, just by reading it. Recipes must, in every respect, have a guaranteed outcome.
But, from a recipe's perspective, optional config is unpredictable. That's not to say optional config is random; it does operate by a known and clear set of rules. Nonetheless, exactly what optional config you will get really depends on the state of the system at any given point in time. What extensions -- including the install profile -- are installed? What config entities exist? Those can change over time, and whenever they do, it directly changes what optional config can be installed from that point on. Recipes have no way to know the state of the system, and alter themselves to fit it. If they did, that would violate one of the main principles of recipes, which is that they are dumb and cannot contain logic or make decisions.
In other words, if recipes installed optional config the "usual" way, applying a single recipe could produce different results depending on when you applied it. That harms, if not outright breaks, both predictability and composability. How can I build a recipe on top of another recipe which can produce different outcomes depending on factors which I, as the recipe author, have no way to know in advance?
If recipes' predictability and composability is harmed, a great deal of recipes' value is lost. That's why I am generally against the idea of having recipes be in the optional config business as we know it. And it's why I suspect the recipe system, as created by @alexpott, was designed this way.
Doing this would also open the door to an entirely new class of bugs which simply doesn't exist right now. And it would increase the complexity of the recipe system (which is currently fairly simple) by orders of magnitude, since now we have to deal with dynamic dependency resolution, which is problematic in the best of times.
Now, having said all that, I can see why the choice between either "import everything" (
*) and "import some stuff" (an array of config names) is limiting. One thing I was considering was maybe introducing support for a new symbol (this is just a guess at syntax):This would mean "import all config from
foo_module, except for its optional config".To me, this:
*would be unchanged).foo_modulechanges the config it ships with, but that is a dependency versioning issue and does not make the recipe more sensitive to the state of the system.Comment #4
m.stentaThanks for taking the time to reply so thoroughly @phenaproxima. I am coming to recipes late(r), so there's a lot to catch up on.
Everything you said makes sense. I will have to consider all this, and whether or not recipes are a workable solution for our use-case (described here: #3560179: Support installing all module configuration entities via recipes).
@bryan also pointed to this as one of the original discussions: #3393086: Optional configuration is imported even when module dependencies aren't there.
So I will close this as a duplicate. Thanks again for the explanations.