diff --git a/src/Command/Auth/AuthAcsfLoginCommand.php b/src/Command/Auth/AuthAcsfLoginCommand.php index 861a180fd..04f27177d 100644 --- a/src/Command/Auth/AuthAcsfLoginCommand.php +++ b/src/Command/Auth/AuthAcsfLoginCommand.php @@ -11,7 +11,7 @@ use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; -#[AsCommand(name: 'auth:acsf-login', description: 'Register your Site Factory API key and secret to use API functionality')] +#[AsCommand(name: 'auth:acsf-login', description: 'Register Acquia Site Factory API credentials')] final class AuthAcsfLoginCommand extends CommandBase { protected function configure(): void { diff --git a/src/Command/Auth/AuthAcsfLogoutCommand.php b/src/Command/Auth/AuthAcsfLogoutCommand.php index 171272e27..2625c4725 100644 --- a/src/Command/Auth/AuthAcsfLogoutCommand.php +++ b/src/Command/Auth/AuthAcsfLogoutCommand.php @@ -10,7 +10,7 @@ use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; -#[AsCommand(name: 'auth:acsf-logout', description: 'Remove your Site Factory key and secret from your local machine.')] +#[AsCommand(name: 'auth:acsf-logout', description: 'Remove Acquia Site Factory API credentials')] final class AuthAcsfLogoutCommand extends CommandBase { protected function execute(InputInterface $input, OutputInterface $output): int { diff --git a/src/Command/Auth/AuthLoginCommand.php b/src/Command/Auth/AuthLoginCommand.php index 321665e83..c6196403e 100644 --- a/src/Command/Auth/AuthLoginCommand.php +++ b/src/Command/Auth/AuthLoginCommand.php @@ -11,7 +11,7 @@ use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; -#[AsCommand(name: 'auth:login', description: 'Register your Cloud API key and secret to use API functionality', aliases: ['login'])] +#[AsCommand(name: 'auth:login', description: 'Register Acquia Cloud API credentials', aliases: ['login'])] final class AuthLoginCommand extends CommandBase { protected function configure(): void { diff --git a/src/Command/Auth/AuthLogoutCommand.php b/src/Command/Auth/AuthLogoutCommand.php index 9edda39f7..d8c22ead6 100644 --- a/src/Command/Auth/AuthLogoutCommand.php +++ b/src/Command/Auth/AuthLogoutCommand.php @@ -5,24 +5,35 @@ namespace Acquia\Cli\Command\Auth; 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\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; -#[AsCommand(name: 'auth:logout', description: 'Remove Cloud API key and secret from local machine.', aliases: ['logout'])] +#[AsCommand(name: 'auth:logout', description: 'Remove Acquia Cloud API credentials', aliases: ['logout'])] final class AuthLogoutCommand extends CommandBase { + protected function configure(): void { + $this->addOption('delete', NULL, InputOption::VALUE_NEGATABLE, 'Delete the active Acquia Cloud API credentials'); + } + protected function execute(InputInterface $input, OutputInterface $output): int { - if ($this->cloudApiClientService->isMachineAuthenticated()) { - $answer = $this->io->confirm('Are you sure you\'d like to unset the Acquia Cloud API key for Acquia CLI?'); - if (!$answer) { - return Command::SUCCESS; - } + if (!$this->cloudApiClientService->isMachineAuthenticated()) { + throw new AcquiaCliException('You are not authenticated and therefore cannot logout'); } + $activeKey = $this->datastoreCloud->get('acli_key'); + $output->writeln("The active key $activeKey will be unset. You may also delete the active credentials entirely."); + $delete = $this->determineOption('delete', FALSE, NULL, NULL, TRUE); $this->datastoreCloud->remove('acli_key'); - - $output->writeln("Unset the Acquia Cloud API key for Acquia CLI"); + if ($delete) { + $this->datastoreCloud->remove("keys.$activeKey"); + $output->writeln("The active Acquia Cloud API credentials were deleted"); + } + else { + $output->writeln("The active Acquia Cloud API credentials were unset"); + } return Command::SUCCESS; } diff --git a/src/Command/CommandBase.php b/src/Command/CommandBase.php index 73be130d9..316e702ab 100644 --- a/src/Command/CommandBase.php +++ b/src/Command/CommandBase.php @@ -62,6 +62,7 @@ use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Question\ChoiceQuestion; +use Symfony\Component\Console\Question\ConfirmationQuestion; use Symfony\Component\Console\Question\Question; use Symfony\Component\Console\Style\SymfonyStyle; use Symfony\Component\Console\Terminal; @@ -1349,7 +1350,7 @@ protected function determineApiSecret(): string { * explicitly or by default. In other words, we can't prompt for the value of * an option that already has a default value. */ - protected function determineOption(string $optionName, bool $hidden = FALSE, ?Closure $validator = NULL, ?Closure $normalizer = NULL, ?string $default = NULL): string|int|null { + protected function determineOption(string $optionName, bool $hidden = FALSE, ?Closure $validator = NULL, ?Closure $normalizer = NULL, string|bool|null $default = NULL): string|int|bool|null { if ($optionValue = $this->input->getOption($optionName)) { if (isset($normalizer)) { $optionValue = $normalizer($optionValue); @@ -1360,18 +1361,32 @@ protected function determineOption(string $optionName, bool $hidden = FALSE, ?Cl return $optionValue; } $option = $this->getDefinition()->getOption($optionName); + if ($option->isNegatable() && $this->input->getOption("no-$optionName")) { + return FALSE; + } $optionShortcut = $option->getShortcut(); $description = lcfirst($option->getDescription()); if ($optionShortcut) { - $message = "Enter $description (option -$optionShortcut, --$optionName)"; + $optionString = "option -$optionShortcut, --$optionName"; + } + else { + $optionString = "option --$optionName"; + } + if ($option->acceptValue()) { + $message = "Enter $description ($optionString)"; } else { - $message = "Enter $description (option --$optionName)"; + $message = "Do you want to $description ($optionString)?"; } $optional = $option->isValueOptional(); $message .= $optional ? ' (optional)' : ''; $message .= $hidden ? ' (input will be hidden)' : ''; - $question = new Question($message, $default); + if ($option->acceptValue()) { + $question = new Question($message, $default); + } + else { + $question = new ConfirmationQuestion($message, $default); + } $question->setHidden($this->localMachineHelper->useTty() && $hidden); $question->setHiddenFallback($hidden); if (isset($normalizer)) { diff --git a/tests/phpunit/src/Application/KernelTest.php b/tests/phpunit/src/Application/KernelTest.php index fc858a044..edac959cb 100644 --- a/tests/phpunit/src/Application/KernelTest.php +++ b/tests/phpunit/src/Application/KernelTest.php @@ -60,10 +60,10 @@ private function getEnd(): string { archive archive:export Export an archive of the Drupal application including code, files, and database auth - auth:acsf-login Register your Site Factory API key and secret to use API functionality - auth:acsf-logout Remove your Site Factory key and secret from your local machine. - auth:login [login] Register your Cloud API key and secret to use API functionality - auth:logout [logout] Remove Cloud API key and secret from local machine. + auth:acsf-login Register Acquia Site Factory API credentials + auth:acsf-logout Remove Acquia Site Factory API credentials + auth:login [login] Register Acquia Cloud API credentials + auth:logout [logout] Remove Acquia Cloud API credentials codestudio codestudio:php-version Change the PHP version in Code Studio codestudio:wizard [cs:wizard] Create and/or configure a new Code Studio project for a given Acquia Cloud application diff --git a/tests/phpunit/src/Commands/Auth/AuthLogoutCommandTest.php b/tests/phpunit/src/Commands/Auth/AuthLogoutCommandTest.php index 4f7f241a2..8f9467210 100644 --- a/tests/phpunit/src/Commands/Auth/AuthLogoutCommandTest.php +++ b/tests/phpunit/src/Commands/Auth/AuthLogoutCommandTest.php @@ -7,6 +7,7 @@ use Acquia\Cli\Command\Auth\AuthLogoutCommand; use Acquia\Cli\Config\CloudDataConfig; use Acquia\Cli\DataStore\CloudDataStore; +use Acquia\Cli\Exception\AcquiaCliException; use Acquia\Cli\Tests\CommandTestBase; use Symfony\Component\Console\Command\Command; @@ -19,36 +20,43 @@ protected function createCommand(): Command { return $this->injectCommand(AuthLogoutCommand::class); } - /** - * @return array - */ - public function providerTestAuthLogoutCommand(): array { - return [ - [FALSE, []], - [ - TRUE, - // Are you sure you'd like to remove your Cloud API login credentials from this machine? - ['y'], - ], - ]; + public function testAuthLogoutCommand(): void { + $this->executeCommand(); + $output = $this->getDisplay(); + $this->assertFileExists($this->cloudConfigFilepath); + $config = new CloudDataStore($this->localMachineHelper, new CloudDataConfig(), $this->cloudConfigFilepath); + $this->assertFalse($config->exists('acli_key')); + $this->assertEmpty($config->get('keys')); + $this->assertStringContainsString('The active Acquia Cloud API credentials were deleted', $output); + } + + public function testAuthLogoutCommandNotAuthenticated(): void { + $this->clientServiceProphecy->isMachineAuthenticated()->willReturn(FALSE); + $this->removeMockCloudConfigFile(); + + $this->expectException(AcquiaCliException::class); + $this->expectExceptionMessage('You are not authenticated and therefore cannot logout'); + $this->executeCommand(); + } + + public function testAuthLogoutCommandNoDeleteArg(): void { + $this->executeCommand(['--no-delete' => TRUE]); + $output = $this->getDisplay(); + $this->assertFileExists($this->cloudConfigFilepath); + $config = new CloudDataStore($this->localMachineHelper, new CloudDataConfig(), $this->cloudConfigFilepath); + $this->assertFalse($config->exists('acli_key')); + $this->assertNotEmpty($config->get('keys')); + $this->assertStringContainsString('The active Acquia Cloud API credentials were unset', $output); } - /** - * @dataProvider providerTestAuthLogoutCommand - * @param array $inputs - */ - public function testAuthLogoutCommand(bool $machineIsAuthenticated, array $inputs): void { - if (!$machineIsAuthenticated) { - $this->clientServiceProphecy->isMachineAuthenticated()->willReturn(FALSE); - $this->removeMockCloudConfigFile(); - } - - $this->executeCommand([], $inputs); + public function testAuthLogoutCommandNoDeleteInput(): void { + $this->executeCommand([], ['n']); $output = $this->getDisplay(); - // Assert creds are removed locally. $this->assertFileExists($this->cloudConfigFilepath); $config = new CloudDataStore($this->localMachineHelper, new CloudDataConfig(), $this->cloudConfigFilepath); $this->assertFalse($config->exists('acli_key')); + $this->assertNotEmpty($config->get('keys')); + $this->assertStringContainsString('The active Acquia Cloud API credentials were unset', $output); } }