diff --git a/core/Command/App/Disable.php b/core/Command/App/Disable.php index ba9b8d769e..88b8539fb2 100644 --- a/core/Command/App/Disable.php +++ b/core/Command/App/Disable.php @@ -78,7 +78,8 @@ class Disable extends Command implements CompletionAwareInterface { try { $this->appManager->disableApp($appId); - $output->writeln($appId . ' disabled'); + $appVersion = \OC_App::getAppVersion($appId); + $output->writeln($appId . ' ' . $appVersion . ' disabled'); } catch (\Exception $e) { $output->writeln($e->getMessage()); $this->exitCode = 2; diff --git a/core/Command/App/Enable.php b/core/Command/App/Enable.php index 2e26184b19..e1605942d8 100644 --- a/core/Command/App/Enable.php +++ b/core/Command/App/Enable.php @@ -120,13 +120,14 @@ class Enable extends Command implements CompletionAwareInterface { } $installer->installApp($appId, $forceEnable); + $appVersion = \OC_App::getAppVersion($appId); if ($groupIds === []) { $this->appManager->enableApp($appId, $forceEnable); - $output->writeln($appId . ' enabled'); + $output->writeln($appId . ' ' . $appVersion . ' enabled'); } else { $this->appManager->enableAppForGroups($appId, $groupIds, $forceEnable); - $output->writeln($appId . ' enabled for groups: ' . implode(', ', $groupNames)); + $output->writeln($appId . ' ' . $appVersion . ' enabled for groups: ' . implode(', ', $groupNames)); } } catch (AppPathNotFoundException $e) { $output->writeln($appId . ' not found'); diff --git a/core/Command/App/Install.php b/core/Command/App/Install.php index 41e3e20c9d..898e39416f 100644 --- a/core/Command/App/Install.php +++ b/core/Command/App/Install.php @@ -74,7 +74,8 @@ class Install extends Command { return 1; } - $output->writeln($appId . ' installed'); + $appVersion = \OC_App::getAppVersion($appId); + $output->writeln($appId . ' ' . $appVersion . ' installed'); if (!$input->getOption('keep-disabled')) { $appClass = new \OC_App(); diff --git a/core/Command/App/Remove.php b/core/Command/App/Remove.php index 96d1efe8c6..1135b7b446 100644 --- a/core/Command/App/Remove.php +++ b/core/Command/App/Remove.php @@ -124,7 +124,8 @@ class Remove extends Command implements CompletionAwareInterface { return 1; } - $output->writeln($appId . ' removed'); + $appVersion = \OC_App::getAppVersion($appId); + $output->writeln($appId . ' ' . $appVersion . ' removed'); return 0; } diff --git a/core/Command/App/Update.php b/core/Command/App/Update.php index 34178c1ee7..1efafc47e9 100644 --- a/core/Command/App/Update.php +++ b/core/Command/App/Update.php @@ -76,7 +76,12 @@ class Update extends Command { InputOption::VALUE_NONE, 'show update(s) without updating' ) - + ->addOption( + 'allow-unstable', + null, + InputOption::VALUE_NONE, + 'allow updating to unstable releases' + ) ; } @@ -100,13 +105,13 @@ class Update extends Command { $return = 0; foreach ($apps as $appId) { - $newVersion = $this->installer->isUpdateAvailable($appId); + $newVersion = $this->installer->isUpdateAvailable($appId, $input->getOption('allow-unstable')); if ($newVersion) { $output->writeln($appId . ' new version available: ' . $newVersion); if (!$input->getOption('showonly')) { try { - $result = $this->installer->updateAppstoreApp($appId); + $result = $this->installer->updateAppstoreApp($appId, $input->getOption('allow-unstable')); } catch (\Exception $e) { $this->logger->logException($e, ['message' => 'Failure during update of app "' . $appId . '"','app' => 'app:update']); $output->writeln('Error: ' . $e->getMessage()); diff --git a/lib/private/App/AppStore/Fetcher/AppFetcher.php b/lib/private/App/AppStore/Fetcher/AppFetcher.php index e4c2ba4e85..f108d23dd9 100644 --- a/lib/private/App/AppStore/Fetcher/AppFetcher.php +++ b/lib/private/App/AppStore/Fetcher/AppFetcher.php @@ -78,15 +78,16 @@ class AppFetcher extends Fetcher { * * @param string $ETag * @param string $content + * @param bool [$allowUnstable] Allow unstable releases * * @return array */ - protected function fetch($ETag, $content) { + protected function fetch($ETag, $content, $allowUnstable = false) { /** @var mixed[] $response */ $response = parent::fetch($ETag, $content); - $allowPreReleases = $this->getChannel() === 'beta' || $this->getChannel() === 'daily'; - $allowNightly = $this->getChannel() === 'daily'; + $allowPreReleases = $allowUnstable || $this->getChannel() === 'beta' || $this->getChannel() === 'daily'; + $allowNightly = $allowUnstable || $this->getChannel() === 'daily'; foreach ($response['data'] as $dataKey => $app) { $releases = []; diff --git a/lib/private/App/AppStore/Fetcher/Fetcher.php b/lib/private/App/AppStore/Fetcher/Fetcher.php index 500a0568c9..fcb837ee16 100644 --- a/lib/private/App/AppStore/Fetcher/Fetcher.php +++ b/lib/private/App/AppStore/Fetcher/Fetcher.php @@ -129,9 +129,10 @@ abstract class Fetcher { /** * Returns the array with the categories on the appstore server * + * @param bool [$allowUnstable] Allow unstable releases * @return array */ - public function get() { + public function get($allowUnstable = false) { $appstoreenabled = $this->config->getSystemValue('appstoreenabled', true); $internetavailable = $this->config->getSystemValue('has_internet_connection', true); @@ -148,7 +149,9 @@ abstract class Fetcher { // File does already exists $file = $rootFolder->getFile($this->fileName); $jsonBlob = json_decode($file->getContent(), true); - if (is_array($jsonBlob)) { + + // Always get latests apps info if $allowUnstable + if (!$allowUnstable && is_array($jsonBlob)) { // No caching when the version has been updated if (isset($jsonBlob['ncversion']) && $jsonBlob['ncversion'] === $this->getVersion()) { @@ -171,7 +174,12 @@ abstract class Fetcher { // Refresh the file content try { - $responseJson = $this->fetch($ETag, $content); + $responseJson = $this->fetch($ETag, $content, $allowUnstable); + // Don't store the apps request file + if ($allowUnstable) { + return $responseJson['data']; + } + $file->putContent(json_encode($responseJson)); return json_decode($file->getContent(), true)['data']; } catch (ConnectException $e) { diff --git a/lib/private/Installer.php b/lib/private/Installer.php index d5c9d076ed..9be79ac72b 100644 --- a/lib/private/Installer.php +++ b/lib/private/Installer.php @@ -189,12 +189,13 @@ class Installer { * Updates the specified app from the appstore * * @param string $appId + * @param bool [$allowUnstable] Allow unstable releases * @return bool */ - public function updateAppstoreApp($appId) { - if ($this->isUpdateAvailable($appId)) { + public function updateAppstoreApp($appId, $allowUnstable = false) { + if ($this->isUpdateAvailable($appId, $allowUnstable)) { try { - $this->downloadApp($appId); + $this->downloadApp($appId, $allowUnstable); } catch (\Exception $e) { $this->logger->logException($e, [ 'level' => ILogger::ERROR, @@ -212,13 +213,14 @@ class Installer { * Downloads an app and puts it into the app directory * * @param string $appId + * @param bool [$allowUnstable] * * @throws \Exception If the installation was not successful */ - public function downloadApp($appId) { + public function downloadApp($appId, $allowUnstable = false) { $appId = strtolower($appId); - $apps = $this->appFetcher->get(); + $apps = $this->appFetcher->get($allowUnstable); foreach ($apps as $app) { if ($app['id'] === $appId) { // Load the certificate @@ -384,9 +386,10 @@ class Installer { * Check if an update for the app is available * * @param string $appId + * @param bool $allowUnstable * @return string|false false or the version number of the update */ - public function isUpdateAvailable($appId) { + public function isUpdateAvailable($appId, $allowUnstable = false) { if ($this->isInstanceReadyForUpdates === null) { $installPath = OC_App::getInstallPath(); if ($installPath === false || $installPath === null) { @@ -405,7 +408,7 @@ class Installer { } if ($this->apps === null) { - $this->apps = $this->appFetcher->get(); + $this->apps = $this->appFetcher->get($allowUnstable); } foreach ($this->apps as $app) { diff --git a/tests/Core/Command/Apps/AppsDisableTest.php b/tests/Core/Command/Apps/AppsDisableTest.php index b5fd18ece2..e19668dea9 100644 --- a/tests/Core/Command/Apps/AppsDisableTest.php +++ b/tests/Core/Command/Apps/AppsDisableTest.php @@ -68,18 +68,18 @@ class AppsDisableTest extends TestCase { public function dataCommandInput(): array { return [ - [['admin_audit'], 0, 'admin_audit disabled'], - [['comments'], 0, 'comments disabled'], + [['admin_audit'], 0, 'admin_audit 1.10.0 disabled'], + [['comments'], 0, 'comments 1.10.0 disabled'], [['invalid_app'], 0, 'No such app enabled: invalid_app'], - [['admin_audit', 'comments'], 0, "admin_audit disabled\ncomments disabled"], - [['admin_audit', 'comments', 'invalid_app'], 0, "admin_audit disabled\ncomments disabled\nNo such app enabled: invalid_app"], + [['admin_audit', 'comments'], 0, "admin_audit 1.10.0 disabled\ncomments 1.10.0 disabled"], + [['admin_audit', 'comments', 'invalid_app'], 0, "admin_audit 1.10.0 disabled\ncomments 1.10.0 disabled\nNo such app enabled: invalid_app"], [['files'], 2, "files can't be disabled"], [['provisioning_api'], 2, "provisioning_api can't be disabled"], - [['files', 'admin_audit'], 2, "files can't be disabled.\nadmin_audit disabled"], - [['provisioning_api', 'comments'], 2, "provisioning_api can't be disabled.\ncomments disabled"], + [['files', 'admin_audit'], 2, "files can't be disabled.\nadmin_audit 1.10.0 disabled"], + [['provisioning_api', 'comments'], 2, "provisioning_api can't be disabled.\ncomments 1.10.0 disabled"], ]; } diff --git a/tests/Core/Command/Apps/AppsEnableTest.php b/tests/Core/Command/Apps/AppsEnableTest.php index b5d781aa12..bcf3d9dd82 100644 --- a/tests/Core/Command/Apps/AppsEnableTest.php +++ b/tests/Core/Command/Apps/AppsEnableTest.php @@ -73,29 +73,29 @@ class AppsEnableTest extends TestCase { public function dataCommandInput(): array { $data = [ - [['admin_audit'], null, 0, 'admin_audit enabled'], - [['comments'], null, 0, 'comments enabled'], - [['comments', 'comments'], null, 0, "comments enabled\ncomments already enabled"], + [['admin_audit'], null, 0, 'admin_audit 1.10.0 enabled'], + [['comments'], null, 0, 'comments 1.10.0 enabled'], + [['comments', 'comments'], null, 0, "comments 1.10.0 enabled\ncomments already enabled"], [['invalid_app'], null, 1, 'Could not download app invalid_app'], - [['admin_audit', 'comments'], null, 0, "admin_audit enabled\ncomments enabled"], - [['admin_audit', 'comments', 'invalid_app'], null, 1, "admin_audit enabled\ncomments enabled\nCould not download app invalid_app"], + [['admin_audit', 'comments'], null, 0, "admin_audit 1.10.0 enabled\ncomments 1.10.0 enabled"], + [['admin_audit', 'comments', 'invalid_app'], null, 1, "admin_audit 1.10.0 enabled\ncomments 1.10.0 enabled\nCould not download app invalid_app"], [['admin_audit'], ['admin'], 1, "admin_audit can't be enabled for groups"], [['comments'], ['admin'], 1, "comments can't be enabled for groups"], - [['updatenotification'], ['admin'], 0, 'updatenotification enabled for groups: admin'], - [['updatenotification', 'accessibility'], ['admin'], 0, "updatenotification enabled for groups: admin\naccessibility enabled for groups: admin"], + [['updatenotification'], ['admin'], 0, 'updatenotification 1.10.0 enabled for groups: admin'], + [['updatenotification', 'accessibility'], ['admin'], 0, "updatenotification 1.10.0 enabled for groups: admin\naccessibility 1.6.0 enabled for groups: admin"], - [['updatenotification'], ['admin', 'invalid_group'], 0, 'updatenotification enabled for groups: admin'], - [['updatenotification', 'accessibility'], ['admin', 'invalid_group'], 0, "updatenotification enabled for groups: admin\naccessibility enabled for groups: admin"], - [['updatenotification', 'accessibility', 'invalid_app'], ['admin', 'invalid_group'], 1, "updatenotification enabled for groups: admin\naccessibility enabled for groups: admin\nCould not download app invalid_app"], + [['updatenotification'], ['admin', 'invalid_group'], 0, 'updatenotification 1.10.0 enabled for groups: admin'], + [['updatenotification', 'accessibility'], ['admin', 'invalid_group'], 0, "updatenotification 1.10.0 enabled for groups: admin\naccessibility 1.6.0 enabled for groups: admin"], + [['updatenotification', 'accessibility', 'invalid_app'], ['admin', 'invalid_group'], 1, "updatenotification 1.10.0 enabled for groups: admin\naccessibility 1.6.0 enabled for groups: admin\nCould not download app invalid_app"], ]; if (getenv('CI') === false) { /** Tests disabled on drone/ci due to appstore dependency */ - $data[] = [['updatenotification', 'contacts'], ['admin'], 0, "updatenotification enabled for groups: admin\ncontacts enabled for groups: admin"]; - $data[] = [['updatenotification', 'contacts'], ['admin', 'invalid_group'], 0, "updatenotification enabled for groups: admin\ncontacts enabled for groups: admin"]; + $data[] = [['updatenotification', 'contacts'], ['admin'], 0, "updatenotification 1.10.0 enabled for groups: admin\ncontacts 3.3.0 enabled for groups: admin"]; + $data[] = [['updatenotification', 'contacts'], ['admin', 'invalid_group'], 0, "updatenotification enabled for groups: admin\ncontacts 3.3.0 enabled for groups: admin"]; $data[] = [['updatenotification', 'contacts', 'invalid_app'], ['admin', 'invalid_group'], 1, "updatenotification enabled for groups: admin\ncontacts enabled for groups: admin\nCould not download app invalid_app"]; }