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

Command documentation #213

Merged
merged 2 commits into from
Nov 12, 2023
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
8 changes: 5 additions & 3 deletions config/packages/draw_framework_extra.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ draw_framework_extra:

configuration: ~

console: ~
console:
documentation:
ignored_commands: [ 'completion', 'help', 'list' ]

doctrine_extra: ~

Expand Down Expand Up @@ -38,7 +40,7 @@ draw_framework_extra:
doctrine_message_bus_hook: ~
retry:
event_driven:
transports: ['async']
transports: [ 'async' ]

serializer_event_dispatcher: ~
versioning: ~
Expand Down Expand Up @@ -72,7 +74,7 @@ draw_framework_extra:
all:
tags: ~
tag:
tags: ['Tags']
tags: [ 'Tags' ]

sort_schema: true

Expand Down
91 changes: 91 additions & 0 deletions packages/console/Command/GenerateDocumentationCommand.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
<?php

namespace Draw\Component\Console\Command;

use Draw\Component\Console\Event\GenerateDocumentationEvent;
use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Helper\DescriptorHelper;
use Symfony\Component\Console\Helper\ProgressBar;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Output\StreamOutput;
use Symfony\Component\Console\Style\SymfonyStyle;
use Symfony\Component\Filesystem\Filesystem;
use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;

#[AsCommand(name: 'draw:console:generate-documentation')]
class GenerateDocumentationCommand extends Command
{
public function __construct(private ?EventDispatcherInterface $eventDispatcher = null)
{
parent::__construct();
}

protected function configure(): void
{
$this
->setDescription('Generate a documentation for all the command of the application.')
->addArgument('path', InputArgument::REQUIRED, 'The path where the documentation will be generated.');
}

protected function execute(InputInterface $input, OutputInterface $output): int
{
$io = new SymfonyStyle($input, $output);

$io->section('Generate documentation');

$filePath = $input->getArgument('path');

$filesystem = new Filesystem();

$directoryPath = \dirname($filePath);

if (!$filesystem->exists($directoryPath)) {
$filesystem->mkdir($directoryPath);
}

file_put_contents($filePath, '');

$file = fopen($filePath, 'w');

$commandOutput = new StreamOutput($file);

$commands = $this->getApplication()->all();

$progress = $io->createProgressBar(\count($commands));
$progress->setFormat(ProgressBar::FORMAT_DEBUG);

$descriptionHelper = new DescriptorHelper();

foreach ($commands as $command) {
$event = new GenerateDocumentationEvent($command);
$this->eventDispatcher?->dispatch($event);

if ($event->isIgnored()) {
continue;
}

$descriptionHelper->describe(
$commandOutput,
$command,
[
'format' => 'md',
'raw_text' => false,
]
);

fwrite($file, "\n\n");

$progress->advance();
}

$progress->finish();

$io->newLine(2);
$io->success('Export completed');

return Command::SUCCESS;
}
}
37 changes: 37 additions & 0 deletions packages/console/Event/GenerateDocumentationEvent.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<?php

namespace Draw\Component\Console\Event;

use Symfony\Component\Console\Command\Command;
use Symfony\Contracts\EventDispatcher\Event;

/**
* Event when we generate the documentation of the application.
* It's dispatched for every command.
*
* You can ignore the documentation of a command by calling the ignore method.
*/
class GenerateDocumentationEvent extends Event
{
private bool $ignore = false;

public function __construct(private Command $command)
{
}

public function getCommand(): Command
{
return $this->command;
}

public function ignore(): void
{
$this->ignore = true;
$this->stopPropagation();
}

public function isIgnored(): bool
{
return $this->ignore;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?php

namespace Draw\Bundle\FrameworkExtraBundle\Console\EventListener;

use Draw\Component\Console\Event\GenerateDocumentationEvent;
use Symfony\Component\EventDispatcher\Attribute\AsEventListener;

class DocumentationIgnoredCommandEventListener
{
public function __construct(private array $ignoredCommandNames)
{
}

#[AsEventListener]
public function onGenerateDocumentationEvent(GenerateDocumentationEvent $event): void
{
if (\in_array($event->getCommand()->getName(), $this->ignoredCommandNames)) {
$event->ignore();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

namespace Draw\Bundle\FrameworkExtraBundle\DependencyInjection\Integration;

use Draw\Bundle\FrameworkExtraBundle\Console\EventListener\DocumentationIgnoredCommandEventListener;
use Draw\Bundle\FrameworkExtraBundle\DrawFrameworkExtraBundle;
use Draw\Component\Console\Command\PurgeExecutionCommand;
use Draw\Component\Console\Entity\Execution;
use Draw\Component\Console\EventListener\CommandFlowListener;
Expand Down Expand Up @@ -41,13 +43,38 @@ public function load(array $config, PhpFileLoader $loader, ContainerBuilder $con
$namespace,
'draw.console.'
);

$this->registerClasses(
$loader,
$namespace = 'Draw\\Bundle\\FrameworkExtraBundle\\Console\\',
\dirname((new \ReflectionClass(DrawFrameworkExtraBundle::class))->getFileName()).'/Console'
);

$container
->getDefinition(DocumentationIgnoredCommandEventListener::class)
->setArgument('$ignoredCommandNames', $config['documentation']['ignored_commands']);

$this->renameDefinitions(
$container,
$namespace,
'draw.console.'
);
}

public function addConfiguration(ArrayNodeDefinition $node): void
{
$node
->children()
->booleanNode('ignore_disabled_command')->defaultFalse()->end()
->arrayNode('documentation')
->addDefaultsIfNotSet()
->children()
->arrayNode('ignored_commands')
->defaultValue([])
->scalarPrototype()->end()
->end()
->end()
->end()
->end();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@
namespace Draw\Bundle\FrameworkExtraBundle\Tests\DependencyInjection\Integration;

use Doctrine\Bundle\DoctrineBundle\DependencyInjection\DoctrineExtension;
use Draw\Bundle\FrameworkExtraBundle\Console\EventListener\DocumentationIgnoredCommandEventListener;
use Draw\Bundle\FrameworkExtraBundle\DependencyInjection\Integration\ConsoleIntegration;
use Draw\Bundle\FrameworkExtraBundle\DependencyInjection\Integration\IntegrationInterface;
use Draw\Component\Console\Command\GenerateDocumentationCommand;
use Draw\Component\Console\Command\PurgeExecutionCommand;
use Draw\Component\Console\Entity\Execution;
use Draw\Component\Console\EventListener\CommandFlowListener;
Expand Down Expand Up @@ -32,6 +34,9 @@ public function getDefaultConfiguration(): array
{
return [
'ignore_disabled_command' => false,
'documentation' => [
'ignored_commands' => [],
],
];
}

Expand Down Expand Up @@ -86,9 +91,20 @@ public static function provideTestLoad(): iterable
[
[
'ignore_disabled_command' => true,
'documentation' => [
'ignored_commands' => [
'help',
],
],
],
],
[
new ServiceConfiguration(
'draw.console.command.generate_documentation_command',
[
GenerateDocumentationCommand::class,
],
),
new ServiceConfiguration(
'draw.console.command.purge_execution_command',
[
Expand All @@ -106,6 +122,18 @@ function (Definition $definition): void {
);
}
),
new ServiceConfiguration(
'draw.console.event_listener.documentation_ignored_command_event_listener',
[
DocumentationIgnoredCommandEventListener::class,
],
function (Definition $definition): void {
static::assertSame(
['help'],
$definition->getArgument('$ignoredCommandNames')
);
}
),
],
];
}
Expand Down
87 changes: 87 additions & 0 deletions tests/Console/Command/GenerateDocumentationCommandTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
<?php

namespace App\Tests\Console\Command;

use App\Tests\FilteredCommandTestTrait;
use App\Tests\TestCase;
use Draw\Component\Console\Command\GenerateDocumentationCommand;
use Draw\Component\Tester\Application\CommandDataTester;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;

/**
* @covers \Draw\Component\Console\Command\GenerateDocumentationCommand
*/
class GenerateDocumentationCommandTest extends TestCase
{
use FilteredCommandTestTrait;

private bool $writeFile = false;

public function createCommand(): Command
{
return static::getContainer()->get(GenerateDocumentationCommand::class);
}

public function getCommandName(): string
{
return 'draw:console:generate-documentation';
}

public static function provideTestArgument(): iterable
{
yield [
'path',
InputArgument::REQUIRED,
];

}

public static function provideTestOption(): iterable
{
return [];
}

public function testExecute(): void
{
$filePath = tempnam(sys_get_temp_dir(), 'testExecute');

register_shutdown_function(
function () use ($filePath): void {
if (file_exists($filePath)) {
unlink($filePath);
}
}
);

$this->execute(['path' => $filePath])
->test(
CommandDataTester::create()
->setExpectedDisplay([
'Generate documentation',
'Export completed',
])
->setExpectedErrorOutput(null)
);

if ($this->writeFile) {
file_put_contents(
__DIR__.'/fixtures/GenerateDocumentationCommandTest/testExecution_expectedExport.md',
file_get_contents($filePath)
);
}

static::assertFileEquals(
__DIR__.'/fixtures/GenerateDocumentationCommandTest/testExecution_expectedExport.md',
$filePath
);
}

public function testWriteFile(): void
{
static::assertFalse(
$this->writeFile,
'Do not forget to put this variable back to false.'
);
}
}
Loading
Loading