diff --git a/Changelog.md b/Changelog.md index ba7df554..c03b3b4a 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,5 +1,15 @@ # Changelog +## 3.0.2 / 2019-03-01 + + * Fix scaffolding of empty files via http + * Add support to limit files handled by twig by an extension as third parameter to copy_assets + * Add support for a dedicated projectFolder, add support for dependent variables, so you can compose variables from other variables + * strip first subfolder from filenames to copy when running app:scaffold, keep folder hierarchy for subsequents folders + * Refactor TaskContext::getStyle to TaskContext::io for clearer code + * Fix a bug on copyFrom for specific multi.site setups + * Fix bug when running app:scaffold where stages do not fire existing docker-tasks + ## 3.0.1 / 2019-02-25 ### Fixed diff --git a/bin/phab b/bin/phab index f9d2d992..2faf16ef 100755 --- a/bin/phab +++ b/bin/phab @@ -54,7 +54,7 @@ $application->setDispatcher($dispatcher); $version = '@git_tag@'; if ($version[0] == '@') { - $version = '3.0.0'; + $version = \Phabalicious\Utilities\Utilities::FALLBACK_VERSION; } $application->setVersion($version); diff --git a/src/Command/AppScaffoldCommand.php b/src/Command/AppScaffoldCommand.php index 5945aa97..2b2a79bd 100644 --- a/src/Command/AppScaffoldCommand.php +++ b/src/Command/AppScaffoldCommand.php @@ -144,56 +144,28 @@ protected function execute(InputInterface $input, OutputInterface $output) ]; $questions = !empty($data['questions']) ? $data['questions'] : []; - $helper = $this->getHelper('question'); - - foreach ($questions as $key => $question_data) { - $errors = new ValidationErrorBag(); - $validation = new ValidationService($question_data, $errors, 'questions'); - $validation->hasKey('question', 'Please provide a question'); - if (!empty($question_data['validation'])) { - $validation->hasKey('validation', 'Please provide a regex for validation'); - $validation->hasKey('error', 'Please provide an error message when a validation fails'); - } - if ($errors->hasErrors()) { - throw new ValidationFailedException($errors); - } + $context = new TaskContext($this, $input, $output); - $option_name = strtolower(preg_replace('%([a-z])([A-Z])%', '\1-\2', $key)); - if (in_array($option_name, $this->dynamicOptions)) { - $value = $input->getOption($option_name); - } else { - $question = new Question($question_data['question']. ': '); - $value = $helper->ask($input, $output, $question); - } - if (!empty($question_data['validation'])) { - if (!preg_match($question_data['validation'], $value)) { - throw new \InvalidArgumentException($question_data['error'] . ': ' . $value); - } - } - if (!empty($question_data['transform'])) { - $transform = strtolower($question_data['transform']); - $mapping = [ - 'lowercase' => 'strtolower', - 'uppercase' => 'strtoupper', - ]; - if (isset($mapping[$transform])) { - $value = call_user_func($mapping[$transform], $value); - } - } - $tokens[$key] = trim($value); - } + $tokens = $this->askQuestions($input, $questions, $context, $tokens); if (empty($tokens['name'])) { throw new \InvalidArgumentException('Missing `name` in questions, aborting!'); } - - $tokens['projectFolder'] = Utilities::cleanupString($tokens['name']); - $tokens['rootFolder'] = realpath($root_folder) . '/' . Utilities::cleanupString($tokens['name']); - - if (!empty($data['variables'])) { $tokens = Utilities::mergeData($data['variables'], $tokens); } + if (empty($tokens['projectFolder'])) { + $tokens['projectFolder'] = $tokens['name']; + } + + // Do a first round of replacements. + $replacements = $this->getReplacements($tokens); + foreach ($tokens as $ndx => $token) { + $tokens[$ndx] = strtr($token, $replacements); + } + + $tokens['projectFolder'] = Utilities::cleanupString($tokens['projectFolder']); + $tokens['rootFolder'] = realpath($root_folder) . '/' . $tokens['projectFolder']; $logger = $this->configuration->getLogger(); $shell = new LocalShellProvider($logger); @@ -203,7 +175,6 @@ protected function execute(InputInterface $input, OutputInterface $output) 'rootFolder' => realpath($input->getOption('output')), 'shellExecutable' => '/bin/bash' ], $shell); - $context = new TaskContext($this, $input, $output); $context->set('scriptData', $data['scaffold']); $context->set('variables', $tokens); @@ -212,6 +183,7 @@ protected function execute(InputInterface $input, OutputInterface $output) ]); $context->set('scaffoldData', $data); $context->set('tokens', $tokens); + $context->set('loaderBase', $twig_loader_base); // Setup twig $loader = new \Twig_Loader_Filesystem($twig_loader_base); @@ -220,19 +192,21 @@ protected function execute(InputInterface $input, OutputInterface $output) if (empty($input->getOption('override')) && is_dir($tokens['rootFolder'])) { - $question = new ConfirmationQuestion('Destination folder exists! Continue anyways? ', false); - if (!$helper->ask($input, $output, $question)) { + if (!$context->io()->confirm( + 'Destination folder exists! Continue anyways?', + false + )) { return 1; } } - $context->getStyle()->comment('Create destination folder ...'); + $context->io()->comment('Create destination folder ...'); $shell->run(sprintf('mkdir -p %s', $tokens['rootFolder'])); - $context->getStyle()->comment('Start scaffolding script ...'); + $context->io()->comment('Start scaffolding script ...'); $script->runScript($host_config, $context); - $context->getStyle()->success('Scaffolding finished successfully!'); + $context->io()->success('Scaffolding finished successfully!'); return 0; } @@ -240,19 +214,21 @@ protected function execute(InputInterface $input, OutputInterface $output) * @param TaskContextInterface $context * @param $target_folder * @param string $data_key + * @param bool $limitedForTwigExtension */ - public function copyAssets(TaskContextInterface $context, $target_folder, $data_key = 'assets') - { + public function copyAssets( + TaskContextInterface $context, + $target_folder, + $data_key = 'assets', + $limitedForTwigExtension = false + ) { if (!is_dir($target_folder)) { mkdir($target_folder, 0777, true); } $data = $context->get('scaffoldData'); $tokens = $context->get('tokens'); $is_remote = substr($data['base_path'], 0, 4) == 'http'; - $replacements = []; - foreach ($tokens as $key => $value) { - $replacements['%' . $key . '%'] = $value; - } + $replacements = $this->getReplacements($tokens); if (empty($data[$data_key])) { throw new \InvalidArgumentException('Scaffold-data does not contain ' . $data_key); @@ -262,7 +238,7 @@ public function copyAssets(TaskContextInterface $context, $target_folder, $data_ $tmp_target_file = false; if ($is_remote) { $tmpl = $this->configuration->readHttpResource($data['base_path'] . '/' . $file_name); - if (empty($tmpl)) { + if ($tmpl === false) { throw new \RuntimeException('Could not read remote asset: '. $data['base_path'] . '/' . $file_name); } $tmp_target_file = '/tmp/' . $file_name; @@ -271,14 +247,35 @@ public function copyAssets(TaskContextInterface $context, $target_folder, $data_ } file_put_contents('/tmp/' . $file_name, $tmpl); } - $converted = $this->twig->render($file_name, $tokens); + + if ($limitedForTwigExtension && + ('.' . pathinfo($file_name, PATHINFO_EXTENSION) !== $limitedForTwigExtension) + ) { + $converted = file_get_contents($context->get('loaderBase') . '/' . $file_name); + } else { + $converted = $this->twig->render($file_name, $tokens); + } + + if ($limitedForTwigExtension) { + $file_name = str_replace($limitedForTwigExtension, '', $file_name); + } + if ($tmp_target_file) { unlink($tmp_target_file); } - $target_file_name = $target_folder. '/' . strtr(basename($file_name), $replacements); - $context->getStyle()->comment(sprintf('Creating %s ...', $target_file_name)); - file_put_contents($target_file_name, $converted); + $file_name = strtr($file_name, $replacements); + if (strpos($file_name, '/') !== false) { + $file_name = substr($file_name, strpos($file_name, '/', 1) + 1); + } + + $target_file_path = $target_folder . '/' . $file_name; + if (!is_dir(dirname($target_file_path))) { + mkdir(dirname($target_file_path), 0777, true); + } + + $context->io()->comment(sprintf('Creating %s ...', $target_file_path)); + file_put_contents($target_file_path, $converted); } } @@ -290,4 +287,69 @@ private function fakeUUID() bin2hex(openssl_random_pseudo_bytes(2)) . '-' . bin2hex(openssl_random_pseudo_bytes(6)); } + + /** + * @param InputInterface $input + * @param array $questions + * @param TaskContext $context + * @param array $tokens + * @return array + * @throws ValidationFailedException + */ + protected function askQuestions(InputInterface $input, array $questions, TaskContext $context, array $tokens): array + { + foreach ($questions as $key => $question_data) { + $errors = new ValidationErrorBag(); + $validation = new ValidationService($question_data, $errors, 'questions'); + $validation->hasKey('question', 'Please provide a question'); + if (!empty($question_data['validation'])) { + $validation->hasKey('validation', 'Please provide a regex for validation'); + $validation->hasKey('error', 'Please provide an error message when a validation fails'); + } + if ($errors->hasErrors()) { + throw new ValidationFailedException($errors); + } + + $option_name = strtolower(preg_replace('%([a-z])([A-Z])%', '\1-\2', $key)); + if (in_array($option_name, $this->dynamicOptions)) { + $value = $input->getOption($option_name); + } else { + $value = $context->io()->ask( + $question_data['question'], + isset($question_data['default']) ? $question_data['default'] : null + ); + } + + if (!empty($question_data['validation'])) { + if (!preg_match($question_data['validation'], $value)) { + throw new \InvalidArgumentException($question_data['error'] . ': ' . $value); + } + } + if (!empty($question_data['transform'])) { + $transform = strtolower($question_data['transform']); + $mapping = [ + 'lowercase' => 'strtolower', + 'uppercase' => 'strtoupper', + ]; + if (isset($mapping[$transform])) { + $value = call_user_func($mapping[$transform], $value); + } + } + $tokens[$key] = trim($value); + } + return $tokens; + } + + /** + * @param $tokens + * @return array + */ + protected function getReplacements($tokens): array + { + $replacements = []; + foreach ($tokens as $key => $value) { + $replacements['%' . $key . '%'] = $value; + } + return $replacements; + } } diff --git a/src/Command/BackupCommand.php b/src/Command/BackupCommand.php index c8a0ac55..6e85f54c 100644 --- a/src/Command/BackupCommand.php +++ b/src/Command/BackupCommand.php @@ -72,7 +72,7 @@ protected function execute(InputInterface $input, OutputInterface $output) $files ); - $context->getStyle()->success('Backups created successfully!'); + $context->io()->success('Backups created successfully!'); } return $context->getResult('exitCode', 0); diff --git a/src/Command/GetBackupCommand.php b/src/Command/GetBackupCommand.php index 4d238f25..c61cce43 100644 --- a/src/Command/GetBackupCommand.php +++ b/src/Command/GetBackupCommand.php @@ -92,7 +92,7 @@ protected function execute(InputInterface $input, OutputInterface $output) if (count($files) > 0) { - $io = $context->getStyle(); + $io = $context->io(); $io->title('Copied backup-set:'); $io->table( ['Type', 'File'], diff --git a/src/Command/GetFileCommand.php b/src/Command/GetFileCommand.php index f85bf5e4..bd731bd8 100644 --- a/src/Command/GetFileCommand.php +++ b/src/Command/GetFileCommand.php @@ -53,7 +53,7 @@ protected function execute(InputInterface $input, OutputInterface $output) $context->set('sourceFile', $file); $context->set('destFile', getcwd()); - $context->getStyle()->comment('Get file `' . $file . '` from `' . $this->getHostConfig()['configName']. '`'); + $context->io()->comment('Get file `' . $file . '` from `' . $this->getHostConfig()['configName']. '`'); $this->getMethods()->runTask('getFile', $this->getHostConfig(), $context); diff --git a/src/Command/InstallCommand.php b/src/Command/InstallCommand.php index b7427174..f130b593 100644 --- a/src/Command/InstallCommand.php +++ b/src/Command/InstallCommand.php @@ -2,10 +2,8 @@ namespace Phabalicious\Command; -use Phabalicious\Configuration\HostType; use Phabalicious\Exception\EarlyTaskExitException; use Phabalicious\Method\TaskContext; -use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; @@ -56,28 +54,26 @@ protected function execute(InputInterface $input, OutputInterface $output) return $result; } + $context = new TaskContext($this, $input, $output); + $host_config = $this->getHostConfig(); if ($host_config['supportsInstalls'] == false) { throw new \InvalidArgumentException('This configuration disallows installs!'); } if (!$input->getOption('yes')) { - $helper = $this->getHelper('question'); - $question = new ConfirmationQuestion( - 'Install new database for configuration `' . $this->getHostConfig()['configName'] . '`? ', - false - ); - - if (!$helper->ask($input, $output, $question)) { + if (!$context->io()->confirm(sprintf( + 'Install new database for configuration `%s`?', + $this->getHostConfig()['configName'] + ), false)) { return 1; } } - $context = new TaskContext($this, $input, $output); $next_tasks = $input->getOption('skip-reset') ? [] : ['reset']; - $context->getStyle()->comment('Installing new app for `' . $this->getHostConfig()['configName']. '`'); + $context->io()->comment('Installing new app for `' . $this->getHostConfig()['configName']. '`'); try { $this->getMethods()->runTask('install', $this->getHostConfig(), $context, $next_tasks); diff --git a/src/Command/InstallFromCommand.php b/src/Command/InstallFromCommand.php index befb0a2d..673f2dbb 100644 --- a/src/Command/InstallFromCommand.php +++ b/src/Command/InstallFromCommand.php @@ -2,14 +2,10 @@ namespace Phabalicious\Command; -use Phabalicious\Configuration\HostType; -use Phabalicious\Exception\EarlyTaskExitException; -use Phabalicious\Method\TaskContext; use Stecman\Component\Symfony\Console\BashCompletion\CompletionContext; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; -use Symfony\Component\Console\Question\ConfirmationQuestion; class InstallFromCommand extends BaseCommand { diff --git a/src/Command/JiraCommand.php b/src/Command/JiraCommand.php index b467be93..f15174ba 100644 --- a/src/Command/JiraCommand.php +++ b/src/Command/JiraCommand.php @@ -68,8 +68,8 @@ protected function execute(InputInterface $input, OutputInterface $output) ); $issues = $client->search($jql); - $context->getStyle()->title('My open tickets on ' . $this->configuration->getSetting('name')); - $context->getStyle()->table( + $context->io()->title('My open tickets on ' . $this->configuration->getSetting('name')); + $context->io()->table( ['Key', 'Summary', 'Url'], array_map(function ($issue) use ($jira_config) { return [ diff --git a/src/Command/StartRemoteAccessCommand.php b/src/Command/StartRemoteAccessCommand.php index 8f396cfd..5dff58e8 100644 --- a/src/Command/StartRemoteAccessCommand.php +++ b/src/Command/StartRemoteAccessCommand.php @@ -78,15 +78,15 @@ protected function execute(InputInterface $input, OutputInterface $output) $port = $input->getOption('port'); $config = $context->getResult('config', $host_config); - $context->getStyle()->comment(sprintf('Starting remote access to %s:%s', $ip, $port)); - $context->getStyle()->success(sprintf( + $context->io()->comment(sprintf('Starting remote access to %s:%s', $ip, $port)); + $context->io()->success(sprintf( 'You should be able to access the remote via %s%s:%s', $this->getSchemeFromPort($port), $input->getOption('public-ip'), $input->getOption('public-port') )); - $context->getStyle()->comment('Usually this will open a new remote shell, type `exit` when you are finished.'); + $context->io()->comment('Usually this will open a new remote shell, type `exit` when you are finished.'); $host_config->shell()->startRemoteAccess( diff --git a/src/Method/DockerMethod.php b/src/Method/DockerMethod.php index 589be91e..456613da 100644 --- a/src/Method/DockerMethod.php +++ b/src/Method/DockerMethod.php @@ -110,7 +110,7 @@ public function docker(HostConfig $host_config, TaskContextInterface $context) $this->runTaskImpl($host_config, $context, $task, false); $this->runTaskImpl($host_config, $context, $task . 'Finished', true); - $context->getStyle()->success(sprintf('Task `%s` executed successfully!', $task)); + $context->io()->success(sprintf('Task `%s` executed successfully!', $task)); } /** @@ -222,7 +222,7 @@ public function waitForServices(HostConfig $hostconfig, TaskContextInterface $co $this->logger->notice('Error running supervisorctl, check the logs'); } if ($result->getExitCode() == 0 && ($count_running == $count_services)) { - $context->getStyle()->comment('Services up and running!'); + $context->io()->comment('Services up and running!'); return; } $tries++; @@ -317,7 +317,7 @@ private function copySSHKeys(HostConfig $hostconfig, TaskContextInterface $conte $data['source'] )); } else { - $context->getStyle()->comment(sprintf('File `%s does not exist, skipping!', $data['source'])); + $context->io()->comment(sprintf('File `%s does not exist, skipping!', $data['source'])); continue; } } @@ -328,7 +328,7 @@ private function copySSHKeys(HostConfig $hostconfig, TaskContextInterface $conte $shell->run(sprintf('#!docker cp %s %s:%s', $temp_file, $container_name, $dest)); $shell->run(sprintf('#!docker exec %s #!chmod %s %s', $container_name, $data['permissions'], $dest)); $shell->run(sprintf('rm %s', $temp_file)); - $context->getStyle()->comment(sprintf('Handled %s successfully!', $dest)); + $context->io()->comment(sprintf('Handled %s successfully!', $dest)); } $shell->run(sprintf('#!docker exec %s #!chmod 700 /root/.ssh', $container_name)); $shell->run(sprintf('#!docker exec %s #!chown -R root /root/.ssh', $container_name)); @@ -489,8 +489,8 @@ public function runAppSpecificTask(HostConfig $host_config, TaskContextInterface $docker_config = $this->getDockerConfig($host_config, $context); $shell = $docker_config->shell(); - if (in_array($current_stage['stage'], $docker_config['tasks']) || - in_array($current_stage['stage'], array('spinUp', 'spinDown', 'deleteContainer', 'prepareDestination')) + if (isset($docker_config['tasks'][$current_stage['stage']]) || + in_array($current_stage['stage'], array('spinUp', 'spinDown', 'deleteContainer')) ) { $this->runTaskImpl($host_config, $context, $current_stage['stage'], false); } diff --git a/src/Method/DrushMethod.php b/src/Method/DrushMethod.php index e004309d..29e2e99e 100644 --- a/src/Method/DrushMethod.php +++ b/src/Method/DrushMethod.php @@ -496,7 +496,7 @@ public function copyFrom(HostConfig $host_config, TaskContextInterface $context) $shell = $this->getShell($host_config, $context); $from_shell = $context->get('fromShell', $from_config->shell()); - $context->getStyle()->comment(sprintf('Dumping database of `%s` ...', $from_config['configName'])); + $context->io()->comment(sprintf('Dumping database of `%s` ...', $from_config['configName'])); $from_filename = $from_config['tmpFolder'] . '/' . $from_config['configName'] . '.' . date('YmdHms') . '.sql'; $from_filename = $this->backupSQL($from_config, $context, $from_shell, $from_filename); @@ -504,7 +504,7 @@ public function copyFrom(HostConfig $host_config, TaskContextInterface $context) $to_filename = $host_config['tmpFolder'] . '/' . basename($from_filename); // Copy filename to host - $context->getStyle()->comment(sprintf( + $context->io()->comment(sprintf( 'Copying dump from `%s` to `%s` ...', $from_config['configName'], $host_config['configName'] @@ -519,11 +519,12 @@ public function copyFrom(HostConfig $host_config, TaskContextInterface $context) $from_shell->run(sprintf(' rm %s', $from_filename)); // Import db. - $context->getStyle()->comment(sprintf( + $context->io()->comment(sprintf( 'Importing dump into `%s` ...', $host_config['configName'] )); + $shell->cd($host_config['siteFolder']); $result = $this->importSqlFromFile($shell, $to_filename, true); if (!$result->succeeded()) { $result->throwException('Could not import DB from file `' . $to_filename . '`'); @@ -531,7 +532,7 @@ public function copyFrom(HostConfig $host_config, TaskContextInterface $context) $shell->run(sprintf('rm %s', $to_filename)); - $context->getStyle()->success('Copied the database successfully!'); + $context->io()->success('Copied the database successfully!'); } public function appUpdate(HostConfig $host_config, TaskContextInterface $context) diff --git a/src/Method/ScriptMethod.php b/src/Method/ScriptMethod.php index 7ff5ca26..aa1df751 100644 --- a/src/Method/ScriptMethod.php +++ b/src/Method/ScriptMethod.php @@ -98,7 +98,7 @@ public function runScript(HostConfig $host_config, TaskContextInterface $context $context->setResult('exitCode', $result ? $result->getExitCode() : 0); $context->setResult('commandResult', $result); } catch (UnknownReplacementPatternException $e) { - $context->getStyle()->error('Unknown replacement in line ' . $e->getOffendingLine()); + $context->io()->error('Unknown replacement in line ' . $e->getOffendingLine()); $printed_replacements = array_map(function ($key) use ($replacements) { $value = $replacements[$key]; @@ -107,7 +107,7 @@ public function runScript(HostConfig $host_config, TaskContextInterface $context } return [$key, $value]; }, array_keys($replacements)); - $context->getStyle()->table(['Key', 'Replacement'], $printed_replacements); + $context->io()->table(['Key', 'Replacement'], $printed_replacements); } } diff --git a/src/Method/TaskContext.php b/src/Method/TaskContext.php index 1ec438cc..f1e19bba 100644 --- a/src/Method/TaskContext.php +++ b/src/Method/TaskContext.php @@ -173,7 +173,7 @@ public function getPasswordManager() /** * @return SymfonyStyle */ - public function getStyle() + public function io() { if (!$this->io) { $this->io = new SymfonyStyle($this->getInput(), $this->getOutput()); diff --git a/src/Method/TaskContextInterface.php b/src/Method/TaskContextInterface.php index 6d41c239..306418cc 100644 --- a/src/Method/TaskContextInterface.php +++ b/src/Method/TaskContextInterface.php @@ -67,5 +67,5 @@ public function getPasswordManager(); /** * @return SymfonyStyle */ - public function getStyle(); + public function io(); } diff --git a/src/Utilities/Utilities.php b/src/Utilities/Utilities.php index ef997f89..f70f639c 100644 --- a/src/Utilities/Utilities.php +++ b/src/Utilities/Utilities.php @@ -5,6 +5,8 @@ class Utilities { + const FALLBACK_VERSION = '3.0.0'; + public static function mergeData(array $data, array $override_data): array { $result = $data; @@ -134,7 +136,11 @@ public static function cleanupString($identifier) ]; $identifier = strtr($identifier, $filter); - $identifier = preg_replace('/[^\\x{002D}\\x{0030}-\\x{0039}\\x{0041}-\\x{005A}\\x{005F}\\x{0061}-\\x{007A}\\x{00A1}-\\x{FFFF}]/u', '', $identifier); + $identifier = preg_replace( + '/[^\\x{002D}\\x{0030}-\\x{0039}\\x{0041}-\\x{005A}\\x{005F}\\x{0061}-\\x{007A}\\x{00A1}-\\x{FFFF}]/u', + '', + $identifier + ); // Convert everything to lower case. return strtolower($identifier); diff --git a/tests/AppCreateCommandTest.php b/tests/AppCreateCommandTest.php new file mode 100644 index 00000000..c687d122 --- /dev/null +++ b/tests/AppCreateCommandTest.php @@ -0,0 +1,83 @@ +application = new Application(); + $this->application->setVersion(Utilities::FALLBACK_VERSION); + $logger = $this->getMockBuilder(LoggerInterface::class)->getMock(); + + $configuration = new ConfigurationService($this->application, $logger); + $method_factory = new MethodFactory($configuration, $logger); + $method_factory->addMethod(new ScriptMethod($logger)); + $method_factory->addMethod(new DockerMethod($logger)); + + $configuration->readConfiguration(getcwd() . '/assets/app-create-tests/fabfile.yaml'); + + $this->application->add(new AppCreateCommand($configuration, $method_factory)); + $this->application->add(new ResetCommand($configuration, $method_factory)); + } + + public function testAppCreateWithoutPrepare() + { + $target_folder = getcwd() . '/tmp'; + if (!is_dir($target_folder)) { + mkdir($target_folder); + } + + $command = $this->application->find('app:create'); + $commandTester = new CommandTester($command); + $commandTester->execute(array( + '--config' => 'test', + )); + + // the output of the command in the console + $output = $commandTester->getDisplay(); + $this->assertNotContains('Could not validate', $output); + $this->assertContains('XX Spin up XX', $output); + $this->assertContains('XX Install XX', $output); + + shell_exec(sprintf('rm -rf %s', $target_folder)); + } + + public function testAppCreateWithPrepare() + { + $target_folder = getcwd() . '/tmp'; + if (!is_dir($target_folder)) { + mkdir($target_folder); + } + + $command = $this->application->find('app:create'); + $commandTester = new CommandTester($command); + $commandTester->execute(array( + '--config' => 'testWithPrepare', + )); + + // the output of the command in the console + $output = $commandTester->getDisplay(); + $this->assertNotContains('Could not validate', $output); + $this->assertContains('XX Spin up XX', $output); + $this->assertContains('XX prepareDestination XX', $output); + $this->assertContains('XX Install XX', $output); + + shell_exec(sprintf('rm -rf %s', $target_folder)); + } +} diff --git a/tests/AppScaffoldCommandTest.php b/tests/AppScaffoldCommandTest.php index 19f2eb46..236a247d 100644 --- a/tests/AppScaffoldCommandTest.php +++ b/tests/AppScaffoldCommandTest.php @@ -9,7 +9,6 @@ namespace Phabalicious\Tests; use Phabalicious\Command\AppScaffoldCommand; -use Phabalicious\Command\GetPropertyCommand; use Phabalicious\Configuration\ConfigurationService; use Phabalicious\Method\MethodFactory; use Phabalicious\Method\ScriptMethod; @@ -149,6 +148,64 @@ public function testScaffoldQuestions() $this->assertContains('Shortname: tst', $output); } + public function testScaffoldSubfolder() + { + $root = getcwd(); + $target_folder = $root . '/tmp/here'; + if (!is_dir($target_folder)) { + mkdir($target_folder, 0777, true); + } + + chdir($target_folder); + + $command = $this->application->find('app:scaffold'); + $commandTester = new CommandTester($command); + $commandTester->execute(array( + '--short-name' => 'TST', + '--name' => 'Test', + '--output' => '.', + '--override' => true, + 'scaffold-url' => $root . '/assets/scaffold-tests/scaffold-subfolder.yml' + )); + + $this->checkFileContent( + $target_folder . '/test/web/modules/custom/tst_utils/tst_utils.info.yml', + 'name: Test utils module' + ); + $this->checkFileContent( + $target_folder . '/test/web/modules/custom/tst_utils/tst_utils.install', + 'function tst_utils_install()' + ); + } + public function testScaffoldExistingProjectFolder() + { + $root = getcwd(); + $target_folder = $root . '/tmp/tst-test'; + if (!is_dir($target_folder)) { + mkdir($target_folder, 0777, true); + } + + chdir($root . '/tmp'); + + $command = $this->application->find('app:scaffold'); + $commandTester = new CommandTester($command); + $commandTester->execute(array( + '--short-name' => 'TST', + '--name' => 'Test', + '--override' => true, + 'scaffold-url' => $root . '/assets/scaffold-tests/scaffold-projectfolder.yml' + )); + + $this->checkFileContent( + $target_folder . '/web/modules/custom/tst_utils/tst_utils.info.yml', + 'name: Test utils module' + ); + $this->checkFileContent( + $target_folder . '/web/modules/custom/tst_utils/tst_utils.install', + 'function tst_utils_install()' + ); + } + private function checkFileContent($filename, $needle) { $haystack = file_get_contents($filename); diff --git a/tests/InstallCommandTest.php b/tests/InstallCommandTest.php index 7a035061..10e3440d 100644 --- a/tests/InstallCommandTest.php +++ b/tests/InstallCommandTest.php @@ -1,10 +1,4 @@