diff --git a/lib/CheckUpdateBackgroundJob.php b/lib/CheckUpdateBackgroundJob.php index 8d1e9ef1..a175c5ca 100644 --- a/lib/CheckUpdateBackgroundJob.php +++ b/lib/CheckUpdateBackgroundJob.php @@ -89,8 +89,12 @@ protected function run($argument) { 'market.page.index' ); $url .= '#/app/' . $appId; - - $this->createNotifications($appId, $appInfo['version'], $url); + if ($appInfo['major'] !== false) { + $this->createNotifications($appId, $appInfo['major'], $url); + } + if ($appInfo['minor'] !== false) { + $this->createNotifications($appId, $appInfo['minor'], $url); + } } } diff --git a/lib/Command/UpgradeApp.php b/lib/Command/UpgradeApp.php index 817edb95..ce1b9dde 100644 --- a/lib/Command/UpgradeApp.php +++ b/lib/Command/UpgradeApp.php @@ -106,7 +106,15 @@ protected function execute(InputInterface $input, OutputInterface $output) { if ($input->getOption('list')) { $updates = $this->marketService->getUpdates(); foreach ($updates as $name => $info) { - $output->writeln("$name : {$info['version']}"); + $versions = []; + if ($info['minor'] !== false) { + $versions[] = "minor:{$info['minor']}"; + } + if ($info['major'] !== false) { + $versions[] = "major:{$info['major']}"; + } + $versionStr = implode(', ', $versions); + $output->writeln("$name : $versionStr"); } return $this->exitCode; } @@ -120,17 +128,23 @@ protected function execute(InputInterface $input, OutputInterface $output) { if (!count($appIds)) { $output->writeln("No appId or path to a local package specified. Nothing to do."); - return $this->exitCode;; + return $this->exitCode; } foreach ($appIds as $appId) { try { if ($this->marketService->isAppInstalled($appId)) { - $updateVersion = $this->marketService->getAvailableUpdateVersion($appId, $isMajorUpdateAllowed); - if ($updateVersion !== false) { + $updateVersions = $this->marketService->getAvailableUpdateVersions($appId); + $updateVersion = $this->marketService->chooseCandidate($updateVersions, $isMajorUpdateAllowed); + if ($updateVersion !== null) { $output->writeln("$appId: Installing new version $updateVersion ..."); $this->marketService->updateApp($appId, $isMajorUpdateAllowed); $output->writeln("$appId: App updated."); + } elseif ($isMajorUpdateAllowed === false + && $updateVersions['major'] !== false + ) { + $major = $updateVersions['major']; + $output->writeln("$appId: update to $major requires --major option"); } else { $output->writeln("$appId: No update available"); } diff --git a/lib/Controller/MarketController.php b/lib/Controller/MarketController.php index 1c7a408d..87512d59 100644 --- a/lib/Controller/MarketController.php +++ b/lib/Controller/MarketController.php @@ -237,7 +237,7 @@ private function enrichApp($app) { unset($app['releases']); if ($app['installed']) { $app['installInfo'] = $this->marketService->getInstalledAppInfo($app['id']); - $app['updateInfo'] = $this->marketService->getAvailableUpdateVersion($app['id']); + $app['updateInfo'] = $this->marketService->getAvailableUpdateVersions($app['id']); $filteredReleases = array_filter($releases, function ($release) use ($app) { if (empty($app['updateInfo'])) { @@ -247,7 +247,10 @@ private function enrichApp($app) { }); $app['release'] = array_pop($filteredReleases); } else { - $app['updateInfo'] = false; + $app['updateInfo'] = [ + 'major' => false, + 'minor' => false + ]; usort($releases, function ($a, $b) { return version_compare($a['version'], $b['version'], '>'); }); diff --git a/lib/HttpService.php b/lib/HttpService.php index ffe75a5b..28eeafdc 100644 --- a/lib/HttpService.php +++ b/lib/HttpService.php @@ -298,6 +298,7 @@ private function getEntities($code) { */ public function getPlatformVersion() { $v = Util::getVersion(); + return '10.0.10.0'; return join('.', $v); } diff --git a/lib/Listener.php b/lib/Listener.php index 9fc72342..36abc990 100644 --- a/lib/Listener.php +++ b/lib/Listener.php @@ -33,12 +33,13 @@ public function __construct(MarketService $marketService) { } public function upgradeAppStoreApp($app, $isMajorUpdate) { - $updateVersion = $this->marketService->getAvailableUpdateVersion( - $app, + $updateVersions = $this->marketService->getAvailableUpdateVersions($app); + $updateVersion = $this->marketService->chooseCandidate( + $updateVersions, $isMajorUpdate ); if ($updateVersion !== false) { - $this->marketService->updateApp($app, $isMajorUpdate); + $this->marketService->updateApp($app, $updateVersion); } else { throw new AppUpdateNotFoundException(); } diff --git a/lib/MarketService.php b/lib/MarketService.php index c2cc77ec..6d7d6881 100644 --- a/lib/MarketService.php +++ b/lib/MarketService.php @@ -138,7 +138,17 @@ public function readAppPackage($path){ return $this->appManager->readAppPackage($path); } - private function downloadPackage($appId, $isMajor, $currentVersion = '0.0.0.0') { + /** + * @param string $appId + * @param string | null $targetVersion + * + * @return string + * + * @throws AppManagerException + * @throws AppNotFoundException + * @throws AppUpdateNotFoundException + */ + private function downloadPackage($appId, $targetVersion = null) { $this->httpService->checkInternetConnection(); $data = $this->getAppInfo($appId); if (empty($data)) { @@ -146,21 +156,22 @@ private function downloadPackage($appId, $isMajor, $currentVersion = '0.0.0.0') } $version = $this->httpService->getPlatformVersion(); - $release = array_filter($data['releases'], function($element) use ($version, $isMajor, $currentVersion) { - if ($isMajor === false) { - $marketVersionMajor = $this->getMajorVersion($element['version']); - $currentVersionMajor = $this->getMajorVersion($currentVersion); - if ($marketVersionMajor > $currentVersionMajor) { + $release = array_filter( + $data['releases'], + function ($element) use ($version, $targetVersion) { + if ($targetVersion !== null + && $element['version'] !== $targetVersion + ) { return false; } - } - $platformMin = $element['platformMin']; - $platformMax = $element['platformMax']; - $tooSmall = $this->compare($version, $platformMin, '<'); - $tooBig = $this->compare($version, $platformMax, '>'); + $platformMin = $element['platformMin']; + $platformMax = $element['platformMax']; + $tooSmall = $this->compare($version, $platformMin, '<'); + $tooBig = $this->compare($version, $platformMax, '>'); - return $tooSmall === false && $tooBig === false; - }); + return $tooSmall === false && $tooBig === false; + } + ); if (empty($release)) { throw new AppUpdateNotFoundException($this->l10n->t('No compatible version for %s', $appId)); } @@ -236,11 +247,52 @@ public function getMajorVersion($version) { return $versionArray[0]; } + /** + * @param string $appId + * + * @return string[] + * + * @throws AppNotFoundException + * @throws AppNotInstalledException + */ + public function getAvailableUpdateVersions($appId) { + $major = $this->getAvailableUpdateVersion($appId, true); + $minor = $this->getAvailableUpdateVersion($appId, false); + // Fixme: major equals to minor if there is no major + if ($major === $minor) { + $major = false; + } + return [ + 'major' => $major, + 'minor' => $minor + ]; + } + + /** + * @param string[] $updateVersions + * @param bool $isMajorAllowed + * + * @return string|false + */ + public function chooseCandidate($updateVersions, $isMajorAllowed) { + $updateVersion = $isMajorAllowed + ? $updateVersions['major'] + : $updateVersions['minor']; + // try to fallback to a minor release if there is no major release + if ($isMajorAllowed === false && $updateVersion === false) { + $updateVersion = $updateVersions['minor']; + } + return $updateVersion; + } + public function getAppInfo($appId) { $data = $this->getApps(); - $data = array_filter($data, function ($element) use ($appId) { - return $element['id'] === $appId; - }); + $data = array_filter( + $data, + function ($element) use ($appId) { + return $element['id'] === $appId; + } + ); if (empty($data)) { return null; } @@ -267,10 +319,14 @@ public function getInstalledAppInfo($appId) { * Update the app * * @param string $appId + * @param null $targetVersion + * * @throws AppManagerException + * @throws AppNotFoundException * @throws AppNotInstalledException + * @throws AppUpdateNotFoundException */ - public function updateApp($appId, $isMajorUpdate = false) { + public function updateApp($appId, $targetVersion = null) { if (!$this->canInstall()) { throw new \Exception("Installing apps is not supported because the app folder is not writable."); } @@ -281,7 +337,7 @@ public function updateApp($appId, $isMajorUpdate = false) { } // download package - $package = $this->downloadPackage($appId, $isMajorUpdate, $info['version']); + $package = $this->downloadPackage($appId, $targetVersion); $this->updatePackage($package); } @@ -344,12 +400,13 @@ public function getUpdates() { if (isset($info['id'])) { try { $appId = $info['id']; - $newVersion = $this->getAvailableUpdateVersion($appId); - if ($newVersion) { - $result[$app] = [ - 'version' => $newVersion, - 'id' => $appId - ]; + $newVersions = $this->getAvailableUpdateVersions($appId); + if ($newVersions['major'] !== false + || $newVersions['minor'] !== false + ) { + $result[$app] = array_merge( + $newVersions, [ 'id' => $appId ] + ); } } catch (AppNotInstalledException $e) { // ignore exceptions thrown by getAvailableUpdateVersion diff --git a/src/components/UpdateList.vue b/src/components/UpdateList.vue index 6272b54c..01e9fc60 100644 --- a/src/components/UpdateList.vue +++ b/src/components/UpdateList.vue @@ -22,7 +22,8 @@ td span {{ application.installInfo.version }} span(uk-icon="icon: arrow-right").uk-margin-small-left.uk-margin-small-right - span {{ application.updateInfo }} + span {{ application.updateInfo.minor }} + span {{ application.updateInfo.major }} td button.uk-button.uk-button-primary.uk-align-right.uk-margin-remove.uk-position-relative(@click="update(application.id)", :disabled="processing(application.id)") span(v-if="processing(application.id)") diff --git a/src/store.js b/src/store.js index d54071a0..1355e318 100644 --- a/src/store.js +++ b/src/store.js @@ -89,7 +89,7 @@ const getters = { updateList: (state) => { return _.filter(state.applications.records, function (application) { - return application.updateInfo != false; + return application.updateInfo.major != false || application.updateInfo.minor != false; }); }, diff --git a/tests/unit/CheckUpdateBackgroundJobTest.php b/tests/unit/CheckUpdateBackgroundJobTest.php index 5a70d94f..dcdc45b3 100644 --- a/tests/unit/CheckUpdateBackgroundJobTest.php +++ b/tests/unit/CheckUpdateBackgroundJobTest.php @@ -73,7 +73,7 @@ protected function getJob(array $methods = []) { public function dataCheckAppUpdate() { return [ [ - [ 'test'=> ['id' => 'test', 'version' => '1.2.4' ]], + [ 'test'=> ['id' => 'test', 'major' => false, 'minor' => '1.2.4' ]], true, ], [ diff --git a/tests/unit/Command/UpgradeAppTest.php b/tests/unit/Command/UpgradeAppTest.php index 26d19299..9d3b579e 100644 --- a/tests/unit/Command/UpgradeAppTest.php +++ b/tests/unit/Command/UpgradeAppTest.php @@ -73,7 +73,12 @@ public function testUpdateUnknownApp() { public function testUpdateNoNewVersion() { $this->marketService->expects($this->once())->method('canInstall')->willReturn(true); $this->marketService->expects($this->once())->method('isAppInstalled')->willReturn(true); - $this->marketService->expects($this->once())->method('getAvailableUpdateVersion')->willReturn(false); + $this->marketService->expects($this->once())->method('getAvailableUpdateVersions')->willReturn( + [ + 'major' => false, + 'minor' => false + ] + ); $this->marketService->expects($this->never())->method('installApp'); $this->marketService->expects($this->never())->method('updateApp'); $this->commandTester->execute([ @@ -86,7 +91,7 @@ public function testUpdateNoNewVersion() { public function testUpdateApp() { $this->marketService->expects($this->once())->method('canInstall')->willReturn(true); $this->marketService->expects($this->once())->method('isAppInstalled')->willReturn(true); - $this->marketService->expects($this->once())->method('getAvailableUpdateVersion')->willReturn('1.2.3'); + $this->marketService->expects($this->once())->method('chooseCandidate')->willReturn('1.2.3'); $this->marketService->expects($this->never())->method('installApp'); $this->marketService->expects($this->once())->method('updateApp'); $this->commandTester->execute([ @@ -133,31 +138,39 @@ public function providesVersions() { public function testListOption() { $this->marketService->expects($this->once())->method('canInstall')->willReturn(true); $this->marketService->expects($this->once())->method('getUpdates')->willReturn([ - 'foo' => ['version' => '1.2.3'], - 'bar' => ['version' => '4.0.0'], + 'foo' => ['major' => '2.2.3', 'minor' => '1.2.3'], + 'bar' => ['major' => '5.0.3', 'minor' => '4.0.0'], ]); $this->commandTester->execute([ '--list' => true ]); $output = $this->commandTester->getDisplay(); - $this->assertContains("foo : 1.2.3\nbar : 4.0.0", $output); + $this->assertContains("foo : minor:1.2.3, major:2.2.3\nbar : minor:4.0.0, major:5.0.3", $output); } public function testAllOption() { $this->marketService->expects($this->once())->method('canInstall')->willReturn(true); $this->marketService->expects($this->any())->method('isAppInstalled')->willReturn(true); - $this->marketService->expects($this->any())->method('getAvailableUpdateVersion')->willReturn('42'); + $this->marketService->expects($this->any())->method('getAvailableUpdateVersions')->willReturn( + [ 'major' => false, 'minor' => '1.2.3'] + ); $this->marketService->expects($this->any())->method('updateApp')->willReturn(true); - $this->marketService->expects($this->once())->method('getUpdates')->willReturn([ + $this->marketService->expects($this->once())->method('getUpdates')->willReturn( + [ 'foo' => [ 'id' => 'foo', - 'version' => '1.2.3' + 'minor' => '1.2.3', + 'major' => false ], 'bar' => [ 'id' => 'bar', - 'version' => '4.0.0' + 'minor' => '4.0.0', + 'major' => false, ], - ]); + ] + ); + $this->marketService->method('chooseCandidate') + ->will($this->onConsecutiveCalls('1.2.3', '4.0.0')); $this->commandTester->execute([ '--all' => true ]);