Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Deprecate Annotated Commands in favor of native Symfony Console commands #6135

Open
wants to merge 49 commits into
base: 13.x
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 13 commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
2f63ffc
Deprecate AnnotatedCommands in favor of native Symfony Console commands
weitzman Oct 14, 2024
ec1f512
PHPCS and rename directory to just Listeners (was EventListener)
weitzman Oct 14, 2024
47bf610
PHPStan
weitzman Oct 14, 2024
a201b1e
Restore handle() methods on a few Formatter Attribute classes
weitzman Oct 14, 2024
756d384
A few fixes
weitzman Oct 14, 2024
000c215
Remove illegal operation
weitzman Oct 14, 2024
2eeb287
A bit ugly but test has to pass
weitzman Oct 14, 2024
ff65ece
Add --filter option automatically for Console commands. Implementatio…
weitzman Oct 14, 2024
f2f179d
Incorporate into the Trait
weitzman Oct 14, 2024
41a8aa6
Support --filter during execute() of formatter supporting commands
weitzman Oct 15, 2024
141fa70
Convert image:flush to a Console command. Add ValidateEntityLoad list…
weitzman Oct 15, 2024
2eea0de
Deprecate constants
weitzman Oct 15, 2024
68cad77
Inject a new io service when StyleInterface is the type hint
weitzman Oct 15, 2024
b3fbd3a
Add visibility and remove use of dt()
weitzman Oct 15, 2024
a194c59
Use io instead of logger for success messages
weitzman Oct 15, 2024
4a9f239
Deal with a PHPStan failure by aliasing SynfonyStyle to DrushStyle in…
weitzman Oct 15, 2024
e78b50a
in ImageFlushCommand, use choice() and remove the deprecation from it
weitzman Oct 15, 2024
2f42025
Convert sql:dump. Optionsets are provided via a Listener
weitzman Oct 15, 2024
ac5ad80
PHPCS
weitzman Oct 15, 2024
0239f0f
Experiment with static method to add OptionSets
weitzman Oct 16, 2024
8b16ff4
Demonstrate a static method approach for Validators
weitzman Oct 16, 2024
7d6e8ea
Experiment with FormatterOptions via code not Attributes
weitzman Oct 16, 2024
9847b61
Build io when needed - don't get it from the container
weitzman Oct 16, 2024
b9e11f3
Use DI
weitzman Oct 16, 2024
6216ad6
Less magic - commands that format have own execute() with a bit of bo…
weitzman Oct 18, 2024
8d7b2e4
FormatterOptions now has methods we need to deprecate formatting Attr…
weitzman Oct 18, 2024
1a795af
Revert Formatting Attributes and use new fluid syntax for setInput
weitzman Oct 18, 2024
680da18
Start restore of automatic mention of the formatting help topic
weitzman Oct 18, 2024
12e74f8
Pass formattterOptions during configure()
weitzman Oct 20, 2024
74becdc
Simplify ImageFlushCommands a bit
weitzman Oct 20, 2024
6c899f4
Start deprecating a few Attribute classes
weitzman Oct 21, 2024
74b697c
Minor improvements
weitzman Oct 24, 2024
5b55f98
Convert sql:sanitize command. Convert the UserTable sanitizer to a Li…
weitzman Oct 24, 2024
ebd367a
PHPStan fixes
weitzman Oct 24, 2024
34afdc7
Convert to UserTableFields listener. Needed for green
weitzman Oct 24, 2024
f923a80
Introduce writeFormattedOutput() - use in execute()
weitzman Oct 24, 2024
2e75912
Just put validators right into the Command
weitzman Oct 25, 2024
a2b44fd
Lets go with calling Optionset methods statically from configure()
weitzman Oct 25, 2024
b4ed0bf
Experiment with CommandTester - it works
weitzman Oct 25, 2024
58c2ddd
Move the install check to setUp()
weitzman Oct 26, 2024
c1056ed
A bit more experimentation with Applicationtester
weitzman Oct 30, 2024
8f4f573
Delay getting $application because that can make entitytypeManager stale
weitzman Oct 31, 2024
fdfaf0f
Dont store $application in local variable. it gets stale.
weitzman Oct 31, 2024
3712e5d
drush() method is good enough for now
weitzman Oct 31, 2024
f0ffbd9
Docs for Console commands
weitzman Nov 1, 2024
955511e
Merge branch '13.x' into use-command-directly
weitzman Nov 2, 2024
aa21ad9
Convert image:derive
weitzman Nov 2, 2024
8ef8994
Migrate config:set into a Console command
weitzman Nov 2, 2024
b9817b9
Config:get is now a Console command
weitzman Nov 4, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ defaults: &defaults
PHP_EXTENSIONS_DISABLE: xdebug
PHP_XDEBUG_MODE: off

#No longer used
requires: &requires
requires:
- check_mergable
Expand Down Expand Up @@ -173,7 +174,8 @@ workflows:
# - test_80_drupal92_security:
# <<: *requires
- test:
<<: *requires
# Not used, for now.
# <<: *requires
<<: *poststeps
matrix:
parameters:
Expand Down
28 changes: 28 additions & 0 deletions src/Application.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
use Drush\Boot\DrupalBootLevels;
use Drush\Command\RemoteCommandProxy;
use Drush\Config\ConfigAwareTrait;
use Drush\Event\ConsoleDefinitionsEvent;
use Drush\Runtime\RedispatchHook;
use Drush\Runtime\ServiceManager;
use Drush\Runtime\TildeExpansionHook;
Expand Down Expand Up @@ -309,6 +310,8 @@ public function configureAndRegisterCommands(InputInterface $input, OutputInterf
// any of the configuration steps we do here.
$this->configureIO($input, $output);

$this->addListeners($commandfileSearchpath);

// Directly add the yaml-cli commands.
$this->addCommands($this->serviceManager->instantiateYamlCliCommands());

Expand All @@ -327,6 +330,9 @@ public function configureAndRegisterCommands(InputInterface $input, OutputInterf
// Note that Robo::register can accept either Annotated Command
// command handlers or Symfony Console Command objects.
Robo::register($this, $commandInstances);

// Dispatch our custom event. It also fires later in \Drush\Boot\DrupalBoot8::bootstrapDrupalFull.
Drush::getContainer()->get('eventDispatcher')->dispatch(new ConsoleDefinitionsEvent($this), ConsoleDefinitionsEvent::class);
}

/**
Expand All @@ -338,4 +344,26 @@ public function renderThrowable(\Throwable $e, OutputInterface $output): void

$this->doRenderThrowable($e, $output);
}

// Discover event listeners, and add those that do not require bootstrap.
protected function addListeners($commandfileSearchpath): void
{
$listenerClasses = $this->serviceManager->discoverListeners($commandfileSearchpath, '\Drush');
$listenerClasses = $this->serviceManager->filterListeners($listenerClasses);
$this->serviceManager->addListeners($listenerClasses, Drush::getContainer());
}

/**
* Remove a command. Initially used by WootDefinitionListener and its test.
*
* An alternative would be console.excluded https://github.com/search?q=repo%3AHuttopia%2Fconsole-bundle%20console.excluded&type=code
*/
public function remove(string $id): void
{
$rf = new \ReflectionProperty(\Symfony\Component\Console\Application::class, 'commands');
$rf->setAccessible(true);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not super excited to do this outside of tests. Is this for some sort of "alter" hook? If we want to do this, maybe we should, during preflight, add commands to some other list and provide a specific hook to alter that before adding to the application. That might be complicated, since today we add in two steps (commands from modules being added later).

Alternately, instead of removing a command, maybe we could change its name, remove its aliases and hide it?

I'm not sure why I think that setAccissible is worse than that.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add commands to some other list and provide a specific hook to alter that before adding to the application

I think thats more more easily done once we use a container to store commands and maybe use a CommandLoader. Yes, this is just used by Woot today - we can remove it if it offends the eyes.

$commands = $rf->getValue($this);
unset($commands[$id]);
$rf->setValue($this, $commands);
}
}
27 changes: 25 additions & 2 deletions src/Attributes/DefaultFields.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,31 @@
namespace Drush\Attributes;

use Attribute;
use Consolidation\AnnotatedCommand\Parser\CommandInfo;
use Drush\Formatters\FormatterConfigurationItemProviderInterface;

#[Attribute(Attribute::TARGET_METHOD)]
class DefaultFields extends \Consolidation\AnnotatedCommand\Attributes\DefaultFields
#[Attribute(Attribute::TARGET_CLASS | Attribute::TARGET_METHOD)]
class DefaultFields implements FormatterConfigurationItemProviderInterface
{
const KEY = 'default-fields';

/**
* @param $fields
* An array of field names to show by default.
*/
public function __construct(public array $fields)
{
}

public function getConfigurationItem(\ReflectionAttribute $attribute): array
{
$args = $attribute->getArguments();
return [self::KEY => $args['fields']];
}

public static function handle(\ReflectionAttribute $attribute, CommandInfo $commandInfo)
{
$args = $attribute->getArguments();
$commandInfo->addAnnotation('default-fields', $args['fields']);
}
}
28 changes: 26 additions & 2 deletions src/Attributes/DefaultTableFields.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,32 @@
namespace Drush\Attributes;

use Attribute;
use Consolidation\AnnotatedCommand\Parser\CommandInfo;
use Consolidation\OutputFormatters\Options\FormatterOptions;
use Drush\Formatters\FormatterConfigurationItemProviderInterface;

#[Attribute(Attribute::TARGET_METHOD)]
class DefaultTableFields extends \Consolidation\AnnotatedCommand\Attributes\DefaultTableFields
#[Attribute(Attribute::TARGET_CLASS | Attribute::TARGET_METHOD)]
class DefaultTableFields implements FormatterConfigurationItemProviderInterface
{
const KEY = FormatterOptions::DEFAULT_TABLE_FIELDS;

/**
* @param $fields
* An array of field names to show by default when using table formatter.
*/
public function __construct(public array $fields)
{
}

public function getConfigurationItem(\ReflectionAttribute $attribute): array
{
$args = $attribute->getArguments();
return [self::KEY => $args['fields']];
}

public static function handle(\ReflectionAttribute $attribute, CommandInfo $commandInfo)
{
$args = $attribute->getArguments();
$commandInfo->addAnnotation('default-table-fields', $args['fields']);
}
}
31 changes: 27 additions & 4 deletions src/Attributes/FieldLabels.php
Original file line number Diff line number Diff line change
@@ -1,12 +1,35 @@
<?php

declare(strict_types=1);

namespace Drush\Attributes;

use Attribute;
use Consolidation\AnnotatedCommand\Parser\CommandInfo;
use Consolidation\OutputFormatters\Options\FormatterOptions;
use Drush\Formatters\FormatterConfigurationItemProviderInterface;

#[Attribute(Attribute::TARGET_METHOD)]
class FieldLabels extends \Consolidation\AnnotatedCommand\Attributes\FieldLabels
#[Attribute(Attribute::TARGET_METHOD | Attribute::TARGET_CLASS)]
class FieldLabels implements FormatterConfigurationItemProviderInterface
{
const KEY = FormatterOptions::FIELD_LABELS;

/**
* @param $labels
* An associative array of field names and labels for display.
*/
public function __construct(
public array $labels
) {
}

public function getConfigurationItem(\ReflectionAttribute $attribute): array
{
$args = $attribute->getArguments();
return [self::KEY => $args['labels']];
}

public static function handle(\ReflectionAttribute $attribute, CommandInfo $commandInfo)
{
$args = $attribute->getArguments();
$commandInfo->addAnnotation('field-labels', $args['labels']);
}
}
30 changes: 26 additions & 4 deletions src/Attributes/FilterDefaultField.php
Original file line number Diff line number Diff line change
@@ -1,12 +1,34 @@
<?php

declare(strict_types=1);

namespace Drush\Attributes;

use Attribute;
use Consolidation\AnnotatedCommand\Parser\CommandInfo;
use Drush\Formatters\FormatterConfigurationItemProviderInterface;

#[Attribute(Attribute::TARGET_METHOD)]
class FilterDefaultField extends \Consolidation\AnnotatedCommand\Attributes\FilterDefaultField
#[Attribute(Attribute::TARGET_METHOD | Attribute::TARGET_CLASS)]
class FilterDefaultField implements FormatterConfigurationItemProviderInterface
{
const KEY = 'filter-default-field';

/**
* @param $field
* A field name to filter on by default.
*/
public function __construct(
public string $field
) {
}

public function getConfigurationItem(\ReflectionAttribute $attribute): array
{
$args = $attribute->getArguments();
return [self::KEY => $args['field']];
}

public static function handle(\ReflectionAttribute $attribute, CommandInfo $commandInfo)
{
$args = $attribute->getArguments();
$commandInfo->addAnnotation('filter-default-field', $args['field']);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here and elsewhere, KEY is defined in the class but not used in handle()

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just pushed a fix with a couple tweaks. Depends on another PR in output-formatters consolidation/output-formatters#113

}
}
13 changes: 11 additions & 2 deletions src/Attributes/Format.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@
use Attribute;
use Consolidation\AnnotatedCommand\Parser\CommandInfo;
use Consolidation\OutputFormatters\Options\FormatterOptions;
use Drush\Boot\Kernels;
use Drush\Formatters\FormatterConfigurationItemProviderInterface;
use JetBrains\PhpStorm\ExpectedValues;

#[Attribute(Attribute::TARGET_METHOD)]
class Format
class Format implements FormatterConfigurationItemProviderInterface
{
/**
* @param ?string $listDelimiter
Expand All @@ -32,4 +32,13 @@ public static function handle(\ReflectionAttribute $attribute, CommandInfo $comm
$commandInfo->addAnnotation(FormatterOptions::LIST_DELIMITER, $instance->listDelimiter);
$commandInfo->addAnnotation(FormatterOptions::TABLE_STYLE, $instance->tableStyle);
}

public function getConfigurationItem(\ReflectionAttribute $attribute): array
{
$instance = $attribute->newInstance();
return [
FormatterOptions::LIST_DELIMITER => $instance->listDelimiter,
FormatterOptions::TABLE_STYLE => $instance->tableStyle
];
}
}
2 changes: 1 addition & 1 deletion src/Attributes/ValidateEntityLoad.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
use Consolidation\AnnotatedCommand\CommandError;
use Drush\Utils\StringUtils;

#[Attribute(Attribute::TARGET_METHOD)]
#[Attribute(Attribute::TARGET_CLASS | Attribute::TARGET_METHOD)]
class ValidateEntityLoad extends ValidatorBase implements ValidatorInterface
{
/**
Expand Down
2 changes: 1 addition & 1 deletion src/Attributes/ValidateModulesEnabled.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
use Consolidation\AnnotatedCommand\CommandData;
use Consolidation\AnnotatedCommand\CommandError;

#[Attribute(Attribute::TARGET_METHOD)]
#[Attribute(Attribute::TARGET_CLASS | Attribute::TARGET_METHOD)]
class ValidateModulesEnabled extends ValidatorBase implements ValidatorInterface
{
/**
Expand Down
24 changes: 22 additions & 2 deletions src/Boot/DrupalBoot8.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,10 @@
use Drush\Config\ConfigLocator;
use Drush\Drupal\DrushLoggerServiceProvider;
use Drush\Drush;
use Drush\Event\ConsoleDefinitionsEvent;
use Drush\Runtime\LegacyServiceFinder;
use Drush\Runtime\LegacyServiceInstantiator;
use Drush\Runtime\ServiceManager;
use Psr\Log\LoggerAwareInterface;
use Psr\Log\LoggerInterface;
use Robo\Robo;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
Expand Down Expand Up @@ -215,12 +214,20 @@ public function bootstrapDrupalFull(BootstrapManager $manager): void
// Directly add the Drupal core bootstrapped commands.
Drush::getApplication()->addCommands($this->serviceManager->instantiateDrupalCoreBootstrappedCommands());

$this->addBootstrapListeners();

$this->addDrupalModuleDrushCommands($manager);

// Dispatch our custom event. It also fires earlier in \Drush\Application::configureAndRegisterCommands.
Drush::getContainer()->get('eventDispatcher')->dispatch(new ConsoleDefinitionsEvent(Drush::getApplication()), ConsoleDefinitionsEvent::class);

// Set a default account to make sure the correct timezone is set
$this->kernel->getContainer()->get('current_user')->setAccount(new AnonymousUserSession());
}

/**
* Adds module supplied commands, as well as Drush Console commands that require bootstrap.
*/
public function addDrupalModuleDrushCommands(BootstrapManager $manager): void
{
$application = Drush::getApplication();
Expand Down Expand Up @@ -323,4 +330,17 @@ public function bootstrapDrupalSite(BootstrapManager $manager)
{
$this->bootstrapDoDrupalSite($manager);
}

// Add the Listeners that require bootstrap.
public function addBootstrapListeners(): void
{
$listenersInThisModule = [];
$moduleHandler = \Drupal::moduleHandler();
foreach ($moduleHandler->getModuleList() as $moduleId => $extension) {
$path = DRUPAL_ROOT . '/' . $extension->getPath() . '/src/Drush';
$listenersInThisModule = array_merge($listenersInThisModule, $this->serviceManager->discoverListeners([$path], "\Drupal\\$moduleId\Drush"));
}
$classes = $this->serviceManager->bootstrapListenerClasses();
$this->serviceManager->addListeners(array_merge($listenersInThisModule, $classes), Drush::getContainer(), \Drupal::getContainer());
}
}
2 changes: 0 additions & 2 deletions src/Commands/AutowireTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,6 @@ trait AutowireTrait
*
* @param ContainerInterface $container
* The service container this instance should use.
*
* @return static
*/
public static function create(ContainerInterface $container)
{
Expand Down
4 changes: 2 additions & 2 deletions src/Commands/core/CoreCommands.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@

namespace Drush\Commands\core;

use Consolidation\OutputFormatters\Options\FormatterOptions;
use Consolidation\OutputFormatters\StructuredData\PropertyList;
use Consolidation\OutputFormatters\StructuredData\RowsOfFields;
use Drush\Attributes as CLI;
use Drush\Commands\DrushCommands;
use Drush\Drush;
use Consolidation\OutputFormatters\StructuredData\RowsOfFields;
use Consolidation\OutputFormatters\Options\FormatterOptions;

final class CoreCommands extends DrushCommands
{
Expand Down
Loading