Problem/Motivation
update_fix_compatibility()
is just remove modules and themes that don't exist.
Steps to replicate
- delete a module from the modules folder
- run updates
- restore the module and try to enable it
You can't enable nor uninstall. But it does point to the process of disabling the module leaving things in a corrupt state.
Proposed resolution
Add an requirement error when the module list or theme list is wrong. We can't fix things really because at least in the case of modules we have no idea what to do. With themes potentially we could force an uninstall with no code present but then again we're making changes without really knowing what the user wants.
Looks something like:
Steps to test:
- Install standard
- Enable stark theme
- Remove dblog, page_cache and stark
- Set update free access in settings.php
- Visit update.php
Remaining tasks
User interface changes
Screenshots
API changes
update_fix_compatibility will no longer attempt to fix incompatibility, and is deprecated. This is necessary because it's the 'fixing' that puts sites into an unrecoverable state.
Data model changes
Release notes snippet
update_fix_compatibility()
has been deprecated. Sites with incompatible or missing modules or themes will need to correct the issue in the codebase prior to running database updates. See update.php will no longer attempt to automatically remove modules for more information.
Comment | File | Size | Author |
---|---|---|---|
#149 | 2917600-149.patch | 30.09 KB | tedbow |
#149 | interdiff-147-149.txt | 1.06 KB | tedbow |
#147 | 2917600-147-8.7.patch | 30.2 KB | tedbow |
#142 | 2917600-142-8.8.patch | 34.9 KB | tedbow |
#127 | 2917600-127-9.0.x.patch | 29.92 KB | tedbow |
Comments
Comment #2
cilefen CreditAttribution: cilefen as a volunteer commentedComment #5
alexpottComment #6
alexpottSo the problem code is
update_fix_compatibility()
- that code is very Drupal 7 and it's update to Drupal 8 didn't really account for the fact we don't have the disabled state.Comment #7
alexpottMy gut feeling says we should not call
update_fix_compatibility()
anymore and deprecate the method. And then inform the user the the update can't be performed until the codebase is inline with configuration. But then how to you fix your site when you moved code or renamed stuff?Comment #8
alexpottSo I tried to do the lighter touch of issuing a warning and continuing on to call
update_fix_compatibility()
but even then things go very very wrong. For example db_log is still in the key value storage for last installed versions other errors.Here's the work I did but I think we should still report an error and indicate update is impossible because we just don't know what is what.
Comment #9
alexpottHere's what I think we should do. We have to tell the user to fix this. We can't really guess what's the correct course.
Comment #11
alexpottComment #12
alexpottOkay here's a more complete patch that deprecates the odd API and adds a properly error to system_requirements().
Added screenshot to issue summary.
Comment #14
alexpottWhoops fixed up some of the logic.
Comment #15
moshe weitzman CreditAttribution: moshe weitzman commentedFYI, Drush stopped calling update_fix_compatibility() a long time ago https://github.com/drush-ops/drush/blob/0616d6a730be9be16988b4d4845a5b48...
Comment #16
alexpottWow this came back to bite me :( see #3031740: Updating to 8.6.8 or 8.6.9 with Drush 8 causes data loss via update_fix_compatibility() - I wish we'd managed to fix this earlier.
Comment #18
tedbowHere is a reroll.
Found this issue because I am working on #2313917: Core version key in module's .info.yml doesn't respect core semantic versioning
If we add support for new values in the core key
update_fix_compatibility()
will affect these modules if they are used on earlier version of Drupal.Comment #20
Wim LeersLike @tedbow said, we ran into this over at #2313917-138: Core version key in module's .info.yml doesn't respect core semantic versioning 😨
Comment #22
tedbowFound this issue again because of #3108159: Database updates should not be allowed if any installed modules are not compatible with Drupal core
Basically if you update core and not all module version are compatible with your new version of core they will have this problem. I guess when using composer this is not likely to happen(impossible?) but for those using the tarball it could.
It could happen on any core update not that we use
core_version_requirement
but I have feeling it is much more likely to happen when someone updates to Drupal 9 via the tarball and doesn't make sure all their modules are update first.In #3108159 we hope to address that but we really can't if this problem happens first.
I have feeling that if we do the patch in #14 then we don't need to #3108159: Database updates should not be allowed if any installed modules are not compatible with Drupal core because it will stop the updates.
if
!isset($extension)
the extension is missing, correct?It seems this should be a separate check.
I think we should have different messages based on whether a module is missing or just incompatible.
Comment #23
tedbowHere is another reroll of #14
Comment #25
alexpott@tedbow thanks for pushing on this again. Wish this was fixed ages ago. Here's an update to fix the test fails. Let's not deprecate
update_check_incompatibility()
as it is not necessary. So we do the minimum deprecation here. We can deprecate it Drupal 9. So we should file a follow-up for that.We still need tests of the update system not running updates for incompatible modules.
The patch attached fixes the tests. I've reworked StableBaseThemeUpdateTest to not mock the ThemeHandler and be a bit more real.
We need to do this in 8.8.x so I've changed the deprecation. Also I think given the impacts on D8 to D9 this is a critical issue.
Comment #26
catchDoes this use cached data? If someone replaces a module in the filesystem, what needs to happen for this message to change?
No-one should ever be using this so it's probably OK. However given it can actually break your site should it issue a warning instead of a suppressed deprecation error? Should it be made a no-op?
If my point above is right, we should add this comment back in when we switch to uncached data.
Same issue with cached data, although also doing this on hook_requirements('runtime') seems excessive.
Comment #27
alexpott@catch my first though was good point - cached data is going to be a problem but then I remembered #3055443: Switch to a null backend for all caches for running the database updates which means we're not using cached data at all during updates. And therefore I think the code in #25 is correct with respect to caching. During the updates we're not using caches but during a regular runtime check we are. You can test this by:
+1 on error and no-op for update_fix_compatibility() this method has never been compatible with Drupal 8.
Comment #28
BerdirAlso +1, it will result in some tricky situations though, there have been a few cases where contrib modules removed dependencies (webform with contribute was a famous one) or even their own submodules (search api with a taxonomy something submodule), which might be tricky for users to understand.
Comment #29
alexpott@Berdir good point about contrib just removing a sub module. I have two thoughts about this:
Re removing the functionality in
update_fix_compatibility()
and making it hard error - we have:I'd be loathe to remove that at this point. Yes Drupal 8.6 is no longer supported but I don;t think we should break the ability of Drush 8 to update from it. We could remove the code that messes with
'core.extension'
config if we want though.Comment #30
catchSo I think the hook_requirements('runtime') might be fine with cached data too in that case, but we should add some comments to indicate where it's going to run without vs. caching.
Also general note that this issue would have prevented what looks like a lot broken sites and confusion in #3099084: Base table or view not found: 1146 Table 'drupal.path_alias' doesn't exist. Update to 8.8.0 fails..
Contrib removing sub modules should leave in a stub with just a .info.yml, add an update hook to uninstall the module, then when they want to remove the .info.yml too that would need to be in a release with a hook_update_last_removed() later than the hook that uninstalls.
Comment #31
tedbowIt seems weird to me to be calling
checkIncompatibility()
here. Though I do think we should be checking for what it check for. But by calling it instead of checking the individual test we are hiding from the user what the actual problem.It checks for 3 things 1) missing file 2) 'core_incompatible' and 3) wrong php requirement.
The PHP requirement is actually check earlier in this function around line 870. It only runs during the
update
phase but we could change that check to run inruntime
also. I am not sure why we wouldn't want all the checks in that loop inruntime
phase.For
core_incompatible
it seems like it would be good to put that into the existing loop above starting at 863 that checks php andrequirements
. We could skip requirements for themes for now but will then want to also check them in #474684: Allow themes to declare dependencies on modules. That way we can a message that explicitly says the module is incompatible with core.That would leave only the case where the module is actually missing from file system It seems we could have 1 loop for both modules and themes that checks that and displays a message.
Comment #32
catchTrying a more alarming issue title.
Comment #33
tedbowHere is the suggested I had in #31.
You can see there it produces 3 unique messages for the problem
\Drupal\Core\Extension\ExtensionList::checkIncompatibility()
would have detect but not differentiated between.Comment #34
tedbowI had to put in this extra check. We must not have test for a module requiring a specific version when there is no other php requirements message set above.
Comment #35
andypostQuick review
Better move
\Drupal::service()
out of loopthe message needs to be adjusted according standards and follow-up to remove in 9.0 (tag already on issue)
Comment #36
catchComment #37
DamienMcKennaComment #38
DamienMcKennaPer #35.
Comment #39
anthonyf CreditAttribution: anthonyf commentedComment #40
anthonyf CreditAttribution: anthonyf at Mediacurrent commentedI'll work on the 2 revisions recommended by andypost:
Comment #41
anthonyf CreditAttribution: anthonyf at Mediacurrent commentedMoved
\Drupal::service()
call out of loop in core/includes/install.incFixed coding standards issues in deprecation comments in core/includes/update.inc
Comment #42
anthonyf CreditAttribution: anthonyf at Mediacurrent commentedComment #43
anthonyf CreditAttribution: anthonyf at Mediacurrent commentedComment #44
catchComment nits and a question:
Now that themes are only installed/uninstalled, can $file->status ever be false here?
Pre-existing issue of course.
Should this be 'extension' now?
This could use an additional note as to why we need to avoid autoescape.
Looks like we also need additional test coverage for missing modules here?
Comment #45
DamienMcKennaComment #46
tedbowre #44
\Drupal\Core\Extension\ExtensionList::getList()
get all extensions(modules or themes) not just ones that are installed.Both
\Drupal\Core\Extension\ModuleExtensionList::doList()
and\Drupal\Core\Extension\ThemeExtensionList::doList()
set the status based on whether the extension is installed or not.I stepped debugged this to make sure at this point in
system_requirements()
we actually have
$file->status === 0
. It does and does skip uninstalled modules.Changing the comment in the code above to say "uninstalled extensions" instead of "disabled modules"
So for now this correct that this will only be modules. Because this is checking for the require module not the module requiring.
But in #474684: Allow themes to declare dependencies on modules we will need to handle both. I have added a todo to remove this if block in 474684. Right now that issue is also adding themes to this loop. which issue gets committed first will have to be rerolled.
I am not sure if themes can declare a php version in their info.yml files. If so we should change the
continue
till after that check. though it is an existing issue so it could be in a follow-up. It would need more tests.Comment #47
tedbowShould we actually be catching the exception here?
If the exception is thrown then
!isset($extension)
will be true so this function would returnFALSE
which means it is not incompatible. We can't really know that if we didn't find a module.I know this is @internal class but this exposed via service so I think we shouldn't hide this problem from callers.
I will fix this.
Even if we didn't fix I think this should be change because
\Drupal\Core\Extension\ExtensionList::get()
will always through the exception if the extension is not found. So it seems better and clear to return in the catch.Comment #48
andypostBetter to move the `\Drupal::service()` call out of loop
Comment #49
tedbowI am assigning to myself as I am working on the functional tests. I haven't looked at #48 yet but will also address that.
Comment #51
tedbowupdate_fix_compatibility()
but still think we shouldn't be introducing the new public method\Drupal\Core\Extension\ExtensionList::checkIncompatibility()
that hides the fact that the extension is missingComment #52
catchRe-reviewed. Apart from the inline template question I think it's just test coverage now.
We should have a test where we have a missing module in core.extension, then visit update.php, and ensure this message is shown and it's not possible to proceed.
Drupal\Tests\System\Functional\UpdateSystem\UpdatePathLastRemovedTest
is very similar.Comment #53
alexpottHere's why we need the inline template. We're joining two strings. In order to join strings and we need to ensure that the safeness (or not) of each part is respected. Translators can add specific HTML tags for other languages to translations and the item list theme has html. If we were to add both strings together we'd have to then create a markup object out of the result but this would not have used Drupal's auto-escape mechanisms and therefore there is the potential for unsafe html.
Any time we have to join two strings together these type of considerations are needed. There are a couple of ways to do it.
new FormattableMarkup('@value1 @value2', ['value1' => $foo, 'value2' => $bar]);
is the cheapest but I've used an inline template here because additionally we want to apply the item list theme to $extensions.Comment #54
catchAhh OK, so we should add a comment summarising #53 but that's a good reason.
Comment #55
catchNeeds work for:
1. Adding a comment explaining why we use the inline template
2. Adding an UpdateSystem test that checks the system_requirements() error kicks in when a module is missing.
Comment #56
tedbowWith my change from #47 we need to check
\Drupal\Core\Extension\ExtensionList::exists()
before checkingcheckIncompatibility()
.This passed before because we didn't have proper test coverage.
I still think this is correct change.
Fixed
Also added test coverage for a module changing to be incompatible.
This could happen if the
core:
orcore_version_requirement
values change in the info.yml file.I didn't add test coverage for themes. I could add it or we could do it in a follow up.
Comment #58
xjmThe CR and IS could both use work to document and justify the BC break. Additionally, while it's less likely that anyone is relying on this if it's as fundamentally broken as described, we should still probably mention it in the 8.8 and 9.0 release notes.
Comment #59
tedbowWhen I was thinking about how to test compatibility changes that would make an extension not compatibility and lead to the original bug I considered using the same method as
testRequirements()
which is to usehook_system_info_alter()
to alter information that comes from the info.yml files.But thought it was more through and realistic test to actually having an info file with changes values because
core_compatiblity
is set in\Drupal\Core\Extension\InfoParserDynamic::parse()
before this hook runs.Comment #61
catchAdded a release notes snippet, and a sentence or two to the API changes section in the issue summary, and also updated the change record. I think that is enough to justify removing the tags although happy to add more detail if somethings is missing - but could not think of much more.
Test coverage looks good to me now.
Comment #62
tedbowMore test coverage:
So adding this to each test theme.
The php requirement is a little different in HEAD.
Here is the problem
php: 10000000
to the info.ymlThis is because in step 3) when you goto update.php even though you see the warning
update_fix_compatibility()
has still been called and becauseupdate_check_incompatibility()
also checks thephp
requirement the extension setting is cleared. So the 2nd time you hit the page requirement is not check because the module is not in the list.I am providing a test only patch to demonstrate the current problem in 8.9.x. I had to change 1 thing in /system.install to actually have the test not error on string concatenation problem though.
This does not happens for themes because we currently don't check for the php version of themes in hook requirements. But the theme still does get extension cleared even though you don't see the message on the screen about the requirement.
This is an existing issue that we don't check for theme php version in
system_requirements()
.So regarding my question in #46.2 I do think we need to fix this for themes the because the current situation won't happen with our new fix. So we always had the problem with themes not enforcing the php version in update.php.
But I think this has been masked by the problem of it silently clearing the extension config. Weird that this hasn't been commented on so I could use a sanity check on this.
I am not fixing the theme problem in this patch. Will do that next.
Comment #65
tedbowcopy/paste error.
This should have been
$extension_info
in the last line.testPhpVersionRequirementChange()
is looking a lot liketestExtensionCompatibilityChange()
. I am going to see if makes sense to combine them and just have different cases in the providerComment #66
tedbowThe fact that we have 3 versions of the info file here, where the fix is different from the initial info, I don't think is actually test anything. I think this can be refactored to just have a correct and breaking info files. So the test will just switch back to the correct to confirm it can be fixed.
Also the $extension_type is not really needed we can just add that value to the info.
whoops! the
. . \Drupal::VERSION
should be inside the parentheses. Gotta love PHP that you can just concat a string to void return from the array 😜testPhpVersionRequirementChange()
and just make it another test case inproviderExtensionCompatibilityChange()
I also added reloading the update page to
testExtensionCompatibilityChange()
to handle the weird php requirements problem where the error disappears when you reload as detailed in #62.3.I am feeling pretty good about the test coverage now.
Left @todo
Comment #67
xjmI did a bit more work on the CR; please review: https://www.drupal.org/node/3026100/revisions/view/11773649/11773914
Also reworded the release note a little and linked the CR from it.
It looks like a module being "incompatible" is limited to the validation of the core branch/core compatibility constraint (plus a per-module PHP version requirement that I didn't even realize existed). Are those indeed the only "incompatibilities", or does other
hook_requirements()
checking come into play at all?Comment #68
xjmLost my release note fixes to a crosspost.
Comment #69
xjmCouple thoughts on the messaging:
Comment #70
alexpottI've improved the inline template comment to explain what is going on. I've not addressed any of the comments since #66.
I've rerolled the patch to apply to D9 too. Unfortunately we need to maintain multiple versions. The D9 patch is smaller because it does not have to change
StableBaseThemeUpdateTest
as that does not exist in D9.Comment #72
xjmProposed fixes for the messages:
Comment #73
tedbowg
I copied a bunch of lines for the tests from other methods in this class.
I just noticed that a lot of these are deprecated in 8.2 and will be removed in 10.0.0. Might as well use the non-deprecated versions since these are totally new test methods.
Only addressing this to keep the interdiff small and clear.
Comment #74
xjm@tedbow is going to work on the messaging improvements etc. here as well.
Comment #75
xjm@tedbow and I also discussed that it's not necessarily safe to tell them what to do in a single sentence, because there are multiple possible sources for the problem (for example, they installed the wrong
core.extension
config). What we're going to do instead is create a handbook page that has some suggestions for how to address each scenario.Comment #76
xjmNew message templates
Comment #77
catchA handbook page is a good idea. I fairly often get missing modules from the filesystem if I switch between development branches with different modules installed, and forget to composer install. In that case the fix is just to run composer install but it's very different if you've actually removed a module from your code base and it's still installed in config.
Comment #78
xjmI drafted: https://www.drupal.org/docs/8/update/troubleshooting-database-updates
Needs review/improvement. So far it only covers the most obvious causes of the specific errors possible due to this issue, but it can be expanded with additional recommendations.
Comment #79
xjmAh, we should also add the
composer install
example to the page.Comment #80
tedbowWith the changes suggested in #76 we are going to have this logic 6x.
So I made an anonymous function
$create_extension_incompatibility_list()
This avoids a lot of duplication. I didn't make a new global function for this because I don't think we should have to worry about changing and BC. This doesn't create any new API surface. I would rather have a class and private method but I think this is as good as we are going to get now.
I changed this to be a for loop so that it is clear on the reload we do the exact same tests.
Comment #81
tedbowI think mentioning "core.extension configuration," makes sense for the missing extension case but for incompatible modules/themes I don't think it makes sense to mention. Yes that is ultimately what determines if an extension is consider installed but you don't need to know that for these cases.
I don’t think I knew “core.extension configuration,” was involved until recently but still could solved the problem without ever knowing that.
In the “missing” case I think it is more important but for the other cases it might send people searching for something they don’t need to figure out.
I chatted with @xjm about and we agreed on the message format:
"The following modules are installed but they are incompatible with Drupal 8.9.0:"
PHP compatibility will follow the same
I think we can just change this to
return !$extension_list->exists($extension_name);
and not have to worry about catching the exception.
The tests pass so if I am missing something we don't have test coverage for the difference.
Fixing
Comment #82
xmacinfoInstead of running
composer install
I usually runcomposer update --lock
.Officially the
composer update --lock
command “updates composer.lock hash without updating any packages”. But it will also add/remove any file(module/vendor/theme/libraries/...) missing from the file system, and apply patches (for example after adding a new patch in composer.json.Comment #83
tedbowI left out the "PHP" string here.
Comment #84
tedbowforgot to upload patch for #83.1
This is ready as far as I know
Comment #85
xjmI don't think "Core incompatible themes" or "PHP incompatible themes" (etc.) work as headers. That would mean themes that aren't compatible with core (at all), or that aren't compatible with PHP (at all). I think we can just use "Incompatible themes" for the heading in either case, and the user can read the rest of the message debug it.
Other than that, the updated screenshots look good to me.
Comment #86
catchAgreed with #85, PHP incompatible makes me think it's a Node module or something, but otherwise looks good.
Reviewed the last three interdiffs, and apart from one indentation issue they look good. Haven't line-by-line reviewed the most recent full patch though.
Comment #87
catchPatch for #85.
Note this does not apply cleanly to 9.0.x - conflicts in at least system.install, so needs an additional 9.0.x patch before we can actually commit it.
Comment #88
xjmWe're onto 8.8.4-dev now so this will need to be updated before commit.
What's happening to this rebuild? I don't see it being moved elsewhere in the API.
Accidental indentation change on the second line here that needs to be reverted.
Ew, is there really a single quote in the requirements array key? We should document why because it's WTFy and could be easy to screw up. Or is this a typo that an IDE helpfully tried to make not-syntax-error-y?
This still needs to be fixed.
If we're also logging at runtime, we should review/test the status report for these messages, since they will end up in both places.
The cleanup for this class looks like a good simplification on scanning, but isn't it out of scope?
Interesting; I thought we'd hardcoded it to only allow
8.7.7
or higher? Or did we not finish that followup?...Or is the fact that it's invalid the point? Are we expecting a fail based on the fact that it's indicating D7, or based on the constraint allowed value restrictions?
Nit: Agreement problem. Should be "prevents".
This key's going to be deprecated eventually, but I guess the test will start failing when that happens, so we don't need an explicit followup to update the test. DrupalCI will tell us when it needs to be fixed.
I know other people allow this in sometimes, but the coding standards policy has not been updated to allow the use of private methods.
Making a method of a public API private doesn't really gain you much in terms of protecting BC; if the parent has public or protected methods that call the private method, children will still need to reimplement it anyway so you're still affecting their code by adding, removing, or changing it, and just forcing them to potentially override the caller as well.
We should really actually have the policy discussion about this and document best practices rather than just adding it under the (often flawed) assumption that it's a free pass for BC.
Things should still be protected until a new policy is adopted, except in rare cases where there's actually specific benefit to using
private
(e.g. a private constructor).php
setting at all, while the handbook page mentions all kinds of settings that aren't listed. Probably needs a docs followup.)array
usually isn't right, but given the structure of theinfo.yml
, this could contain anything frombool
child keys to nested arrays (dependencies etc.). It's also getting encoded anyway. Maybemixed[]
for clarity's sake.$additional_settings
is the correct parameter name. With a grep, that specifically means the additional settings of field formatters and is not used in any other way really.Comment #89
catchupdate.php runs entirely without caches enabled due to
UpdateServiceProvider
, so the cache rebuild here is redundant.Comment #90
xjmIsn't #89 out of scope though?
We'll need new screenshots once #88.5 is fixed. (They're for the handbook page as well as the IS, so making them at high res would be good. If you're using Skitch, this is an option in the lower left under the file type menu.)
Comment #91
catch@xjm well we're gutting the function because it's broken, so it's in scope for gutting it. It would be possible to leave the rebuilds in though.
The only places that call this in contrib are recreating update.php from scratch (drush etc. and an unsupported version of drush dealing with updating 6.x and 7.x sites, not 8.x updates even from a quick look), so there should be no impact at all from the change. http://grep.xnddx.ru/search?text=update_fix_compatibility&filename=
Comment #92
xjm@catch I'm about equally concerned about unintended side effects and the review burden/bad example of scope creep. 🤷♀️
Comment #93
catchHmm well minimum scope would be to just stop calling it in core and move the deprecation to a follow-up, leaving it as dead code for now.
Comment #94
xjmThe thing is that the hunk I highlighted in #88.7 isn't dead code from a deprecation; it's part of a test class. Edit: Meant to also say, it's also not clear to me how removing the rebuild is related to a deprecation or not.
Comment #95
catchI've been talking about 88.2 not 88.7, i.e. update_fix_compatibility() itself. I think it's fine to do the gutting in a follow-up since it doesn't impact fixing the actual critical bug here, but it's also not out of scope to make it harmless in this issue.
It should hopefully be moot because no-one calls it, but it'd be a shame to find out that someone still was and it was breaking their site in the future, so I do think we should do what the patch does here, whether it's in this issue or another one.
Comment #96
xjm@tedbow is wokring on an updated patch.
Comment #97
catchThinking ahead to an 8.8.x backport (and only for that). We want sites to hit this error message if they update from 8.9 to 9.0, or 8.8 to 8.9, or <= 8.7 to 8.8. However, we don't necessarily want them to hit the error message if they update from 8.8.3 to 8.8.4 - it's unlikely they'll be running an update affected by this issue, and it will stop them upgrading altogether including to future security releases.
One way to workaround this would be in the 8.8.x patch only check the schema version in $phase == 'update', and only show the error message if system schema version is < 8801. We could still show the message added here at runtime. Can discuss this more once this is committed to 9.0.x and 8.9.x but posting here so I don't forget.
Comment #98
tedbowre #87 thanks for the patch
re #88 thanks for the review
update_fix_compatibility()
except the deprecation. And removing all changes toupdate_check_incompatibility()
I don't think we absolutely need this for the fix.
We do need to change this test because otherwise we get an error on the update.php call that
test_stable
is missing because when we call$this->runUpdates();
It won't use our custom theme extension list class and will find it missing.
\Drupal\Core\Extension\InfoParserDynamic::parse()
we actually check if you allow versions of 8 before 8.7.7 unless you are allowing all versions of 8, such as ^8 which is allowedWe don't actually checks for version before 8. It is hard using
Composer\Semver
let me know if it matches anything below 8. I don't realistically this is something we probably need to check for. But this test was just checking that when the module become incompatible we don't have the bug this issue is fixing and you can't update.So I will change this use a different value which proves the same point,
core_version_requirement: 8.7.7
. This will never be core compatible in testing going forward.core: 8.x
to another value what will not throw an error in the parser but will be core incompatible.mixed[] $additional_info_values
I added a comment that array keys should be valid yaml file keys and the values will be encoded via
\Drupal\Component\Serialization\Yaml::encode()
Comment #99
xjmThe two followups for us to file are:
update_fix_incompatibility()
and deprecate it in Drupal 9. (Might end up being two separate issues.)StableBaseThemeUpdateTest
Comment #100
catchHere they are:
#3118788: Clean up StableBaseThemeUpdateTest
#3118786: update_fix_incompatibility() is (theoretically) dead code, but not theoretically dangerous
Comment #101
tedbowaddressing #88.6 adding testing coverage for the new message on
admin/reports/status
system_requirements
or the message would not show up. I think this is because in update.php these were being reset somewhere else so we were relying on that.UpdateScriptTest
With this I was getting 8 and 10 line code segments that were getting repeated. So I made to 2 new assert methods
assertUpdateWithNoError()
andassertErrorOnUpdate()
I had previously thought about making these but the segments just got longer here so I did.Comment #102
catchCaching is completely disabled (set to the null backend) on update.php via the update service provider, so not reset as such, but no cache in the first place to retrieve from.
Comment #103
catchCould this be left as well if we're going to make all the changes to this function (apart from deprecation) in a follow-up? Deprecated code calling deprecated code is OK really.
Could this not go inside the
block?
Comment #104
xjmI asked @tedbow why all the big, seemingly out-of-scope changes to
StableBaseThemeUpdateTest
were still included despite creating a followup for them. He replied that the "fake extension list" the test previously used wouldn't work, and I guess everything that's being removed is dead code once those few lines inprepareEnvironment()
are changed.I think part of what was tripping me up was this comment:
...which I guess actually contains that information; I just didn't understand what it was saying. We could add a "...We do not do [blah blah blah what we did before] because [what would happen if we did]."
Comment #105
xjm@tedbow is working on addressing #103 and #104.
Comment #106
tedbowwhen trying to load the .install file for the missing module. It is probably an existing problem but we didn't have test coverage for missing module before so it wasn't noticed.
I was going to say no we can't because we need in 2 different blocks but I noticed that new one we add
Could actually just go into the existing if block.
So removed the new if block at end and added to the existing one.
But as for reset the services I think we should keep them at the beginning of the function.
There are other existing cases where we do
\Drupal::service('extension.list.module')
in
system_requirement()
so I think we should reset these before all of the calls, not just the new ones.I think the problem with the existing comment is that we mention the listing service at all. It made sense we had test extension list that used a VFS stream for the files but now just creating the theme makes it available the extension list like any other theme.
I don't think we should have to mention why we don't use VFS stream.
I think though copying the theme over without an explanation as to why we need a test theme without a base theme makes the test very hard to understand. So I add more explination.
Comment #107
tedbowHeld off on making screenshot because I was wondering if we should change thit "Missing" instead of "Invalid"
Comment #108
xjmThis theme and a verb are in the sentence twice. Let's make it:
"The update fixture drupalsl;'dafjksl'f will enable this theme."
The comment still doesn't quite get at why we're doing this copying/writing to the file system, and the last sentence about the base theme property doesn't seem to have anything to do with the rest of the comment. Also, I thought we got rid of the base theme fallback last fall? Confused all around.
For #107 I suggested "Missing or invalid modules".
Comment #109
tedbowJust addressing #107 in this patch.
We actually don't have test coverage for the headings so I am adding that now.
In this process I refactored
assertUpdateWithNoError()
andassertErrorOnUpdate()
to expect multiple strings as the error texts.Comment #110
xjmQueued a test to see what happens on 9.0.x since all this stuff about the base theme fallback is confusing (we deprecated the ability for core to automatically set the base theme to stable, or I thought we did).
Comment #111
tedbowaddressing #108
Updated the comment
I figured out this was added in #3065545-24: Deprecate base theme fallback to Stable. Basically if this was regular test theme it would be scanned by all tests where
\Drupal\Core\Extension\ThemeExtensionList::createExtensionInfo()
and they would all need an expected deprecation notice about not having a base theme . So making this theme only in a scannable location for the 1 test avoids this.Comment #112
xjmLooks like we need a 9.0.x version of the patch. Hopefully we need it because the confusing test has been removed from 9.0.x. :)
Comment #113
xjmThe updated comment makes way more sense, thanks!
However, I still don't understand why that test is requiring changes for this issue. I've read this several times:How is the nonexistent fake theme for a legacy test even still present when the test for this issue runs? The first mention oftest_stable
on this issue is in my review in #88 so I still don't understand what the stable base theme has to do with testing a critical upgrade path bug or where the change in the patch came from in the first place. Does the way the test was written previously with all the vfs business somehow cause data to persist even after teardown?Disregard all that; I finally figured it out. The stupid thing is an update path test itself. Okay. It's green and I'll leave it at that. Thanks for your patience. 😺
A few points of review for the latest patch:
This still also needs to be changed to 8.8.4.
So the array in the test method calls them "expected error texts", but the method calls them "unexpected error texts". Which is it?
Also, we should typehint the function signature for the array.
string[]
now right?Ah, the "expected" comes from this method. Maybe we could just call them
$test_error_texts
or something like that in the caller?Same point about
string[]
and the signature array typehint here.Comment #114
tedbowworking on #113
Comment #115
tedbowre #113
No problem excited this one is close.
$test_error_text
singular nowComment #116
tedbowComment #117
tedbowHere is 9.0.x version. Just 1 use statement didn't apply in system.install
Also StableBaseThemeUpdateTest.php has been removed in 9.0.x
Comment #118
catchJust to say +1 to #106.2 and how it looks in the current patch, that's a good explanation and the fact the test fails without the change means we have implicit test coverage of the reset now (which I think is fine for system requirements stuff).
Comment #119
alexpottCan this const be protected so it doesn't bleed out into IDEs? Protected (and private) constants are only supported in PHP 7.2 or 7.3 so this doesn't work for Drupal 8 but this new pattern hasn't had an issue to discuss and atm it's going to pollute the public namespace for no reason and at least we can prevent that in 9.0.x
Edit: I tried to provide a screenshot but uploaded the wrong thing. I don't want to add more noise to the issue by correcting it but it would be great if we could fix the above in the D9 patch.
Comment #121
catchReal test failure.
Comment #122
tedbowLooking at 9.0.x test failures. I didn't actually run those locally.
re #119 should we just make it a
protected
var so it is the same on both branches?Comment #123
tedbowchanging this to
protected const ONLY IN 9.0.X patch
Using
core: 8.x
makes it fail on 9.0.x. I think just always usingcore_version_requirement: ^8 || ^9
is ok for the version of the info file that is compatible and will install.we really just want to test that when it is marked
core_incompatible === TRUE
it shows the error but does not unset the config.We already have sufficient test coverage in
\Drupal\Tests\Core\Extension\InfoParserUnitTest
that settingcore_incompatible
is done correctly we don't need to test that here.I will also updated the 8.9.x test so these are the same.
Comment #124
tedbowHere are screenshots
Comment #125
catchExtreme nitpick: should this say extension rather than module?
Isn't using variables in PluralTranslatableMarkup going to mean that it won't show up as a translatable string on l.d.o? I think we need to run everything through PluralTranslatableMarkup individually even if it results in more code duplication.
Additionally, we shouldn't concatenate version here (and similar with other strings), should be done with a placeholder.
Comment #126
tedbowfixed both in #125
Comment #127
tedbowfixing the PHPLint fail in #126. I guess the 9.0.x patch didn't fail because the comma at the end of the a list of arguments is allowed in later version of php.
I will upload 9.0.x version to keep the patches as close as possible
Comment #128
catchInterdiff looks great. Went through the patch again and didn't find anything else, so I think this is ready.
Comment #129
tim.plunkettI also re-reviewed this and +1 to RTBC.
Comment #130
xjmWe could have made this a class property just as easily, but I'm fine with a protected constant too.
These are legit
string[][]
given the data provider, but if that's all, I"m going to commit it anyway.The postgres tests are still running and seem to have... failed horribly? What?
Comment #131
xjmOh, I see the postgres 10.12 run was accidentally queued against 8.9.x initially. Alright, assiging and saving issue credits.
Comment #132
xjmI'm trying to commit this atm, but running into some issues...
Comment #133
xjm@tedbow is going to address my nitpicks while we wait for GitLab to allow core commits to start happening again.
Comment #135
xjmDisregard, it started working again.
Comment #137
xjmCommitted and pushed to 9.0.x and 8.9.x, thanks!
This is another one we might want to discuss for backport.
Comment #138
catchYes we need to backport this to 8.8.x, because it is what fixes #3099084: Base table or view not found: 1146 Table 'drupal.path_alias' doesn't exist. Update to 8.8.0 fails..
However, I think we need to do #2917600-97: update_fix_compatibility() puts sites into unrecoverable state, so that 8.8 -> 8.8.NEXT updates are not affected by the new error (i.e. to allow sites with this issue to update between patch releases), we'd then only show the error on update.php for <= 8.7 to 8.8 updates which is where it's needed to prevent path alias fatals.
Comment #139
xjmWe never did get those higher-res screenshots, but I'll use the lower-res versions in the handbook page. https://www.drupal.org/docs/8/update/troubleshooting-database-updates could still use review.
Comment #140
Berdir> However, I think we need to do #2917600-97: update_fix_compatibility() puts sites into unrecoverable state, so that 8.8 -> 8.8.NEXT updates are not affected by the new error (i.e. to allow sites with this issue to update between patch releases), we'd then only show the error on update.php for <= 8.7 to 8.8 updates which is where it's needed to prevent path alias fatals.
Not 100% sure about this. If we ignore this, then we still end up doing an incomplete uninstall that leaves things like schema version and config in place, resulting in problems on config reimport and trying to reinstall the module?
And it's then also a one-time thing, we don't get a chance to block it later when updating to 8.9, the module is gone then.
So yes, it might be annoying for patch updates, but not sure if the alternative is better?
Comment #141
catchHmm I was thinking not preventing people from updating and also not doing the incomplete uninstall but that would also be new behaviour in 8.8
So...yes probably a straight backport is best then.
Comment #142
tedbowHere is the 8.8 reroll
Comment #143
xjmReviewed the reroll's code and diffstat, and diffed it against the 8.9.x patch locally. The only differences were in context lines. Looks good!
Comment #145
catchCommitted f8a6d96 and pushed to 8.8.x. Thanks!
Backporting this to 8.8.x means that we've fixed #3099084: Base table or view not found: 1146 Table 'drupal.path_alias' doesn't exist. Update to 8.8.0 fails. for sites updating to 8.8.x (they'll get a helpful error message instead of data loss, and be able to upgrade once they've restored their missing module).
I personally do not think this is a priority for backport to 8.7.x - it's a good critical bugfix in its own right, but to our knowledge it's not affecting 8.7.x upgrade paths - installing a module in hook_update_N() and then trying to do a data migration based on that module being installed is very unusual. Also relatively unlikely that a site on 8.7.x will be doing that sort of major contrib module update prior to an 8.8.x update.
However, moving there for discussion.
Comment #146
tedbow1 reason in favor of backporting this is that it is more and more likely that contrib modules will be updating their info.yml files with
core_version_requirement: ^8.8 || 9
or other values that make it incompatible with 8.7.x. Since support forcore_version_requirement
support was backported to 8.7.x then this will cause this bug to be hit for any sites that mistakenly update their contrib modules to versions withcore_version_requirement: ^8.8 || 9
.Also #3096078: Display core compatibility ranges for available module updates was not backported to 8.7.x so the won't have the advantage of the Update module telling these contrib modules are incompatible.
Comment #147
tedbowHere is patch for 8.7. I don't know all the complications of backporting as far as release management so I don't know if #146 is good enough reason but here is patch against 8.7.x in case we decide to do it.
Applied cleaning except for system.install and
\Drupal\Tests\system\Functional\Update\StableBaseThemeUpdateTest
I don't think StableBaseThemeUpdateTest needs any changes because 8.7.x doesn't have the changes regarding base themes that updated that test.
Comment #148
tim.plunkettKeeping this review to only the backport itself, to keep it as close to 8.8 as possible.
I will post my other thoughts to #3122116: Nitpick follow-up to update_fix_compatibility() fix.
The 8.8. patch fixed the first == to be ===, this might as well too.
#474684: Allow themes to declare dependencies on modules was committed, but not backported to either 8.8 or 8.7, and idk that it will be.
Let's leave the @todo to match 8.8, and remove the "Question ..." lines.
Comment #149
tedbow@tim.plunkett thanks for the review. Fixed
Comment #150
tim.plunkettThanks for the quick fix! This is now the best approximation of the 8.8 patch, and ready to go!
Comment #152
xjmGot this yummy upon commit-attempt:
Fixed on commit with:
Thanks!
Comment #154
dawehnerWhile updating to 8.8.5 I ran into a fatal during running the update, which I pin pointed down to this issue, see https://www.drupal.org/project/drupal/issues/3136668