Skip to content

Commit c86fe25

Browse files
ernolfbackportbot[bot]
authored andcommitted
feat(updater): clear app_install_overwrite on major upgrades
- A force-enable states that an app was accepted against the major version it was enabled on, nothing beyond that - Carrying the list across a major upgrade re-enables apps that were never checked against the new release - Drop the config value at the start of the upgrade so the compatibility check is intact again - Read the overwrites on demand in the incompatibleAppDisabled listeners, a copy taken before the upgrade would suppress the very messages the admin needs Fixes #43026 Assisted-by: ClaudeCode:claude-opus-5 Signed-off-by: ernolf <raphael.gradenwitz@googlemail.com>
1 parent a19757e commit c86fe25

4 files changed

Lines changed: 40 additions & 4 deletions

File tree

core/Command/Upgrade.php

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,6 @@ protected function execute(InputInterface $input, OutputInterface $output): int
6767

6868
$self = $this;
6969
$updater = Server::get(Updater::class);
70-
$incompatibleOverwrites = $this->config->getSystemValue('app_install_overwrite', []);
7170

7271
/** @var IEventDispatcher $dispatcher */
7372
$dispatcher = Server::get(IEventDispatcher::class);
@@ -159,7 +158,9 @@ function ($success) use ($output, $self): void {
159158
$updater->listen('\OC\Updater', 'dbUpgrade', function () use ($output): void {
160159
$output->writeln('<info>Updated database</info>');
161160
});
162-
$updater->listen('\OC\Updater', 'incompatibleAppDisabled', function ($app) use ($output, &$incompatibleOverwrites): void {
161+
$updater->listen('\OC\Updater', 'incompatibleAppDisabled', function ($app) use ($output): void {
162+
// Read per event, the overwrites are cleared during a major upgrade
163+
$incompatibleOverwrites = $this->config->getSystemValue('app_install_overwrite', []);
163164
if (!in_array($app, $incompatibleOverwrites)) {
164165
$output->writeln('<comment>Disabled incompatible app: ' . $app . '</comment>');
165166
}

core/Controller/UpdateController.php

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,6 @@ public function update(): DataResponse {
8585
\OC_User::setIncognitoMode(true);
8686

8787
$incompatibleApps = [];
88-
$incompatibleOverwrites = $this->config->getSystemValue('app_install_overwrite', []);
8988

9089
$this->dispatcher->addListener(
9190
MigratorExecuteSqlEvent::class,
@@ -126,7 +125,9 @@ function (MigratorExecuteSqlEvent $event) use ($eventSource): void {
126125
$this->updater->listen('\OC\Updater', 'appUpgrade', function ($app, $version) use ($eventSource): void {
127126
$eventSource->send('success', $this->l->t('Updated "%1$s" to %2$s', [$app, $version]));
128127
});
129-
$this->updater->listen('\OC\Updater', 'incompatibleAppDisabled', function ($app) use (&$incompatibleApps, &$incompatibleOverwrites): void {
128+
$this->updater->listen('\OC\Updater', 'incompatibleAppDisabled', function ($app) use (&$incompatibleApps): void {
129+
// Read per event, the overwrites are cleared during a major upgrade
130+
$incompatibleOverwrites = $this->config->getSystemValue('app_install_overwrite', []);
130131
if (!in_array($app, $incompatibleOverwrites)) {
131132
$incompatibleApps[] = $app;
132133
}

lib/private/Updater.php

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,16 @@ public function isUpgradePossible(string $oldVersion, string $newVersion, array
187187
|| isset($allowedPreviousVersions[$currentVendor][$oldVersion]);
188188
}
189189

190+
/**
191+
* Whether the upgrade crosses a major version boundary
192+
*/
193+
private function isMajorUpgrade(string $installedVersion, string $currentVersion): bool {
194+
$installedMajor = (int)explode('.', $installedVersion)[0];
195+
$currentMajor = (int)explode('.', $currentVersion)[0];
196+
197+
return $currentMajor > $installedMajor;
198+
}
199+
190200
/**
191201
* runs the update actions in maintenance mode, does not upgrade the source files
192202
* except the main .htaccess file
@@ -203,6 +213,11 @@ private function doUpgrade(string $currentVersion, string $installedVersion): vo
203213
throw new \Exception('Updates between multiple major versions and downgrades are unsupported.');
204214
}
205215

216+
// A force-enable applies to the major version it was granted on
217+
if ($this->isMajorUpgrade($installedVersion, $currentVersion)) {
218+
$this->config->deleteSystemValue('app_install_overwrite');
219+
}
220+
206221
// Update .htaccess files
207222
try {
208223
Setup::updateHtaccess();

tests/lib/UpdaterTest.php

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,25 @@ public function testIsUpgradePossible($oldVersion, $newVersion, $allowedVersions
110110
$this->assertSame($result, $this->updater->isUpgradePossible($oldVersion, $newVersion, $allowedVersions));
111111
}
112112

113+
/**
114+
* @return array
115+
*/
116+
public static function majorUpgradeTestData(): array {
117+
return [
118+
// Same major version
119+
['33.0.0.10', '33.1.2.3', false],
120+
// Major upgrade
121+
['33.0.5.1', '34.0.0.10', true],
122+
// Downgrade, only reachable with debug enabled
123+
['34.0.0.10', '33.0.5.1', false],
124+
];
125+
}
126+
127+
#[\PHPUnit\Framework\Attributes\DataProvider('majorUpgradeTestData')]
128+
public function testIsMajorUpgrade(string $installedVersion, string $currentVersion, bool $result): void {
129+
$this->assertSame($result, self::invokePrivate($this->updater, 'isMajorUpgrade', [$installedVersion, $currentVersion]));
130+
}
131+
113132
public function testUpgradeAppStoreAppsRestoresMissingAutoDisabledAppBeforeEnabling(): void {
114133
$this->installer->expects($this->once())
115134
->method('isUpdateAvailable')

0 commit comments

Comments
 (0)