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

CLI-1402: [push:db] Warn if view database connection details permission is missing #1810

Merged
merged 8 commits into from
Oct 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@
"symfony/yaml": "^6.3",
"thecodingmachine/safe": "^2.4",
"typhonius/acquia-logstream": "^0.0.13",
"typhonius/acquia-php-sdk-v2": "^3.1.1",
"typhonius/acquia-php-sdk-v2": "^3.3.2",
"vlucas/phpdotenv": "^5.5",
"zumba/amplitude-php": "^1.0.4"
},
Expand Down
304 changes: 152 additions & 152 deletions composer.lock

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@
namespace Acquia\Cli\Attribute;

/**
* Specify that a command requires authentication.
* Specify that a command requires local database.
*/
#[\Attribute(\Attribute::TARGET_CLASS)]
class RequireDb
class RequireLocalDb
{
}
13 changes: 13 additions & 0 deletions src/Attribute/RequireRemoteDb.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 remote database.
*/
#[\Attribute(\Attribute::TARGET_CLASS)]
class RequireRemoteDb
{
}
4 changes: 2 additions & 2 deletions src/Command/Archive/ArchiveExportCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
namespace Acquia\Cli\Command\Archive;

use Acquia\Cli\Attribute\RequireAuth;
use Acquia\Cli\Attribute\RequireDb;
use Acquia\Cli\Attribute\RequireLocalDb;
use Acquia\Cli\Command\CommandBase;
use Acquia\Cli\Exception\AcquiaCliException;
use Acquia\Cli\Output\Checklist;
Expand All @@ -21,7 +21,7 @@
use Symfony\Component\Filesystem\Path;

#[RequireAuth]
#[RequireDb]
#[RequireLocalDb]
#[AsCommand(name: 'archive:export', description: 'Export an archive of the Drupal application including code, files, and database')]
final class ArchiveExportCommand extends CommandBase
{
Expand Down
8 changes: 6 additions & 2 deletions src/Command/CommandBase.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@
use Acquia\Cli\AcsfApi\AcsfClientService;
use Acquia\Cli\ApiCredentialsInterface;
use Acquia\Cli\Attribute\RequireAuth;
use Acquia\Cli\Attribute\RequireDb;
use Acquia\Cli\Attribute\RequireLocalDb;
use Acquia\Cli\Attribute\RequireRemoteDb;
use Acquia\Cli\CloudApi\ClientService;
use Acquia\Cli\Command\Ssh\SshKeyCommandBase;
use Acquia\Cli\DataStore\AcquiaCliDatastore;
Expand Down Expand Up @@ -119,10 +120,13 @@ public function __construct(
if ((new \ReflectionClass(static::class))->getAttributes(RequireAuth::class)) {
$this->appendHelp('This command requires authentication via the Cloud Platform API.');
}
if ((new \ReflectionClass(static::class))->getAttributes(RequireDb::class)) {
if ((new \ReflectionClass(static::class))->getAttributes(RequireLocalDb::class)) {
$this->appendHelp('This command requires an active database connection. Set the following environment variables prior to running this command: '
. 'ACLI_DB_HOST, ACLI_DB_NAME, ACLI_DB_USER, ACLI_DB_PASSWORD');
}
if ((new \ReflectionClass(static::class))->getAttributes(RequireRemoteDb::class)) {
$this->appendHelp('This command requires the \'View database connection details\' permission.');
}
}

public function appendHelp(string $helpText): void
Expand Down
4 changes: 2 additions & 2 deletions src/Command/Pull/PullCodeCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
namespace Acquia\Cli\Command\Pull;

use Acquia\Cli\Attribute\RequireAuth;
use Acquia\Cli\Attribute\RequireDb;
use Acquia\Cli\Attribute\RequireLocalDb;
use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
Expand All @@ -14,7 +14,7 @@
use Symfony\Component\Console\Output\OutputInterface;

#[RequireAuth]
#[RequireDb]
#[RequireLocalDb]
#[AsCommand(name: 'pull:code', description: 'Copy code from a Cloud Platform environment')]
final class PullCodeCommand extends PullCommandBase
{
Expand Down
4 changes: 2 additions & 2 deletions src/Command/Pull/PullCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
namespace Acquia\Cli\Command\Pull;

use Acquia\Cli\Attribute\RequireAuth;
use Acquia\Cli\Attribute\RequireDb;
use Acquia\Cli\Attribute\RequireLocalDb;
use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
Expand All @@ -14,7 +14,7 @@
use Symfony\Component\Console\Output\OutputInterface;

#[RequireAuth]
#[RequireDb]
#[RequireLocalDb]
#[AsCommand(name: 'pull:all', description: 'Copy code, database, and files from a Cloud Platform environment', aliases: [
'refresh',
'pull',
Expand Down
1 change: 1 addition & 0 deletions src/Command/Pull/PullCommandBase.php
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@ protected function pullCode(InputInterface $input, OutputInterface $output, bool
/**
* @param bool $onDemand Force on-demand backup.
* @param bool $noImport Skip import.
* @throws \Acquia\Cli\Exception\AcquiaCliException
*/
protected function pullDatabase(InputInterface $input, OutputInterface $output, EnvironmentResponse $sourceEnvironment, bool $onDemand = false, bool $noImport = false, bool $multipleDbs = false): void
{
Expand Down
8 changes: 6 additions & 2 deletions src/Command/Pull/PullDatabaseCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,16 @@
namespace Acquia\Cli\Command\Pull;

use Acquia\Cli\Attribute\RequireAuth;
use Acquia\Cli\Attribute\RequireDb;
use Acquia\Cli\Attribute\RequireLocalDb;
use Acquia\Cli\Attribute\RequireRemoteDb;
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;

#[RequireAuth]
#[RequireDb]
#[RequireLocalDb]
#[AsCommand(name: 'pull:database', description: 'Import database backup from a Cloud Platform environment', aliases: ['pull:db'])]
final class PullDatabaseCommand extends PullCommandBase
{
Expand Down Expand Up @@ -49,6 +50,9 @@ protected function configure(): void
);
}

/**
* @throws \Acquia\Cli\Exception\AcquiaCliException
*/
protected function execute(InputInterface $input, OutputInterface $output): int
{
$noScripts = $input->hasOption('no-scripts') && $input->getOption('no-scripts');
Expand Down
12 changes: 10 additions & 2 deletions src/Command/Push/PushDatabaseCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
namespace Acquia\Cli\Command\Push;

use Acquia\Cli\Attribute\RequireAuth;
use Acquia\Cli\Attribute\RequireDb;
use Acquia\Cli\Attribute\RequireLocalDb;
use Acquia\Cli\Attribute\RequireRemoteDb;
use Acquia\Cli\Exception\AcquiaCliException;
use Acquia\Cli\Output\Checklist;
use AcquiaCloudApi\Response\DatabaseResponse;
Expand All @@ -16,7 +17,8 @@
use Symfony\Component\Console\Output\OutputInterface;

#[RequireAuth]
#[RequireDb]
#[RequireLocalDb]
#[RequireRemoteDb]
#[AsCommand(name: 'push:database', description: 'Push a database from your local environment to a Cloud Platform environment', aliases: ['push:db'])]
final class PushDatabaseCommand extends PushCommandBase
{
Expand All @@ -27,13 +29,19 @@ protected function configure(): void
->acceptSite();
}

/**
* @throws \Acquia\Cli\Exception\AcquiaCliException
*/
protected function execute(InputInterface $input, OutputInterface $output): int
{
$destinationEnvironment = $this->determineEnvironment($input, $output);
$acquiaCloudClient = $this->cloudApiClientService->getClient();
$databases = $this->determineCloudDatabases($acquiaCloudClient, $destinationEnvironment, $input->getArgument('site'));
// We only support pushing a single database.
$database = $databases[0];
if ($database->user_name === null) {
throw new AcquiaCliException('Database connection details missing');
}
$answer = $this->io->confirm("Overwrite the <bg=cyan;options=bold>$database->name</> database on <bg=cyan;options=bold>$destinationEnvironment->name</> with a copy of the database from the current machine?");
if (!$answer) {
return Command::SUCCESS;
Expand Down
3 changes: 3 additions & 0 deletions src/EventListener/ExceptionListener.php
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,9 @@ public function onConsoleError(ConsoleErrorEvent $event): void
$this->helpMessages[] = 'Check for MySQL warnings above or in the server log (/var/log/mysql/error.log)';
$this->helpMessages[] = 'Frequently, `MySQL server has gone away` messages are caused by max_allowed_packet being exceeded.';
break;
case 'Database connection details missing':
$this->helpMessages[] = 'Check that you have the \'View database connection details\' permission';
break;
}
}

Expand Down
2 changes: 1 addition & 1 deletion tests/phpunit/src/Commands/Pull/PullCommandTestBase.php
Original file line number Diff line number Diff line change
Expand Up @@ -354,7 +354,7 @@ protected function mockListSites(SshHelper|ObjectProphecy $sshHelper): void
public function mockGetBackup(mixed $environment): void
{
$databases = $this->mockRequest('getEnvironmentsDatabases', $environment->id);
$tamper = function ($backups): void {
$tamper = static function ($backups): void {
$backups[0]->completedAt = $backups[0]->completed_at;
};
$backups = new BackupsResponse(
Expand Down
25 changes: 25 additions & 0 deletions tests/phpunit/src/Commands/Push/PushDatabaseCommandTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

use Acquia\Cli\Command\CommandBase;
use Acquia\Cli\Command\Push\PushDatabaseCommand;
use Acquia\Cli\Exception\AcquiaCliException;
use Acquia\Cli\Helpers\LocalMachineHelper;
use Acquia\Cli\Helpers\SshHelper;
use Acquia\Cli\Tests\CommandTestBase;
Expand Down Expand Up @@ -108,6 +109,30 @@ public function testPushDatabase(int $verbosity, bool $printOutput, bool $pv): v
$this->assertStringContainsString('Overwrite the jxr136 database on dev with a copy of the database from the current machine?', $output);
}

public function testPushDbHelp(): void
{
$help = $this->command->getHelp();
$this->assertStringContainsString('This command requires authentication via the Cloud Platform API.', $help);
$this->assertStringContainsString('This command requires an active database connection. Set the following environment variables prior to running this command: ACLI_DB_HOST, ACLI_DB_NAME, ACLI_DB_USER, ACLI_DB_PASSWORD', $help);
$this->assertStringContainsString('This command requires the \'View database connection details\' permission.', $help);
}

/**
* @throws \Exception
*/
public function testPushDatabaseWithMissingPermission(): void
{
$environment = $this->mockGetEnvironment();
$tamper = static function ($databases): void {
$databases[0]->user_name = null;
};
$this->mockRequest('getEnvironmentsDatabases', $environment->id, null, null, $tamper);

$this->expectException(AcquiaCliException::class);
$this->expectExceptionMessage('Database connection details missing');
$this->executeCommand([], self::inputChooseEnvironment());
}

protected function mockUploadDatabaseDump(
ObjectProphecy $localMachineHelper,
ObjectProphecy $process,
Expand Down
4 changes: 4 additions & 0 deletions tests/phpunit/src/Misc/ExceptionListenerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,10 @@ public function providerTestHelp(): array
'Frequently, `MySQL server has gone away` messages are caused by max_allowed_packet being exceeded.',
],
],
[
new AcquiaCliException('Database connection details missing'),
'Check that you have the \'View database connection details\' permission',
],
[
new ApiErrorException((object) [
'error' => '',
Expand Down