diff options
-rw-r--r-- | core/command/upgrade.php | 38 | ||||
-rw-r--r-- | core/register_command.php | 6 | ||||
-rw-r--r-- | core/templates/update.admin.php | 5 | ||||
-rw-r--r-- | lib/base.php | 3 | ||||
-rw-r--r-- | lib/private/releasenotes.php | 109 | ||||
-rw-r--r-- | tests/lib/releasenotestest.php | 103 |
6 files changed, 261 insertions, 3 deletions
diff --git a/core/command/upgrade.php b/core/command/upgrade.php index c45984d7a30..a60eee9e327 100644 --- a/core/command/upgrade.php +++ b/core/command/upgrade.php @@ -30,6 +30,7 @@ namespace OC\Core\Command; use OC\Console\TimestampFormatter; +use OC\ReleaseNotes; use OC\Updater; use OCP\IConfig; use OCP\ILogger; @@ -37,8 +38,9 @@ use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Input\InputOption; +use Symfony\Component\Console\Question\ConfirmationQuestion; -class Upgrade extends Command { +class Upgrade extends Base { const ERROR_SUCCESS = 0; const ERROR_NOT_INSTALLED = 1; @@ -53,17 +55,23 @@ class Upgrade extends Command { /** @var ILogger */ private $logger; + /** @var ReleaseNotes */ + private $releaseNotes; + /** * @param IConfig $config * @param ILogger $logger + * @param ReleaseNotes $releaseNotes */ - public function __construct(IConfig $config, ILogger $logger) { + public function __construct(IConfig $config, ILogger $logger, ReleaseNotes $releaseNotes) { parent::__construct(); $this->config = $config; $this->logger = $logger; + $this->releaseNotes = $releaseNotes; } protected function configure() { + parent::configure(); $this ->setName('upgrade') ->setDescription('run upgrade routines after installation of a new release. The release has to be installed before.') @@ -95,6 +103,19 @@ class Upgrade extends Command { */ protected function execute(InputInterface $input, OutputInterface $output) { + if ($input->isInteractive()) { + $installedVersion = $this->config->getSystemValue('version', '0.0.0'); + $currentVersion = implode('.', \OCP\Util::getVersion()); + + $releaseNotesArray = $this->releaseNotes->getReleaseNotes($installedVersion, $currentVersion); + if (!empty($releaseNotesArray)) { + $this->writeArrayInOutputFormat($input, $output, $releaseNotesArray); + if (!$this->ask($input, $output)){ + return self::ERROR_SUCCESS; + } + } + } + $simulateStepEnabled = true; $updateStepEnabled = true; $skip3rdPartyAppsDisable = false; @@ -262,4 +283,17 @@ class Upgrade extends Command { ); } } + + /** + * Ask for confirmation + * @param InputInterface $input + * @param OutputInterface $output + * @return bool + */ + public function ask(InputInterface $input, OutputInterface $output){ + $helper = $this->getHelper('question'); + $question = new ConfirmationQuestion('Continue with update (y/n)' . PHP_EOL, true); + return $helper->ask($input, $output, $question); + } + } diff --git a/core/register_command.php b/core/register_command.php index 17bd573133a..e06ff436f50 100644 --- a/core/register_command.php +++ b/core/register_command.php @@ -114,7 +114,11 @@ if (\OC::$server->getConfig()->getSystemValue('installed', false)) { $application->add(new OC\Core\Command\Maintenance\Repair(new \OC\Repair(\OC\Repair::getRepairSteps()), \OC::$server->getConfig())); $application->add(new OC\Core\Command\Maintenance\SingleUser(\OC::$server->getConfig())); - $application->add(new OC\Core\Command\Upgrade(\OC::$server->getConfig(), \OC::$server->getLogger())); + $application->add(new OC\Core\Command\Upgrade( + \OC::$server->getConfig(), + \OC::$server->getLogger(), + new \OC\ReleaseNotes(\OC::$server->getDatabaseConnection()) + )); $application->add(new OC\Core\Command\User\Add(\OC::$server->getUserManager(), \OC::$server->getGroupManager())); $application->add(new OC\Core\Command\User\Delete(\OC::$server->getUserManager())); diff --git a/core/templates/update.admin.php b/core/templates/update.admin.php index 75815de84bc..543820e054f 100644 --- a/core/templates/update.admin.php +++ b/core/templates/update.admin.php @@ -34,6 +34,11 @@ <div class="infogroup bold"> <?php p($l->t('Please make sure that the database, the config folder and the data folder have been backed up before proceeding.')) ?> </div> + <?php foreach ($_['releaseNotes'] as $note): ?> + <div class="infogroup bold"> + <?php p($note) ?> + </div> + <?php endforeach; ?> <input class="updateButton" type="button" value="<?php p($l->t('Start update')) ?>"> <div class="infogroup"> <?php p($l->t('To avoid timeouts with larger installations, you can instead run the following command from your installation directory:')) ?> diff --git a/lib/base.php b/lib/base.php index 35c8592fe10..e77a07239c4 100644 --- a/lib/base.php +++ b/lib/base.php @@ -392,12 +392,15 @@ class OC { $tmpl->assign('isAppsOnlyUpgrade', false); } + $releaseNotes = new \OC\ReleaseNotes(\OC::$server->getDatabaseConnection()); + // get third party apps $ocVersion = \OCP\Util::getVersion(); $tmpl->assign('appsToUpgrade', $appManager->getAppsNeedingUpgrade($ocVersion)); $tmpl->assign('incompatibleAppsList', $appManager->getIncompatibleApps($ocVersion)); $tmpl->assign('productName', 'ownCloud'); // for now $tmpl->assign('oldTheme', $oldTheme); + $tmpl->assign('releaseNotes', $releaseNotes->getReleaseNotes($installedVersion, $currentVersion)); $tmpl->printPage(); } diff --git a/lib/private/releasenotes.php b/lib/private/releasenotes.php new file mode 100644 index 00000000000..5da416c19f0 --- /dev/null +++ b/lib/private/releasenotes.php @@ -0,0 +1,109 @@ +<?php +/** + * @author Victor Dubiniuk <dubiniuk@owncloud.com> + * + * @copyright Copyright (c) 2016, ownCloud, Inc. + * @license AGPL-3.0 + * + * This code is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License, version 3, + * along with this program. If not, see <http://www.gnu.org/licenses/> + * + */ + +namespace OC; + +use Doctrine\DBAL\Platforms\MySqlPlatform; +use OCP\IDBConnection; + +/** + * Class to store release notes + */ +class ReleaseNotes { + /** @var IDBConnection $dbConnection */ + protected $dbConnection; + + /** + * @param IDBConnection $dbConnection + */ + public function __construct(IDBConnection $dbConnection) { + $this->dbConnection = $dbConnection; + } + + /** + * @param string $fromVersion + * @param string $toVersion + * @return string[] + */ + public function getReleaseNotes($fromVersion, $toVersion) { + $releaseNotes = []; + $l10n = \OC::$server->getL10N('core'); + + try { + $fromVersionMajorMinor = $this->getMajorMinor($fromVersion); + } catch (\InvalidArgumentException $e) { + $fromVersionMajorMinor = ''; + } + + try { + $toVersionMajorMinor = $this->getMajorMinor($toVersion); + } catch (\InvalidArgumentException $e) { + $toVersionMajorMinor = ''; + } + + if ($fromVersionMajorMinor === '8.2' && $toVersionMajorMinor === '9.0') { + if ($this->isMysql() && $this->countFilecacheEntries() > 200000) { + $releaseNotes[] = $l10n->t( + 'Hint: You can speed up the upgrade by executing this SQL command manually: ALTER TABLE %s ADD COLUMN checksum varchar(255) DEFAULT NULL AFTER permissions;', + [$this->dbConnection->getQueryBuilder()->getTableName('filecache')] + ); + } + } + return $releaseNotes; + } + + /** + * @return bool + */ + protected function isMysql(){ + return $this->dbConnection->getDatabasePlatform() instanceof MySqlPlatform; + } + + /** + * Count entries in filecache table + * @return int + */ + protected function countFilecacheEntries(){ + $query = $this->dbConnection->getQueryBuilder(); + $query->selectAlias($query->createFunction('COUNT(*)'), 'num_entries') + ->from('filecache'); + + $result = $query->execute(); + $row = $result->fetch(); + $result->closeCursor(); + + return (int) $row['num_entries']; + } + + /** + * Strip everything except first digits + * @param string $version + * @return string + * @throws \InvalidArgumentException + */ + private function getMajorMinor($version){ + $versionArray = explode('.', $version); + if (count($versionArray) < 2) { + throw new \InvalidArgumentException('Version should have at least 2 parts separated by dot.'); + } + return implode('.', [ $versionArray[0], $versionArray[1] ]); + } +} diff --git a/tests/lib/releasenotestest.php b/tests/lib/releasenotestest.php new file mode 100644 index 00000000000..584f396038b --- /dev/null +++ b/tests/lib/releasenotestest.php @@ -0,0 +1,103 @@ +<?php +/** + * @author Victor Dubiniuk <dubiniuk@owncloud.com> + * + * @copyright Copyright (c) 2016, ownCloud, Inc. + * @license AGPL-3.0 + * + * This code is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License, version 3, + * along with this program. If not, see <http://www.gnu.org/licenses/> + * + */ + +namespace Test; + +class ReleaseNotesTest extends \Test\TestCase { + + /** + * @param bool $isMysql + * @param int $fileCount + * @return \PHPUnit_Framework_MockObject_MockObject|\OC\ReleaseNotes + */ + protected function getReleaseNotesMock($isMysql, $fileCount) { + $query = $this->getMockBuilder('OCP\DB\QueryBuilder\IQueryBuilder') + ->disableOriginalConstructor() + ->getMock(); + $query->expects($this->any()) + ->method('getTableName') + ->willReturnCallback(function($tableName) { + return 'ocx_' . $tableName; + }); + + $dbConnectionMock = $this->getMockBuilder('OCP\IDBConnection') + ->disableOriginalConstructor() + ->getMock(); + $dbConnectionMock->expects($this->any()) + ->method('getQueryBuilder') + ->willReturn($query); + $releaseNotesMock = $this->getMockBuilder('OC\ReleaseNotes') + ->setConstructorArgs([$dbConnectionMock]) + ->setMethods(['isMysql', 'countFilecacheEntries']) + ->getMock(); + + $releaseNotesMock->expects($this->any()) + ->method('isMysql') + ->willReturn($isMysql); + $releaseNotesMock->expects($this->any()) + ->method('countFilecacheEntries') + ->willReturn($fileCount); + return $releaseNotesMock; + } + + public function data82to90() { + return [ + [[], false, 20], + [[], true, 20], + [[], false, 1000000], + [['Hint: You can speed up the upgrade by executing this SQL command manually: ALTER TABLE ocx_filecache ADD COLUMN checksum varchar(255) DEFAULT NULL AFTER permissions;'], true, 1000000], + ]; + } + + /** + * @dataProvider data82to90 + * + * @param string[] $expected + * @param bool $isMysql + * @param int $fileCount + */ + public function test82to90($expected, $isMysql, $fileCount) { + $releaseNotesMock = $this->getReleaseNotesMock($isMysql, $fileCount); + $actual = $releaseNotesMock->getReleaseNotes('8.2.22', '9.0.1'); + $this->assertEquals($expected, $actual); + } + + public function data90to91() { + return [ + [false, 20], + [true, 20], + [false, 1000000], + [true, 1000000], + ]; + } + + /** + * @dataProvider data90to91 + * + * @param bool $isMysql + * @param int $fileCount + */ + public function test90to91($isMysql, $fileCount) { + $releaseNotesMock = $this->getReleaseNotesMock($isMysql, $fileCount); + $actual = $releaseNotesMock->getReleaseNotes('9.0.1', '9.1.0'); + $this->assertCount(0, $actual); + } +} |