protected function execute(InputInterface $input, OutputInterface $output) { $output->writeln('Hello Terra!'); // Ask for an app and environment. $this->getApp($input, $output); $this->getEnvironment($input, $output); $environment_factory = new EnvironmentFactory($this->environment, $this->app); $environment_factory->getConfig(); // Run the tests // @TODO: Move to factory. $output->writeln('<info>TERRA</info> | <comment>Test: Start...</comment>'); $output->writeln('<info>TERRA</info> | ' . $environment_factory->config['hooks']['test']); // Set environment variables for behat tests $env = array(); $env['HOME'] = $_SERVER['HOME']; $behat_vars = array('extensions' => array('Behat\\MinkExtension' => array('base_url' => 'http://' . $environment_factory->getUrl()))); // @TODO: This is NOT WORKING. We MUST figure out how to override the base_url. $env['BEHAT_PARAMS'] = json_encode($behat_vars); $process = new Process($environment_factory->config['hooks']['test'], $environment_factory->getSourcePath(), $env); $process->run(function ($type, $buffer) { if (Process::ERR === $type) { echo $buffer; } else { echo $buffer; } }); if (!$process->isSuccessful()) { $output->writeln('<info>TERRA</info> | <fg=red>Test Failed</> ' . $hook); } else { $output->writeln('<info>TERRA</info> | <info>Test Passed: </info> ' . $hook); } $output->writeln(''); }
protected function execute(InputInterface $input, OutputInterface $output) { // Ask for an app and environment. $this->getApp($input, $output); $this->getEnvironment($input, $output); $environment_name = $this->environment->name; $app_name = $this->app->name; // Confirm removal of the app. $helper = $this->getHelper('question'); $question = new ConfirmationQuestion("Are you sure you would like to remove the environment <question>{$app_name}:{$environment_name}</question>? All files at {$this->environment->path} will be deleted, and all containers will be killed. [y/N] ", false); if (!$helper->ask($input, $output, $question)) { $output->writeln('<error>Cancelled</error>'); return; } else { // Remove the environment from config registry. // @TODO: Move this to EnvironmentFactory class // Remove files $fs = new Filesystem(); try { $fs->remove(array($this->environment->path)); $output->writeln("<info>Files for environment {$app_name}:{$environment_name} has been deleted.</info>"); } catch (IOExceptionInterface $e) { $output->writeln('<error>Unable to remove ' . $e->getPath() . '</error>'); } // Destroy the environment $environmentFactory = new EnvironmentFactory($this->environment, $this->app); $environmentFactory->destroy(); unset($this->app->environments[$environment_name]); $this->getApplication()->getTerra()->getConfig()->add('apps', $app_name, (array) $this->app); $this->getApplication()->getTerra()->getConfig()->save(); $output->writeln("<info>Environment {$app_name}:{$environment_name} has been removed.</info>"); } }
protected function execute(InputInterface $input, OutputInterface $output) { // If there are no apps, return if (count($this->getApplication()->getTerra()->getConfig()->get('apps')) == 0) { $output->writeln("<comment>There are no apps to remove!</comment>"); $output->writeln("Use the command <info>terra app:add</info> to add your first app."); return; } $helper = $this->getHelper('question'); $app_name = $input->getArgument('app_name'); $environment_name = $input->getArgument('environment_name'); // If no name specified provide options if (empty($app_name)) { $question = new ChoiceQuestion('Which app? ', array_keys($this->getApplication()->getTerra()->getConfig()->get('apps')), NULL); $app_name = $helper->ask($input, $output, $question); } $app = $this->getApplication()->getTerra()->getConfig()->get('apps', $app_name); // If no environments: if (count($app['environments']) == 0) { $output->writeln("<comment>There are no environments for the app {$app_name}!</comment>"); $output->writeln("Use the command <info>terra environment:add</info> to add your first environment."); return; } // If no environment name specified provide options if (empty($environment_name)) { $question = new ChoiceQuestion('Which environment? ', array_keys($app['environments']), NULL); $environment_name = $helper->ask($input, $output, $question); } $environment = $app['environments'][$environment_name]; // Confirm removal of the app. $question = new ConfirmationQuestion("Are you sure you would like to remove the environment <question>{$app_name}:{$environment_name}</question>? All files at {$environment['path']} will be deleted, and all containers will be killed.", false); if (!$helper->ask($input, $output, $question)) { $output->writeln('<error>Cancelled</error>'); return; } else { // Remove the environment from config registry. // @TODO: Move this to EnvironmentFactory class // Remove files $fs = new Filesystem(); try { $fs->remove(array($environment['path'])); $output->writeln("<info>Files for environment {$app_name}:{$environment_name} has been deleted.</info>"); } catch (IOExceptionInterface $e) { $output->writeln("<error>Unable to remove " . $e->getPath() . "</error>"); } // Run docker-compose kill $environmentFactory = new EnvironmentFactory($environment, $app); // @TODO: Remove ~/.terra/environments/* folder. if ($environmentFactory->destroy()) { $output->writeln("<info>Killed the docker containers.</info>"); } unset($app['environments'][$environment_name]); $this->getApplication()->getTerra()->getConfig()->add('apps', $app_name, $app); $this->getApplication()->getTerra()->getConfig()->save(); $output->writeln("<info>Environment {$app_name}:{$environment_name} has been removed.</info>"); } }
protected function execute(InputInterface $input, OutputInterface $output) { // App $helper = $this->getHelper('question'); $app_name = $input->getArgument('app'); if (empty($app_name)) { $question = new ChoiceQuestion('For which app? ', array_keys($this->getApplication()->getTerra()->getConfig()->get('apps')), 0); $app_name = $helper->ask($input, $output, $question); } $app = $this->getApplication()->getTerra()->getConfig()->get('apps', $app_name); // Environment Name $environment_name = $input->getArgument('name'); if (empty($environment_name)) { $question = new Question('Environment Name: ', ''); $environment_name = $helper->ask($input, $output, $question); } // Path $path = $input->getArgument('path'); if (empty($path)) { $default_path = realpath('.') . '/' . $app_name . '/' . $environment_name; $question = new Question("Path: ({$default_path})", ''); $path = $helper->ask($input, $output, $question); if (empty($path)) { $path = $default_path; } } // Check for path $fs = new Filesystem(); if (!$fs->isAbsolutePath($path)) { $path = getcwd() . '/' . $path; } // Environment object $environment = array('name' => $environment_name, 'path' => $path, 'document_root' => '', 'url' => '', 'version' => ''); // Prepare the environment factory. // Clone the apps source code to the desired path. $environmentFactory = new EnvironmentFactory($environment, $this->getApplication()->getTerra()->getConfig()->get('apps', $app_name)); // Save environment to config. if ($environmentFactory->init($path)) { // Load config from file. $environmentFactory->getConfig(); $environment['document_root'] = $environmentFactory->config['document_root']; // Save current branch $environment['version'] = $environmentFactory->getRepo()->getCurrentBranch(); // Save to registry. $this->getApplication()->getTerra()->getConfig()->add('apps', array($app_name, 'environments', $environment_name), $environment); $this->getApplication()->getTerra()->getConfig()->save(); $output->writeln('<info>Environment saved to registry.</info>'); } else { $output->writeln('<error>Unable to clone repository. Check app settings and try again.</error>'); } }
protected function execute(InputInterface $input, OutputInterface $output) { $output->writeln('Hello Terra!'); // If there are no apps, return if (count($this->getApplication()->getTerra()->getConfig()->get('apps')) == 0) { $output->writeln('<comment>There are no apps!</comment>'); $output->writeln('Use the command <info>terra app:add</info> to add your first app.'); return; } $helper = $this->getHelper('question'); $app_name = $input->getArgument('app_name'); $environment_name = $input->getArgument('environment_name'); $scale = $input->getArgument('scale'); // If no name specified provide options if (empty($app_name)) { $question = new ChoiceQuestion('Which app? ', array_keys($this->getApplication()->getTerra()->getConfig()->get('apps')), null); $app_name = $helper->ask($input, $output, $question); } $app = $this->getApplication()->getTerra()->getConfig()->get('apps', $app_name); if (empty($app)) { $output->writeln('<error>No app by that name!</error>'); $output->writeln('Use the command <info>terra app:add</info> to add your first app.'); return; } // If no environments: if (count($app['environments']) == 0) { $output->writeln('<comment>There are no environments!</comment>'); $output->writeln('Use the command <info>terra environment:add</info> to add your first environment.'); return; } // If no environment name specified provide options if (empty($environment_name)) { $question = new ChoiceQuestion('Which environment? ', array_keys($app['environments']), null); $environment_name = $helper->ask($input, $output, $question); } $app = $this->getApplication()->getTerra()->getConfig()->get('apps', $app_name); $environment = $app['environments'][$environment_name]; $environment_factory = new EnvironmentFactory($environment, $app); $environment_factory->writeConfig(); $current_scale = $environment_factory->getScale(); $output->writeln("Scaling Environment <comment>{$app_name} {$environment_name}</comment>..."); $output->writeln("Current scale: <comment>{$current_scale}</comment>"); // If no scale ask for scale. if (empty($scale)) { $question = new Question('How many app containers? '); $scale = $helper->ask($input, $output, $question); } $output->writeln("Target scale: <comment>{$scale}</comment>"); $environment_factory->scale($scale); $output->writeln("Environment <comment>{$app_name} {$environment_name}</comment> scaled to <info>{$scale}</info>"); }
protected function execute(InputInterface $input, OutputInterface $output) { // Ask for an app and environment. $this->getApp($input, $output); $this->getEnvironment($input, $output); $environment_name = $this->environment->name; $app_name = $this->app->name; // Attempt to disable the environment. $environment_factory = new EnvironmentFactory($this->environment, $this->app); if (!$environment_factory->disable()) { $output->writeln('<error>Something went wrong, environment not disabled.</error>'); return; } }
protected function execute(InputInterface $input, OutputInterface $output) { // Ask for an app and environment. $this->getApp($input, $output); $this->getEnvironment($input, $output); $environment_name = $this->environment->name; $app_name = $this->app->name; // Attempt to enable the environment. $environment_factory = new EnvironmentFactory($this->environment, $this->app); if (!$environment_factory->enable()) { $output->writeln('<error>Something went wrong, environment not enabled.</error>'); return; } // Get new port, set new URL to environment object. $port = $environment_factory->getPort(); $host = $environment_factory->getHost(); $this->environment->url = "http://{$host}:{$port}"; // When passing to saveEnvironment, it must have app and name properties (for now). $this->environment->app = $app_name; $this->environment->name = $environment_name; // Save environment metadata. $this->getApplication()->getTerra()->getConfig()->saveEnvironment($this->environment); if ($this->getApplication()->getTerra()->getConfig()->save()) { $output->writeln('<info>Environment enabled!</info> Available at http://' . $environment_factory->getUrl() . ' and ' . $this->environment->url); } else { $output->writeln('<error>Environment info not saved.</error>'); } // Write drush alias. $drush_alias_file_path = "{$_SERVER['HOME']}/.drush/{$app_name}.aliases.drushrc.php"; if ($environment_factory->writeDrushAlias()) { $output->writeln("<info>Drush alias file created at {$drush_alias_file_path}</info>"); $output->writeln("Wrote drush alias file to <comment>{$drush_alias_file_path}</comment>"); $output->writeln("Use <info>drush @{$app_name}.{$environment_name}</info> to access the site."); } else { $output->writeln('<error>Unable to save drush alias.</error>'); } // Run the enable hooks $output->writeln(''); $output->writeln('Running <comment>ENABLE</comment> app hook...'); $environment_factory->getConfig(); // @TODO: Figure out how to only run this hook the first time! if (!empty($environment_factory->config['hooks']['enable_first'])) { // Output what we are running $formatter = $this->getHelper('formatter'); $errorMessages = array($environment_factory->config['hooks']['enable_first']); $formattedBlock = $formatter->formatBlock($errorMessages, 'question'); $output->writeln($formattedBlock); chdir($environment_factory->getSourcePath()); $process = new Process($environment_factory->config['hooks']['enable_first']); $process->setTimeout(null); $process->run(function ($type, $buffer) { if (Process::ERR === $type) { echo $buffer; } else { echo $buffer; } }); } }
protected function execute(InputInterface $input, OutputInterface $output) { // Check if "app" argument is an action. if ($input->getArgument('app_name') == 'add' || $input->getArgument('app_name') == 'remove') { // Move argument from app_name to action $input->setArgument('action', $input->getArgument('app_name')); $input->setArgument('app_name', ''); // Move argument from env_name to domain $input->setArgument('domain', $input->getArgument('environment_name')); $input->setArgument('environment_name', ''); } // Ask for an app. $helper = $this->getHelper('question'); $this->getApp($input, $output); // Ask for an environment. $helper = $this->getHelper('question'); $this->getEnvironment($input, $output); // If action argument is empty, show the list. if (empty($input->getArgument('action'))) { $environment = new EnvironmentFactory($this->environment, $this->app); $rows[] = array('http://' . $environment->getHost() . ':' . $environment->getPort()); $rows[] = array('http://' . $environment->getUrl()); // Get all domains foreach ($environment->environment->domains as $domain) { $rows[] = array('http://' . $domain); } $table = $this->getHelper('table'); $table->setHeaders(array("Domains for {$this->app->name} {$this->environment->name}"))->setRows($rows); $table->render($output); return; } elseif ($input->getArgument('action') == 'add') { $this->executeAddDomain($input, $output); } elseif ($input->getArgument('action') == 'remove') { $this->executeRemoveDomain($input, $output); } // Offer to re-enable the environment $helper = $this->getHelper('question'); $question = new ConfirmationQuestion("Re-enable the environment <info>{$this->app->name}:{$this->environment->name}</info> [y/N]? ", FALSE); if ($helper->ask($input, $output, $question)) { // Run environment:enable command. $command = $this->getApplication()->find('environment:enable'); $arguments = array('app_name' => $this->app->name, 'environment_name' => $this->environment->name); $input = new ArrayInput($arguments); $command->run($input, $output); } }
protected function execute(InputInterface $input, OutputInterface $output) { $output->writeln('Hello Terra!'); // Ask for an app and environment. $this->getApp($input, $output); $this->getEnvironment($input, $output); $environment_name = $this->environment->name; $app_name = $this->app->name; $environment_factory = new EnvironmentFactory($this->environment, $this->app); $environment_factory->writeConfig(); $current_scale = $environment_factory->getScale(); $output->writeln("Scaling Environment <comment>{$app_name} {$environment_name}</comment>..."); $output->writeln("Current scale: <comment>{$current_scale}</comment>"); // If no scale ask for scale. if (empty($scale)) { $question = new Question('How many app containers? '); $helper = $this->getHelper('question'); $scale = $helper->ask($input, $output, $question); } $output->writeln("Target scale: <comment>{$scale}</comment>"); $environment_factory->scale($scale); $output->writeln("Environment <comment>{$app_name} {$environment_name}</comment> scaled to <info>{$scale}</info>"); // Output the new URL. $local_url = 'http://' . $environment_factory->getHost() . ':' . $environment_factory->getPort(); $output->writeln('<info>Environment enabled!</info> Available at http://' . $environment_factory->getUrl() . ' and ' . $local_url); }
protected function execute(InputInterface $input, OutputInterface $output) { // If there are no apps, return if (count($this->getApplication()->getTerra()->getConfig()->get('apps')) == 0) { $output->writeln("<comment>There are no apps to remove!</comment>"); $output->writeln("Use the command <info>terra app:add</info> to add your first app."); return; } $helper = $this->getHelper('question'); $app_name = $input->getArgument('app_name'); $environment_name = $input->getArgument('environment_name'); // If no name specified provide options if (empty($app_name)) { $question = new ChoiceQuestion('Which app? ', array_keys($this->getApplication()->getTerra()->getConfig()->get('apps')), NULL); $app_name = $helper->ask($input, $output, $question); } $app = $this->getApplication()->getTerra()->getConfig()->get('apps', $app_name); // If no environments: if (count($app['environments']) == 0) { $output->writeln("<comment>There are no environments for the app {$app_name}!</comment>"); $output->writeln("Use the command <info>terra environment:add</info> to add your first environment."); return; } // If no environment name specified provide options if (empty($environment_name)) { $question = new ChoiceQuestion('Which environment? ', array_keys($app['environments']), NULL); $environment_name = $helper->ask($input, $output, $question); } $environment = $app['environments'][$environment_name]; $environment_factory = new EnvironmentFactory($environment, $app); $output->writeln($environment_factory->enable()); $port = $environment_factory->getPort(); $port = array_pop(explode(':', $port)); $app['environments'][$environment_name]['url'] = "http://localhost:{$port}"; $this->getApplication()->getTerra()->getConfig()->add('apps', $app_name, $app); if ($this->getApplication()->getTerra()->getConfig()->save()) { $output->writeln('<info>Environment enabled!</info> Available at http://' . $environment_factory->getUrl()); } else { $output->writeln('<error>Environment info not saved.</error>'); } }
protected function execute(InputInterface $input, OutputInterface $output) { $output->writeln("Hello Terra!"); // If there are no apps, return if (count($this->getApplication()->getTerra()->getConfig()->get('apps')) == 0) { $output->writeln("<comment>There are no apps!</comment>"); $output->writeln("Use the command <info>terra app:add</info> to add your first app."); return; } $helper = $this->getHelper('question'); $app_name = $input->getArgument('app_name'); $environment_name = $input->getArgument('environment_name'); // If no name specified provide options if (empty($app_name)) { $question = new ChoiceQuestion('Which app? ', array_keys($this->getApplication()->getTerra()->getConfig()->get('apps')), NULL); $app_name = $helper->ask($input, $output, $question); } $app = $this->getApplication()->getTerra()->getConfig()->get('apps', $app_name); // If no environments: if (count($app['environments']) == 0) { $output->writeln("<comment>There are no environments!</comment>"); $output->writeln("Use the command <info>terra environment:add</info> to add your first environment."); return; } // If no environment name specified provide options if (empty($environment_name)) { $question = new ChoiceQuestion('Which environment? ', array_keys($app['environments']), NULL); $environment_name = $helper->ask($input, $output, $question); } $environment = $app['environments'][$environment_name]; $environment_factory = new EnvironmentFactory($environment, $app); $environment['scale'] = $environment_factory->getScale(); $environment['url'] .= PHP_EOL . 'http://' . $environment_factory->getUrl(); $table = $this->getHelper('table'); $table->setHeaders(array('Name', 'Code Path', 'URL', 'Version', 'Scale')); $rows = array($environment); $table->setRows($rows); $table->render($output); $output->writeln("Docker Compose Path: " . $environment_factory->getDockerComposePath()); }
protected function execute(InputInterface $input, OutputInterface $output) { // Ask for an app and environment. $this->getApp($input, $output); $this->getEnvironment($input, $output); // Get desired version. $question = new Question('What version would you like to deploy? This can be any git ref. (branch, tag, or sha) ', ''); $git_ref = $this->getAnswer($input, $output, $question, 'git_ref'); // Notify user. $output->writeln("Deploying App <info>{$this->app->name}</info> environment <comment>{$this->environment->name}</comment> to version <question> {$git_ref} </question> ..."); // Ask for confirmation. $helper = $this->getHelper('question'); $question = new ConfirmationQuestion("Are you sure? This will checkout the version and run the deploy hooks in .terra.yml [y\\N] ", false); if (!$helper->ask($input, $output, $question)) { $output->writeln('<error>Deploy Cancelled</error>'); return; } // Run the deployment. $environment = new EnvironmentFactory($this->environment, $this->app); $this->environment->version = $environment->deploy($git_ref); // Save the new version to the config. $this->getApplication()->getTerra()->getConfig()->add('apps', array($this->app->name, 'environments', $this->environment->name), (array) $this->environment); $this->getApplication()->getTerra()->getConfig()->save(); }
protected function prepareBehat(InputInterface $input, OutputInterface $output, EnvironmentFactory $environment_factory) { $output->writeln("I noticed you don't have behat tests for your project."); $helper = $this->getHelper('question'); $question = new ConfirmationQuestion('Would you like to add behat tests? [y\\N] '); if ($helper->ask($input, $output, $question)) { $question = new Question('Where would you like to add your tests? (tests) ', 'tests'); $tests_path = $helper->ask($input, $output, $question); // Create tests path $fs = new Filesystem(); try { $fs->mkdir($environment_factory->getSourcePath() . '/' . $tests_path); } catch (IOException $e) { throw \Exception($e->getMessage()); } $output->writeln("<info>SUCCESS</info> Created {$tests_path}."); // Create composer.json and behat.yml $composer_path = $environment_factory->getSourcePath() . '/' . $tests_path . '/composer.json'; $behat_yml_path = $environment_factory->getSourcePath() . '/' . $tests_path . '/behat.yml'; try { $fs->dumpFile($composer_path, $this->getBehatDrupalComposer()); $url = "http://{$environment_factory->getHost()}:{$environment_factory->getPort()}"; $fs->dumpFile($behat_yml_path, $this->getBehatYml($url)); $output->writeln("<info>SUCCESS</info> Created composer.json and behat.yml."); } catch (IOException $e) { throw \Exception($e->getMessage()); } $behat_path = $this->environment->path . '/' . $tests_path; // Run composer install $output->writeln("<info>RUNNING</info> composer install"); $output->writeln("in: {$behat_path}"); $process = new Process('composer install', $behat_path); $process->setTimeout(NULL); $process->run(function ($type, $buffer) { if (Process::ERR === $type) { echo $buffer; } else { echo $buffer; } }); $output->writeln(""); // Run behat --init $output->writeln("<info>RUNNING</info> bin/behat --init"); $output->writeln("in: {$behat_path}"); $process = new Process('bin/behat --init', $behat_path); $process->run(function ($type, $buffer) { if (Process::ERR === $type) { echo $buffer; } else { echo $buffer; } }); // Set behat_path in .terra.yml $output->writeln("<comment>NOTE You should add `behat_path: {$tests_path}` to .terra.yml.</>"); } }
protected function execute(InputInterface $input, OutputInterface $output) { // Ask for an app. $helper = $this->getHelper('question'); $this->getApp($input, $output); // Ask for environment name $environment_name = $input->getArgument('environment_name'); while (empty($environment_name) || isset($this->app->environments[$environment_name]) || !preg_match('/^[a-zA-Z0-9]+$/', $environment_name)) { $question = new Question('Environment name? '); $environment_name = $helper->ask($input, $output, $question); if (!preg_match('/^[a-zA-Z0-9]+$/', $environment_name)) { $output->writeln("<error> ERROR </error> Environment <comment>{$environment_name}</comment> cannot contain spaces or special characters."); } // Look for environment with this name if (isset($this->app->environments[$environment_name])) { $output->writeln("<error> ERROR </error> Environment <comment>{$environment_name}</comment> already exists in app <comment>{$this->app->name}</comment>"); } } // Path $path = $input->getArgument('path'); if (empty($path)) { // Load apps base path from Config. $config_path = $this->getApplication()->getTerra()->getConfig()->get('apps_basepath'); // If it already exists, use "realpath" to load it. if (file_exists($config_path)) { $default_path = realpath($config_path) . '/' . $this->app->name . '/' . $environment_name; } else { // Offer to create the apps path. $question = new ConfirmationQuestion("Create default apps path at {$config_path}? [y\\N] ", false); if ($helper->ask($input, $output, $question)) { mkdir($config_path); $default_path = $_SERVER['HOME'] . '/Apps/' . $this->app->name . '/' . $environment_name; } } $question = new Question("Path: ({$default_path}) ", $default_path); $path = $helper->ask($input, $output, $question); if (empty($path)) { $path = $default_path; } } // Check for path $fs = new Filesystem(); if (!$fs->isAbsolutePath($path)) { $path = getcwd() . '/' . $path; } $branch_name = $input->getArgument('branch'); while (empty($branch_name)) { $output->writeln("<info>Getting the default branch for <comment>{$this->app->repo}</comment> </info>"); // command to get default branch $process = new Process("git ls-remote " . $this->app->repo . " | awk '{if (a[\$1]) { print \$2 } a[\$1] = \$2}' | grep heads | awk -F\"/\" '{print \$3 }'"); try { $process->mustRun(); } catch (ProcessFailedException $e) { $output->writeln("<error> ERROR </error> Unable to find default git branch. <comment>{$e->getMessage()}</comment>"); } $default_branch = trim($process->getOutput()); $question = new Question("Version? [{$default_branch}]", $default_branch); $branch_name = $helper->ask($input, $output, $question); // Check if the remote branch exists if ($branch_name) { $output->writeln("<info>Checking if branch <comment>{$branch_name}</comment> exists in <comment>{$this->app->repo}</comment> </info>"); $process = new Process('git ls-remote ' . $this->app->repo . ' | grep -sw "' . $branch_name . '"'); $process->run(); if (!$process->isSuccessful()) { $output->writeln("<error> ERROR </error> Branch <comment>{$branch_name}</comment> not found in repote repo <comment>{$this->app->repo}</comment>"); return; } } } // Environment object $environment = array('app' => $this->app->name, 'name' => $environment_name, 'path' => $path, 'document_root' => '', 'url' => '', 'version' => $branch_name); // Prepare the environment factory. // Clone the apps source code to the desired path. $environmentFactory = new EnvironmentFactory($environment, $this->app); // Save environment to config. if ($environmentFactory->init($path)) { // Load config from file. $environmentFactory->getConfig(); $environment['document_root'] = isset($environmentFactory->config['document_root']) ? $environmentFactory->config['document_root'] : ''; // Save current branch $environment['version'] = $environmentFactory->getRepo()->getCurrentBranch(); // Save to registry. $this->getApplication()->getTerra()->getConfig()->saveEnvironment($environment); $this->getApplication()->getTerra()->getConfig()->save(); $output->writeln('<info>Environment saved to registry.</info>'); } else { $output->writeln('<error>Unable to clone repository. Check app settings and try again.</error>'); return; } // Offer to enable the environment $question = new ConfirmationQuestion("Enable this environment? [y\\N] ", false); if ($input->getOption('enable') || $helper->ask($input, $output, $question)) { // Run environment:add command. $command = $this->getApplication()->find('environment:enable'); $arguments = array('app_name' => $this->app->name, 'environment_name' => $environment_name); $input = new ArrayInput($arguments); $command->run($input, $output); } }
protected function prepareBehat(InputInterface $input, OutputInterface $output, EnvironmentFactory $environment_factory) { $output->writeln("I noticed you don't have behat tests for your project."); $helper = $this->getHelper('question'); $question = new ConfirmationQuestion('Would you like to add behat tests? [y\\N] '); if ($helper->ask($input, $output, $question)) { $question = new Question('Where would you like to add your tests? (tests) ', 'tests'); $tests_path = $helper->ask($input, $output, $question); // Create tests path $tests_path = $environment_factory->getSourcePath() . '/' . $tests_path; $fs = new Filesystem(); try { $fs->mkdir($environment_factory->getSourcePath() . '/' . $tests_path); } catch (IOException $e) { throw \Exception($e->getMessage()); } $output->writeln("<info>SUCCESS</info> Created {$tests_path}."); // Create composer.json and behat.yml $composer_path = $environment_factory->getSourcePath() . '/' . $tests_path . '/composer.json'; $behat_yml_path = $environment_factory->getSourcePath() . '/' . $tests_path . '/behat.yml'; try { $fs->dumpFile($composer_path, $this->getBehatDrupalComposer()); $fs->dumpFile($behat_yml_path, $this->getBehatYml($environment_factory->getUrl())); $output->writeln("<info>SUCCESS</info> Created composer.json and behat.yml."); } catch (IOException $e) { throw \Exception($e->getMessage()); } // Run composer install $process = new Process('composer install', $tests_path); // Run behat --init // Set behat_path in .terra.yml } }
/** * Outputs the status of an environment. * * @param \Symfony\Component\Console\Input\InputInterface $input * @param \Symfony\Component\Console\Output\OutputInterface $output * @param $app * @param $environment * */ protected function environmentStatus(InputInterface $input, OutputInterface $output) { // If there are no apps, return if (count($this->getApplication()->getTerra()->getConfig()->get('apps')) == 0) { $output->writeln('<comment>There are no apps!</comment>'); $output->writeln('Use the command <info>terra app:add</info> to add your first app.'); return; } $app_name = $input->getArgument('app_name'); $environment_name = $input->getArgument('environment_name'); $app = $this->getApplication()->getTerra()->getConfig()->get('apps', $app_name); // If no environments: if (count($app['environments']) == 0) { $output->writeln('<comment>There are no environments!</comment>'); $output->writeln('Use the command <info>terra environment:add</info> to add your first environment.'); return; } // If no environment by that name... if (!isset($app['environments'][$environment_name])) { $output->writeln("<error>There is no environment named {$environment_name} in the app {$app_name}</error>"); return; } $environment = $app['environments'][$environment_name]; $environment_factory = new EnvironmentFactory($environment, $app); $environment['scale'] = $environment_factory->getScale(); $environment['url'] = 'http://' . $environment_factory->getHost() . ':' . $environment_factory->getPort(); $environment['url'] .= PHP_EOL . 'http://' . $environment_factory->getUrl(); $table = $this->getHelper('table'); $table->setHeaders(array('Name', 'Code Path', 'docroot', 'URLs', 'Version', 'Scale')); $rows = array($environment); $table->setRows($rows); $table->render($output); $output->writeln('Docker Compose Path: ' . $environment_factory->getDockerComposePath()); }
protected function execute(InputInterface $input, OutputInterface $output) { // Ask for an app. $helper = $this->getHelper('question'); $this->getApp($input, $output); // Ask for environment name $environment_name = $input->getArgument('environment_name'); while (empty($environment_name) || isset($this->app->environments[$environment_name])) { $question = new Question('Environment name? '); $environment_name = $helper->ask($input, $output, $question); // Check for spaces or characters. if (!preg_match('/^[a-zA-Z0-9]+$/', $environment_name)) { $output->writeln("<error> ERROR </error> Environment name cannot contain spaces or special characters."); $environment_name = ''; continue; } // Look for environment with this name. if (isset($this->app->environments[$environment_name])) { $output->writeln("<error> ERROR </error> Environment <comment>{$environment_name}</comment> already exists in app <comment>{$this->app->name}</comment>"); } } // Path $path = $input->getArgument('path'); if (empty($path)) { // Load apps base path from Config. $config_path = $this->getApplication()->getTerra()->getConfig()->get('apps_basepath'); // If it already exists, use "realpath" to load it. if (file_exists($config_path)) { $default_path = realpath($config_path) . '/' . $this->app->name . '/' . $environment_name; } else { // Offer to create the apps path. $question = new ConfirmationQuestion("Create default apps path at {$config_path}? [y\\N] ", false); if ($helper->ask($input, $output, $question)) { mkdir($config_path); $default_path = $_SERVER['HOME'] . '/Apps/' . $this->app->name . '/' . $environment_name; } } $question = new Question("Path: ({$default_path}) ", $default_path); $path = $helper->ask($input, $output, $question); } // Check for path $fs = new Filesystem(); if (!$fs->isAbsolutePath($path)) { // Don't save the "." to the environments path. if ($path == '.') { $path = getcwd(); } else { $path = getcwd() . '/' . $path; } } // Environment object $environment = array('app' => $this->app->name, 'name' => $environment_name, 'path' => $path, 'document_root' => '', 'url' => '', 'version' => $input->getOption('ref'), 'domains' => array()); // Prepare the environment factory. // Clone the apps source code to the desired path. $environmentFactory = new EnvironmentFactory($environment, $this->app); // Save environment to config. if ($environmentFactory->init($path)) { // Load config from file. $environmentFactory->getConfig(); $environment['document_root'] = isset($environmentFactory->config['document_root']) ? $environmentFactory->config['document_root'] : ''; // Save current branch $environment['version'] = $environmentFactory->getRepo()->getCurrentBranch(); // Save to registry. $this->getApplication()->getTerra()->getConfig()->saveEnvironment($environment); $this->getApplication()->getTerra()->getConfig()->save(); $output->writeln('<info>Environment saved to registry.</info>'); } else { $output->writeln('<error>Unable to clone repository. Check app settings and try again.</error>'); return; } // Offer to enable the environment $question = new ConfirmationQuestion("Enable this environment? [y\\N] ", false); if ($input->getOption('enable') || $helper->ask($input, $output, $question)) { // Run environment:add command. $command = $this->getApplication()->find('environment:enable'); $arguments = array('app_name' => $this->app->name, 'environment_name' => $environment_name); $input = new ArrayInput($arguments); $command->run($input, $output); } }
protected function execute(InputInterface $input, OutputInterface $output) { // If there are no apps, return if (count($this->getApplication()->getTerra()->getConfig()->get('apps')) == 0) { $output->writeln('<comment>There are no apps to remove!</comment>'); $output->writeln('Use the command <info>terra app:add</info> to add your first app.'); return; } $helper = $this->getHelper('question'); $app_name = $input->getArgument('app_name'); $environment_name = $input->getArgument('environment_name'); // If no name specified provide options if (empty($app_name)) { $question = new ChoiceQuestion('Which app? ', array_keys($this->getApplication()->getTerra()->getConfig()->get('apps')), null); $app_name = $helper->ask($input, $output, $question); } $app = $this->getApplication()->getTerra()->getConfig()->get('apps', $app_name); // If no environments: if (count($app['environments']) == 0) { $output->writeln("<comment>There are no environments for the app {$app_name}!</comment>"); $output->writeln('Use the command <info>terra environment:add</info> to add your first environment.'); return; } // If no environment name specified provide options if (empty($environment_name)) { $question = new ChoiceQuestion('Which environment? ', array_keys($app['environments']), null); $environment_name = $helper->ask($input, $output, $question); } $environment = $app['environments'][$environment_name]; // Attempt to enable the environment. $environment_factory = new EnvironmentFactory($environment, $app); if (!$environment_factory->enable()) { $output->writeln('<error>Something went wrong, environment not enabled.</error>'); return; } // Get new port, set new URL to environment object. $port = $environment_factory->getPort(); $host = $environment_factory->getHost(); $app['environments'][$environment_name]['url'] = "http://{$host}:{$port}"; // Save environment metadata. $this->getApplication()->getTerra()->getConfig()->add('apps', array($app_name, 'environments', $environment_name), $app['environments'][$environment_name]); // Save config to files. if ($this->getApplication()->getTerra()->getConfig()->save()) { $output->writeln('<info>Environment enabled!</info> Available at http://' . $environment_factory->getUrl() . ' and ' . $app['environments'][$environment_name]['url']); } else { $output->writeln('<error>Environment info not saved.</error>'); } // Write drush alias. $drush_alias_file_path = "{$_SERVER['HOME']}/.drush/{$app_name}.aliases.drushrc.php"; if ($environment_factory->writeDrushAlias()) { $output->writeln("<info>Drush alias file created at {$drush_alias_file_path}</info>"); $output->writeln("Wrote drush alias file to <comment>{$drush_alias_file_path}</comment>"); $output->writeln("Use <info>drush @{$app_name}.{$environment_name}</info> to access the site."); } else { $output->writeln('<error>Unable to save drush alias.</error>'); } // Run the enable hooks $output->writeln(''); $output->writeln('Running <comment>ENABLE</comment> app hook...'); $environment_factory->getConfig(); if (!empty($environment_factory->config['hooks']['enable'])) { // Output what we are running $formatter = $this->getHelper('formatter'); $errorMessages = array($environment_factory->config['hooks']['enable']); $formattedBlock = $formatter->formatBlock($errorMessages, 'question'); $output->writeln($formattedBlock); chdir($environment_factory->getSourcePath()); $process = new Process($environment_factory->config['hooks']['enable']); $process->run(function ($type, $buffer) { if (Process::ERR === $type) { echo $buffer; } else { echo $buffer; } }); } }
protected function execute(InputInterface $input, OutputInterface $output) { // Ask for an app and environment. $this->getApp($input, $output); $this->getEnvironment($input, $output); // Don't continue unless we have an environment. if (empty($this->environment)) { return; } // Get Environment and Config $environment_factory = new EnvironmentFactory($this->environment, $this->app); $environment_factory->getConfig(); // Get argument override $rebuild_source_argument = $input->getOption('source'); // Check for config if (empty($environment_factory->config['rebuild_source'])) { if (empty($rebuild_source_argument)) { throw new \Exception("To run the 'environment:rebuild' command you must have 'rebuild_source: @drushalias' in your app's .terra.yml file (or specify the source drush alias with 'environment:rebuild --rebuild_source=@alias')."); } } else { $rebuild_source_config = $environment_factory->config['rebuild_source']; $output->writeln("Found <comment>rebuild_source: {$rebuild_source_config}</comment> in <fg=cyan>.terra.yml</> file..."); } // Get source and target aliases $source_alias = $rebuild_source_argument ? $rebuild_source_argument : $environment_factory->config['rebuild_source']; $target_alias = $environment_factory->getDrushAlias(); // Mention to user where the alias is coming from. if ($rebuild_source_argument) { $output->writeln("Using terra command option for source alias: <fg=cyan>{$rebuild_source_argument}</>"); } // Check that source doesn't equal target if ($source_alias == $target_alias) { throw new \Exception("You cannot use the same source and target (Source: {$source_alias} Target:{$target_alias}). Please check your config and try again."); } // Check ssh & sql access to both. $output->writeln(''); $errors = FALSE; foreach (array($source_alias, $target_alias) as $alias) { $output->writeln("Checking access to alias <fg=cyan>{$alias}</> ..."); $cmd = "drush {$alias} ssh 'echo \$SSH_CLIENT'"; // SSH Check $process = new Process($cmd); $process->setTimeout(NULL); $process->run(); if ($process->isSuccessful()) { $output->writeln("<info>SUCCESS</info> Connected to {$alias} via SSH. <comment>{$cmd}</comment>"); } else { $output->writeln("<error>FAILURE</error> Unable to connect to {$alias} via SSH. <comment>{$cmd}</comment>"); $errors = TRUE; } // SQL $cmd = "drush {$alias} sql-query 'SHOW TABLES'"; $process = new Process($cmd); $process->setTimeout(NULL); $process->run(); if ($process->isSuccessful()) { $output->writeln("<info>SUCCESS</info> Connected to {$alias} via MySQL. <comment>{$cmd}</comment>"); } else { $output->writeln("<error>FAILURE</error> Unable to connect to {$alias} via MySQL. <comment>{$cmd}</comment>"); $errors = TRUE; } $output->writeln(''); } // If errors, don't continue if ($errors) { throw new \Exception('We were unable to connect to both of your environments. Please check your config & try again.'); } // Database Sync Confirmation $helper = $this->getHelper('question'); $question = new ConfirmationQuestion("Are you sure you want to destroy <fg=red>{$target_alias}</> and replace it with data from <fg=cyan>{$source_alias}</>? [y\\N] ", false); if (!$helper->ask($input, $output, $question)) { $output->writeln('<error>Database sync Cancelled</error>'); } else { // Database Sync $cmd = "drush {$source_alias} sql-dump --gzip | gzip -cd | drush {$target_alias} sqlc"; $output->writeln(''); $output->writeln('Running...'); $output->writeln("<comment>{$cmd}</comment>"); $process = new Process($cmd); $process->setTimeout(NULL); $process->run(); if ($process->isSuccessful()) { $output->writeln("<info>SUCCESS</info> Database Copied successfully!"); } else { $output->writeln("<error>FAILURE</error> Database Copy Failed!"); } } // Files Sync Confirmation $helper = $this->getHelper('question'); $question = new ConfirmationQuestion("Copy files from <fg=cyan>{$source_alias}</> to <fg=red>{$target_alias}</>? Any existing files will be overwritten [y\\N] ", false); if (!$helper->ask($input, $output, $question)) { $output->writeln('<error>Files sync cancelled</error>'); return; } // Files Sync // Get Source Path $source_files_path = $environment_factory->runDrushCommand('vget file_public_path --format=string', $source_alias); $target_files_path = $environment_factory->runDrushCommand('vget file_public_path --format=string'); // If either variable is blank, assume default if (strpos($source_files_path, 'No matching') === 0) { $source_files_path = 'sites/default/files'; } if (strpos($target_files_path, 'No matching') === 0) { $target_files_path = 'sites/default/files'; } $default_source = "{$source_alias}:{$source_files_path}/"; $default_target = $environment_factory->getSourcePath() . '/' . $environment_factory->config['document_root'] . '/' . $target_files_path . '/'; $source_question = new Question("Source path? [{$default_source}] ", $default_source); $destination_question = new Question("Destination path? [{$default_target}] ", $default_target); $source = $helper->ask($input, $output, $source_question); $target = $helper->ask($input, $output, $destination_question); $cmd = "drush -y rsync {$source} {$target}"; $output->writeln(''); $output->writeln('Running...'); $output->writeln("<comment>{$cmd}</comment>"); $process = new Process($cmd); $process->setTimeout(NULL); $process->run(); if ($process->isSuccessful()) { $output->writeln("<info>SUCCESS</info> Files copied successfully!"); } else { $output->writeln("<error>FAILURE</error> Files did not copy successfully!"); } // Rebuild Hooks if (isset($environment_factory->config['hooks']['rebuild'])) { $output->writeln(''); $output->writeln('Running <fg=cyan>rebuild</> hooks from .terra.yml...'); $output->writeln("<comment>{$environment_factory->config['hooks']['rebuild']}</comment>"); $process = new Process($environment_factory->config['hooks']['rebuild'], $environment_factory->getSourcePath()); $process->setTimeout(NULL); $process->run(function ($type, $buffer) { if (Process::ERR === $type) { echo $buffer; } else { echo $buffer; } }); if ($process->isSuccessful()) { $output->writeln("<info>SUCCESS</info> Rebuild hooks completed successfully."); } else { $output->writeln("<error>FAILURE</error> Rebuild hooks did not complete successfully."); } $output->writeln(''); } }
/** * Using the config item "behat_path", run composer update and bin/behat in the behat path. * * @param InputInterface $input * @param OutputInterface $output */ protected function executeBehatTests(InputInterface $input, OutputInterface $output) { $output->writeln('Running Behat Tests...'); $environment_factory = new EnvironmentFactory($this->environment, $this->app); $environment_factory->getConfig(); // 1. Look for behat.yml $behat_path = $this->environment->path . '/' . $environment_factory->config['behat_path']; $behat_yml_path = $behat_path . '/behat.yml'; if (!file_exists($behat_path)) { throw new \Exception("Path {$behat_path} not found. Check your app's .terra.yml file."); } elseif (!file_exists($behat_yml_path)) { throw new \Exception("Behat.yml file not found at {$behat_yml_path}. Check your app's .terra.yml file."); } $output->writeln('Found behat.yml file at ' . $behat_yml_path); // 2. Load it, replace necessary items, and clone it to a temporary file. $behat_yml = Yaml::parse(file_get_contents($behat_yml_path)); // Set Base URL $behat_yml['default']['extensions']['Behat\\MinkExtension']['base_url'] = 'http://' . $environment_factory->getUrl(); $behat_yml['default']['extensions']['Drupal\\DrupalExtension']['drush']['alias'] = $environment_factory->getDrushAlias(); // If driver is drupal, add root. if ($behat_yml['default']['extensions']['Drupal\\DrupalExtension']['api_driver'] == 'drupal') { $behat_yml['default']['extensions']['Drupal\\DrupalExtension']['drupal']['root'] = $environment_factory->getDocumentRoot(); } $behat_yml_new = Yaml::dump($behat_yml, 5, 2); $behat_path_new = 'behat.terra.yml'; $fs = new Filesystem(); $fs->dumpFile($behat_path_new, $behat_yml_new); $output->writeln('Generated new behat.yml file at ' . $behat_path_new); // 3. Run `composer install` in behat_path. $output->writeln(''); $output->writeln('<fg=cyan>TERRA</> | <comment>Running: composer install</comment>'); $process = new Process('composer install', $behat_path); $process->setTimeout(NULL); $process->run(function ($type, $buffer) { if (Process::ERR === $type) { echo $buffer; } else { echo $buffer; } }); $output->writeln(''); $output->writeln('<fg=cyan>TERRA</> | <comment>Behat Tests: Start</comment>'); // 4. Run `bin/behat --colors --config=$PATH` in behat_path. // "expand:true" expands scenario outlines, making them readable. $cmd = 'bin/behat --colors --format-settings=\'{"expand": true}\' --config=' . $behat_path_new; if ($input->getOption('name')) { $cmd .= ' --name=' . $input->getOption('name'); } $output->writeln("Running: {$cmd}"); $output->writeln("in: {$behat_path}"); $output->writeln(''); $process = new Process($cmd, $behat_path); $process->setTimeout(NULL); $process->run(function ($type, $buffer) { if (Process::ERR === $type) { echo $buffer; } else { echo $buffer; } }); $output->writeln(''); if (!$process->isSuccessful()) { $output->writeln('<fg=cyan>TERRA</> | <fg=red>Test Failed</> '); return 1; } else { $output->writeln('<fg=cyan>TERRA</> | <info>Test Passed!</info> '); return 0; } }