Problem/Motivation
NOTE: This issue supersedes #3301370: Model core's standard install profile as recipes. Its issue fork got all bungled up and is not usable. Since there can only be one issue fork per issue, @alexpott and I decided to open a new issue where we could continue the work from a clean state. And now, back to our regularly scheduled issue summary:
Recipes are conceived as composable, with any given recipe often requiring a chain of other recipes. But there's little practical sense as yet of just how this would work, or of what recommended patterns might be.
Proposed resolution
Let's "rebuild" the Standard install profile as a set of recipes!
There still needs to be an install profile, so but let's begin with Minimal. From there, let's create a set of recipes that are composed together into a new recipe, called Standard. If the Standard recipe is applied, then you should get exactly the same site that you would if you just installed the Standard profile.
We'll want the following test coverage:
- If you install Minimal, then apply the Standard recipe, all the same expectations as
\Drupal\Tests\standard\Functional\StandardTest
should pass. - Each individual recipe that makes up the Standard recipe should be able to be independently applied, successfully, on top of the Minimal profile.
- For each individual recipe, each piece of config in it should have its config dependencies fulfilled either by other config in the same recipe, or some config elsewhere in that recipe's dependency tree. This, happily, is proven by the previous test.
There are some things that Standard does, which are currently beyond the capabilities of the recipe system:
- Default Shortcut set can not be created. See https://git.drupalcode.org/project/distributions_recipes/-/merge_request... → follow-up: #3418706: [PP-1] Populate the default shortcut set
- Can not have menu links similar to standard.links.menu.yml. See https://git.drupalcode.org/project/distributions_recipes/-/merge_request... → follow-up: ⚠️TBD⚠️
- Can not assign user 1 the "administrator" role. See https://git.drupalcode.org/project/distributions_recipes/-/merge_request... → follow-up: #3418704: Assign user 1 the "administrator" role. — but probably does not need to be fixed, hence it's already closed
- Can not set Contact feedback form recipients. → follow-up: #3303126: Getting user input during / before applying a recipe
There are also certain parts of Standard which aren't installed by Standard itself -- for example, all of its media types are only installed if the Media module is installed. Since recipes don't have the concept of "optional config", Standard's media types, along with the Editorial workflow, should be converted to recipes as well, but they not be amongst the sub-recipes installed by the standard
recipe.
What needs to be decided and can be done in follow-ups:
- Decide on use of composer.json files for core recipes. One example is #3306904: Add the ability to suggest other recipes.
- Decide on naming convention on recipes. See #22.1 and #26.1
What recipes make up Standard-the-Recipe, and why?
In general, each recipe in Standard aims to provide something complete, tangible, and at least somewhat useful. So if you install any given recipe from Standard, you should end up with something new on your site that is ready to use. The following recipes fall into that category:
basic_block_type
article_content_type
page_content_type
feedback_contact_form
basic_html_format_editor
full_html_format_editor
editorial_workflow
image_media_type
document_media_type
local_video_media_type
remote_video_media_type
audio_media_type
standard_responsive_images
tags_taxonomy
A couple of the recipes are there to enhance something created by another recipe. Again, the end goal is something tangible and useful, but not necessarily "new". article_tags
and article_comment
fall into this category.
A few of the recipes are more aimed at establishing common-sense defaults and best practices. Their aim is "set it and forget it":
core_recommended_performance
core_recommended_maintenance
core_recommended_admin_theme
core_recommended_front_end_theme
Two recipes are more special-case:
comment_base
provides basic underlying infrastructure for adding comments to content. We could fold this intoarticle_comment
, but I can definitely see a case for having "all the infrastructure for comments, not attached to anything" as a useful "API-only" recipe that would be useful to other recipes in the wild. Therefore, I think keeping this as its own lower-level recipe makes sense.restricted_html_format
doesn't seem to fit anywhere else. It feels like another one that might be handy for building on top of, but is very low-key as shipped.
You may happily refer to #3301370: Model core's standard install profile as recipes as needed for prior art and discussion.
Remaining tasks
- Build out the recipe tree I've just described.
- Add the requested test coverage.
- Manually test.
- Commit!
User interface changes
None.
API changes
Should be none. If any are needed, they should be filed in blocking or follow-up issues.
Data model changes
None anticipated.
Issue fork distributions_recipes-3417835
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 #8
phenaproximaWelp, just as I submitted this issue, @alexpott gave me permission to assign credit. So, transferring credit from #3301370: Model core's standard install profile as recipes.
Comment #9
phenaproximaComment #11
phenaproximaTest failures ahoy!
Comment #12
phenaproximaI have a sneaking suspicion that one of the tests (
StandardRecipeTest
) is failing due to the config ordering bug I described in #3416287: ConfigConfigurator should be insensitive to key order when comparing active config to recipe config.Since I'm not certain that's the cause, I'm not going to explicitly call it a blocking issue...at least, not yet. But I'm linking it as a related one.
Comment #13
narendraRRe #12, Test failure is due to change in recipients email in tests from
admin@example.com
tosimpletest@example.com
. How can I fix this?Also I have added test coverage as per https://www.drupal.org/project/distributions_recipes/issues/3301370#comm...
Comment #14
phenaproximaAh, I see what you mean, @narendraR; the Empty profile is creating the
feedback
contact form one way, and then the feedback_contact_form recipe is trying to fully replace it.I think what I would do in this case is remove the contact form, and the code related to it, from the Empty profile entirely. That stuff only seems to be there to emulate Standard, but frankly that contradicts the purpose of the Empty profile. :)
The real problem here is that when the feedback_contact_form recipe is applied, it needs to be able to ask the user for the recipients (or at least, it needs to be able to extrapolate it from somewhere). So to really properly solve this, we should fix #3303126: Getting user input during / before applying a recipe, but that's a job for another time.
What would be even better is if the feedback_contact_form recipe could automatically copy the
system.site:mail
config value into to the contact form! But that's currently beyond the capabilities of the recipe system.I'll open a follow-up issue to at least raise that as a possible feature, since that's the kind of thing recipe authors will likely need from time to time.
Comment #15
phenaproximaOkay, I updated #3303126-6: Getting user input during / before applying a recipe with our use case. We probably don't need a whole new follow-up, IMHO, since this problem falls into the scope of "collecting input while applying a recipe".
Comment #16
thejimbirch CreditAttribution: thejimbirch commentedRe: #14, I had created the empty profile to have no configuration at all. Investigating what made its way in there.
Comment #17
thejimbirch CreditAttribution: thejimbirch commentedAh, I see that functionality that cannot be currently done in recipes is being configured in the empty profile.
I had called some of that out in https://www.drupal.org/project/distributions_recipes/issues/3301370#comm...
I suggest that rather than state that only Install Profiles can do these things, that we wait until we do everything we can using recipes, and then figure out how to do the remaining items. Some of those items may bring to light additional config actions we need, or be possible with functionality on the roadmap like "default content".
I'd rather for now we leave the empty profile empty, to be used as an unadulterated clean slate for applying recipes.
Comment #18
narendraRRe #17, I agree with your point, but did it here in MR so that we can plan some action and then remove them. Also it seems to me that the points which you raised in https://www.drupal.org/project/distributions_recipes/issues/3301370#comm... are the only action items to make this recipe identical to standard profile.
Comment #19
thejimbirch CreditAttribution: thejimbirch commentedMakes sense, thanks @narendraR!
Comment #20
narendraRI copied
StandardTest.php
code intoStandardRecipeTest.php
to check how much it works.It basically failed at 2 points:
Comment #21
Wim Leers#20:
Exciting to see that we're already so close to have
StandardRecipeTest
passing! 🤩👏Comment #22
Wim LeersWhy do recipe names start with "the subjective use case label" rather than "the objective thing"?
Is it because then it becomes harder to spot the connection between the
article_*
recipes? 🤔article_comment
+article_content_type
+article_tags
? Why not justarticle
? Articles have comments and tags, period. If you don't want that, use a different recipe. It feels like unnecessary granularity to me.Heck, we could go with
standard_article
. And then there could be more opinionated variants of "articles" in other recipes provided by contrib?Comment #23
narendraRRe #21.1, the reason is #13. I am not sure why but the value of recipients email is not changing from
admin@example.com
tosimpletest@example.com
Comment #24
Wim Leers#23: Are you saying that we named recipes this particular way to ensure a particular execution order of the recipes? 😰
Comment #25
narendraRRe #24, No. I am saying this in reference to #20.
Comment #26
thejimbirch CreditAttribution: thejimbirch commentedRe #22
1.
As part of https://www.drupal.org/project/distributions_recipes/issues/3284777 , documentation was added to the 1.0.x branch. The naming convention is peppered throughout the documentation, but the definition of it is in this doc: https://git.drupalcode.org/project/distributions_recipes/-/blob/1.0.x/do...
I do agree with @wimleers though, I like bundle_uniquename better rather than uniquename_bundle.
Should we propose a different naming convention and update the documentation?
2.
To make it as composable and reusable as possible.
Not in any Drupal site I have built in 11 years. Most articles we build do not have comments, and have more specific taxonomy vocabularies like Topics, Category, Subject.
I believe this may have been a norm in Drupal 6 days of the web, and we should still support it in a composed recipe like standard_article (or article_standard).
But to make it usable, and extendable by all, it would be good to have the stack of
article_comment
article_content_type
article_tags
So I could create my own deliverable using the pieces.
Comment #27
narendraRRe #20,
I have found the reason for these 2 test failures.
This is because standard.profile file's
hook_form_FORM_ID_alter
changes recipient's email.These is because tested configuration files exists in standard profile's config folder and only enabling module without standard profile will not help. Recipes do have these files and hence it worked.
Now as we know the reasons for test failures in
StandardRecipeTest.php
, what else can be done here.Comment #28
narendraRComment #29
narendraRAll feedback addressed/answered, tests passing, IS updated.
Comment #30
Wim LeersNice progress here! Some questions on the MR :)
Comment #31
phenaproximaComment #32
Wim LeersLet's please document the rationale behind the current recipes that
…/standard/recipe.yml
depends upon.That information will be crucial in eventually landing this in Drupal core. People will nitpick this apart and question why these particular recipes were created (because there is no objectively optimal or best choice). If that happens in 1 year from today, none of us will remember those choices.
Comment #33
phenaproximaComment #34
phenaproximaComment #35
phenaproximaRe #32, I have updated the issue summary to try and explain the rationale for these recipes as architected.
Comment #36
phenaproximaWhoops, HTML error.
Comment #37
phenaproximaComment #38
phenaproximaComment #39
phenaproximaComment #40
phenaproximaComment #41
phenaproximaI think I'm pretty happy with the way this looks.
All tests are passing, and the issue summary is up to date. I think we're ready for review.
Comment #42
Wim LeersRead the entire issue summary prior to re-reviewing the entire merge request. Thanks for the excellent issue summary! 😊🙏 This is definitely going to help Recipes land in core too, because we'll
probablyhopefully be able to copy/paste this verbatim for the future core inclusion issue 👍Thoughts:
empty
is a fine name, but the inner nerd in me really wants this to be … punnier. Isn there something we can do that is borrowing cooking terminology?comment_base
is less precise than it could be. I thinkcomment_structure
would be better, because creating this stuff by hand would also fall under the subtree of the information architecture. Alternatively, I thinkcomment_storage
also is a better name. Thinking about this more, this is actually specific to Nodes, socomment_for_nodes
orcomment_storage_for_node
probably are better still.StandardTest
allowed me to not check all config in detail, but instead focus on the recipes and their dependencies. This made my life as a reviewer a lot simpler 👍restricted_html_format
: that's the only text format available to the anonymous user. So as soon as a site decides to allow anonymous users to post comments, it becomes relevant. It's kind of like "optional config not if a module is installed but if one small tweak is made to other config". So I think it does make sense in the Standard install profile.Great work here! 👍
Comment #43
narendraRAddressed feedback
Comment #44
Wim LeersAlmost there!
Comment #45
Wim LeersSorry, @narendraR, I got confused! I actually have zero remarks left — this is ready IMHO! 🤩
Congrats on and thank you for this excellent work. It's strong validation of the current state of Recipes! 🎉
Speaking of which: I think the next thing to do is #3400672: Robustly validate the structure of recipe.yml, while your mind still has the encountered problems fresh, and to help avoid the next recipe author from running into the same problems 😊
Comment #46
thejimbirch CreditAttribution: thejimbirch at Kanopi Studios commentedUpdating my attribution.
Comment #47
narendraRFollow-up #3421660: Add a new console command to visualize the tree structure of all recipes and #3421666: Decide on naming convention on recipes created.
Comment #48
DamienMcKennaShould this be blocked until #3400672: Robustly validate the structure of recipe.yml is finished, to avoid committing something that might need to be changed soon afterwards?
Comment #49
phenaproximaNo need, @DamienMcKenna. If it needs to be changed (I suspect it will pass all validation), we can just change it.
Besides, this is ready to go, and #3400672: Robustly validate the structure of recipe.yml has quite a bit of work still needed. If you manually test the recipes in this issue, you'll see that they work as intended. :)
So, I see no compelling reason to block this.
Comment #50
Wim LeersAgreed with @phenaproxima in #49.
But I disagree with this 😅 My site has zero external dependencies (I want to own/control all content), with the exception of embedding remote videos for e.g. a DrupalCon recording on YouTube (those recordings I do not own).
Comment #51
Wim Leers@phenaproxima or @narendraR Can you please update the metadata + summary of this issue per the discussion in Drupal Slack? 🙏
Comment #52
phenaproximaComment #53
Wim LeersThanks!
Comment #54
effulgentsia CreditAttribution: effulgentsia at Acquia commentedI only reviewed this quickly, but at least on first glance, it looks great!
I'm curious why
core_recommended_themes
is a single recipe rather than splitting front-end theme (Olivero) and admin theme (Claro) into separate recipes. For example, might people want to reuse the Claro recipe with a different front-end theme, or reuse the Olivero recipe with Gin or some other admin theme? Is there discussion that led to combining them that I can read up on?Comment #55
thejimbirch CreditAttribution: thejimbirch at Kanopi Studios commentedThe work here always set both themes. Up until the following issue, it was in the primary standard recipe. I believe this is where it was broken out into its own, core_recommended_themes recipe:
https://www.drupal.org/project/distributions_recipes/issues/3301370#comm...
They could be broken into their own recipes, but for simplicity's sake, the core_recommended_themes does what it states.
There are also some sticky things with themes and recipes, like blocks are created from the frontend theme for both the frontend and admin, that we probably don't want to get into in this issue.
Comment #56
Wim Leers@effulgentsia in #54: That's a very good point! Let's do that. 💪 (@thejimbirch in #55: as long as we install the same theme, just split across two recipes instead of one, AFAICT everything should continue to work exactly the same.)
Marked
for implementing @effulgentsia's suggestion.RE: @phenaproxima in https://git.drupalcode.org/project/distributions_recipes/-/merge_request...
Right, not all core config is validatable today. We have issues to make that happen though, and we're making progress:
But even when we get that to 100%, that still doesn't mean all contrib config will overnight be validatable.
The good news is that I see a viable middle ground: … only validating config that is marked as
FullyValidatable
(i.e. has that as a top-level validation constraint).Is that great? No.
Is that realistic? Yes.
We don’t want Recipes to become too limited to be useful by validating everything, including things that have not yet been made validatable. Because yes, e.g.
type: label
,type: config_dependencies
have gotten validation constraints, which means that virtually all config will have some validatability. But that’s not a guarantee that all the concrete config using those types actually has been updated to comply.Hence that
FullyValidatable
middle ground proposal.If you agree, we should postpone this issue on a yet-to-be-created validation-refining Recipes issue. It can copy/paste the logic in
\Drupal\KernelTests\Core\Config\ConfigEntityValidationTestBase::isFullyValidatable()
to achieve what it needs.(That would also solve the
simple_config_update
scenario that @phenaproxima refers to. To make that scenario (as well as any other config action) comply with this as well, we need to makeConfigActionManager::applyAction()
also check whether the modified config isFullyValidatable
.)Comment #57
Wim LeersI bet that we'll run into the very same problem over at #3401925: [PP-2] After a recipe is successfully applied, validate all of the config that was imported or modified by config actions, so proposed at #3401925-8: [PP-2] After a recipe is successfully applied, validate all of the config that was imported or modified by config actions to implement #56 there. If you agree, @phenaproxima, then let's postpone this issue on that one.
Comment #58
phenaproximaYeah, I agree with you, Wim. Postponing.
Comment #59
narendraRComment #60
Wim LeersMy reason for postponing this in #56 which @phenaproxima agreed with in #58. I wrote in #57/at #3401925-8: [PP-2] After a recipe is successfully applied, validate all of the config that was imported or modified by config actions to implement the -check there, but that was then extracted into its own issue: #3425540: Only validate config which is fully validatable.
#3425540: Only validate config which is fully validatable has landed, which means this is unblocked! We should not block this on #3401925: [PP-2] After a recipe is successfully applied, validate all of the config that was imported or modified by config actions, because the scope of that is bigger than the specific thing this was blocked on!
Comment #61
Wim Leers@effulgentsia's remark about
core_recommended_themes
in #54 has been addressed 👍I do think that @alexpott would prefer to not commit this until #1170362: Install profile is disabled for lots of different reasons and core doesn't allow for that lands, but … I think we could just as easily land this now, so we can get started on the Umami install profile net, and then just remove the
empty
install profile that this issue is adding.Almost ready! 😄
Comment #62
narendraRDone #61.2
Comment #63
phenaproximaComment #64
Wim LeersOne question on the MR, plus two requested follow-ups based on the big set of changes you've just pushed, @phenaproxima.
config.import
entries are listed alphabetically and inform the Recipe author that this should be the case? Example: https://git.drupalcode.org/project/distributions_recipes/-/merge_request...Comment #65
phenaproximaI'm not sure we can ever reliably detect this. The simple reason being: what gives us the right to say whether an extension is superfluous? By what metric do we decide that? In this issue, it's a judgment call I made based on my intimate knowledge of what we're trying to accomplish here, and how the Standard profile's pieces fit together.
It's entirely possible you'd want to install a module that only exposes simple config, like automatic_updates, and therefore it would only be in the
install
list, and not mentioned anywhere else in the recipe. But it would not be superfluous. I imagine that many zero-configuration modules would fall into that category.I'd really rather not do this. Having them alphabetically is a purely stylistic thing for readability in my opinion, but it's not remotely important and not something we need to warn a recipe author about. I think such a warning would land on the wrong side of the line separating "useful" from "annoying".
If anything, it should be a coding standard, if we ever develop some coding standards specifically aimed at recipes. And that's just so minor right now that even creating a follow-up seems pointless.
Comment #66
Wim LeersRE #65: okay, so you're saying that most of what you did in the last ~dozen commits was purely subjective preference than an objective improvement. I wish you'd described that in the commit messages and/or left a comment explaining this. I was under the impression that you deemed these changes necessary, which is why I asked for those follow-ups; to ensure that future recipes are held to the same standards (pun not intended). +1 for not creating follow-ups.
Ugh, looks like GitLab failed to post my review 😞 can't access it here because it's in the
localStorage
of my work laptop. I'll post it in the morning… (I can't recall if it should be RTBC-blocking or if it was minor. I bet it was minor … but I also don't want to waste Alex' time, so I'd rather err on the cautious side 😅)Comment #67
phenaproximaOverall, yes, I'd say most of what I did was subjectively preferential tweaking. You could argue that removing superfluous modules was an objective improvement, but they weren't hurting anything by their presence. They were just cruft. It did not occur to me to use my commit messages (which can be awfully short and callous - I'm particularly proud of things like "GET F**KED, PHPSTAN") to explain my rationale, but I should have left a comment here. My bad.
Comment #68
Wim LeersAll good, no worries! 't Was but a mere suggestion to allow me (or whomever is reviewing your indeed often delightful commit messages 😆) to understand your rationale and which level of rigor is appropriate :)
Comment #69
Wim LeersPosted the comment that failed to post: https://git.drupalcode.org/project/distributions_recipes/-/merge_request...
This made me wonder why some of those subjective changes are even accurate. And that is why I requested those follow-ups.
Comment #70
phenaproximaComment #71
Wim LeersAFAICT the oversight would've been caught by #3423526: Validate that every config entity listed in the config.actions section of recipe.yml belongs to an extension that is installed, or will be by the recipe or one of its dependencies, so let's postpone on that? 😊
Comment #72
phenaproximaThe core blocker landed!
Our next step here is to remove the Empty profile, and convert our test coverage to apply the Standard recipe suite on top of Minimal, since I imagine that's how most people will actually use these right now (it wouldn't make much sense to apply the Standard recipes on top of Standard).
We'll also need an issue summary update to remove the mention of the Empty profile.
Comment #73
phenaproximaUpdated the IS to remove mentions of Empty.
Comment #74
phenaproximaComment #75
Wim Leers🤩
P.S.: there's a single line whitespace-only change in
Recipe.php
that could be reverted.EDIT: the issue summary is saying that this is postponed on #3401925: [PP-2] After a recipe is successfully applied, validate all of the config that was imported or modified by config actions but AFAICT that's not actually the case?
Comment #76
phenaproximaI...I don't think it need be blocked on that. Not sure why it was. Fixing.
Comment #77
alexpottSo rather than painstakingly review all the config the standard recipes create and check against the standard profile I thought I'd make the test do that for us. This will ensure if there are change in core's Standard profile we'll find them.
This gives us some things to fix:
We need to fix it so that the only thing changing is core.extension. Or we agree to not do something... ie. the shortcuts. It seems we're not creating the media views. I think we should be doing that. The missing claro.settings is interesting too.
Comment #78
alexpottOkay we're green and found two kinda config bugs in Standard FTW. Let's do this!
Comment #81
alexpottWoot
Comment #84
thejimbirch CreditAttribution: thejimbirch at Kanopi Studios commentedAmazing! Great work everyone!
Comment #85
Wim Leers🥳🥳🥳
Best thing to happen all week!