- Issue created by @wim leers
- Assigned to wim leers
- Open on Drupal.org āEnvironment: PHP 8.2 & MySQL 8
25:05 25:05 Queueing - @wim-leers opened merge request.
- Merge request !4094Issue #3364108: Configuration schema & required keys ā (Open) created by wim leers
- Open on Drupal.org āEnvironment: PHP 8.2 & MySQL 8last update
over 1 year ago Not currently mergeable. - last update
over 1 year ago 1 pass - Status changed to Postponed
over 1 year ago 1:39pm 1 June 2023 - š§šŖBelgium wim leers Ghent š§šŖšŖšŗ
This should land after š Configuration schema & required values: add test coverage for `nullable: true` validation support Fixed , because that requires fewer config schema infrastructure additions and changes.
- š§šŖBelgium wim leers Ghent š§šŖšŖšŗ
š Configuration schema & required values: add test coverage for `nullable: true` validation support Fixed is almost ready, expect progress here next week!
- Status changed to Active
over 1 year ago 1:17pm 7 August 2023 - š§šŖBelgium wim leers Ghent š§šŖšŖšŗ
The blocker was just RTBC'd at #3364109-19: Configuration schema & required values: add test coverage for `nullable: true` validation support ā , time to get this started!
- last update
over 1 year ago 1 pass - last update
over 1 year ago 1 fail - last update
over 1 year ago 2 fail - last update
over 1 year ago 2 fail - last update
over 1 year ago 2 fail - last update
over 1 year ago 2 fail - last update
over 1 year ago 1 pass - Issue was unassigned.
- Status changed to Needs review
over 1 year ago 10:21am 8 August 2023 - š§šŖBelgium wim leers Ghent š§šŖšŖšŗ
Commits explained:
- Added test expectations to the most low-level config system/config schema infrastructure test.
šThis causes tests to fail š Subsequent commits aim to get this to green again. Current failure:1) Drupal\KernelTests\Core\Config\SchemaCheckTraitTest::testTrait true does not match expected type "array".
- Added a new
RequiredKeysConstraint(Validator)
, modeled afterValidKeysConstraint(Validator)
which was added in āØ Add validation constraints to config_entity.dependencies Fixed . - Enabled the use of
RequiredKeys: <infer>
by default for alltype: mapping
, just like we did forValidKeys
in š `type: mapping` should use `ValidKeys: ` constraint by default Fixed .Expected test output at this point:
1) Drupal\KernelTests\Core\Config\SchemaCheckTraitTest::testTrait Exception: Exception when installing config for module config_test, message was: Schema errors for config_test.dynamic.dotted.default with the following errors: 0 [] 'third_party_settings' is a required key., 1 [dependencies] 'config' is a required key., 2 [dependencies] 'content' is a required key., 3 [dependencies] 'module' is a required key., 4 [dependencies] 'theme' is a required key., 5 [dependencies] 'enforced' is a required key.
š No more hard crash, but an actual config validation error š
- It's reasonable to require the top-level
dependencies
, but we shouldn't require every config entity to list very possible dependency type. So let's mark those keys optional.Expected test output at this point:
1) Drupal\KernelTests\Core\Config\SchemaCheckTraitTest::testTrait Exception: Exception when installing config for module config_test, message was: Schema errors for config_test.no_status.default with the following errors: 0 [] '_core' is a required key.
š Previous validation errors gone, new validation error instead š
- The top-level
_core
is necessary for Drupal core only, it's an internal concern. Config is not REQUIRED to contain it for it to be valid. So let's mark this key optional.Expected test output at this point:
1) Drupal\KernelTests\Core\Config\SchemaCheckTraitTest::testTrait Exception: Exception when installing config for module config_test, message was: Schema errors for config_test.system with the following errors: 0 [] 'baz' is a required key.
š Previous validation error gone, new validation error instead. Now we've left the realm of "generic simple config & generic config entity validation config schema errors", and have entered the realm of the config schema specific to the config at hand:
config_test.system
š - There are strong reasons to mark
system.test:baz
as optional. So did that, and documented why.Expected test output at this point:
1) Drupal\KernelTests\Core\Config\SchemaCheckTraitTest::testTrait Exception: Exception when installing config for module config_test, message was: Schema errors for config_test.types with the following errors: 0 [] 'octal' is a required key.
š Previous validation error gone, new validation error instead. We're running into a long-standing bug with PECL YAML, for which š Drop PECL YAML library support in favor of only Symfony YAML Fixed has been open for a few years.
- This issue cannot solve (plus, it'd be out of scope)
š
Drop PECL YAML library support in favor of only Symfony YAML
Fixed
. That's why
core/modules/config/tests/config_test/config/install/config_test.types.yml
has the octal key-value pair commented out, and hence we have no choice but to mark this key as optional.Expected test output at this point:
OK (1 test, 4 assertions)
ā Tests are green again!
This concludes the basic infrastructure required for this issue.
Next steps:
- running all Unit & Kernel tests, which will result in test failures
- get to green
- running all tests again, which likely will also result in test failures
- get to green
For now, I'd like to get a review of this part already š¤ Just a review of the general pattern and approach. Doing all the remaining work will have to wait for š Configuration schema & required values: add test coverage for `nullable: true` validation support Fixed , because doing all the next steps now will likely cause painful conflicts.
- Added test expectations to the most low-level config system/config schema infrastructure test.
- šØšSwitzerland bircher šØšæ
I like the approach.
I didn't know that$definition->toArray();
and then reading the keys is the way to do it. But since this is core this is allowed.To me it makes sense. And I am curious to see how many things fail when this is turned on for everything.
- š§šŖBelgium borisson_ Mechelen, š§šŖ
The documentation in #9 is great, this is super clear. Just like bircher, I'm also very curious to see what breaks when this is turned on for everything.
- last update
over 1 year ago 21,507 pass, 1,608 fail - š§šŖBelgium wim leers Ghent š§šŖšŖšŗ
Now that I've got A) confirmation for the approach, B) 2 curious people besides me ā¦ pushed commit that runs all Unit & Kernel tests! šš¤š¤
- Assigned to wim leers
- Status changed to Needs work
over 1 year ago 2:06pm 8 August 2023 - š§šŖBelgium wim leers Ghent š§šŖšŖšŗ
Okay, I'm intrigued, that's not as bad as I thought it would be! 21.5K passes, 1.6K fails š¤©
Let's transplant the
::$ignoredPropertyPaths
infrastructure from š Configuration schema & required values: add test coverage for `nullable: true` validation support Fixed and see how many things we'd need to ignore or fix! š¤ - last update
over 1 year ago Custom Commands Failed - š§šŖBelgium wim leers Ghent š§šŖšŖšŗ
Infra lifted out of š Configuration schema & required values: add test coverage for `nullable: true` validation support Fixed . Should have the exact same test results.
- last update
over 1 year ago 21,519 pass, 1,606 fail - last update
over 1 year ago 21,519 pass, 1,606 fail - š§šŖBelgium wim leers Ghent š§šŖšŖšŗ
Added things to ignore to
::$ignoredPropertyPaths
to makeCommentFieldAccessTest
and\Drupal\Tests\system\Kernel\Migrate\d7\MigrateActionsTest
pass tests.To be continued. But it's looking promising! š
- last update
over 1 year ago 22,199 pass, 1,166 fail - last update
over 1 year ago 23,243 pass, 848 fail - last update
over 1 year ago 23,408 pass, 776 fail - last update
over 1 year ago 23,538 pass, 698 fail - last update
over 1 year ago 23,985 pass, 470 fail - last update
over 1 year ago 24,009 pass, 455 fail - last update
over 1 year ago 24,054 pass, 427 fail - last update
over 1 year ago 24,181 pass, 375 fail - last update
over 1 year ago 24,245 pass, 327 fail - š§šŖBelgium wim leers Ghent š§šŖšŖšŗ
The number of potential config schema property in Views is mind-boggling! š³
I've already accumulated some 460 lines of ignored property paths!
On the bright side, I think there's a lot of of these ignored property paths for
views.view.*
that would be conditionally required: AFAICT many of these would be inherited from thedefault
display to all other displays. Dealing with that will require issues of its own ā we always knew sanitizing Views' configuration would be a big undertaking.Then again: it's by far the most complex, most pluggable, most configurable thing we have in Drupal core, so it only makes sense! š
- last update
over 1 year ago 24,313 pass, 297 fail - Open on Drupal.org āEnvironment: PHP 8.2 & MySQL 8last update
over 1 year ago Not currently mergeable. - last update
over 1 year ago 24,421 pass, 215 fail - last update
over 1 year ago 24,433 pass, 193 fail - last update
over 1 year ago 24,741 pass, 60 fail - last update
over 1 year ago 24,804 pass, 34 fail - last update
over 1 year ago 24,817 pass, 31 fail - š§šŖBelgium wim leers Ghent š§šŖšŖšŗ
Very big push today. The end is near! šµļøāāļø
- last update
over 1 year ago 24,879 pass, 18 fail - Open on Drupal.org āEnvironment: PHP 8.2 & MySQL 8last update
over 1 year ago Not currently mergeable. - š§šŖBelgium wim leers Ghent š§šŖšŖšŗ
Down to 18 failures!
And šÆ% of those 18 failures look like this:
Drupal\Core\Config\Schema\SchemaIncompleteException: Schema errors for editor.editor.test with the following errors: 0 [image_upload] 'status' is a required key., 1 [image_upload] 'scheme' is a required key., 2 [image_upload] 'directory' is a required key., 3 [image_upload] 'max_size' is a required key., 4 [image_upload] 'max_dimensions' is a required key.
Analysis
editor.editor.*:image_upload
has 5 keys:status
scheme
directory
max_size
max_dimensions
However, when
status === FALSE
, the other 4 keys clearly do not make sense to exist!this indicates the
RequiredKeys
validation constraint needs to support conditionally required keys.I'm sure there's many more examples of this all across Drupal core. But because:
- this is the
Editor
(Text Editor) config entity, which is already the most validatable config entity type ever since āØ Add CKEditor 5 module to Drupal core Fixed - it's also the only one to actually use config validation in Drupal core
- I'm the subsystem maintainer for both Text Editor and CKEditor 5
I'd like to use this one as the single concrete example of how to adopt conditionally required keys. A single concrete example + abstract test coverage is enough to prove it works reliably; we don't want to burden this issue with adopting it all over the place. (
SchemaCheckTrait::$ignoredPropertyPaths
is effectively already our todo-list for things to re-assess, where in some places conditionally required keys will make sense. But each of those need sign-off from the relevant subsystem maintainer(s).)š Just pushed 2 commits that introduce the necessary infrastructure + test coverage.
- last update
over 1 year ago Custom Commands Failed - last update
over 1 year ago 24,884 pass, 18 fail - last update
over 1 year ago 24,884 pass, 17 fail - last update
over 1 year ago Custom Commands Failed - š§šŖBelgium wim leers Ghent š§šŖšŖšŗ
š„³
Now we only need to add
+ 'image_upload' => [ + 'status' => FALSE, + ],
in a bunch of places! š
Just pushed that :)
- last update
over 1 year ago 24,983 pass, 5 fail - last update
over 1 year ago 24,989 pass, 4 fail - š§šŖBelgium wim leers Ghent š§šŖšŖšŗ
Now most of the failures are due to
--- Expected +++ Actual @@ @@ -Array &0 () +Array &0 ( + 0 => ''id' is a required key.' + 1 => ''provider' is a required key.' + 2 => ''status' is a required key.' + 3 => ''weight' is a required key.' + 4 => ''settings' is a required key.' +)
ā¦ turns out this is because of bugs in the config schema: some use
type: filter
instead oftype: mapping
ā which actually results in a recursive schema definition! š³ Config schema does not care nor help detect this š« That's a fight for another day. For now, let's fix this. - last update
over 1 year ago 24,990 pass, 2 fail - Issue was unassigned.
- Status changed to Needs review
over 1 year ago 4:33pm 17 August 2023 - š§šŖBelgium wim leers Ghent š§šŖšŖšŗ
And with one final commit, this should now be green!
I know that as a next step, we need to run all tests. But, before doing that, I'd like to get a review from @bircher especially, but ideally more people, such as @borisson_ and others š
- š§šŖBelgium wim leers Ghent š§šŖšŖšŗ
Aha!
- 'settings.plugins.ckeditor5_language' => 'Configuration for the enabled plugin "Language" (ckeditor5_language) is missing.' + 'settings.plugins.ckeditor5_language' => ''language_list' is a required key.'
Looks like I need to tweak things a little bit further, because CKEditor 5's existing validation constraints already are generating a better (more specific, more context-aware, more humane) error message.
Will do that. But I think the two remaining CKEditor 5-only test failures prove that this overall system works! š
- last update
over 1 year ago 25,059 pass, 2 fail - last update
over 1 year ago 25,079 pass, 1 fail - last update
over 1 year ago 25,079 pass, 1 fail - last update
over 1 year ago 25,129 pass - last update
over 1 year ago 25,129 pass - last update
over 1 year ago 25,134 pass - last update
over 1 year ago 25,134 pass - šØšSwitzerland bircher šØšæ
The conversation from slack to put it more in context:
I meant you can have optional types this way:# Schema for the configuration files of the Editor module. editor.editor.*: type: config_entity label: 'Text editor' mapping: format: type: string label: 'Name' editor: type: string label: 'Text editor' constraints: PluginExists: manager: plugin.manager.editor interface: Drupal\editor\Plugin\EditorPluginInterface settings: type: editor.settings.[%parent.editor] image_upload: type: mapping label: 'Image upload settings' mapping: status: type: boolean label: 'Status' scheme: type: optional_type.string.[%parent.status] label: 'File storage' directory: type: optional_type.string.[%parent.status] label: 'Upload directory' max_size: type: optional_type.string.[%parent.status] label: 'Maximum file size' max_dimensions: type: optional_type.mapping.[%parent.status] label: 'Maximum dimensions' mapping: width: type: integer nullable: true label: 'Maximum width' height: type: integer nullable: true label: 'Maximum height' optional_type.string.0: type: null requiredKey: false optional_type.string.1: type: string optional_type.mapping.0: type: null requiredKey: false optional_type.mapping.1: type: mapping
Of course type Null is not a schema type, but we could make one, ie a value that is always null, ignoring everything else.
also of course the optional_type definition doesn't go in that file.. but this is how we make dynamic schemas and I think then the logic of whether a key is required or not can already be described this way. Similarly to how we also don't have more of a conditional validation on whether the value is required or follow some rules based on other values outside of dedicated validation constraints.
So we could say requiredKey: false and it will mostly work since it will also not have null values when the status is true.In the end what I would be mostly interested in when analysing the schema is to know if the resulting array needs to have the key or not..
- last update
over 1 year ago 25,117 pass, 1 fail 15:16 14:51 Running- š§šŖBelgium wim leers Ghent š§šŖšŖšŗ
One piece of important context is missing ā @bircher's original concern as stated in Slack:
Hmmm I will have to give this a more proper look, but I am not a huge fan of making the constraint have non boolean values. it is either required or can be omitted. One can already have a different schema based on values of other fields.. But I would have to check it with the codebase open to see if that is as easy to do as I make it out to be
AFAICT this means that he's not a fan of
requiredKeyIf
, which accepts nottrue
orfalse
, but{path: 'some_key', value: 'some value'}
. That'd be a big difference compared to all other config schema properties ā , which all are either a string or a boolean (with the exception ofmapping
andsequence
).@bircher, can you confirm that's indeed your main concern? š
Concerns about @bircher's proposal for conditionally required keys in #25
I had written in Slack:
But that would imply that weād have to change the structure of LOTS of existing config! šØšØ That upgrade path would be a complete nightmare.
In #25, @bircher shows what he meant with a concrete example. š Thank you! š That helps a lot!
So turns out that the concrete config wouldn't have to change (good), but the config schema would have to (bad, but less bad). It does make the schema much more verbose though š³
I also worry that the already very abstract config schema will become even more abstract/complex to create. There currently is no way to verify it's a valid/sensible config schema, which is why for example a circular schema does not trigger any complaints and has hence been broken in core for years š
There is one important bug in the concrete example in #25:
ā¦ max_dimensions: type: optional_type.mapping.[%parent.status] label: 'Maximum dimensions' mapping: width: type: integer nullable: true label: 'Maximum width' height: type: integer nullable: true label: 'Maximum height' optional_type.mapping.0: type: null requiredKey: false optional_type.mapping.1: type: mapping
It would not be valid to define the
mapping
property inmax_dimensions
in the case ofoptional_type.mapping.0
. It would actually need to be:ā¦ max_dimensions: type: optional_type.mapping.editor_image_upload_max_dimensions.[%parent.status] label: 'Maximum dimensions' optional_type.mapping.editor_image_upload_max_dimensions.0: type: null requiredKey: false optional_type.mapping.editor_image_upload_max_dimensions.1: type: mapping mapping: width: type: integer nullable: true label: 'Maximum width' height: type: integer nullable: true label: 'Maximum height'
ā¦ which implies this would lead to a significant increase in the number of config schema types that
TypedConfigManager
would need to know about ā from 1 to 5 in this single example:Now, some of those would be reusable (
optional_type.string.*
), but many wouldn't (none of the conditional mappings ones).IMHO this is infeasibly complex. Ironically, it'd be infeasibly complex in an effort to simplify the cumulative config schema infrastructure ā but as I hope the above shows, it'd actually make things far more complex for the actual developer š (Hence why I use the word "infeasibly".)
š The current MR fails to catch the inverse: conditionally required keys that should NOT be present
Your proposal made me realize I had forgotten about the inverse side of required keys: when
image_upload.status
isfalse
, we should indeed not requireimage_upload.scheme
(the MR is already doing that part š) ā¦ but we should actually forbidimage_upload.scheme
(the MR is not yet doing that part š)!š Added test coverage for that.
Fresh look
- Alternatively,
š
TypedConfigManager::_getDefinitionWithReplacements() incorrectly replaces generic definition
Fixed
introduced the
type: some_type||some_subtype
notation ā perhaps using that could make sense.š No, that's only designed for reading the resulting type as computed by
TypedConfigManager::getDefinition()
handling type inheritance. Introducing this would make the config schema infrastructure even more complex. - Looking at the
official documentation for config schema properties ā
, we already have
nullable
andtranslatable
that are supported for every type, and then there are some type-specific properties listed. Fortype: mapping
, onlymapping
is currently a type-specific property. The current MR is essentially makingrequiredKey
andrequiredKeyIf
additional type-specific properties.That naming is perhaps confusingly similar to "required values" (which is what š Configuration schema & required keys Fixed is handling), which is solely about
nullable: true
being set, and hence works for all types.But this issue is about "required keys", which applies only to
type: mapping
. So perhapsomittable
andomittableIf
would be better names?You even mentioned that in Slack:
š That still wouldn't address your concern that we'd be adding a new config schema property ā with a complex structure: it's neither a boolean nor a string.
- Alternative solution: only allow the unconditional
requiredKey: false
, remove support for conditionally required keys, and instead make conditionally required keys a responsibility of validation constraints?CKEditor 5 already has something like this:
\Drupal\ckeditor5\Plugin\Validation\Constraint\EnabledConfigurablePluginsConstraint
, which verifies that a plugin that is enabled and is configurable in fact has CKE5 plugin configuration present in theConfig
ā configuration guaranteed to be present when needed\Drupal\ckeditor5\Plugin\Validation\Constraint\ToolbarItemDependencyConstraint
, which verifies that if configuration is present, that the corresponding toolbar item is also present ā configuration guaranteed to be absent when not needed
Implemented fresh look point 3 in
5a2ad02d1368de65f8d9bd1e010f640da4db8f9b
. I hope that addresses your concern š¤ - Alternatively,
š
TypedConfigManager::_getDefinitionWithReplacements() incorrectly replaces generic definition
Fixed
introduced the
- last update
over 1 year ago 25,140 pass - šŗšøUnited States phenaproxima Massachusetts
Wim Leers ā credited phenaproxima ā .
- š§šŖBelgium wim leers Ghent š§šŖšŖšŗ
IS updated. It now specifically references @bircher's #25 and @phenaproxima's MR comment with similar concerns to explain the current architecture. š
- last update
over 1 year ago Build Successful - š§šŖBelgium wim leers Ghent š§šŖšŖšŗ
212 test failures in the full test run. Many are in update path tests, as well as in CKEditor 5/Text Editor tests (which is to be expected given I used
editor.editor.*:image_upload
as the sole concrete example forConditionallyRequiredKeys
).This seems very doable! šš
- last update
over 1 year ago Build Successful - last update
over 1 year ago Build Successful - šØšSwitzerland bircher šØšæ
Ok so my idea from 25 didn't work straight away because it would require a new type that wants its value to be empty/null.
But we can still do this conditional magic without anything new with the following example:# Schema for the configuration files of the Editor module. editor.editor.*: type: config_entity label: 'Text editor' mapping: format: type: string label: 'Name' editor: type: string label: 'Text editor' constraints: PluginExists: manager: plugin.manager.editor interface: Drupal\editor\Plugin\EditorPluginInterface settings: type: editor.settings.[%parent.editor] image_upload: type: mapping label: 'Image upload settings' mapping: status: type: boolean label: 'Status' scheme: type: optional_type.string.image_upload_status_[%parent.status] label: 'File storage' directory: type: optional_type.string.image_upload_status_[%parent.status] label: 'Upload directory' max_size: type: optional_type.string.image_upload_status_[%parent.status] label: 'Maximum file size' max_dimensions: type: optional_type.mapping.image_upload_status_[%parent.status] label: 'Maximum dimensions' mapping: width: type: integer nullable: true label: 'Maximum width' height: type: integer nullable: true label: 'Maximum height' # This would go to some other file optional_type.string.*: type: string optional_type.mapping.*: type: mapping # Set the 0 at the end to 1 in order to debug it on vanilla core and see that the requiredKey is set. optional_type.string.image_upload_status_0: type: string requiredKey: false optional_type.mapping.image_upload_status_0: type: mapping requiredKey: false
The reason this works is because the mapping information is inherited from the definition it is used on.
So we can add a new validation constraint.. but we don't have to necessarily as far as I can tell. - šØšSwitzerland bircher šØšæ
Oh just a comment on my code comment...
it only works for the happy path :(if the data is not there it won't parse the type.
- last update
over 1 year ago 25,140 pass - last update
over 1 year ago 24,965 pass, 16 fail - last update
over 1 year ago 21,078 pass, 948 fail - š§šŖBelgium wim leers Ghent š§šŖšŖšŗ
After back-and-forth, I'm now starting to see the light in @bircher's proposal š¤š
Also, there's a pre-existing example of this in core, which I noticed while running the tests after I got it working:
core.date_format.*: type: config_entity label: 'Date format' mapping: id: type: string label: 'ID' label: type: required_label label: 'Label' locked: type: boolean label: 'Locked' pattern: type: core_date_format_pattern.[%parent.locked] label: 'PHP date format' # Unlocked date formats should use the translatable type. core_date_format_pattern.0: type: date_format label: 'Date format' # Locked date formats are just used to transport the value. core_date_format_pattern.1: type: string label: 'Date format'
š
#31: Worked around that in
\Drupal\Core\Validation\Plugin\Validation\Constraint\RequiredKeysConstraint::resolveMapping()
š š We can choose to move that into a newMapping::getSchemaElements()
or something like that later if we like. Detailed comments in place.I worked the entire day to figure out how to rely solely on schema to figure out which keys are required vs optional vs extraneous, so that the test coverage in
\Drupal\Tests\editor\Kernel\EditorValidationTest::testImageUploadSettingsAreConditionallyRequired()
would not need to change at all! What a journey that was! š¤ÆBut it WORKS!
It's rather complicated ā¦ but that's only because config schema is complicated, and because the whole point of #30 is to rely solely on the config schema's existing support for dynamic types to determine when which type is actually used: for example
type: core_date_format_pattern.[%parent.locked]
in HEAD resolves to eithercore_date_format_pattern.0
orcore_date_format_pattern.1
already too ā this uses that exact same mechanism.I'll once again need to update the issue summary for this approach.
I HOPE that this is the one that gets @bircher's firm approval šš
- last update
over 1 year ago 23,479 pass, 511 fail - last update
over 1 year ago 24,355 pass, 410 fail - last update
over 1 year ago 24,368 pass, 395 fail - š§šŖBelgium wim leers Ghent š§šŖšŖšŗ
Oh, wow! Some of the test failures are actually proving that this is totally worth it, for example:
Exception: Exception when installing config for module node, message was: Schema errors for core.entity_view_display.node.book.default with the following errors: 0 [content.links] 'settings' is a conditionally required key.
š The logic I added figured out that
settings
is not just required forcontent.links
, it's conditionally required. That's much more helpful of an error message.Just pushed fe3aa1871378de6972d978f1d6b7a1657f78db60, which will make some additional tests pass.
The fact that this just made it work automatically for many existing types is just definitive proof that the approach proposed by @bircher is the right one.
Turns out that
editor.editor.*:image_upload
was just a bad example, because it doesn't follow Config Schema best practices. #30 makes it use best practices ā¦ and then it Just Works šš - last update
over 1 year ago 24,827 pass, 26 fail - last update
over 1 year ago 24,848 pass, 23 fail - last update
over 1 year ago 24,850 pass, 12 fail - last update
over 1 year ago 25,142 pass - š§šŖBelgium wim leers Ghent š§šŖšŖšŗ
Tweaked the ignored property paths to expect the
conditionally required key
message when appropriate (seegit diff cd045a0e6c08a41c42e7d6ad5d0b959d051c6c87 0c745c33ecac926a4bba4f035f7935efd7b771c5
to the full set of changes).Now hitting a new core bug, which š Make 'sequence' Typed Data instances return type of 'sequence' instead of 'list' Fixed recently almost fixed, but apparently not quite:
\Drupal\Core\Config\Schema\SequenceDataDefinition::getDataType()
was wrong before (it hardcodedreturn 'list';
) but is still wrong now (return 'sequence';
), it must instead return the current sequence type or subtype:return $definition['type'];
.
( is already present š).Once I push that, this should be green againā¦
- last update
over 1 year ago 23,888 pass, 606 fail - last update
over 1 year ago 23,910 pass, 605 fail - š§šŖBelgium wim leers Ghent š§šŖšŖšŗ
That was green, yay!
Time to break it again, but for good reasons š¤
Over the weekend, I was thinking about this. I was not quite satisfied with the
'SOMETHING' is a conditionally required key.
message: it lacks precision. WHY is it conditionally required? What does that even mean?!? š¤ šš¤·āāļøThanks to the massive rewrite that I did based on @bircher's proposal (see #32 and related commits), I actually should have everything I need to generate a very precise message. That should allow us to make a big leap forward in having Drupal generate messages that actually help make config schema less mysterious. š„³š
So, here's the logic, plus a first round of updated tests that should make the before vs after crystal clear:
- "'scheme' is an extraneous key.", + "'scheme' is an extraneous key because image_upload.status is set to 0 (see config schema type optional_type.string.image_upload_status_0).",
and
- "'scheme' is a conditionally required key.", + "'scheme' is a conditionally required key because image_upload.status is set to 1 (see config schema type optional_type.string.*).",
Much better, right?! š
- last update
over 1 year ago 24,302 pass, 417 fail - last update
over 1 year ago 24,762 pass, 217 fail - šØšSwitzerland bircher šØšæ
I have a few high level remarks. I thought I had posted a review to this issue already, but I guess it got corss posted with #33 and I didn't notice.
First and foremost I don't like that the boolean
requiredKey
on the schema does now more than indicating whether a key is required or not. I am not against being able to express this information, after all this is what my "dummy null type" suggestion from #25 was supposed to do.
I also don't like that you can only set it to false even though true is redundant.
As it is now actually there are three states:- key required
- key optional (if there is a non-null/empty value the key is there otherwise not)
- key extraneous (ie empty/null value is enforced.)
You have it spelled out in the code already.
Secondly and related to the first is that this information is not accessible from a resolved schema but only if you analyse what other schema types a particular type could have resolved to. This is highly unpractical for modules that try to use the schema to do something to arbitrary config. It would be much better if the logic to decide was either more explicit in the schema or in class other than the validation constraint so that the validation constraint can just check if the condition is met and fail the validation with a pretty message.
For example we could add a method to
\Drupal\Core\Config\Schema\Mapping
to return which keys are in this resolved instance to be used and which to be omitted or set to empty. - last update
over 1 year ago 25,037 pass, 13 fail - š§šŖBelgium wim leers Ghent š§šŖšŖšŗ
Thanks for the review, @bircher! šš Let's get this DONE! š
First and foremost I don't like that the boolean
requiredKey
on the schema does now more than indicating whether a key is required or not.Can you elaborate why you write this now "does more"? Because in my reading, that still is the only thing it does. š¤
I also don't like that you can only set it to false even though true is redundant.
Can you elaborate why you do not like this? I'm open to allowing
requiredKey: true
. But it's confusing and pointlessly verbose to allow this because the very purpose of this issue is to make all keys defined for a mapping in its schema required. If it's the default, then there's no reason to state that explicitly in the schema. That's why I specifically added explicit validation for this (config schema is sorely lacking validation: the learning curve of writing config schema is steep, the DX is essentially "use a debugger"): to not make config schema even harder to write! šAs it is now actually there are three states:
- key required
- key optional (if there is a non-null/empty value the key is there otherwise not)
- key extraneous (ie empty/null value is enforced.)
This is inaccurate. A key being optional or extraneous is unrelated to the value for that key.
Accurate imprecise version:
- key required ā if
requiredKey: false
IS NOT specified for it - key optional ā if
requiredKey: false
IS specified for it - key conditionally required ā if the key is in a mapping inside a dynamic type AND
requiredKey: false
IS NOT specified for that key in its eventual (resolved) type - key extraneous ā if the key is in a mapping inside a dynamic type AND
requiredKey: false
IS specified for that key in its eventual (resolved) type
(Dynamic type: most commonly:
[%parent.type]
)Accurate precise version (yay truth tables):
- Assigned to wim leers
- š§šŖBelgium wim leers Ghent š§šŖšŖšŗ
Secondly and related to the first is that this information is not accessible from a resolved schema but only if you analyse what other schema types a particular type could have resolved to. This is highly unpractical for modules that try to use the schema to do something to arbitrary config. It would be much better if the logic to decide was either more explicit in the schema or in class other than the validation constraint so that the validation constraint can just check if the condition is met and fail the validation with a pretty message.
For example we could add a method to
\Drupal\Core\Config\Schema\Mapping
to return which keys are in this resolved instance to be used and which to be omitted or set to empty.Will make this happen! ššŖ
(This is why we have the issue tag šš )
- šØšSwitzerland bircher šØšæ
I think I don't understand what you mean by "optional".
For all practical purposes a mapping key is either there or not, there are only two states. Now if the key is required then the mapping needs to have it even with an empty value. so far so good.
When the key, however, is not required then it is therefore optional. Now the question is if you should set the key with an empty value or not set it at all. Being optional, I would understand both to be valid.
An example here is a role which depends on a module but then a permission is removed and the role no longer depends on the module. should it still have an empty module key under the dependencies? are both options valid? will they result in a unnecessary diff if the code that made this transition is not the same for the active config and the sync config?For me this means optional, or not required. And by looking at how dependencies or third party settings work, I would say not required means unset it if empty.
Now the extraneous property effectively means that no value is allowed. So this is definitely a quality that I would not associate with being optional.
But more importantly in the current approach the extraneousnes depends on other branches of types. And one can very well make one of the branches be dynamic again and maybe circle to a previous one, or have a type more depending on other modules that may or may not be installed.
My argument is that because this is not immediately visible from the schema it is hard to grasp. Both from config schema consumer perspective and a module author that struggles to make a schema that validates their config.
In other words if you need a table to document how it works it is not simple enough. - š§šŖBelgium wim leers Ghent š§šŖšŖšŗ
I think I don't understand what you mean by "optional".
Uh oh! š«£
Reading #40, it's clear that the one thing you're worried about is the "extraneous" validation error message.
I explained the reason for this in #18 (and the issue summary also specifically links to that comment):
editor.editor.*:image_upload
has 5 keys:status
scheme
directory
max_size
max_dimensions
However, when
status === FALSE
, the other 4 keys clearly do not make sense to exist!If those 4 keys besides
status
do not make sense to exist, then keeping them around would be:- confusing ("what is the of these things if uploads are disabled?!")
- pointless ("they are , why are they here?")
That's why I worked hard to add support for that: so that somebody auditing a site's config or looking at the diffs for a site's config can make sense of it.
š @bircher Do you agree with that rationale? If not: why not?
- last update
over 1 year ago 25,069 pass, 9 fail - šØšSwitzerland bircher šØšæ
Yes I understand that these keys should not be there and are therefore extraneous.
But they are not optional! they are forbidden! they are required to not exist! That is a different thing than being optional.
And I think it would be much more expressive for the schema to say that explicitly.
For example like in my suggestion from #25 with a new type which can not contain any value. But other options are also possible, for example adding yet another flagrequiredEmpty: true
The flaw with putting too much information into the boolean flag is that it limits what the conditional config can express. Bear in mind that the example here uses a conditional schema of [%parent.boolean_state] there are usually more than two options often a string. the way the current MR implements it you can not make the key optional in one branch,
- š§šŖBelgium borisson_ Mechelen, š§šŖ
Bear in mind that the example here uses a conditional schema of [%parent.boolean_state] there are usually more than two options often a string. the way the current MR implements it you can not make the key optional in one branch,
Do you have an example of this kind of optional states?
- šØšSwitzerland bircher šØšæ
RE #43: Just search
[%
in all files ending in.yml
and you will see lots of config schema.
Just a few examples in the general area of editors and filters ie the what you would be familiar with:- The type of filter settings is
filter_settings.[%parent.id]
where the id is a string. - The editor.settings.ckeditor5 plugins are a sequence with type
ckeditor5.plugin.[%key]
- In editor.editor.* the settings is a mapping with type
editor.settings.[%parent.editor]
where editor is a plugin name. (plugin ids is a very commonway to have a dynamic schema) - Or the layout_builder.component which is a mapping with a key of configuration that has the type
block.settings.[id]
(so the type is inferred from the value itself. (there are a handful of examples like that) - And of course third party settings have the type
[%parent.%parent.%type].third_party.[%key]
- The type of filter settings is
25:54 19:28 Running- last update
over 1 year ago 25,144 pass - last update
over 1 year ago 25,144 pass - last update
over 1 year ago 24,364 pass, 404 fail - š§šŖBelgium wim leers Ghent š§šŖšŖšŗ
Finished #39 ā API additions:
Mapping::getResolvedDataDefinitions()
: Resolves (dynamic) subtypes of `type: mapping`, to determine the exact data definitions for each key in the mapping, as prescribed by config schema.Mapping::getValidKeys()
Mapping::getRequiredKeys()
Mapping::getOptionalKeys()
Mapping::getConditionallyOptionalKeys()
The first one is for fairly advanced use cases, the last 4 are what you were really hoping for I think, @bircher? š
- last update
over 1 year ago 24,364 pass, 404 fail - last update
over 1 year ago 24,896 pass, 18 fail - last update
over 1 year ago 25,144 pass - last update
over 1 year ago 23,675 pass, 740 fail - š§šŖBelgium wim leers Ghent š§šŖšŖšŗ
#42:
Yes I understand that these keys should not be there and are therefore extraneous.
But they are not optional! they are forbidden! they are required to not exist! That is a different thing than being optional.Hm ā¦ š¤š¤š¤
I see your point! š
So actually the problem here is that I am conflating "required/optional" (
RequiredKeys
constraint, being added here) š "allowed/forbidden" (ValidKeys
constraint). This is how it should really work:āāāāāāāāāāāā āāāāāāŗā required?ā āāāāāāāāāā ā āāāāāāāāāāāā āāāāāāŗā valid? āāāāāāā¤ ā āāāāāāāāāā ā āāāāāāāāāāāā āāāāāāā¤ āāāāāāŗā optional?ā ā āāāāāāāāāāā āāāāāāāāāāāā āāāāāāŗā invalid?ā āāāāāāāāāāā
š
- Step 1: assess the keys that are present using the
ValidKeys
constraint (a key-value pair in a mapping either has either a valid key or an invalid key: it's valid if it's specified for this mapping type) - Step 2: assess whether keys are missing that should be present using the
RequiredKeys
constraint
ā¦ which means that I'm incorrectly putting this logic for "extraneous keys" in the
RequiredKeys
constraint validator instead of in theValidKeys
validator, where it belongs: a key is extraneous if some types for a given dynamic mapping type allow that key, but not the current type!Now that I've implemented all that, look at we get magnificently beautiful and helpful errors like this:
[display.block_1.display_options] 'block_category' is a conditionally required key because display.block_1.display_plugin is block (see config schema type views.display.block).
or
[display.block_2.display_options.arguments.created] 'date' is a conditionally required key because display.block_2.display_options.arguments.created.plugin_id is date (see config schema type views.argument.date).
š¤©
So now it finally is fully using config schema as intended šš That's what I was hoping for all along: to make virtually no changes to the existing config schema (nor its infrastructure), and just surface actually helpful messages! š
Stay tuned while I get this to green ā¦ hopefully the last iteration! š¤ The revised API additions:
Mapping::getValidKeys()
Mapping::getRequiredKeys()
Mapping::getOptionalKeys()
Mapping::getConditionallyValidKeys()
- Step 1: assess the keys that are present using the
- last update
over 1 year ago Custom Commands Failed - last update
over 1 year ago 23,675 pass, 740 fail - last update
over 1 year ago 23,757 pass, 729 fail - last update
over 1 year ago 23,779 pass, 728 fail - šØšSwitzerland bircher šØšæ
Yes! I think we are converging to a great solution.
I didn't check the latest code, but I hope it doesn't use the
requiredKey
for deciding that in the other branch the key is not optional and therefore in this branch it is forbidden.
But I had an idea last night that would solve your problem of making keys forbidden without anything new. ie this schema works even in Drupal 9 and theValidKeys
constraint would take care of it. Since nothing here is optional.editor.editor.*: type: config_entity label: 'Text editor' mapping: format: type: string label: 'Name' editor: type: string label: 'Text editor' constraints: PluginExists: manager: plugin.manager.editor interface: Drupal\editor\Plugin\EditorPluginInterface settings: type: editor.settings.[%parent.editor] image_upload: type: editor_editor_image_upload.[status] label: 'Image upload settings' # This is the fallback type so that it works even with unpatched config, ie the one where the status is also omitted entirely. editor_editor_image_upload.*: type: mapping mapping: status: type: boolean label: 'Status' requiredKey: false editor_editor_image_upload.1: type: mapping mapping: status: type: boolean label: 'Status' scheme: type: string label: 'File storage' directory: type: string label: 'Upload directory' max_size: type: string label: 'Maximum file size' max_dimensions: type: mapping label: 'Maximum dimensions' mapping: width: type: integer nullable: true label: 'Maximum width' height: type: integer nullable: true label: 'Maximum height'
- šØšSwitzerland bircher šØšæ
hahaha lol..
I was curious and took a peek at the MR anyway and looking at the code now I see that you had the same idea!! excellent!
I will review it more in detail later when I have some time for it. - last update
over 1 year ago 24,189 pass, 432 fail - last update
over 1 year ago 24,319 pass, 390 fail - last update
over 1 year ago 24,790 pass, 164 fail - last update
over 1 year ago 24,817 pass, 154 fail - last update
over 1 year ago 25,042 pass, 89 fail - last update
over 1 year ago 25,099 pass, 13 fail - last update
over 1 year ago 25,193 pass, 6 fail - last update
over 1 year ago 25,204 pass, 5 fail - last update
over 1 year ago 25,203 pass, 8 fail - last update
over 1 year ago 25,203 pass, 7 fail - last update
over 1 year ago 25,188 pass, 11 fail - last update
over 1 year ago 25,191 pass, 8 fail - last update
over 1 year ago 25,194 pass, 4 fail - last update
over 1 year ago 25,195 pass, 3 fail - last update
over 1 year ago 25,207 pass - Issue was unassigned.
- š§šŖBelgium wim leers Ghent š§šŖšŖšŗ
The mysterious failures I couldn't reproduce: due to āØ Provide options to sanitize filenames (transliterate, lowercase, replace whitespace, etc) Fixed having landed in the mean time š Extracted the migration test improvement to #3197324-58: Exception trace cannot be serialized because of closure ā .
Green again!
I need to shift attention to other things and I'll be on vacation starting next Wed until the Fri the week after it. I'm hoping that while I'm out:
- @bircher does a thorough review of everything in
Mapping
š¤š§ - @alexpott is back from vacation and can hopefully do a high-level review of the approach ā by starting in the issue summary and then only looking at the final set of changes, not the >100 commits š¤
(and maybe ā a man can dream ā I'll come back to this issue being unblocked because š Configuration schema & required values: add test coverage for `nullable: true` validation support Fixed landed? š)
- @bircher does a thorough review of everything in
- š§šŖBelgium borisson_ Mechelen, š§šŖ
I reviewed the pull request again, this is looking super solid and is well documented. I think I understand most of what is going on, and based on the conversations here, and in slack, with @bircher it looks like it catches all the special cases we currently have. I am curious to see what happens if we let this loose on contrib, but since the should not be doing any schema checking yet, there are no issues with that either.
I think the state this has ended up in is a lot more solid than what we started with, kudos to @Wim Leers to keep up with all the comments on this issue.
- šØšSwitzerland bircher šØšæ
The MR needs to be "re-rolled". There are two merge conflicts.
both modified: core/modules/ckeditor5/tests/src/Kernel/ValidatorsTest.php both modified: core/tests/Drupal/KernelTests/Core/Config/ConfigEntityValidationTestBase.php
The second one I think is pretty trivial to solve, the first one I am less sure.
I tried to use this new API in config split on the line mentioned in the issue summary here. And I haven't done manual checks but the relevant test passes when core is on this MR branch. See š Use required keys of mappings instead of special casing Needs review
I did have to change some things to make the config validation happy and I haven't finished that yet because I am using config from a core test module and it makes my test fail.. so that is on me and I need to fix that. But I just wanted to note that this is much more strict now. And is probably more disruptive than we would like. but there is another issue to address that if my memory is right.
But over all I am happy with where this is going! the API addition is useful and solves the problem it is set out to solve.
- last update
over 1 year ago Custom Commands Failed - š§šŖBelgium wim leers Ghent š§šŖšŖšŗ
š \Drupal\Tests\ckeditor5\Kernel\ValidatorsTest::test() obscures 2nd, 3rd etc violation message for the same property path Fixed was extracted from this issue and landed. That explains 1 of the 2 conflicts. The other conflict is š Add new `ImmutableProperties` constraint Fixed , which tightened the existing test infra. MR updated! š
I tried to use this new API in config split [ā¦] See #3390285: Use required keys of mappings instead of special casing
Thank you! (Linking the issue.)
And is probably more disruptive than we would like.
Nothing enforces config to be valid in Drupal core today.
Modules can choose when to opt in. Site owners can optionally choose to validate all their config, by using https://www.drupal.org/project/config_inspector ā 's Drush command.
Nobody is being forced into disruption. Everybody is given the choice to not change anything, or to reduce the pain of configuration-triggered bugs (module maintainers) or managing configuration (site maintainers).
Module maintainers know what the expected structure is. So module maintainers can provide automatic update paths, just like core has already done in a whole range of issues ā most recently: š Views should require a label, rather than falling back to an unhelpful ID RTBC . Even if only core writes upgrade paths for all of the invalid config, then this is still worth doing. But hopefully, eventually, by Drupal 11 or maybe only by Drupal 12, we'd be able to do this for all config.
But over all I am happy with where this is going! the API addition is useful and solves the problem it is set out to solve.
š„³š„³š„³š„³ So ā¦ what's next? š¤š Besides cleaning up this MR, what is blocking an RTBC from you?
- last update
over 1 year ago 25,293 pass, 7 fail - Status changed to Needs work
over 1 year ago 8:03pm 13 October 2023 - šŗšøUnited States smustgrave
Have not reviewed but see it has some test failures.
Also do CR updates and the follow up still need to happen?
- Assigned to wim leers
- š§šŖBelgium wim leers Ghent š§šŖšŖšŗ
Indeed, did not yet find the time to solve those. Will get that done in the next 2 days.
- last update
over 1 year ago 25,322 pass, 7 fail - last update
over 1 year ago Custom Commands Failed - last update
over 1 year ago 25,386 pass - Open on Drupal.org āEnvironment: PHP 8.2 & MySQL 8last update
over 1 year ago Not currently mergeable. - Issue was unassigned.
- Status changed to Needs review
over 1 year ago 8:58am 18 October 2023 - š§šŖBelgium wim leers Ghent š§šŖšŖšŗ
All done here now!
Test coverage has been finished, the obsolete
ConditionallyRequiredKeys
stuff is gone.@smustgrave I think this should update the change record at https://www.drupal.org/node/3362879 ā , rather than a separate change record, because now the validation is actually behaving as people expected (similar to what we did at š `type: mapping` should use `ValidKeys: ` constraint by default Fixed , which also did not get its own change record).
However, a separate change record just for marking a key as optional would probably make sense?
- last update
over 1 year ago Custom Commands Failed - last update
over 1 year ago Custom Commands Failed - last update
over 1 year ago 25,385 pass - last update
over 1 year ago 25,385 pass - last update
over 1 year ago Custom Commands Failed - last update
over 1 year ago 25,385 pass - last update
over 1 year ago 25,385 pass - last update
over 1 year ago 25,385 pass - last update
over 1 year ago 25,385 pass - last update
over 1 year ago 25,385 pass - last update
over 1 year ago 25,385 pass - last update
over 1 year ago 25,385 pass - last update
over 1 year ago 25,385 pass - š§šŖBelgium wim leers Ghent š§šŖšŖšŗ
Walked @alexpott through this yesterday, together with @borisson_ and @bircher.
Conclusions:
- "conditionally required key" is not just confusing to interpret, it's actually wrong: it should be "required key"
- "extraneous key" has a similar problem, "unknown key" would be more appropriate
- š Follow-up for #3361534: config validation errors in contrib modules should cause deprecation notices, not test failures Fixed did not go far enough: even deprecation notices/errors would be too disruptive for the contributed module ecosystem. No errors/notices whatsoever should be triggered, unless a module opts in to strict config schema compliance & testing. Opened š Follow-up for #3361534: config validation errors in contrib modules should not cause deprecation notices, unless they opt in Active for this.
- @alexpott is +1 to the overall approach
- š§šŖBelgium wim leers Ghent š§šŖšŖšŗ
@alexpott Wouldn't it be easier to understand the concrete example in this issue (image uploads) if it were done in a separate merge request, so that the consequences of those schema changes can be seen independent of the infrastructure we're adding here?
(It'd mean extra work for me, but I think it might be better for Drupal users looking for an example.)
- last update
over 1 year ago Custom Commands Failed - last update
over 1 year ago 25,385 pass - last update
over 1 year ago Custom Commands Failed - last update
over 1 year ago 25,385 pass - last update
over 1 year ago Custom Commands Failed - last update
over 1 year ago 25,381 pass, 2 fail - last update
over 1 year ago 25,387 pass - last update
over 1 year ago 30,431 pass - last update
over 1 year ago 30,431 pass - last update
over 1 year ago 30,431 pass 9:05 7:09 Running- Status changed to Needs work
over 1 year ago 11:22pm 28 October 2023 The Needs Review Queue Bot ā tested this issue. It no longer applies to Drupal core. Therefore, this issue status is now "Needs work".
This does not mean that the patch needs to be re-rolled or the MR rebased. Read the Issue Summary, the issue tags and the latest discussion here to determine what needs to be done.
Consult the Drupal Contributor Guide ā to find step-by-step guides for working with issues.
- Status changed to Needs review
over 1 year ago 7:58am 29 October 2023 - š§šŖBelgium borisson_ Mechelen, š§šŖ
Merged 11.x back into this branch, also hopefully the MR should be green now.
- š§šŖBelgium borisson_ Mechelen, š§šŖ
I'm not sure if I can rtbc this issue now that I did some work on it, but to me it looks like it is done.
I'll start creating followups when this lands, so leaving that tag in place. - š§šŖBelgium borisson_ Mechelen, š§šŖ
Created (and fixed) an example followup already: š Remove system.mail from SchemaCheckTrait ignored property paths Postponed .
- Assigned to wim leers
- Status changed to Needs work
about 1 year ago 4:01pm 3 November 2023 - š§šŖBelgium wim leers Ghent š§šŖšŖšŗ
Iām working on the missing test coverage.
See https://git.drupalcode.org/issue/drupal-3364108/-/pipelines/43969/test_r....
It is impossible to test the new
RequiredKeys
constraint in isolation.Combine that with the observation that it doesnāt really make sense to separate it from the
ValidKeys
constraint (they are complementary in what they do, butRequiredKeys
must currently be made aware of what options are passed toValidKeys
to ensure all edge cases are handled correctly), and the logical conclusion is: we should have ONLYValidKeys
and just make it more capable.It is already impossible anyway for any other type to reuse this validator, so it simplifies everything: fewer edge cases to test, simpler logic, one less TODO, simpler test coverage.
Will do that and update the issue summary. š
- š§šŖBelgium wim leers Ghent š§šŖšŖšŗ
we should have ONLY
ValidKeys
and just make it more capable.It is already impossible anyway for any other type to reuse this validator, so it simplifies everything: fewer edge cases to test, simpler logic, one less TODO, simpler test coverage.
Done. ā
Next up: explicit test coverage for the new methods on
\Drupal\Core\Config\Schema\Mapping
. - š§šŖBelgium wim leers Ghent š§šŖšŖšŗ
Bug deep in core, discovered here, but with a work-around in place: š Follow-up for #2663410: calling TypedConfigManager::getDefinition() causes cache pollution Active , work-around: https://git.drupalcode.org/project/drupal/-/merge_requests/4094/diffs?co....
- Issue was unassigned.
- Status changed to Needs review
about 1 year ago 4:00pm 8 November 2023 - š§šŖBelgium wim leers Ghent š§šŖšŖšŗ
Whew! š¤
- Self-reviewed the entire MR after having let it rest for ~2 weeks.
- Wrote the missing test coverage
- Cleaned up
DONE š„³
Removing , because at this point it does not matter anymore which lands first: this one or š Configuration schema & required values: add test coverage for `nullable: true` validation support Fixed . In fact, this one is much higher impact and should probably land first at this point!
IMHO the best way to observe this in action is through
\Drupal\Tests\editor\Kernel\EditorValidationTest::testImageUploadSettingsAreConditionallyRequired()
, because it most clearly demonstrates how this issue/MR will both improve the UX (precise error messages) and the DX (no more "garbage" or "noise" in config).Recommended review plan
- Understand the real-world impact
- new
EditorValidationTest::testImageUploadSettingsAreConditionallyRequired()
test editor.schema.yml
changes- consequences of this throughout the codebase (grep for
image_upload
andsetImageUploadSettings
in the diff): many tests were required to be updated, because test fixtures must now be strictly valid (in core ā contrib tests are unaffected thanks to š Follow-up for #3361534: config validation errors in contrib modules should cause deprecation notices, not test failures Fixed and š Follow-up for #3361534: config validation errors in contrib modules should not cause deprecation notices, unless they opt in Active
- new
- Understand how we achieve this without adding any new APIs, and are just inspecting the existing config schema
- read the new
\Drupal\KernelTests\Config\Schema\MappingTest
test, and make sure to understand all the@see
-referenced things - once you agree that these things make sense, move on to the new methods on
\Drupal\Core\Config\Schema\Mapping
ā this makes up the bulk of the complexity. But it's not new complexity: it's "just" automatically making sense of all of the existing config schemas! - Now move on to
ValidKeysConstraintValidator
and observe how it uses these methods. - Note: these new methods are also what
config_split
and other modules can use ā see š Use required keys of mappings instead of special casing Needs review
- read the new
- šŗšøUnited States phenaproxima Massachusetts
As you can tell, I reviewed this.
A lot of it was relatively straightforward and makes sense. The stuff that really ties my brain into knots is the stuff that was added to
Mapping
. That's really complicated. The inline comments are very helpful, but there is a terminology problem that, IMHO, would be improved by having a lot of examples to illustrate what is being transformed into what (if that makes sense). I just found it quite difficult to visualize the stages of resolving these dynamic types, and what their possible keys are, from comments alone.Having said all that...this is extraordinarily complicated stuff and I don't know how much more heroic of an effort could have been made here. But I fear that this will be too intimidating for anyone else to maintain. The priority is getting this functionality into core, though; refactoring, if there's any useful refactoring to be done, can come later.
- Status changed to Needs work
about 1 year ago 7:49am 9 November 2023 - š§šŖBelgium wim leers Ghent š§šŖšŖšŗ
The inline comments are very helpful, but IMHO, they would be improved by having a lot of examples to illustrate what is being transformed into what (if that makes sense), at every stage of the logic.
I just found it quite difficult to visualize the stages of resolving these dynamic types, and what their possible keys are, from comments alone.
+1, will do! I personally really like having those kinds of comments too š
- Assigned to wim leers
- š§šŖBelgium wim leers Ghent š§šŖšŖšŗ
Turns out that because this was rebased on top of the recently landed š Introduce a new #config_target Form API property to make it super simple to use validation constraints on simple config forms, and adopt it in several core config forms Fixed , which made
FileSystemForm
use validation constraints, that we run intopath
being a required key. But that was deprecated into #3039026: Deprecate file_directory_temp() and move to FileSystem service ā , so it makes sense that that key is not set.So why is it still in the config schema? Because it was necessary for tests. Why was it not deprecated? Because #2997100: Introduce a way to deprecate config schemas ā landed a year later.
Conclusion:
- Separate issue needed to fix the config schema for
system.file
- This issue must be updated to automatically treat deprecated keys as optional, and test coverage must be updated
- Separate issue needed to fix the config schema for
- š§šŖBelgium wim leers Ghent š§šŖšŖšŗ
- Added kernel test coverage + fix for treating deprecated property paths as optional keys.
- @borisson_ created š Deprecate path.temporary in system.file configuration schema Fixed for #69.1. I created an MR. Unfortunately, turns out that it is forced to fix a small bug in both the 9.4.0 "bare" and "phpass" update path fixtures š„², so I'm forced to bring that into this MR too.
- First batch of feedback from @borisson_ and @phenaproxima on the MR addressed. Follow-ups created: (out-of-scope) š "type" in Constraint plugin definitions not used nor validated, should be enforced Active .
Down to only 4 failures, Continuing to get this back to green and in a more reviewable state.
This MR is likely too impractical to land in one piece (even if #3400368 were to land today), so I will extract issues from this one, once all feedback has been addressed and the tests are green.
- š§šŖBelgium wim leers Ghent š§šŖšŖšŗ
New issues:
- BLOCKER: š Deprecate path.temporary in system.file configuration schema Fixed
- non-blocker systemic fix for an out-of-scope decade old bug:
š
Provide guidance to config schema developers: detect broken config schema types
Needs work
(to justify fixing the incorrect schema for
filter_settings.filter_html
here) - non-blocking follow-up to remove a
@todo
discovered here: š Fix bugs in update path surfaced by config validation Active - BLOCKER (would land a subset):
š
Introduce Mapping::getValidKeys(), ::getRequiredKeys() etc.
Active
(unblocks both this issue +
config_split
in contrib)
- Status changed to Needs review
about 1 year ago 3:48pm 15 November 2023 - š§šŖBelgium wim leers Ghent š§šŖšŖšŗ
PP-2 for š Deprecate path.temporary in system.file configuration schema Fixed + š Introduce Mapping::getValidKeys(), ::getRequiredKeys() etc. Active .
This can still be reviewed to see how this builds on top of #3401883 though!
- š§šŖBelgium wim leers Ghent š§šŖšŖšŗ
Well well, https://git.drupalcode.org/project/drupal/-/merge_requests/4094/diffs?co... in response to @phenaproxima's review uncovered a bug:
%key
-based dynamism did not yet generate appropriate validation error messages!This also means the test coverage in
\Drupal\KernelTests\Config\Schema\MappingTest
is insufficient. - š§šŖBelgium wim leers Ghent š§šŖšŖšŗ
š Deprecate path.temporary in system.file configuration schema Fixed landed š¢
- Status changed to Needs work
about 1 year ago 8:27pm 15 November 2023 The Needs Review Queue Bot ā tested this issue. It no longer applies to Drupal core. Therefore, this issue status is now "Needs work".
This does not mean that the patch needs to be re-rolled or the MR rebased. Read the Issue Summary, the issue tags and the latest discussion here to determine what needs to be done.
Consult the Drupal Contributor Guide ā to find step-by-step guides for working with issues.
- š§šŖBelgium wim leers Ghent š§šŖšŖšŗ
Making this opt-in using the mechanism proposed at
- #3395099-11: Allow config types to opt in to config validation, use as signal to opt in to "keys/values are required by default" ā
- #3395099-19: Allow config types to opt in to config validation, use as signal to opt in to "keys/values are required by default" ā
Already proven to be successful over at #3364109-49: Configuration schema & required values: add test coverage for `nullable: true` validation support ā šŗ
- š§šŖBelgium wim leers Ghent š§šŖšŖšŗ
Turns out the hardening I just did here turned up over at š Introduce Mapping::getValidKeys(), ::getRequiredKeys() etc. Active too after I addressed @alexpott's feedback, because thanks to that feedback the validation of the schema now happens earlier š
- š§šŖBelgium wim leers Ghent š§šŖšŖšŗ
š Introduce Mapping::getValidKeys(), ::getRequiredKeys() etc. Active landed! I didn't get to finish #77 yet, but that having landed will definitely make this MR infinitely easier to review & read š
- š§šŖBelgium wim leers Ghent š§šŖšŖšŗ
Found a bug in
TypedConfigManager
: š Calling TypedConfigManager::create() does not use the definitions of TypedConfigManager (config schema), but of TypedDataManager (field types) Active . - Issue was unassigned.
- Status changed to Needs review
about 1 year ago 5:00pm 27 November 2023 - š§šŖBelgium wim leers Ghent š§šŖšŖšŗ
Similar to #3364108-49: Configuration schema & required keys ā , I reverted all changes, got tests to pass on HEAD, and then introduced the opt-in infrastructure proposed at #3395099-19: Allow config types to opt in to config validation, use as signal to opt in to "keys/values are required by default" ā .
Similar to #3364108-51: Configuration schema & required keys ā , the MR was nice and simple until a702b532 (no more >1000 lines being added to
$ignoredPropertyPaths
!).Then I opted in the
Editor
config entity type by adding theFullyValidatable
constraint. Which then required schema changes and test adjustments. I'm fine with omitting all of that from this MR, but @alexpott indicated at DrupalCon Lille he'd prefer to demonstrate how this can be used. I think that could happen in a separate issue too, but I'm not opposed to adding it here.Finally, I added test coverage similar to #3364108-51, to prove that config entity types are not affected by this change until they opt in: setting
type: mapping
properties on config entities that have not opted in now are proven to not trigger any validation errors, which also proves the absence of disruption.Change record created: https://www.drupal.org/node/3404425 ā , one change record updated by creating a draft revision ā and updated the issue summary.
- Assigned to wim leers
- Status changed to Needs work
about 1 year ago 9:25pm 30 November 2023 - šŗšøUnited States phenaproxima Massachusetts
Reviewed this and found some relatively minor stuff, but in general it seems pretty good.
It's really complicated, but I also understand that other MRs are merged into this one right now and will be stripped out when they land in other issues.
- š§šŖBelgium wim leers Ghent š§šŖšŖšŗ
@claudiu.cristea independently found the same "invalid filter settings schema" problem and worked on a tightly scoped fix in š Filter settings schema types are incorrect Active . That issue is now RTBC, and much preferable over the far bigger undertaking to prevent this bug pattern from ever getting reintroduced, for which we still have š Provide guidance to config schema developers: detect broken config schema types Needs work .
- Issue was unassigned.
- Status changed to Needs review
about 1 year ago 5:14pm 5 December 2023 - š§šŖBelgium wim leers Ghent š§šŖšŖšŗ
All feedback from @phenaproxima has been addressed.
- Status changed to Postponed
about 1 year ago 1:49pm 6 December 2023 - š§šŖBelgium wim leers Ghent š§šŖšŖšŗ
All feedback from @phenaproxima once again addressed.
Extracted š Refine ValidKeysConstraintValidator's messages: use #3401883's new Mapping infrastructure Needs review from this issue, which does NOT do the more complex/harder to understand "required keys" change, but only the refinement of the existing message of the
ValidKeys
validation constraint.Once that lands, this MR becomes 30% smaller.
- š§šŖBelgium wim leers Ghent š§šŖšŖšŗ
š Configuration schema & required values: add test coverage for `nullable: true` validation support Fixed landed!
That means the changes to be merged. It was the most complex merge conflict of the year for sure š³ I think I got it! š¤
This is still soft-postponed on š Refine ValidKeysConstraintValidator's messages: use #3401883's new Mapping infrastructure Needs review , that would remove
4 files, +361, -60
from this MR. - š§šŖBelgium wim leers Ghent š§šŖšŖšŗ
Merged in upstream. This caused a failure in
\Drupal\Tests\block\Kernel\Migrate\d6\MigrateBlockTest
due to š Remove forum from block migration tests Fixed (landed 2 days ago), whose expected messages become more precise thanks to this issue. š Trivial update! - š§šŖBelgium wim leers Ghent š§šŖšŖšŗ
Merged in upstream because š [PP-1] Make NodeType config entities fully validatable Needs review landed! š
\Drupal\Tests\node\Kernel\NodeTypeValidationTest
passes. Let's find out if everything else does too. š - Status changed to Needs work
about 1 year ago 9:54am 25 December 2023 - š§šŖBelgium borisson_ Mechelen, š§šŖ
Now that š Refine ValidKeysConstraintValidator's messages: use #3401883's new Mapping infrastructure Needs review landed, I'm removing the postponed status from this issue.
- Assigned to wim leers
- š§šŖBelgium wim leers Ghent š§šŖšŖšŗ
Merged in upstream; resolved conflicts with š Refine ValidKeysConstraintValidator's messages: use #3401883's new Mapping infrastructure Needs review . Before:
45 files, +1053, -151
. After:44 files, +761, -91
. š„³Due to š [PP-1] Make NodeType config entities fully validatable Needs review having landed, we have three test failures (also already occurring at #88).
3 test failures:
\Drupal\Tests\forum\Kernel\Migrate\d7\MigrateTaxonomyTermTest
\Drupal\Tests\forum\Kernel\Migrate\d7\MigrateTaxonomyTermTranslationTest
\Drupal\Tests\menu_ui\Functional\MenuUiNodeTest::testMainMenuIsPrioritized()
The first 2 are occurring because they contain a
NodeType
config entity that specifiesthird_party_settings.menu_ui.parent
, butnode.type.*.third_party.menu_ui
inmenu_ui.schema.yml
dictatesthird_party_settings.menu_ui.allowed_menus
also is required.For the third it's the other way around:
allowed_menus
is defined, butparent
is not.We can make tests pass by doing
diff --git a/core/lib/Drupal/Core/Config/Schema/SchemaCheckTrait.php b/core/lib/Drupal/Core/Config/Schema/SchemaCheckTrait.php index 88682009ae2..a130d0b3cb2 100644 --- a/core/lib/Drupal/Core/Config/Schema/SchemaCheckTrait.php +++ b/core/lib/Drupal/Core/Config/Schema/SchemaCheckTrait.php @@ -52,6 +52,13 @@ trait SchemaCheckTrait { 'This value should not be blank.', ], ], + 'node.type.*' => [ + // @todo Fix config or tweak schema of `node.type.*.third_party.menu_ui` + // @see menu_ui.schema.yml + 'third_party_settings.menu_ui' => [ + '.* is a required key.', + ], + ], ]; /**
ā¦ but it would be better to fix š [PP-2] Fully validatable config schema types: support dynamic types Postponed instead.
On top of that: this issue is modifying
editor.editor.*:image_upload
to demonstrate how to evolve config schema to take advantage of dynamically required keys, which means there's now two reasons to fix š [PP-2] Fully validatable config schema types: support dynamic types Postponed .I think it probably would be easier to fix š [PP-2] Fully validatable config schema types: support dynamic types Postponed here.
- Issue was unassigned.
- Status changed to Needs review
about 1 year ago 10:55am 27 December 2023 - š§šŖBelgium wim leers Ghent š§šŖšŖšŗ
Expanded test coverage. It failed š
Then pushed the solution to handle the dynamic type boundaries as suggested by @effulgentsia at #3364109-60: Configuration schema & required values: add test coverage for `nullable: true` validation support ā .
- š§šŖBelgium wim leers Ghent š§šŖšŖšŗ
There were failures in
EditorValidationTest
and\Drupal\Tests\ckeditor5\Kernel\ValidatorsTest
.Marking all of core's text editor plugin configuration as well as the CKEditor 5 plugin configuration as fully validatable made all tests green again ā because the test coverage specific to Text Editor + CKEditor 5 was already expecting validation errors that this issue was introducing.
(Complying with @effulgentsia's observation at #3364109-60: Configuration schema & required values: add test coverage for `nullable: true` validation support ā that this should be opt-in to prevent disruption was proven in practice by that. š)
- Status changed to RTBC
about 1 year ago 11:25am 27 December 2023 - š§šŖBelgium borisson_ Mechelen, š§šŖ
We can probably extract more from this into smaller issues, but I think it is now in a very reviewable state, the Change Request is still up to date with the changes in the MR.
- last update
about 1 year ago Custom Commands Failed - last update
about 1 year ago 25,958 pass, 1,815 fail - last update
about 1 year ago 25,964 pass, 1,832 fail - last update
about 1 year ago 25,962 pass, 1,834 fail - Status changed to Needs work
about 1 year ago 8:21pm 3 January 2024 - šŗšøUnited States effulgentsia
This MR looks really great. My only hesitation with committing it is the various changes in here related to enforcing the lack of any other keys when an editor's
image_upload.status
is FALSE. For example, the need to remove those other keys from Umami'seditor.editor.basic_html.yml
. I think that should all be removed from this MR and moved to a follow-up that gets its own commit and its own change record.I don't think separating that out needs to affect this MR too much though. For example, could we accomplish that by adding a
editor.image_upload_settings.0
config schema object that doesn't addFullyValidatable
? We can still leave FullyValidatable in place oneditor.image_upload_settings.1
.The reason I want to punt on enforcing FullyValidatable on
editor.image_upload_settings.0
is that I think it could be useful in some situations to have default config that adds the upload configuration even with a status=false, so that someone could change the status to true and have the other stuff already properly configured. Maybe I'm wrong and that's not useful, but in either case, I'd like us to discuss that in its own issue without holding up this one.Other than that, I think this is good to go.
- Status changed to RTBC
about 1 year ago 3:03pm 4 January 2024 - š§šŖBelgium wim leers Ghent š§šŖšŖšŗ
This MR looks really great.
š„³
My only hesitation with committing it is the various changes in here related to enforcing the lack of any other keys when an editor's
image_upload.status
is FALSE. For example, the need to remove those other keys from Umami'seditor.editor.basic_html.yml
. I think that should all be removed from this MR and moved to a follow-up that gets its own commit and its own change record.I've suggested that before, so I'm totally fine with that š It's @alexpott who requested during DrupalCon Lille for this to stay part of this MR to showcase it here. But, a lot has changed then, so I doubt he'd be opposed.
I don't think separating that out needs to affect this MR too much though. For example, could we accomplish that by adding a
editor.image_upload_settings.0
config schema object that doesn't addFullyValidatable
? We can still leave FullyValidatable in place oneditor.image_upload_settings.1
.No, that is not enough. Observe it by applying this:
$ git diff diff --git a/core/modules/editor/config/schema/editor.schema.yml b/core/modules/editor/config/schema/editor.schema.yml index eeb9c6a363d..a8daf9f2b7f 100644 --- a/core/modules/editor/config/schema/editor.schema.yml +++ b/core/modules/editor/config/schema/editor.schema.yml @@ -24,8 +24,8 @@ editor.editor.*: editor.image_upload_settings.*: type: mapping label: 'Image upload settings' - constraints: - FullyValidatable: ~ +# constraints: +# FullyValidatable: ~ mapping: status: type: boolean diff --git a/core/profiles/demo_umami/config/install/editor.editor.basic_html.yml b/core/profiles/demo_umami/config/install/editor.editor.basic_html.yml index 60cd331cc87..eba91ebf2f8 100644 --- a/core/profiles/demo_umami/config/install/editor.editor.basic_html.yml +++ b/core/profiles/demo_umami/config/install/editor.editor.basic_html.yml @@ -59,3 +59,9 @@ settings: allow_view_mode_override: true image_upload: status: false + scheme: public + directory: inline-images + max_size: '' + max_dimensions: + width: null + height: null
and then running
DemoUmamiProfileTest::testConfig()
.You'll get:
1) Drupal\Tests\demo_umami\Functional\DemoUmamiProfileTest::testConfig Drupal\Core\Config\Schema\SchemaIncompleteException: Schema errors for editor.editor.basic_html with the following errors: editor.editor.basic_html:image_upload.scheme missing schema, editor.editor.basic_html:image_upload.directory missing schema, editor.editor.basic_html:image_upload.max_size missing schema, editor.editor.basic_html:image_upload.max_dimensions missing schema, editor.editor.basic_html:image_upload.width missing schema, editor.editor.basic_html:image_upload.height missing schema, 0 [image_upload.width] 'width' is not a supported key., 1 [image_upload.height] 'height' is not a supported key., 2 [image_upload] 'scheme' is an unknown key because image_upload.status is 0 (see config schema type editor.image_upload_settings.*)., 3 [image_upload] 'directory' is an unknown key because image_upload.status is 0 (see config schema type editor.image_upload_settings.*)., 4 [image_upload] 'max_size' is an unknown key because image_upload.status is 0 (see config schema type editor.image_upload_settings.*)., 5 [image_upload] 'max_dimensions' is an unknown key because image_upload.status is 0 (see config schema type editor.image_upload_settings.*). /Users/wim.leers/core/core/lib/Drupal/Core/Config/Development/ConfigSchemaChecker.php:98 /Users/wim.leers/core/core/lib/Drupal/Component/EventDispatcher/ContainerAwareEventDispatcher.php:111 /Users/wim.leers/core/core/lib/Drupal/Core/Config/Config.php:230 ā¦
ā¦ because those in the case of
editor.image_upload_settings.0
, none of those keys are defined.[ā¦] I think it could be useful in some situations to have default config that adds the upload configuration even with a status=false, so that someone could change the status to true and have the other stuff already properly configured
š¤ Oh, I thought it was the mere additional complexity in this MR, I didn't realize it'd be this.
This I disagree with. š
I disagree because: where do we draw the line? Are we going to allow arbitrary "default optional values" everywhere in config where something is conditionally configured? For example, would we provide default configuration for some filter plugins in the text format just in case they get enabled at some point?
Note that the values in Demo Umami already have no meaning at all, they are just the materialized-to-config-YAML values that are actually defined in the logic at
editor_image_upload_settings_form()
!And that is actually supporting the point I've been making (see #66 and earlier): this is usually just meaningless noise! Not only was this config not used, it's just values that happened to be the default values at the time the config was created š
I'm fine with splitting off all the
Editor
-related changes to a separate issue. But then I'd prefer to extract the entirety of those changes, not just that one subset, because as I've shown above: it's neither trivially possible nor desirable. If the desirability in this particular case needs further discussion, just say so, and I'd be happy to split it off into a new issue š - last update
about 1 year ago 25,962 pass, 1,841 fail - Assigned to phenaproxima
- Status changed to Needs work
about 1 year ago 4:22pm 4 January 2024 - šŗšøUnited States phenaproxima Massachusetts
@effulgentsia confirmed in Acquia Slack that splitting off the Editor-related changes from this MR is a reasonable compromise. Self-assigning to take care of that.
- šŗšøUnited States phenaproxima Massachusetts
Opened āØ [PP-1] Mark parts of CKEditor 5 and Editor config schema as fully validatable Postponed to land the Editor and CKEditor 5 changes separately.
- Issue was unassigned.
- Status changed to RTBC
about 1 year ago 4:48pm 4 January 2024 - šŗšøUnited States phenaproxima Massachusetts
OK, I reverted basically all changes in the CKEditor5 and Editor modules. I think tests oughta pass.
Restoring RTBC here because this was basically all reverts; I did not make any substantive changes.
-
effulgentsia ā
committed 7b49d870 on 11.x
Issue #3364108 by Wim Leers, borisson_, phenaproxima, bircher:...
-
effulgentsia ā
committed 7b49d870 on 11.x
- Status changed to Fixed
about 1 year ago 6:41pm 4 January 2024 - šŗšøUnited States effulgentsia
Pushed to 11.x, and published the CR. The CR doesn't currently mention that requiredKey can be set to false, so that might be a good thing to add to it.
Also tagging this (not just this issue, but all the stricter validation features) for 10.3.0 release highlights.
- šŗšøUnited States phenaproxima Massachusetts
Thanks, @effulgentsia! Good catch on the missing info from the CR; I've added that.
- š§šŖBelgium wim leers Ghent š§šŖšŖšŗ
Wonderful! š„³
This allowed me to close the meta/plan issue at #3395099-33: [meta] Allow config types to opt in to config validation, use "FullyValidatable" constraint at root as signal to opt in to "keys/values are required by default" ā , because only one issue remains in that plan: #3408158-6: Run config validation for config schema types opted in to be fully validatable ā , which is now unblocked š
This also means that we can truly start working on āØ [PP-2] POST/PATCH config entities via REST for config entity types that support validation Needs work , after 9.5 years of being blocked š š¤Æ
Automatically closed - issue fixed for 2 weeks with no activity.
- šØšSwitzerland berdir Switzerland
This causes a PHP warning when a sequence schema uses the old, deprecated but still supported format: š Undefined array key "type" in TypedConfigManager::getStaticTypeRoot Active