Skip to content

Commit

Permalink
feat(cli): added command to execute a single upgrade
Browse files Browse the repository at this point in the history
fixes #11889
  • Loading branch information
jdalsem committed Jan 15, 2020
1 parent 04355ad commit ed14adf
Show file tree
Hide file tree
Showing 7 changed files with 217 additions and 5 deletions.
55 changes: 55 additions & 0 deletions engine/classes/Elgg/Cli/UpgradeBatchCommand.php
@@ -0,0 +1,55 @@
<?php

namespace Elgg\Cli;

use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Input\InputArgument;
use Psr\Log\LogLevel;

/**
* elgg-cli upgrade:batch
*/
class UpgradeBatchCommand extends Command {

/**
* {@inheritdoc}
*/
protected function configure() {
$this->setName('upgrade:batch')
->setDescription(elgg_echo('cli:upgrade:batch:description'))
->addOption('force', 'f', InputOption::VALUE_NONE,
elgg_echo('cli:upgrade:batch:option:force')
)
->addArgument('upgrades', InputArgument::REQUIRED | InputArgument::IS_ARRAY,
elgg_echo('cli:upgrade:batch:argument:upgrades')
);
}

/**
* {@inheritdoc}
*/
protected function command() {
$upgrades = (array) $this->argument('upgrades');
$force = (bool) $this->option('force');

foreach ($upgrades as $upgrade_class) {
$upgrade = _elgg_services()->upgradeLocator->getUpgradeByClass($upgrade_class);
if (!$upgrade instanceof \ElggUpgrade) {
$this->log(LogLevel::WARNING, elgg_echo('cli:upgrade:batch:notfound', [$upgrade_class]));
continue;
}

if (!$force && $upgrade->isCompleted()) {
continue;
}

_elgg_services()->upgrades->executeUpgrade($upgrade);
}

if (!$this->option('quiet')) {
$this->write(elgg_echo('cli:upgrade:batch:finished'));
}

return 0;
}
}
26 changes: 26 additions & 0 deletions engine/classes/Elgg/Upgrade/Locator.php
Expand Up @@ -165,4 +165,30 @@ public function upgradeExists($upgrade_id) {
return $upgrades ? $upgrades[0] : false;
});
}

/**
* Check if there already is an ElggUpgrade for this upgrade class
*
* @param string $class_name name of the class used for the upgrade
*
* @return ElggUpgrade|false
*
* @since 3.3
*/
public function getUpgradeByClass(string $class_name) {
return elgg_call(ELGG_IGNORE_ACCESS, function () use ($class_name) {
$upgrades = \Elgg\Database\Entities::find([
'type' => 'object',
'subtype' => 'elgg_upgrade',
'private_setting_name_value_pairs' => [
[
'name' => 'class',
'value' => $class_name,
],
],
]);

return $upgrades ? $upgrades[0] : false;
});
}
}
1 change: 1 addition & 0 deletions engine/cli_commands.php
Expand Up @@ -12,5 +12,6 @@
\Elgg\Cli\PluginsActivateCommand::class,
\Elgg\Cli\PluginsDeactivateCommand::class,
\Elgg\Cli\SimpletestCommand::class,
\Elgg\Cli\UpgradeBatchCommand::class,
\Elgg\Cli\UpgradeCommand::class,
];
@@ -0,0 +1,52 @@
<?php

namespace Elgg\Cli;

use Elgg\IntegrationTestCase;
use Symfony\Component\Console\Application;
use Symfony\Component\Console\Tester\CommandTester;

/**
* @group Cli
*/
class UpgradeBatchCommandTest extends IntegrationTestCase {

public function up() {
self::createApplication([
'isolate'=> true,
]);
}

public function down() {

}

public function testExecuteWithoutOptions() {
$application = new Application();
$application->add(new UpgradeBatchCommand());

$command = $application->find('upgrade:batch');
$commandTester = new CommandTester($command);
$commandTester->execute([
'command' => $command->getName(),
'upgrades' => ['RandomNonExistingClass'],
]);

$this->assertStringContainsString(elgg_echo('cli:upgrade:batch:finished'), $commandTester->getDisplay());
}

public function testExecuteWithQuietOutput() {
$application = new Application();
$application->add(new UpgradeBatchCommand());

$command = $application->find('upgrade:batch');
$commandTester = new CommandTester($command);
$commandTester->execute([
'command' => $command->getName(),
'upgrades' => ['RandomNonExistingClass'],
'--quiet' => true,
]);

$this->assertEmpty($commandTester->getDisplay());
}
}
@@ -0,0 +1,77 @@
<?php

namespace Elgg;

use Elgg\Upgrade\AsynchronousUpgrade;
use Elgg\Upgrade\Result;

class LocatorIntegrationTest extends IntegrationTestCase {

/**
* @var \ElggUpgrade
*/
protected $upgrade_entity;

public function up() {

$batch = new UpgradeLocatorTestBatch();
$version = $batch->getVersion();

$upgrade = new \ElggUpgrade();
$upgrade->setClass(UpgradeLocatorTestBatch::class);
$upgrade->setId("test_plugin:$version");
$upgrade->title = "test_plugin:upgrade:$version:title";
$upgrade->description = "test_plugin:upgrade:$version:title";
$upgrade->access_id = ACCESS_PUBLIC;
$upgrade->save();

$this->upgrade_entity = $upgrade;
}

public function down() {
elgg_call(ELGG_IGNORE_ACCESS, function() {
$this->upgrade_entity->delete();
});
}

public function testCanGetExistingUpgradeFromId() {
$found_entity = _elgg_services()->upgradeLocator->upgradeExists($this->upgrade_entity->id);
$this->assertInstanceOf(\ElggUpgrade::class, $found_entity);
$this->assertEquals($this->upgrade_entity->guid, $found_entity->guid);
}

public function testCanGetExistingUpgradeByClass() {
$found_entity = _elgg_services()->upgradeLocator->getUpgradeByClass(UpgradeLocatorTestBatch::class);
$this->assertInstanceOf(\ElggUpgrade::class, $found_entity);
$this->assertEquals($this->upgrade_entity->guid, $found_entity->guid);
}
}

class UpgradeLocatorTestBatch implements AsynchronousUpgrade {

protected $_version;

public function getVersion() {
if (!isset($this->_version)) {
$this->_version = date('Ymd') . rand(10, 99);
}

return $this->_version;
}

public function needsIncrementOffset() {
return true;
}

public function shouldBeSkipped() {
return false;
}

public function countItems() {
return 100;
}

public function run(Result $result, $offset) {
$result->addSuccesses(10);
}
}
5 changes: 0 additions & 5 deletions engine/tests/phpunit/unit/Elgg/Upgrade/LocatorUnitTest.php
Expand Up @@ -52,11 +52,6 @@ public function testCanGetPluginUpgrade() {
});
}

public function testCanGetExistingUpgrade() {
// Can be implemented once PluginsSettingsTable::getEntities() is mocked
$this->markTestIncomplete();
}

public function testIgnoresNonRequiredUpgrade() {
$class = NonRequiredTestBatch::class;

Expand Down
6 changes: 6 additions & 0 deletions languages/en.php
Expand Up @@ -1757,6 +1757,12 @@
'cli:simpletest:error:file' => "%s is not a valid simpletest class",
'cli:simpletest:output:summary' => "Time: %.2f seconds, Memory: %.2fMb",

'cli:upgrade:batch:description' => "Executes one or more upgrades",
'cli:upgrade:batch:argument:upgrades' => "One or more upgrades (class names) to be executed",
'cli:upgrade:batch:option:force' => "Run upgrade even if it has been completed before",
'cli:upgrade:batch:finished' => "Running upgrades finished",
'cli:upgrade:batch:notfound' => "No upgrade class found for %s",

/**
* Languages according to ISO 639-1 (with a couple of exceptions)
*/
Expand Down

0 comments on commit ed14adf

Please sign in to comment.