Thanks to visit codestin.com
Credit goes to github.com

Skip to content

[Dotenv] Variable filter added to debug command #46502

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

Merged
merged 1 commit into from
Jul 20, 2022
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
5 changes: 5 additions & 0 deletions src/Symfony/Component/Dotenv/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
CHANGELOG
=========

6.2
---

* Add new `filter` argument to `debug:dotenv` command to be able to filter certain variable

5.4
---

Expand Down
55 changes: 47 additions & 8 deletions src/Symfony/Component/Dotenv/Command/DebugCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

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;
use Symfony\Component\Console\Style\SymfonyStyle;
Expand Down Expand Up @@ -47,6 +48,25 @@ public function __construct(string $kernelEnvironment, string $projectDirectory)
parent::__construct();
}

protected function configure(): void
{
$this
->setDefinition([
new InputArgument('filter', InputArgument::OPTIONAL, 'The name of an environment variable or a filter.', null, $this->getAvailableVars(...)),
])
->setHelp(<<<'EOT'
The <info>%command.full_name%</info> command displays all the environment variables configured by dotenv:

<info>php %command.full_name%</info>

To get specific variable, specify its full or partial name:

<info>php %command.full_name% FOO_BAR</info>

EOT
);
}

protected function execute(InputInterface $input, OutputInterface $output): int
{
$io = new SymfonyStyle($input, $output);
Expand Down Expand Up @@ -78,25 +98,36 @@ protected function execute(InputInterface $input, OutputInterface $output): int
: sprintf('<fg=red>⨯</> %s', $envFile);
}, $envFiles));

$nameFilter = $input->getArgument('filter');
$variables = $this->getVariables($availableFiles, $nameFilter);

$io->section('Variables');
$io->table(
array_merge(['Variable', 'Value'], $availableFiles),
$this->getVariables($availableFiles)
);

$io->comment('Note real values might be different between web and CLI.');
if ($variables || null === $nameFilter) {
$io->table(
array_merge(['Variable', 'Value'], $availableFiles),
$this->getVariables($availableFiles, $nameFilter)
);

$io->comment('Note that values might be different between web and CLI.');
} else {
$io->warning(sprintf('No variables match the given filter "%s".', $nameFilter));
}

return 0;
}

private function getVariables(array $envFiles): array
private function getVariables(array $envFiles, ?string $nameFilter): array
{
$vars = explode(',', $_SERVER['SYMFONY_DOTENV_VARS'] ?? '');
sort($vars);
$vars = $this->getAvailableVars();

$output = [];
$fileValues = [];
foreach ($vars as $var) {
if (null !== $nameFilter && 0 !== stripos($var, $nameFilter)) {
continue;
}

$realValue = $_SERVER[$var];
$varDetails = [$var, $realValue];
foreach ($envFiles as $envFile) {
Expand All @@ -113,6 +144,14 @@ private function getVariables(array $envFiles): array
return $output;
}

private function getAvailableVars(): array
{
$vars = explode(',', $_SERVER['SYMFONY_DOTENV_VARS'] ?? '');
sort($vars);

return $vars;
}

private function getEnvFiles(): array
{
$files = [
Expand Down
86 changes: 84 additions & 2 deletions src/Symfony/Component/Dotenv/Tests/Command/DebugCommandTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
use PHPUnit\Framework\TestCase;
use Symfony\Component\Console\Helper\FormatterHelper;
use Symfony\Component\Console\Helper\HelperSet;
use Symfony\Component\Console\Tester\CommandCompletionTester;
use Symfony\Component\Console\Tester\CommandTester;
use Symfony\Component\Dotenv\Command\DebugCommand;
use Symfony\Component\Dotenv\Dotenv;
Expand Down Expand Up @@ -138,15 +139,96 @@ public function testWarningOnPhpEnvFile()
$this->assertStringContainsString('[WARNING] Due to existing dump file (.env.local.php)', $output);
}

private function executeCommand(string $projectDirectory, string $env): string
public function testScenario1InDevEnvWithNameFilter()
{
$output = $this->executeCommand(__DIR__.'/Fixtures/Scenario1', 'dev', ['filter' => 'FoO']);

// Scanned Files
$this->assertStringContainsString('⨯ .env.local.php', $output);
$this->assertStringContainsString('⨯ .env.dev.local', $output);
$this->assertStringContainsString('⨯ .env.dev', $output);
$this->assertStringContainsString('✓ .env.local', $output);
$this->assertStringContainsString('✓ .env'.\PHP_EOL, $output);

// Skipped Files
$this->assertStringNotContainsString('.env.prod', $output);
$this->assertStringNotContainsString('.env.test', $output);
$this->assertStringNotContainsString('.env.dist', $output);

// Variables
$this->assertStringContainsString('Variable Value .env.local .env', $output);
$this->assertStringContainsString('FOO baz baz bar', $output);
$this->assertStringNotContainsString('TEST123 true n/a true', $output);
}

public function testScenario1InProdEnvWithMissingNameFilter()
{
$output = $this->executeCommand(__DIR__.'/Fixtures/Scenario1', 'prod', ['filter' => 'unknown']);

// Scanned Files
$this->assertStringContainsString('⨯ .env.local.php', $output);
$this->assertStringContainsString('✓ .env.prod.local', $output);
$this->assertStringContainsString('⨯ .env.prod', $output);
$this->assertStringContainsString('✓ .env.local', $output);
$this->assertStringContainsString('✓ .env'.\PHP_EOL, $output);

// Skipped Files
$this->assertStringNotContainsString('.env.dev', $output);
$this->assertStringNotContainsString('.env.test', $output);
$this->assertStringNotContainsString('.env.dist', $output);

// Variables
$this->assertStringContainsString('[WARNING] No variables match the given filter "unknown".', $output);
$this->assertStringNotContainsString('Variable Value .env.prod.local .env.local .env', $output);
$this->assertStringNotContainsString('FOO baz n/a baz bar', $output);
$this->assertStringNotContainsString('HELLO world world n/a n/a', $output);
$this->assertStringNotContainsString('TEST123 true n/a n/a true', $output);
}

public function testScenario2InProdEnvWithNameFilterPrefix()
{
$output = $this->executeCommand(__DIR__.'/Fixtures/Scenario2', 'prod', ['filter' => 'tes']);

// Scanned Files
$this->assertStringContainsString('✓ .env.local.php', $output);
$this->assertStringContainsString('⨯ .env.prod.local', $output);
$this->assertStringContainsString('✓ .env.prod', $output);
$this->assertStringContainsString('⨯ .env.local', $output);
$this->assertStringContainsString('✓ .env.dist', $output);

// Skipped Files
$this->assertStringNotContainsString('.env'.\PHP_EOL, $output);
$this->assertStringNotContainsString('.env.dev', $output);
$this->assertStringNotContainsString('.env.test', $output);

// Variables
$this->assertStringContainsString('Variable Value .env.local.php .env.prod .env.dist', $output);
$this->assertStringNotContainsString('FOO BaR BaR BaR n/a', $output);
$this->assertStringContainsString('TEST 1234 1234 1234 0000', $output);
}

public function testCompletion()
{
$env = 'prod';
$projectDirectory = __DIR__.'/Fixtures/Scenario2';

$_SERVER['TEST_ENV_KEY'] = $env;
(new Dotenv('TEST_ENV_KEY'))->bootEnv($projectDirectory.'/.env');

$command = new DebugCommand($env, $projectDirectory);
$tester = new CommandCompletionTester($command);
$this->assertSame(['FOO', 'HELLO', 'TEST', 'TEST123'], $tester->complete(['']));
}

private function executeCommand(string $projectDirectory, string $env, array $input = []): string
{
$_SERVER['TEST_ENV_KEY'] = $env;
(new Dotenv('TEST_ENV_KEY'))->bootEnv($projectDirectory.'/.env');

$command = new DebugCommand($env, $projectDirectory);
$command->setHelperSet(new HelperSet([new FormatterHelper()]));
$tester = new CommandTester($command);
$tester->execute([]);
$tester->execute($input);

return $tester->getDisplay();
}
Expand Down