Skip to content

Commit

Permalink
CLI-1227: Implement PHP 8 attributes (#1642)
Browse files Browse the repository at this point in the history
* MakeCommandLazyRector

* envrc

* CommandPropertyToAttributeRector (broken)

* aliasfirst

* rector

* cleanup

* cleanup

* convert requires auth

* mark commands final

* Requiredb

* sethidden

* clean up
  • Loading branch information
danepowell authored Nov 28, 2023
1 parent ef27522 commit 928c361
Show file tree
Hide file tree
Showing 75 changed files with 324 additions and 421 deletions.
1 change: 1 addition & 0 deletions .envrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export PATH="$PATH:${PWD}/vendor/bin"
13 changes: 13 additions & 0 deletions src/Attribute/RequireAuth.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php

declare(strict_types = 1);

namespace Acquia\Cli\Attribute;

/**
* Specify that a command requires authentication.
*/
#[\Attribute(\Attribute::TARGET_CLASS)]
class RequireAuth {

}
13 changes: 13 additions & 0 deletions src/Attribute/RequireDb.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php

declare(strict_types = 1);

namespace Acquia\Cli\Attribute;

/**
* Specify that a command requires authentication.
*/
#[\Attribute(\Attribute::TARGET_CLASS)]
class RequireDb {

}
3 changes: 2 additions & 1 deletion src/Command/Acsf/AcsfApiBaseCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

namespace Acquia\Cli\Command\Acsf;

use Acquia\Cli\Attribute\RequireAuth;
use Acquia\Cli\Command\Api\ApiBaseCommand;
use Acquia\Cli\Exception\AcquiaCliException;
use Symfony\Component\Console\Attribute\AsCommand;
Expand All @@ -13,7 +14,7 @@
class AcsfApiBaseCommand extends ApiBaseCommand {

protected function checkAuthentication(): void {
if ($this->commandRequiresAuthentication() && !$this->cloudApiClientService->isMachineAuthenticated()) {
if ((new \ReflectionClass(static::class))->getAttributes(RequireAuth::class) && !$this->cloudApiClientService->isMachineAuthenticated()) {
throw new AcquiaCliException('This machine is not yet authenticated with the Acquia Cloud Site Factory. Run `acli auth:acsf-login`');
}
}
Expand Down
11 changes: 4 additions & 7 deletions src/Command/Acsf/AcsfListCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,13 @@

namespace Acquia\Cli\Command\Acsf;

use Acquia\Cli\Attribute\RequireAuth;
use Symfony\Component\Console\Attribute\AsCommand;

#[AsCommand(name: 'acsf:list')]
class AcsfListCommand extends AcsfListCommandBase {
#[RequireAuth]
#[AsCommand(name: 'acsf:list', description: 'List all Acquia Cloud Site Factory commands', aliases: ['acsf'])]
final class AcsfListCommand extends AcsfListCommandBase {

protected string $namespace = 'acsf';

protected function configure(): void {
$this->setDescription("List all Acquia Cloud Site Factory commands")
->setAliases(['acsf']);
}

}
8 changes: 0 additions & 8 deletions src/Command/Acsf/AcsfListCommandBase.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,6 @@ public function setNamespace(string $namespace): void {
$this->namespace = $namespace;
}

/**
* Indicates whether the command requires the machine to be authenticated with the Cloud Platform.
*/
protected function commandRequiresAuthentication(): bool {
// Assume commands require authentication unless they opt out by overriding this method.
return FALSE;
}

protected function execute(InputInterface $input, OutputInterface $output): int {
$commands = $this->getApplication()->all();
foreach ($commands as $command) {
Expand Down
9 changes: 3 additions & 6 deletions src/Command/Api/ApiBaseCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

namespace Acquia\Cli\Command\Api;

use Acquia\Cli\Attribute\RequireAuth;
use Acquia\Cli\Command\CommandBase;
use AcquiaCloudApi\Connector\Client;
use AcquiaCloudApi\Exception\ApiErrorException;
Expand All @@ -21,7 +22,8 @@
use Symfony\Component\Validator\Exception\ValidatorException;
use Symfony\Component\Validator\Validation;

#[AsCommand(name: 'api:base')]
#[RequireAuth]
#[AsCommand(name: 'api:base', hidden: TRUE)]
class ApiBaseCommand extends CommandBase {

protected string $method;
Expand Down Expand Up @@ -53,11 +55,6 @@ class ApiBaseCommand extends CommandBase {
*/
private array $pathParams = [];

protected function configure(): void {
$this->setHidden();
parent::configure();
}

protected function interact(InputInterface $input, OutputInterface $output): void {
$params = array_merge($this->queryParams, $this->postParams, $this->pathParams);
foreach ($this->getDefinition()->getArguments() as $argument) {
Expand Down
11 changes: 4 additions & 7 deletions src/Command/Api/ApiListCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,13 @@

namespace Acquia\Cli\Command\Api;

use Acquia\Cli\Attribute\RequireAuth;
use Symfony\Component\Console\Attribute\AsCommand;

#[AsCommand(name: 'api:list')]
class ApiListCommand extends ApiListCommandBase {
#[RequireAuth]
#[AsCommand(name: 'api:list', description: 'List all API commands', aliases: ['api'])]
final class ApiListCommand extends ApiListCommandBase {

protected string $namespace = 'api';

protected function configure(): void {
$this->setDescription("List all API commands")
->setAliases(['api']);
}

}
11 changes: 6 additions & 5 deletions src/Command/App/AppOpenCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,21 @@

namespace Acquia\Cli\Command\App;

use Acquia\Cli\Attribute\RequireAuth;
use Acquia\Cli\Command\CommandBase;
use Acquia\Cli\Exception\AcquiaCliException;
use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;

#[AsCommand(name: 'app:open')]
class AppOpenCommand extends CommandBase {
#[RequireAuth]
#[AsCommand(name: 'app:open', description: 'Opens your browser to view a given Cloud application', aliases: ['open', 'o'])]
final class AppOpenCommand extends CommandBase {

protected function configure(): void {
$this->setDescription('Opens your browser to view a given Cloud application')
->acceptApplicationUuid()
->setAliases(['open', 'o']);
$this
->acceptApplicationUuid();
}

protected function execute(InputInterface $input, OutputInterface $output): int {
Expand Down
6 changes: 4 additions & 2 deletions src/Command/App/AppVcsInfo.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

namespace Acquia\Cli\Command\App;

use Acquia\Cli\Attribute\RequireAuth;
use Acquia\Cli\Command\CommandBase;
use Acquia\Cli\Exception\AcquiaCliException;
use AcquiaCloudApi\Endpoints\Code;
Expand All @@ -14,11 +15,12 @@
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;

#[AsCommand(name: 'app:vcs:info')]
#[RequireAuth]
#[AsCommand(name: 'app:vcs:info', description: 'Get all branches and tags of the application with the deployment status')]
class AppVcsInfo extends CommandBase {

protected function configure(): void {
$this->setDescription('Get all branches and tags of the application with the deployment status')
$this
->addOption('deployed', NULL, InputOption::VALUE_OPTIONAL, 'Show only deployed branches and tags')
->addUsage('[<applicationAlias>] --deployed');
$this->acceptApplicationUuid();
Expand Down
8 changes: 4 additions & 4 deletions src/Command/App/LinkCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,18 @@

namespace Acquia\Cli\Command\App;

use Acquia\Cli\Attribute\RequireAuth;
use Acquia\Cli\Command\CommandBase;
use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;

#[AsCommand(name: 'app:link')]
class LinkCommand extends CommandBase {
#[RequireAuth]
#[AsCommand(name: 'app:link', description: 'Associate your project with a Cloud Platform application', aliases: ['link'])]
final class LinkCommand extends CommandBase {

protected function configure(): void {
$this->setDescription('Associate your project with a Cloud Platform application')
->setAliases(['link']);
$this->acceptApplicationUuid();
}

Expand Down
11 changes: 6 additions & 5 deletions src/Command/App/LogTailCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,21 @@

namespace Acquia\Cli\Command\App;

use Acquia\Cli\Attribute\RequireAuth;
use Acquia\Cli\Command\CommandBase;
use AcquiaCloudApi\Endpoints\Logs;
use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;

#[AsCommand(name: 'app:log:tail')]
class LogTailCommand extends CommandBase {
#[RequireAuth]
#[AsCommand(name: 'app:log:tail', description: 'Tail the logs from your environments', aliases: ['tail', 'log:tail'])]
final class LogTailCommand extends CommandBase {

protected function configure(): void {
$this->setDescription('Tail the logs from your environments')
->acceptEnvironmentId()
->setAliases(['tail', 'log:tail']);
$this
->acceptEnvironmentId();
}

protected function execute(InputInterface $input, OutputInterface $output): int {
Expand Down
13 changes: 4 additions & 9 deletions src/Command/App/NewCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,12 @@
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Filesystem\Path;

#[AsCommand(name: 'app:new:local')]
class NewCommand extends CommandBase {
#[AsCommand(name: 'app:new:local', description: 'Create a new Drupal or Next.js project', aliases: ['new'])]
final class NewCommand extends CommandBase {

protected function configure(): void {
$this->setDescription('Create a new Drupal or Next.js project')
->addArgument('directory', InputArgument::OPTIONAL, 'The destination directory')
->setAliases(['new']);
$this
->addArgument('directory', InputArgument::OPTIONAL, 'The destination directory');
}

protected function execute(InputInterface $input, OutputInterface $output): int {
Expand Down Expand Up @@ -65,10 +64,6 @@ protected function execute(InputInterface $input, OutputInterface $output): int
return Command::SUCCESS;
}

protected function commandRequiresAuthentication(): bool {
return FALSE;
}

private function createNextJsProject(string $dir): void {
$process = $this->localMachineHelper->execute([
'npx',
Expand Down
23 changes: 9 additions & 14 deletions src/Command/App/NewFromDrupal7Command.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,13 @@
use Symfony\Component\Filesystem\Path;
use Symfony\Component\Validator\Exception\ValidatorException;

#[AsCommand(name: 'app:new:from:drupal7')]
class NewFromDrupal7Command extends CommandBase {
#[AsCommand(name: 'app:new:from:drupal7', description: 'Generate a new Drupal 9+ project from a Drupal 7 application using the default Acquia Migrate Accelerate recommendations.', aliases: [
// Currently only "from Drupal 7", more to potentially follow.
'from:d7',
// A nod to its roots.
'ama',
])]
final class NewFromDrupal7Command extends CommandBase {

/**
* Exit code raised when the URI flag does not correspond to configuration.
Expand All @@ -42,18 +47,12 @@ class NewFromDrupal7Command extends CommandBase {
public const ERR_INDETERMINATE_SITE = 4;

protected function configure(): void {
$this->setDescription('Generate a new Drupal 9+ project from a Drupal 7 application using the default Acquia Migrate Accelerate recommendations.')
$this
->addOption('drupal7-directory', 'source', InputOption::VALUE_OPTIONAL, 'The root of the Drupal 7 application')
->addOption('drupal7-uri', 'uri', InputOption::VALUE_OPTIONAL, 'Only necessary in case of a multisite. If a single site, this will be computed automatically.')
->addOption('stored-analysis', 'analysis', InputOption::VALUE_OPTIONAL, 'As an alternative to drupal7-directory, it is possible to pass a stored analysis.')
->addOption('recommendations', 'recommendations', InputOption::VALUE_OPTIONAL, 'Overrides the default recommendations.')
->addOption('directory', 'destination', InputOption::VALUE_OPTIONAL, 'The directory where to generate the new application.')
->setAliases([
// Currently only "from Drupal 7", more to potentially follow.
'from:d7',
// A nod to its roots.
'ama',
]);
->addOption('directory', 'destination', InputOption::VALUE_OPTIONAL, 'The directory where to generate the new application.');
}

private function getInspector(InputInterface $input): SiteInspectorInterface {
Expand Down Expand Up @@ -215,10 +214,6 @@ function (mixed $path): string {
return Command::SUCCESS;
}

protected function commandRequiresAuthentication(): bool {
return FALSE;
}

private function initializeGitRepository(string $dir): void {
if ($this->localMachineHelper->getFilesystem()->exists(Path::join($dir, '.git'))) {
$this->logger->debug('.git directory detected, skipping Git repo initialization');
Expand Down
8 changes: 5 additions & 3 deletions src/Command/App/TaskWaitCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,20 @@

namespace Acquia\Cli\Command\App;

use Acquia\Cli\Attribute\RequireAuth;
use Acquia\Cli\Command\CommandBase;
use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;

#[AsCommand(name: 'app:task-wait')]
class TaskWaitCommand extends CommandBase {
#[RequireAuth]
#[AsCommand(name: 'app:task-wait', description: 'Wait for a task to complete')]
final class TaskWaitCommand extends CommandBase {

protected function configure(): void {
$this->setDescription('Wait for a task to complete')
$this
->addArgument('notification-uuid', InputArgument::REQUIRED, 'The task notification UUID or Cloud Platform API response containing a linked notification')
->setHelp('Accepts either a notification UUID or Cloud Platform API response as JSON string. The JSON string must contain the _links->notification->href property.')
->addUsage('"$(acli api:environments:domain-clear-caches [environmentId] [domain])"');
Expand Down
13 changes: 2 additions & 11 deletions src/Command/App/UnlinkCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,8 @@
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;

#[AsCommand(name: 'app:unlink')]
class UnlinkCommand extends CommandBase {

protected function configure(): void {
$this->setDescription('Remove local association between your project and a Cloud Platform application')
->setAliases(['unlink']);
}

protected function commandRequiresAuthentication(): bool {
return FALSE;
}
#[AsCommand(name: 'app:unlink', description: 'Remove local association between your project and a Cloud Platform application', aliases: ['unlink'])]
final class UnlinkCommand extends CommandBase {

protected function execute(InputInterface $input, OutputInterface $output): int {
$this->validateCwdIsValidDrupalProject();
Expand Down
15 changes: 8 additions & 7 deletions src/Command/Archive/ArchiveExportCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,14 @@

namespace Acquia\Cli\Command\Archive;

use Acquia\Cli\Attribute\RequireAuth;
use Acquia\Cli\Attribute\RequireDb;
use Acquia\Cli\Command\CommandBase;
use Acquia\Cli\Exception\AcquiaCliException;
use Acquia\Cli\Output\Checklist;
use Acquia\DrupalEnvironmentDetector\AcquiaDrupalEnvironmentDetector;
use Closure;
use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
Expand All @@ -17,7 +20,10 @@
use Symfony\Component\Filesystem\Filesystem;
use Symfony\Component\Filesystem\Path;

class ArchiveExportCommand extends CommandBase {
#[RequireAuth]
#[RequireDb]
#[AsCommand(name: 'archive:export', description: 'Export an archive of the Drupal application including code, files, and database')]
final class ArchiveExportCommand extends CommandBase {

protected Checklist $checklist;

Expand All @@ -30,13 +36,8 @@ class ArchiveExportCommand extends CommandBase {

private const PUBLIC_FILES_DIR = '/docroot/sites/default/files';

protected function commandRequiresDatabase(): bool {
return TRUE;
}

protected function configure(): void {
$this->setName('archive:export');
$this->setDescription('Export an archive of the Drupal application including code, files, and database')
$this
->addArgument('destination-dir', InputArgument::REQUIRED, 'The destination directory for the archive file')
->addOption('source-dir', 'dir', InputOption::VALUE_REQUIRED, 'The directory containing the Drupal project to be pushed')
->addOption('no-files', NULL, InputOption::VALUE_NONE, 'Exclude public files directory from archive')
Expand Down
Loading

0 comments on commit 928c361

Please sign in to comment.