diff --git a/core/Command/Upgrade.php b/core/Command/Upgrade.php index 0451156a3ec06..9fd0f2f8de48a 100644 --- a/core/Command/Upgrade.php +++ b/core/Command/Upgrade.php @@ -70,7 +70,6 @@ protected function execute(InputInterface $input, OutputInterface $output): int $self = $this; $updater = Server::get(Updater::class); - $incompatibleOverwrites = $this->config->getSystemValue('app_install_overwrite', []); /** @var IEventDispatcher $dispatcher */ $dispatcher = Server::get(IEventDispatcher::class); @@ -161,7 +160,9 @@ function ($success) use ($output, $self): void { $updater->listen('\OC\Updater', 'dbUpgrade', function () use ($output): void { $output->writeln('Updated database'); }); - $updater->listen('\OC\Updater', 'incompatibleAppDisabled', function ($app) use ($output, &$incompatibleOverwrites): void { + $updater->listen('\OC\Updater', 'incompatibleAppDisabled', function ($app) use ($output): void { + // Read per event, the overwrites are cleared during a major upgrade + $incompatibleOverwrites = $this->config->getSystemValue('app_install_overwrite', []); if (!in_array($app, $incompatibleOverwrites)) { $output->writeln('Disabled incompatible app: ' . $app . ''); } diff --git a/core/Controller/UpdateController.php b/core/Controller/UpdateController.php index 14308c12d51f5..a027b30d05377 100644 --- a/core/Controller/UpdateController.php +++ b/core/Controller/UpdateController.php @@ -86,7 +86,6 @@ public function update(): DataResponse { \OC_User::setIncognitoMode(true); $incompatibleApps = []; - $incompatibleOverwrites = $this->config->getSystemValue('app_install_overwrite', []); $this->dispatcher->addListener( MigratorExecuteSqlEvent::class, @@ -127,7 +126,9 @@ function (MigratorExecuteSqlEvent $event) use ($eventSource): void { $this->updater->listen('\OC\Updater', 'appUpgrade', function ($app, $version) use ($eventSource): void { $eventSource->send('success', $this->l->t('Updated "%1$s" to %2$s', [$app, $version])); }); - $this->updater->listen('\OC\Updater', 'incompatibleAppDisabled', function ($app) use (&$incompatibleApps, &$incompatibleOverwrites): void { + $this->updater->listen('\OC\Updater', 'incompatibleAppDisabled', function ($app) use (&$incompatibleApps): void { + // Read per event, the overwrites are cleared during a major upgrade + $incompatibleOverwrites = $this->config->getSystemValue('app_install_overwrite', []); if (!in_array($app, $incompatibleOverwrites)) { $incompatibleApps[] = $app; } diff --git a/lib/private/Updater.php b/lib/private/Updater.php index b33dfcf8b855d..d6fba6789aa88 100644 --- a/lib/private/Updater.php +++ b/lib/private/Updater.php @@ -188,6 +188,16 @@ public function isUpgradePossible(string $oldVersion, string $newVersion, array || isset($allowedPreviousVersions[$currentVendor][$oldVersion]); } + /** + * Whether the upgrade crosses a major version boundary + */ + private function isMajorUpgrade(string $installedVersion, string $currentVersion): bool { + $installedMajor = (int)explode('.', $installedVersion)[0]; + $currentMajor = (int)explode('.', $currentVersion)[0]; + + return $currentMajor > $installedMajor; + } + /** * runs the update actions in maintenance mode, does not upgrade the source files * except the main .htaccess file @@ -204,6 +214,11 @@ private function doUpgrade(string $currentVersion, string $installedVersion): vo throw new \Exception('Updates between multiple major versions and downgrades are unsupported.'); } + // A force-enable applies to the major version it was granted on + if ($this->isMajorUpgrade($installedVersion, $currentVersion)) { + $this->config->deleteSystemValue('app_install_overwrite'); + } + // Update .htaccess files try { Setup::updateHtaccess(); diff --git a/tests/lib/UpdaterTest.php b/tests/lib/UpdaterTest.php index 059b4edeb340a..41f88d2c10d40 100644 --- a/tests/lib/UpdaterTest.php +++ b/tests/lib/UpdaterTest.php @@ -110,6 +110,25 @@ public function testIsUpgradePossible($oldVersion, $newVersion, $allowedVersions $this->assertSame($result, $this->updater->isUpgradePossible($oldVersion, $newVersion, $allowedVersions)); } + /** + * @return array + */ + public static function majorUpgradeTestData(): array { + return [ + // Same major version + ['33.0.0.10', '33.1.2.3', false], + // Major upgrade + ['33.0.5.1', '34.0.0.10', true], + // Downgrade, only reachable with debug enabled + ['34.0.0.10', '33.0.5.1', false], + ]; + } + + #[\PHPUnit\Framework\Attributes\DataProvider('majorUpgradeTestData')] + public function testIsMajorUpgrade(string $installedVersion, string $currentVersion, bool $result): void { + $this->assertSame($result, self::invokePrivate($this->updater, 'isMajorUpgrade', [$installedVersion, $currentVersion])); + } + public function testUpgradeAppStoreAppsRestoresMissingAutoDisabledAppBeforeEnabling(): void { $this->installer->expects($this->once()) ->method('isUpdateAvailable')