diff --git a/CHANGELOG.md b/CHANGELOG.md index 4772627..7d758f6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ CHANGELOG for 3.X ================= * 3.2.0 (2017-04-xx) + * Allow to pre-register Custom Tasks * [PR#365] New option "from" to define deployment start point * Allow to define excludes in the global scope. * Improve code quality, remove duplications on Symfony Tasks. diff --git a/docs/example-config.yml b/docs/example-config.yml index e6ab14b..e1a5cb2 100644 --- a/docs/example-config.yml +++ b/docs/example-config.yml @@ -26,3 +26,6 @@ magephp: on-release: post-release: post-deploy: + - magic + custom_tasks: + - App\Deployment\MagicTask \ No newline at end of file diff --git a/src/Task/TaskFactory.php b/src/Task/TaskFactory.php index 0a5950b..68bd5c3 100644 --- a/src/Task/TaskFactory.php +++ b/src/Task/TaskFactory.php @@ -42,6 +42,7 @@ class TaskFactory { $this->runtime = $runtime; $this->loadBuiltInTasks(); + $this->loadCustomTasks($runtime->getConfigOption('custom_tasks', [])); } /** @@ -102,11 +103,11 @@ class TaskFactory /** @var SplFileInfo $file */ foreach ($finder as $file) { - $class = substr('\\Mage\\Task\\BuiltIn\\' . str_replace('/', '\\', $file->getRelativePathname()), 0, -4); - if (class_exists($class)) { - $reflex = new ReflectionClass($class); + $taskClass = substr('\\Mage\\Task\\BuiltIn\\' . str_replace('/', '\\', $file->getRelativePathname()), 0, -4); + if (class_exists($taskClass)) { + $reflex = new ReflectionClass($taskClass); if ($reflex->isInstantiable()) { - $task = new $class(); + $task = new $taskClass(); if ($task instanceof AbstractTask) { $this->add($task); } @@ -114,4 +115,31 @@ class TaskFactory } } } + + /** + * Load Custom Tasks + * @param array $tasksToLoad PreRegistered Tasks + * @throws RuntimeException + */ + protected function loadCustomTasks($tasksToLoad) + { + foreach ($tasksToLoad as $taskClass) { + if (!class_exists($taskClass)) { + throw new RuntimeException(sprintf('Custom Task "%s" does not exists.', $taskClass)); + } + + $reflex = new ReflectionClass($taskClass); + if (!$reflex->isInstantiable()) { + throw new RuntimeException(sprintf('Custom Task "%s" can not be instantiated.', $taskClass)); + } + + $task = new $taskClass(); + if (!$task instanceof AbstractTask) { + throw new RuntimeException(sprintf('Custom Task "%s" must inherit "Mage\\Task\\AbstractTask".', $taskClass)); + } + + // Add Task + $this->add($task); + } + } } diff --git a/tests/Resources/custom-task-invalid-class.yml b/tests/Resources/custom-task-invalid-class.yml new file mode 100644 index 0000000..389c9c9 --- /dev/null +++ b/tests/Resources/custom-task-invalid-class.yml @@ -0,0 +1,13 @@ +magephp: + environments: + production: + user: app + host_path: /var/www/myapp + hosts: + - webserver + pre-deploy: + on-deploy: + - custom-invalid-class + post-deploy: + custom_tasks: + - Mage\Tests\Task\Custom\InvalidClass diff --git a/tests/Resources/custom-task-invalid-inheritance.yml b/tests/Resources/custom-task-invalid-inheritance.yml new file mode 100644 index 0000000..bbc69bc --- /dev/null +++ b/tests/Resources/custom-task-invalid-inheritance.yml @@ -0,0 +1,13 @@ +magephp: + environments: + production: + user: app + host_path: /var/www/myapp + hosts: + - webserver + pre-deploy: + on-deploy: + - custom-invalid-inheritance + post-deploy: + custom_tasks: + - Mage\Tests\Task\Custom\InvalidInheritanceTask diff --git a/tests/Resources/custom-task-not-instantiable.yml b/tests/Resources/custom-task-not-instantiable.yml new file mode 100644 index 0000000..04f20df --- /dev/null +++ b/tests/Resources/custom-task-not-instantiable.yml @@ -0,0 +1,13 @@ +magephp: + environments: + production: + user: app + host_path: /var/www/myapp + hosts: + - webserver + pre-deploy: + on-deploy: + - custom-not-instantiable + post-deploy: + custom_tasks: + - Mage\Tests\Task\Custom\NotInstantiableTask diff --git a/tests/Resources/custom-task.yml b/tests/Resources/custom-task.yml new file mode 100644 index 0000000..f4f8bea --- /dev/null +++ b/tests/Resources/custom-task.yml @@ -0,0 +1,13 @@ +magephp: + environments: + production: + user: app + host_path: /var/www/myapp + hosts: + - webserver + pre-deploy: + on-deploy: + - custom-valid + post-deploy: + custom_tasks: + - Mage\Tests\Task\Custom\ValidTask diff --git a/tests/Task/Custom/InvalidInheritanceTask.php b/tests/Task/Custom/InvalidInheritanceTask.php new file mode 100644 index 0000000..9fb04e8 --- /dev/null +++ b/tests/Task/Custom/InvalidInheritanceTask.php @@ -0,0 +1,47 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Mage\Tests\Task\Custom; + +use Symfony\Component\Process\Process; + +/** + * Custom PreRegistered Task for Testing + * + * @author Andrés Montañez + */ +class InvalidInheritanceTask +{ + /** + * @return string + */ + public function getName() + { + return 'custom-invalid-inheritance'; + } + + /** + * @return string + */ + public function getDescription() + { + return '[Custom] Invalid Inheritance*'; + } + + /** + * @return bool + */ + public function execute() + { + /** @var Process $process */ + $process = $this->runtime->runCommand('echo "custom-invalid-inheritance"'); + return $process->isSuccessful(); + } +} diff --git a/tests/Task/Custom/NotInstantiableTask.php b/tests/Task/Custom/NotInstantiableTask.php new file mode 100644 index 0000000..e7eff55 --- /dev/null +++ b/tests/Task/Custom/NotInstantiableTask.php @@ -0,0 +1,48 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Mage\Tests\Task\Custom; + +use Mage\Task\AbstractTask; +use Symfony\Component\Process\Process; + +/** + * Custom PreRegistered Task for Testing + * + * @author Andrés Montañez + */ +abstract class NotInstantiableTask extends AbstractTask +{ + /** + * @return string + */ + public function getName() + { + return 'custom-not-instantiable'; + } + + /** + * @return string + */ + public function getDescription() + { + return '[Custom] Not Instantiable*'; + } + + /** + * @return bool + */ + public function execute() + { + /** @var Process $process */ + $process = $this->runtime->runCommand('echo "custom-not-instantiable"'); + return $process->isSuccessful(); + } +} diff --git a/tests/Task/Custom/ValidTask.php b/tests/Task/Custom/ValidTask.php new file mode 100644 index 0000000..ce2b1a8 --- /dev/null +++ b/tests/Task/Custom/ValidTask.php @@ -0,0 +1,48 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Mage\Tests\Task\Custom; + +use Mage\Task\AbstractTask; +use Symfony\Component\Process\Process; + +/** + * Custom PreRegistered Task for Testing + * + * @author Andrés Montañez + */ +class ValidTask extends AbstractTask +{ + /** + * @return string + */ + public function getName() + { + return 'custom-valid'; + } + + /** + * @return string + */ + public function getDescription() + { + return '[Custom] Valid*'; + } + + /** + * @return bool + */ + public function execute() + { + /** @var Process $process */ + $process = $this->runtime->runCommand('echo "custom-valid"'); + return $process->isSuccessful(); + } +} diff --git a/tests/Task/TaskFactoryTest.php b/tests/Task/TaskFactoryTest.php index 8972568..110c4f0 100644 --- a/tests/Task/TaskFactoryTest.php +++ b/tests/Task/TaskFactoryTest.php @@ -10,11 +10,15 @@ namespace Mage\Tests\Task; +use Mage\Command\AbstractCommand; +use Mage\Command\BuiltIn\DeployCommand; use Mage\Task\TaskFactory; use Mage\Runtime\Runtime; use Mage\Runtime\Exception\RuntimeException; use Exception; +use Mage\Tests\MageApplicationMockup; use PHPUnit_Framework_TestCase as TestCase; +use Symfony\Component\Console\Tester\CommandTester; class TaskFactoryTest extends TestCase { @@ -43,4 +47,83 @@ class TaskFactoryTest extends TestCase $this->assertEquals('Invalid task name "stdClass"', $exception->getMessage()); } } + + public function testPreRegisteredCustomTask() + { + $application = new MageApplicationMockup(__DIR__ . '/../Resources/custom-task.yml'); + + /** @var AbstractCommand $command */ + $command = $application->find('deploy'); + $this->assertTrue($command instanceof DeployCommand); + + $tester = new CommandTester($command); + $tester->execute(['command' => $command->getName(), 'environment' => 'production']); + + $this->assertContains('[Custom] Valid*', $tester->getDisplay()); + + $ranCommands = $application->getRuntime()->getRanCommands(); + + $testCase = array( + 0 => 'rsync -e "ssh -p 22 -q -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no" -avz --exclude=.git ./ app@webserver:/var/www/myapp', + 1 => 'ssh -p 22 -q -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no app@webserver "cd /var/www/myapp && echo \"custom-valid\""', + ); + + // Check total of Executed Commands + $this->assertEquals(count($testCase), count($ranCommands)); + + // Check Generated Commands + foreach ($testCase as $index => $command) { + $this->assertEquals($command, $ranCommands[$index]); + } + + $this->assertEquals(0, $tester->getStatusCode()); + } + + public function testPreRegisteredCustomTaskInvalidClass() + { + $application = new MageApplicationMockup(__DIR__ . '/../Resources/custom-task-invalid-class.yml'); + + /** @var AbstractCommand $command */ + $command = $application->find('deploy'); + $this->assertTrue($command instanceof DeployCommand); + + $tester = new CommandTester($command); + $tester->execute(['command' => $command->getName(), 'environment' => 'production']); + + $this->assertContains('Custom Task "Mage\Tests\Task\Custom\InvalidClass" does not exists.', $tester->getDisplay()); + + $this->assertNotEquals(0, $tester->getStatusCode()); + } + + public function testPreRegisteredCustomTaskNonInstantiable() + { + $application = new MageApplicationMockup(__DIR__ . '/../Resources/custom-task-not-instantiable.yml'); + + /** @var AbstractCommand $command */ + $command = $application->find('deploy'); + $this->assertTrue($command instanceof DeployCommand); + + $tester = new CommandTester($command); + $tester->execute(['command' => $command->getName(), 'environment' => 'production']); + + $this->assertContains('Custom Task "Mage\Tests\Task\Custom\NotInstantiableTask" can not be instantiated.', $tester->getDisplay()); + + $this->assertNotEquals(0, $tester->getStatusCode()); + } + + public function testPreRegisteredCustomTaskInvalidInheritance() + { + $application = new MageApplicationMockup(__DIR__ . '/../Resources/custom-task-invalid-inheritance.yml'); + + /** @var AbstractCommand $command */ + $command = $application->find('deploy'); + $this->assertTrue($command instanceof DeployCommand); + + $tester = new CommandTester($command); + $tester->execute(['command' => $command->getName(), 'environment' => 'production']); + + $this->assertContains('Custom Task "Mage\Tests\Task\Custom\InvalidInheritanceTask" must inherit "Mage\Task\AbstractTask".', $tester->getDisplay()); + + $this->assertNotEquals(0, $tester->getStatusCode()); + } }