diff --git a/CHANGELOG.md b/CHANGELOG.md index f642a44e..00a628c9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,14 @@ CHANGELOG for 3.X ================= +* 3.2.0 (2017-04-14) + * 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. + * Improve code quality, remove duplications on Composer Tasks. + * [PR#364] Allow to define custom timeout to Composer:Install + * 3.1.0 (2017-02-25) * Add new Exec task to execute arbitrary shell commands * Add new Composer task, to update phar (composer/self-update) diff --git a/docs/example-config.yml b/docs/example-config.yml index a3036b78..a59e97a4 100644 --- a/docs/example-config.yml +++ b/docs/example-config.yml @@ -3,6 +3,7 @@ magephp: production: user: app branch: test + from: ./ host_path: /var/www/test releases: 4 exclude: @@ -25,3 +26,6 @@ magephp: on-release: post-release: post-deploy: + - magic + custom_tasks: + - App\Deployment\MagicTask diff --git a/src/Mage.php b/src/Mage.php index 0f5455af..4944c52d 100644 --- a/src/Mage.php +++ b/src/Mage.php @@ -17,6 +17,6 @@ */ class Mage { - const VERSION = '3.1.0'; + const VERSION = '3.x-dev'; const CODENAME = 'Nostromo'; } diff --git a/src/Task/BuiltIn/Composer/AbstractComposerTask.php b/src/Task/BuiltIn/Composer/AbstractComposerTask.php new file mode 100644 index 00000000..bce2234c --- /dev/null +++ b/src/Task/BuiltIn/Composer/AbstractComposerTask.php @@ -0,0 +1,38 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Mage\Task\BuiltIn\Composer; + +use Mage\Task\AbstractTask; + +/** + * Abstract Composer Task + * + * @author Andrés Montañez + */ +abstract class AbstractComposerTask extends AbstractTask +{ + protected function getOptions() + { + $options = array_merge( + ['path' => 'composer'], + $this->getComposerOptions(), + $this->runtime->getMergedOption('composer'), + $this->options + ); + + return $options; + } + + protected function getComposerOptions() + { + return []; + } +} diff --git a/src/Task/BuiltIn/Composer/DumpAutoloadTask.php b/src/Task/BuiltIn/Composer/DumpAutoloadTask.php index af66d1ef..4e09bce5 100644 --- a/src/Task/BuiltIn/Composer/DumpAutoloadTask.php +++ b/src/Task/BuiltIn/Composer/DumpAutoloadTask.php @@ -11,14 +11,13 @@ namespace Mage\Task\BuiltIn\Composer; use Symfony\Component\Process\Process; -use Mage\Task\AbstractTask; /** * Composer Task - Generate Autoload * * @author Andrés Montañez */ -class DumpAutoloadTask extends AbstractTask +class DumpAutoloadTask extends AbstractComposerTask { public function getName() { @@ -41,14 +40,8 @@ public function execute() return $process->isSuccessful(); } - protected function getOptions() + protected function getComposerOptions() { - $options = array_merge( - ['path' => 'composer', 'flags' => '--optimize'], - $this->runtime->getMergedOption('composer'), - $this->options - ); - - return $options; + return ['flags' => '--optimize']; } } diff --git a/src/Task/BuiltIn/Composer/InstallTask.php b/src/Task/BuiltIn/Composer/InstallTask.php index 42299929..55a6a8d5 100644 --- a/src/Task/BuiltIn/Composer/InstallTask.php +++ b/src/Task/BuiltIn/Composer/InstallTask.php @@ -11,14 +11,13 @@ namespace Mage\Task\BuiltIn\Composer; use Symfony\Component\Process\Process; -use Mage\Task\AbstractTask; /** * Composer Task - Install Vendors * * @author Andrés Montañez */ -class InstallTask extends AbstractTask +class InstallTask extends AbstractComposerTask { public function getName() { @@ -36,19 +35,13 @@ public function execute() $cmd = sprintf('%s install %s', $options['path'], $options['flags']); /** @var Process $process */ - $process = $this->runtime->runCommand(trim($cmd)); + $process = $this->runtime->runCommand(trim($cmd), $options['timeout']); return $process->isSuccessful(); } - protected function getOptions() + protected function getComposerOptions() { - $options = array_merge( - ['path' => 'composer', 'flags' => '--optimize-autoloader'], - $this->runtime->getMergedOption('composer'), - $this->options - ); - - return $options; + return ['flags' => '--optimize-autoloader', 'timeout' => 120]; } } diff --git a/src/Task/BuiltIn/Composer/SelfUpdateTask.php b/src/Task/BuiltIn/Composer/SelfUpdateTask.php index f07fd519..153ba3f0 100644 --- a/src/Task/BuiltIn/Composer/SelfUpdateTask.php +++ b/src/Task/BuiltIn/Composer/SelfUpdateTask.php @@ -12,7 +12,6 @@ use Mage\Task\Exception\SkipException; use Symfony\Component\Process\Process; -use Mage\Task\AbstractTask; use DateTime; /** @@ -20,7 +19,7 @@ * * @author Yanick Witschi */ -class SelfUpdateTask extends AbstractTask +class SelfUpdateTask extends AbstractComposerTask { public function getName() { @@ -80,14 +79,8 @@ protected function getCompareDate() return $compareDate; } - protected function getOptions() + protected function getComposerOptions() { - $options = array_merge( - ['path' => 'composer', 'days' => 60], - $this->runtime->getMergedOption('composer'), - $this->options - ); - - return $options; + return ['days' => 60]; } } diff --git a/src/Task/BuiltIn/Deploy/RsyncTask.php b/src/Task/BuiltIn/Deploy/RsyncTask.php index 1dce74e2..b1ac64bf 100644 --- a/src/Task/BuiltIn/Deploy/RsyncTask.php +++ b/src/Task/BuiltIn/Deploy/RsyncTask.php @@ -45,7 +45,8 @@ public function execute() } $excludes = $this->getExcludes(); - $cmdRsync = sprintf('rsync -e "ssh -p %d %s" %s %s ./ %s@%s:%s', $sshConfig['port'], $sshConfig['flags'], $flags, $excludes, $user, $host, $targetDir); + $from = $this->runtime->getEnvOption('from', './'); + $cmdRsync = sprintf('rsync -e "ssh -p %d %s" %s %s %s %s@%s:%s', $sshConfig['port'], $sshConfig['flags'], $flags, $excludes, $from, $user, $host, $targetDir); /** @var Process $process */ $process = $this->runtime->runLocalCommand($cmdRsync, 600); @@ -54,7 +55,7 @@ public function execute() protected function getExcludes() { - $excludes = $this->runtime->getEnvOption('exclude', []); + $excludes = $this->runtime->getMergedOption('exclude', []); $excludes = array_merge(['.git'], array_filter($excludes)); foreach ($excludes as &$exclude) { diff --git a/src/Task/BuiltIn/Deploy/Tar/PrepareTask.php b/src/Task/BuiltIn/Deploy/Tar/PrepareTask.php index e694f8f0..fb0c5fe2 100644 --- a/src/Task/BuiltIn/Deploy/Tar/PrepareTask.php +++ b/src/Task/BuiltIn/Deploy/Tar/PrepareTask.php @@ -42,7 +42,8 @@ public function execute() $excludes = $this->getExcludes(); $flags = $this->runtime->getEnvOption('tar_create', 'cfzp'); - $cmdTar = sprintf('tar %s %s %s ./', $flags, $tarLocal, $excludes); + $from = $this->runtime->getEnvOption('from', './'); + $cmdTar = sprintf('tar %s %s %s %s', $flags, $tarLocal, $excludes, $from); /** @var Process $process */ $process = $this->runtime->runLocalCommand($cmdTar, 300); @@ -51,7 +52,7 @@ public function execute() protected function getExcludes() { - $excludes = $this->runtime->getEnvOption('exclude', []); + $excludes = $this->runtime->getMergedOption('exclude', []); $excludes = array_merge(['.git'], array_filter($excludes)); foreach ($excludes as &$exclude) { diff --git a/src/Task/BuiltIn/Symfony/AbstractSymfonyTask.php b/src/Task/BuiltIn/Symfony/AbstractSymfonyTask.php new file mode 100644 index 00000000..6ee9475c --- /dev/null +++ b/src/Task/BuiltIn/Symfony/AbstractSymfonyTask.php @@ -0,0 +1,38 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Mage\Task\BuiltIn\Symfony; + +use Mage\Task\AbstractTask; + +/** + * Abstract Symfony Task + * + * @author Andrés Montañez + */ +abstract class AbstractSymfonyTask extends AbstractTask +{ + protected function getOptions() + { + $options = array_merge( + ['console' => 'bin/console', 'env' => 'dev', 'flags' => ''], + $this->getSymfonyOptions(), + $this->runtime->getMergedOption('symfony'), + $this->options + ); + + return $options; + } + + protected function getSymfonyOptions() + { + return []; + } +} diff --git a/src/Task/BuiltIn/Symfony/AssetsInstallTask.php b/src/Task/BuiltIn/Symfony/AssetsInstallTask.php index 001d100f..d13300af 100644 --- a/src/Task/BuiltIn/Symfony/AssetsInstallTask.php +++ b/src/Task/BuiltIn/Symfony/AssetsInstallTask.php @@ -11,14 +11,13 @@ namespace Mage\Task\BuiltIn\Symfony; use Symfony\Component\Process\Process; -use Mage\Task\AbstractTask; /** * Symfony Task - Install Assets * * @author Andrés Montañez */ -class AssetsInstallTask extends AbstractTask +class AssetsInstallTask extends AbstractSymfonyTask { public function getName() { @@ -41,14 +40,8 @@ public function execute() return $process->isSuccessful(); } - protected function getOptions() + protected function getSymfonyOptions() { - $options = array_merge( - ['console' => 'bin/console', 'env' => 'dev', 'target' => 'web', 'flags' => '--symlink --relative'], - $this->runtime->getMergedOption('symfony'), - $this->options - ); - - return $options; + return ['target' => 'web', 'flags' => '--symlink --relative']; } } diff --git a/src/Task/BuiltIn/Symfony/CacheClearTask.php b/src/Task/BuiltIn/Symfony/CacheClearTask.php index a0b64751..a309ffa7 100644 --- a/src/Task/BuiltIn/Symfony/CacheClearTask.php +++ b/src/Task/BuiltIn/Symfony/CacheClearTask.php @@ -11,14 +11,13 @@ namespace Mage\Task\BuiltIn\Symfony; use Symfony\Component\Process\Process; -use Mage\Task\AbstractTask; /** * Symfony Task - Clear Cache * * @author Andrés Montañez */ -class CacheClearTask extends AbstractTask +class CacheClearTask extends AbstractSymfonyTask { public function getName() { @@ -40,15 +39,4 @@ public function execute() return $process->isSuccessful(); } - - protected function getOptions() - { - $options = array_merge( - ['console' => 'bin/console', 'env' => 'dev', 'flags' => ''], - $this->runtime->getMergedOption('symfony'), - $this->options - ); - - return $options; - } } diff --git a/src/Task/BuiltIn/Symfony/CacheWarmupTask.php b/src/Task/BuiltIn/Symfony/CacheWarmupTask.php index 8584beb2..d35f0a44 100644 --- a/src/Task/BuiltIn/Symfony/CacheWarmupTask.php +++ b/src/Task/BuiltIn/Symfony/CacheWarmupTask.php @@ -11,14 +11,13 @@ namespace Mage\Task\BuiltIn\Symfony; use Symfony\Component\Process\Process; -use Mage\Task\AbstractTask; /** * Symfony Task - Cache Warmup * * @author Andrés Montañez */ -class CacheWarmupTask extends AbstractTask +class CacheWarmupTask extends AbstractSymfonyTask { public function getName() { @@ -40,15 +39,4 @@ public function execute() return $process->isSuccessful(); } - - protected function getOptions() - { - $options = array_merge( - ['console' => 'bin/console', 'env' => 'dev', 'flags' => ''], - $this->runtime->getMergedOption('symfony'), - $this->options - ); - - return $options; - } } diff --git a/src/Task/TaskFactory.php b/src/Task/TaskFactory.php index 0a5950b3..68bd5c3e 100644 --- a/src/Task/TaskFactory.php +++ b/src/Task/TaskFactory.php @@ -42,6 +42,7 @@ public function __construct(Runtime $runtime) { $this->runtime = $runtime; $this->loadBuiltInTasks(); + $this->loadCustomTasks($runtime->getConfigOption('custom_tasks', [])); } /** @@ -102,11 +103,11 @@ protected function loadBuiltInTasks() /** @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 @@ protected function loadBuiltInTasks() } } } + + /** + * 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/Command/BuiltIn/DeployCommandMiscTasksTest.php b/tests/Command/BuiltIn/DeployCommandMiscTasksTest.php index ae13f8b3..c8be597d 100644 --- a/tests/Command/BuiltIn/DeployCommandMiscTasksTest.php +++ b/tests/Command/BuiltIn/DeployCommandMiscTasksTest.php @@ -80,6 +80,36 @@ public function testComposerFlags() $this->assertEquals(0, $tester->getStatusCode()); } + public function testGlobalExcludeFlags() + { + $application = new MageApplicationMockup(__DIR__ . '/../../Resources/global-exclude.yml'); + + /** @var AbstractCommand $command */ + $command = $application->find('deploy'); + $this->assertTrue($command instanceof DeployCommand); + + $tester = new CommandTester($command); + $tester->execute(['command' => $command->getName(), 'environment' => 'test']); + + $ranCommands = $application->getRuntime()->getRanCommands(); + + $testCase = array( + 0 => '/usr/bin/composer.phar install --prefer-source', + 1 => '/usr/bin/composer.phar dump-autoload --no-scripts', + 2 => 'rsync -e "ssh -p 22 -q -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no" -avz --exclude=.git --exclude=./var/cache/* --exclude=./var/log/* --exclude=./web/app_dev.php ./ tester@testhost:/var/www/test', + ); + + // 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 testComposerEnvFlags() { $application = new MageApplicationMockup(__DIR__ . '/../../Resources/composer-env.yml'); diff --git a/tests/Command/BuiltIn/DeployCommandWithReleasesTest.php b/tests/Command/BuiltIn/DeployCommandWithReleasesTest.php index 116bbd38..ead00533 100644 --- a/tests/Command/BuiltIn/DeployCommandWithReleasesTest.php +++ b/tests/Command/BuiltIn/DeployCommandWithReleasesTest.php @@ -68,6 +68,56 @@ public function testDeploymentWithReleasesCommands() $this->assertEquals(0, $tester->getStatusCode()); } + public function testDeploymentWithReleasesWithFromCommands() + { + $application = new MageApplicationMockup(__DIR__ . '/../../Resources/testhost-with-from.yml'); + + $application->getRuntime()->setReleaseId('20170101015120'); + + /** @var AbstractCommand $command */ + $command = $application->find('deploy'); + $this->assertTrue($command instanceof DeployCommand); + + $tester = new CommandTester($command); + $tester->execute(['command' => $command->getName(), 'environment' => 'test']); + + $ranCommands = $application->getRuntime()->getRanCommands(); + + $testCase = array( + 0 => 'git branch | grep "*"', + 1 => 'git checkout test', + 2 => 'git pull', + 3 => 'composer install --optimize-autoloader', + 4 => 'composer dump-autoload --optimize', + 5 => 'tar cfzp /tmp/mageXYZ --exclude=".git" --exclude="./var/cache/*" --exclude="./var/log/*" --exclude="./web/app_dev.php" ./dist', + 6 => 'ssh -p 22 -q -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no tester@testhost "mkdir -p /var/www/test/releases/1234567890"', + 7 => 'scp -P 22 -q -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no /tmp/mageXYZ tester@testhost:/var/www/test/releases/1234567890/mageXYZ', + 8 => 'ssh -p 22 -q -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no tester@testhost "cd /var/www/test/releases/1234567890 && tar xfzop mageXYZ"', + 9 => 'ssh -p 22 -q -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no tester@testhost "rm /var/www/test/releases/1234567890/mageXYZ"', + 10 => 'ssh -p 22 -q -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no tester@testhost "cd /var/www/test/releases/1234567890 && bin/console cache:warmup --env=dev"', + 11 => 'ssh -p 22 -q -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no tester@testhost "cd /var/www/test/releases/1234567890 && bin/console assets:install web --env=dev --symlink --relative"', + 12 => 'ssh -p 22 -q -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no tester@testhost "cd /var/www/test/releases/1234567890 && bin/console assetic:dump --env=dev"', + 13 => 'ssh -p 22 -q -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no tester@testhost "cd /var/www/test && ln -snf releases/1234567890 current"', + 14 => 'ssh -p 22 -q -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no tester@testhost "ls -1 /var/www/test/releases"', + 15 => 'ssh -p 22 -q -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no tester@testhost "rm -rf /var/www/test/releases/20170101015110"', + 16 => 'ssh -p 22 -q -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no tester@testhost "rm -rf /var/www/test/releases/20170101015111"', + 17 => 'ssh -p 22 -q -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no tester@testhost "rm -rf /var/www/test/releases/20170101015112"', + 18 => 'ssh -p 22 -q -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no tester@testhost "rm -rf /var/www/test/releases/20170101015113"', + 19 => 'rm /tmp/mageXYZ', + 20 => 'git checkout master', + ); + + // 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 testDeploymentWithoutReleasesTarPrepare() { $application = new MageApplicationMockup(__DIR__ . '/../../Resources/testhost-force-tar1.yml'); diff --git a/tests/Command/BuiltIn/DeployCommandWithoutReleasesTest.php b/tests/Command/BuiltIn/DeployCommandWithoutReleasesTest.php index a0e90f34..0ba490b3 100644 --- a/tests/Command/BuiltIn/DeployCommandWithoutReleasesTest.php +++ b/tests/Command/BuiltIn/DeployCommandWithoutReleasesTest.php @@ -55,6 +55,43 @@ public function testDeploymentWithoutReleasesCommands() $this->assertEquals(0, $tester->getStatusCode()); } + public function testDeploymentWithoutReleasesWithFromCommands() + { + $application = new MageApplicationMockup(__DIR__ . '/../../Resources/testhost-without-releases-with-from.yml'); + + /** @var AbstractCommand $command */ + $command = $application->find('deploy'); + $this->assertTrue($command instanceof DeployCommand); + + $tester = new CommandTester($command); + $tester->execute(['command' => $command->getName(), 'environment' => 'test']); + + $ranCommands = $application->getRuntime()->getRanCommands(); + + $testCase = array( + 0 => 'git branch | grep "*"', + 1 => 'git checkout test', + 2 => 'git pull', + 3 => 'composer install --optimize-autoloader', + 4 => 'composer dump-autoload --optimize', + 5 => 'rsync -e "ssh -p 22 -q -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no" -avz --exclude=.git --exclude=./var/cache/* --exclude=./var/log/* --exclude=./web/app_dev.php ./dist tester@testhost:/var/www/test', + 6 => 'ssh -p 22 -q -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no tester@testhost "cd /var/www/test && bin/console cache:warmup --env=dev"', + 7 => 'ssh -p 22 -q -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no tester@testhost "cd /var/www/test && bin/console assets:install web --env=dev --symlink --relative"', + 8 => 'ssh -p 22 -q -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no tester@testhost "cd /var/www/test && bin/console assetic:dump --env=dev"', + 9 => 'git checkout master', + ); + + // 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 testDeploymentFailMidway() { $application = new MageApplicationMockup(__DIR__ . '/../../Resources/testhost-without-releases.yml'); diff --git a/tests/Resources/custom-task-invalid-class.yml b/tests/Resources/custom-task-invalid-class.yml new file mode 100644 index 00000000..389c9c93 --- /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 00000000..bbc69bc6 --- /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 00000000..04f20df1 --- /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 00000000..f4f8beab --- /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/Resources/global-exclude.yml b/tests/Resources/global-exclude.yml new file mode 100644 index 00000000..cfa5ddfc --- /dev/null +++ b/tests/Resources/global-exclude.yml @@ -0,0 +1,17 @@ +magephp: + log_dir: /tmp + composer: + path: /usr/bin/composer.phar + exclude: + - ./var/cache/* + - ./var/log/* + - ./web/app_dev.php + environments: + test: + user: tester + host_path: /var/www/test + hosts: + - testhost + pre-deploy: + - composer/install: { flags: '--prefer-source' } + - composer/dump-autoload: { flags: '--no-scripts' } diff --git a/tests/Resources/testhost-with-from.yml b/tests/Resources/testhost-with-from.yml new file mode 100644 index 00000000..228730dd --- /dev/null +++ b/tests/Resources/testhost-with-from.yml @@ -0,0 +1,28 @@ +magephp: + log_dir: /tmp + environments: + test: + user: tester + branch: test + from: ./dist + host_path: /var/www/test + releases: 4 + exclude: + - ./var/cache/* + - ./var/log/* + - ./web/app_dev.php + - + - + hosts: + - testhost + pre-deploy: + - git/update + - composer/install + - composer/dump-autoload + on-deploy: + - symfony/cache-warmup: { env: 'dev' } + - symfony/assets-install: { env: 'dev' } + - symfony/assetic-dump: { env: 'dev' } + on-release: + post-release: + post-deploy: \ No newline at end of file diff --git a/tests/Resources/testhost-without-releases-with-from.yml b/tests/Resources/testhost-without-releases-with-from.yml new file mode 100644 index 00000000..d7b63eda --- /dev/null +++ b/tests/Resources/testhost-without-releases-with-from.yml @@ -0,0 +1,25 @@ +magephp: + log_dir: /tmp + environments: + test: + user: tester + branch: test + from: ./dist + host_path: /var/www/test + exclude: + - ./var/cache/* + - ./var/log/* + - ./web/app_dev.php + hosts: + - testhost + pre-deploy: + - git/update + - composer/install + - composer/dump-autoload + on-deploy: + - symfony/cache-warmup: { env: 'dev' } + - symfony/assets-install: { env: 'dev' } + - symfony/assetic-dump: { env: 'dev' } + on-release: + post-release: + post-deploy: \ No newline at end of file diff --git a/tests/Task/BuiltIn/Composer/BasicComposerTask.php b/tests/Task/BuiltIn/Composer/BasicComposerTask.php new file mode 100644 index 00000000..3261aefe --- /dev/null +++ b/tests/Task/BuiltIn/Composer/BasicComposerTask.php @@ -0,0 +1,43 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Mage\Tests\Task\BuiltIn\Composer; + +use Mage\Task\BuiltIn\Composer\AbstractComposerTask; +use Symfony\Component\Process\Process; + +/** + * Basic Composer Task + * + * @author Andrés Montañez + */ +class BasicComposerTask extends AbstractComposerTask +{ + public function getName() + { + return 'composer/help'; + } + + public function getDescription() + { + return '[Composer] Help'; + } + + public function execute() + { + $options = $this->getOptions(); + $cmd = sprintf('%s help', $options['path']); + + /** @var Process $process */ + $process = $this->runtime->runCommand(trim($cmd)); + + return $process->isSuccessful(); + } +} diff --git a/tests/Task/BuiltIn/Composer/BasicComposerTaskTest.php b/tests/Task/BuiltIn/Composer/BasicComposerTaskTest.php new file mode 100644 index 00000000..f8f63ac8 --- /dev/null +++ b/tests/Task/BuiltIn/Composer/BasicComposerTaskTest.php @@ -0,0 +1,36 @@ +setConfiguration(['environments' => ['test' => []]]); + $runtime->setEnvironment('test'); + + $task = new BasicComposerTask(); + $task->setRuntime($runtime); + $this->assertEquals('[Composer] Help', $task->getDescription()); + + $task->execute(); + + $ranCommands = $runtime->getRanCommands(); + $testCase = array( + 0 => 'composer help', + ); + + // Check total of Executed Commands + $this->assertEquals(count($testCase), count($ranCommands)); + + // Check Generated Commands + foreach ($testCase as $index => $command) { + $this->assertEquals($command, $ranCommands[$index]); + } + } + +} diff --git a/tests/Task/Custom/InvalidInheritanceTask.php b/tests/Task/Custom/InvalidInheritanceTask.php new file mode 100644 index 00000000..9fb04e88 --- /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 00000000..e7eff55f --- /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 00000000..ce2b1a8d --- /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 89725680..110c4f0a 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 @@ public function testNotExtendingAbstractTask() $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()); + } }