From 4d110d2b60055909ebaa7629bd3d2d2b7bbea287 Mon Sep 17 00:00:00 2001 From: Greg Anderson Date: Mon, 2 May 2016 10:07:02 -0700 Subject: [PATCH] Set backend results and add tests for annotated commands. --- includes/preflight.inc | 23 ++- lib/Drush/Backend/BackendResultSetter.php | 14 ++ tests/annotatedCommandTest.php | 148 ++++++++++++++++++ .../modules/d7/woot/Command/.gitignore | 1 + tests/resources/modules/d7/woot/woot.info | 4 + tests/resources/modules/d7/woot/woot.module | 22 +++ tests/resources/modules/d8/woot/composer.json | 14 ++ .../d8/woot/src/Command/WootCommands.php | 66 ++++++++ .../d8/woot/src/Controller/WootController.php | 31 ++++ tests/resources/modules/d8/woot/woot.info.yml | 5 + tests/resources/modules/d8/woot/woot.module | 33 ++++ .../modules/d8/woot/woot.routing.yml | 8 + 12 files changed, 363 insertions(+), 6 deletions(-) create mode 100644 lib/Drush/Backend/BackendResultSetter.php create mode 100644 tests/annotatedCommandTest.php create mode 100644 tests/resources/modules/d7/woot/Command/.gitignore create mode 100644 tests/resources/modules/d7/woot/woot.info create mode 100644 tests/resources/modules/d7/woot/woot.module create mode 100644 tests/resources/modules/d8/woot/composer.json create mode 100644 tests/resources/modules/d8/woot/src/Command/WootCommands.php create mode 100644 tests/resources/modules/d8/woot/src/Controller/WootController.php create mode 100644 tests/resources/modules/d8/woot/woot.info.yml create mode 100644 tests/resources/modules/d8/woot/woot.module create mode 100644 tests/resources/modules/d8/woot/woot.routing.yml diff --git a/includes/preflight.inc b/includes/preflight.inc index 4bbb2f5c18..de41a7c0f4 100644 --- a/includes/preflight.inc +++ b/includes/preflight.inc @@ -275,11 +275,13 @@ function drush_init_dependency_injection_container($input = null, $output = null ->withArgument(\Drush::getVersion()) ->withMethodCall('setDispatcher', ['eventDispatcher']) ->withMethodCall('setAutoExit', [false]); - $container->share('commandDiscovery', 'Consolidation\AnnotatedCommand\CommandFileDiscovery') - ->withMethodCall('addSearchLocation', ['CommandFiles']) - ->withMethodCall('setSearchPattern', ['#.*(Commands|CommandFile).php$#']); + $container->share('commandDiscovery', 'Consolidation\AnnotatedCommand\CommandFileDiscovery'); +// ->withMethodCall('addSearchLocation', ['CommandFiles']) +// ->withMethodCall('setSearchPattern', ['#.*(Commands|CommandFile).php$#']); $container->share('formatterManager', 'Consolidation\OutputFormatters\FormatterManager'); - $container->share('hookManager', 'Consolidation\AnnotatedCommand\Hooks\HookManager'); + $container->share('backendResultSetter', 'Drush\Backend\BackendResultSetter'); + $container->share('hookManager', 'Consolidation\AnnotatedCommand\Hooks\HookManager') + ->withMethodCall('addOutputExtractor', ['backendResultSetter']); $container->share('commandProcessor', 'Consolidation\AnnotatedCommand\CommandProcessor') ->withArgument('hookManager') ->withMethodCall('setFormatterManager', ['formatterManager']); @@ -295,6 +297,7 @@ function drush_init_dependency_injection_container($input = null, $output = null return $container; } + // TODO: Where should this go? function drush_init_application_global_options($container) { $application = $container->get('application'); @@ -353,14 +356,22 @@ function drush_init_register_command_files($container, $commandFiles) { $application = $container->get('application'); $commandFactory = $container->get('commandFactory'); foreach ($commandFiles as $sourcePath => $className) { + if (!class_exists($className)) { + include $sourcePath; + } $classAlias = str_replace('\\', '', $className); - // Add and fetch our class from the container to apply the inductors $container->share($classAlias, $className); $commandFileInstance = $container->get($classAlias); $commandList = $commandFactory->createCommandsFromClass($commandFileInstance); foreach ($commandList as $command) { - $application->add($command); + $commandName = $command->getName(); + $drushAlias = strtr($commandName, ':', '-'); + if ($commandName != $drushAlias) { + $aliases = $command->getAliases(); + $command->setAliases(array_unique(array_merge($aliases, [$drushAlias]))); + } + $application->add($command); } } } diff --git a/lib/Drush/Backend/BackendResultSetter.php b/lib/Drush/Backend/BackendResultSetter.php new file mode 100644 index 0000000000..b22c998810 --- /dev/null +++ b/lib/Drush/Backend/BackendResultSetter.php @@ -0,0 +1,14 @@ +setUpDrupal(1, TRUE); + $uri = key($sites); + $root = $this->webroot(); + $options = array( + 'root' => $root, + 'uri' => $uri, + 'yes' => NULL, + ); + + // Copy the 'woot' module over to the Drupal site we just set up. + $this->setupModulesForTests($root); + + // Enable out module. This will also clear the commandfile cache. + $this->drush('pm-enable', array('woot'), $options, NULL, NULL, self::EXIT_SUCCESS); + + // drush woot --help + $this->drush('woot', array(), $options + ['help' => NULL], NULL, NULL, self::EXIT_SUCCESS); + $output = $this->getOutput(); + $this->assertContains('Woot mightily.', $output); + // TODO: Symfony Console does not print alias info like this + // $this->assertContains('Aliases: wt', $output); + + // drush help woot. TODO: drush help does not find annotated commands yet +// $this->drush('help', array('woot'), $options, NULL, NULL, self::EXIT_SUCCESS); +// $output = $this->getOutput(); +// $this->assertContains('Woot mightily.', $output); + + // drush woot + $this->drush('woot', array(), $options, NULL, NULL, self::EXIT_SUCCESS); + $output = $this->getOutput(); + $this->assertEquals('Woot!', $output); + + // drush my-cat --help + $this->drush('my-cat', array(), $options + ['help' => NULL], NULL, NULL, self::EXIT_SUCCESS); + $output = $this->getOutput(); + // TODO: the command description does not appear in the help text yet + //$this->assertContains('This is the my-cat command', $output); + $this->assertContains('bet alpha --flip', $output); + $this->assertContains('The first parameter', $output); + $this->assertContains('The other parameter', $output); + $this->assertContains('Whether or not the second parameter', $output); + // TODO: Symfony Console does not print alias info like this + // $this->assertContains('Aliases: c', $output); + + // drush help my-cat + // TODO: help cannot find annotated commands yet + //$this->drush('help', array('my-cat'), $options, NULL, NULL, self::EXIT_SUCCESS); + //$output = $this->getOutput(); + //$this->assertContains('This is the my-cat command', $output); + + // drush my-cat bet alpha --flip + $this->drush('my-cat', array('bet', 'alpha'), $options + ['flip' => NULL], NULL, NULL, self::EXIT_SUCCESS); + $output = $this->getOutput(); + $this->assertEquals('alphabet', $output); + + // drush woot --help with the 'woot' module ignored + $this->drush('woot', array(), $options + ['help' => NULL, 'ignored-modules' => 'woot'], NULL, NULL, self::EXIT_ERROR); + + // drush my-cat bet alpha --flip + $this->drush('my-cat', array('bet', 'alpha'), $options + ['flip' => NULL, 'ignored-modules' => 'woot'], NULL, NULL, self::EXIT_ERROR); + + $this->drush('try-formatters', array(), $options, NULL, NULL, self::EXIT_SUCCESS); + $output = $this->getOutput(); + $expected = <<assertEquals($expected, $output); + + $this->drush('try-formatters --format=yaml --fields=III,II', array(), $options, NULL, NULL, self::EXIT_SUCCESS); + $output = $this->getOutput(); + $expected = <<assertEquals($expected, $output); + + $this->drush('try-formatters', array(), $options + ['backend' => NULL]); + $parsed = $this->parse_backend_output($this->getOutput()); + $data = $parsed['object']; + $expected = <<assertEquals($expected, json_encode($data)); + + // drush try-formatters --help + $this->drush('try-formatters', array(), $options + ['help' => NULL], NULL, NULL, self::EXIT_SUCCESS); + $output = $this->getOutput(); + // TODO: Command description does not appear in help text yet + //$this->assertContains('Demonstrate formatters', $output); + $this->assertContains('try:formatters --fields=first,third', $output); + $this->assertContains('try:formatters --fields=III,II', $output); + // TODO: Help for formats and fields not available yet + //$this->assertContains('--fields=', $output); + //$this->assertContains('Fields to output. All available', $output); + //$this->assertContains('--format=', $output); + //$this->assertContains('Select output format. Available:', $output); + // TODO: Symfony Console does not print alias info like this + // $this->assertContains('Aliases: try-formatters', $output); + + // Disable the woot module to avoid cross-contamination of the Drupal + // test site's database. (not necessary?) + if (UNISH_DRUPAL_MAJOR_VERSION == 8) { + $this->drush('pm-uninstall', array('woot'), $options, NULL, NULL, self::EXIT_SUCCESS); + } + else { + $this->drush('pm-disable', array('woot'), $options, NULL, NULL, self::EXIT_SUCCESS); + } + // Also kill the Drush cache so that our 'woot' command is not cached. + $this->drush('cache-clear', array('drush'), $options, NULL, NULL, self::EXIT_SUCCESS); + } + + public function setupModulesForTests($root) { + $wootModule = __DIR__ . '/resources/modules/d' . UNISH_DRUPAL_MAJOR_VERSION . '/woot'; + $modulesDir = "$root/sites/all/modules"; + $this->mkdir($modulesDir); + \symlink($wootModule, "$modulesDir/woot"); + if ((UNISH_DRUPAL_MAJOR_VERSION < 8) && !file_exists("$wootModule/Command/WootCommands.php")) { + $woot8Module = __DIR__ . '/resources/modules/d8/woot'; + \symlink("$woot8Module/src/Command/WootCommands.php", "$wootModule/Command/WootCommands.php"); + } + } +} diff --git a/tests/resources/modules/d7/woot/Command/.gitignore b/tests/resources/modules/d7/woot/Command/.gitignore new file mode 100644 index 0000000000..772f99a1e4 --- /dev/null +++ b/tests/resources/modules/d7/woot/Command/.gitignore @@ -0,0 +1 @@ +WootCommands.php diff --git a/tests/resources/modules/d7/woot/woot.info b/tests/resources/modules/d7/woot/woot.info new file mode 100644 index 0000000000..4a01a94af5 --- /dev/null +++ b/tests/resources/modules/d7/woot/woot.info @@ -0,0 +1,4 @@ +name = woot +description = Woot Mightily +core = 7.x +files[] = woot.module diff --git a/tests/resources/modules/d7/woot/woot.module b/tests/resources/modules/d7/woot/woot.module new file mode 100644 index 0000000000..f51b34a5be --- /dev/null +++ b/tests/resources/modules/d7/woot/woot.module @@ -0,0 +1,22 @@ + 'Woot', + 'description' => 'Woot mightily.', + 'page callback' => 'woot_page', + 'access callback' => TRUE, + 'type' => MENU_CALLBACK, + ); + + return $items; +} + +function woot_page() { + return array('#markup' => 'Woot!'); +} diff --git a/tests/resources/modules/d8/woot/composer.json b/tests/resources/modules/d8/woot/composer.json new file mode 100644 index 0000000000..72d8757320 --- /dev/null +++ b/tests/resources/modules/d8/woot/composer.json @@ -0,0 +1,14 @@ +{ + "name": "drupal/woot", + "type": "drupal-module", + "description": "Woot Mightily.", + "keywords": ["Drupal"], + "license": "GPL-2.0+", + "homepage": "http://drupal.org/project/woot", + "minimum-stability": "dev", + "support": { + "issues": "http://drupal.org/project/issues/woot", + "source": "http://cgit.drupalcode.org/woot" + }, + "require": { } +} diff --git a/tests/resources/modules/d8/woot/src/Command/WootCommands.php b/tests/resources/modules/d8/woot/src/Command/WootCommands.php new file mode 100644 index 0000000000..0f2cdfe882 --- /dev/null +++ b/tests/resources/modules/d8/woot/src/Command/WootCommands.php @@ -0,0 +1,66 @@ + false]) + { + if ($options['flip']) { + return "{$two}{$one}"; + } + return "{$one}{$two}"; + } + + /** + * Demonstrate formatters. Default format is 'table'. + * + * @field-labels + * first: I + * second: II + * third: III + * @usage try:formatters --format=yaml + * @usage try:formatters --format=csv + * @usage try:formatters --fields=first,third + * @usage try:formatters --fields=III,II + * @return Consolidation\OutputFormatters\StructuredData\RowsOfFields + */ + public function tryFormatters($options = ['format' => 'table', 'fields' => '']) + { + $outputData = [ + 'en' => [ 'first' => 'One', 'second' => 'Two', 'third' => 'Three' ], + 'de' => [ 'first' => 'Eins', 'second' => 'Zwei', 'third' => 'Drei' ], + 'jp' => [ 'first' => 'Ichi', 'second' => 'Ni', 'third' => 'San' ], + 'es' => [ 'first' => 'Uno', 'second' => 'Dos', 'third' => 'Tres' ], + ]; + return new RowsOfFields($outputData); + } +} diff --git a/tests/resources/modules/d8/woot/src/Controller/WootController.php b/tests/resources/modules/d8/woot/src/Controller/WootController.php new file mode 100644 index 0000000000..4f9234d019 --- /dev/null +++ b/tests/resources/modules/d8/woot/src/Controller/WootController.php @@ -0,0 +1,31 @@ + 'markup', + '#markup' => $this->t('Woot!') + ]; + } + +} diff --git a/tests/resources/modules/d8/woot/woot.info.yml b/tests/resources/modules/d8/woot/woot.info.yml new file mode 100644 index 0000000000..cd849fbd5e --- /dev/null +++ b/tests/resources/modules/d8/woot/woot.info.yml @@ -0,0 +1,5 @@ +name: Woot +type: module +description: Woot Mightily. +core: 8.x +package: Other diff --git a/tests/resources/modules/d8/woot/woot.module b/tests/resources/modules/d8/woot/woot.module new file mode 100644 index 0000000000..b1535c4d4a --- /dev/null +++ b/tests/resources/modules/d8/woot/woot.module @@ -0,0 +1,33 @@ +' . t('About') . ''; + $output .= '

' . t('Woot Mightily.') . '

'; + return $output; + + default: + } +} + +/** + * Implements hook_theme(). + */ +function woot_theme() { + $theme = []; + + return $theme; +} diff --git a/tests/resources/modules/d8/woot/woot.routing.yml b/tests/resources/modules/d8/woot/woot.routing.yml new file mode 100644 index 0000000000..a607603b65 --- /dev/null +++ b/tests/resources/modules/d8/woot/woot.routing.yml @@ -0,0 +1,8 @@ + +woot.woot_controller_woot: + path: '/woot' + defaults: + _controller: '\Drupal\woot\Controller\WootController::woot' + _title: 'Woot' + requirements: + _permission: 'access content'