Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
96.05% covered (success)
96.05%
73 / 76
66.67% covered (warning)
66.67%
2 / 3
CRAP
0.00% covered (danger)
0.00%
0 / 1
ReportsCommand
96.05% covered (success)
96.05%
73 / 76
66.67% covered (warning)
66.67%
2 / 3
15
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 configure
100.00% covered (success)
100.00%
25 / 25
100.00% covered (success)
100.00%
1 / 1
1
 execute
94.00% covered (success)
94.00%
47 / 50
0.00% covered (danger)
0.00%
0 / 1
13.04
1<?php
2
3declare(strict_types=1);
4
5/**
6 * Fast Forward Development Tools for PHP projects.
7 *
8 * This file is part of fast-forward/dev-tools project.
9 *
10 * @author   Felipe SayĆ£o Lobato Abreu <github@mentordosnerds.com>
11 * @license  https://opensource.org/licenses/MIT MIT License
12 *
13 * @see      https://github.com/php-fast-forward/
14 * @see      https://github.com/php-fast-forward/dev-tools
15 * @see      https://github.com/php-fast-forward/dev-tools/issues
16 * @see      https://php-fast-forward.github.io/dev-tools/
17 * @see      https://datatracker.ietf.org/doc/html/rfc2119
18 */
19
20namespace FastForward\DevTools\Console\Command;
21
22use FastForward\DevTools\Console\Command\Traits\LogsCommandResults;
23use Composer\Command\BaseCommand;
24use Composer\Console\Input\InputOption;
25use FastForward\DevTools\Console\Input\HasJsonOption;
26use FastForward\DevTools\Process\ProcessBuilderInterface;
27use FastForward\DevTools\Process\ProcessQueueInterface;
28use FastForward\DevTools\Path\ManagedWorkspace;
29use Psr\Log\LoggerInterface;
30use Symfony\Component\Console\Attribute\AsCommand;
31use Symfony\Component\Console\Input\InputInterface;
32use Symfony\Component\Console\Output\BufferedOutput;
33use Symfony\Component\Console\Output\OutputInterface;
34
35/**
36 * Coordinates the generation of Fast Forward documentation frontpage and related reports.
37 * This class MUST NOT be overridden and SHALL securely combine docs and testing commands.
38 */
39#[AsCommand(
40    name: 'reports',
41    description: 'Generates the frontpage for Fast Forward documentation.',
42    help: 'This command generates the frontpage for Fast Forward documentation, including links to API documentation and test reports.'
43)]
44 class ReportsCommand extends BaseCommand implements LoggerAwareCommandInterface
45{
46    use HasJsonOption;
47    use LogsCommandResults;
48
49    /**
50     * Initializes the command with required dependencies.
51     *
52     * @param ProcessBuilderInterface $processBuilder the builder instance used to construct execution processes
53     * @param ProcessQueueInterface $processQueue the execution queue mechanism for running sub-processes
54     * @param LoggerInterface $logger the output-aware logger
55     */
56    public function __construct(
57        private  ProcessBuilderInterface $processBuilder,
58        private  ProcessQueueInterface $processQueue,
59        private  LoggerInterface $logger,
60    ) {
61        parent::__construct();
62    }
63
64    /**
65     * @return void
66     */
67    protected function configure(): void
68    {
69        $this->addJsonOption()
70            ->addOption(
71                name: 'progress',
72                mode: InputOption::VALUE_NONE,
73                description: 'Whether to enable progress output from generated report commands.',
74            )
75            ->addOption(
76                name: 'target',
77                mode: InputOption::VALUE_OPTIONAL,
78                description: 'The target directory for the generated reports.',
79                default: ManagedWorkspace::getOutputDirectory(),
80            )
81            ->addOption(
82                name: 'coverage',
83                shortcut: 'c',
84                mode: InputOption::VALUE_OPTIONAL,
85                description: 'The target directory for the generated test coverage report.',
86                default: ManagedWorkspace::getOutputDirectory(ManagedWorkspace::COVERAGE),
87            )
88            ->addOption(
89                name: 'metrics',
90                mode: InputOption::VALUE_OPTIONAL,
91                description: 'Generate code metrics and optionally choose the HTML output directory.',
92                default: ManagedWorkspace::getOutputDirectory(ManagedWorkspace::METRICS),
93            );
94    }
95
96    /**
97     * Executes the generation logic for diverse reports.
98     *
99     * The method MUST run the underlying `docs` and `tests` commands. It SHALL process
100     * and generate the frontpage output file successfully.
101     *
102     * @param InputInterface $input the structured inputs holding specific arguments
103     * @param OutputInterface $output the designated output interface
104     *
105     * @return int the integer outcome from the base process execution
106     */
107    protected function execute(InputInterface $input, OutputInterface $output): int
108    {
109        $jsonOutput = $this->isJsonOutput($input);
110        $prettyJsonOutput = $this->isPrettyJsonOutput($input);
111        $progress = ! $jsonOutput && (bool) $input->getOption('progress');
112        $processOutput = $jsonOutput ? new BufferedOutput() : $output;
113        $target = (string) $input->getOption('target');
114        $coveragePath = (string) $input->getOption('coverage');
115        $metricsPath = (string) $input->getOption('metrics');
116
117        $this->logger->info('Generating frontpage for Fast Forward documentation...', [
118            'input' => $input,
119        ]);
120
121        $docsBuilder = $this->processBuilder
122            ->withArgument('--target', $target);
123
124        if ($progress) {
125            $docsBuilder = $docsBuilder->withArgument('--progress');
126        }
127
128        if ($jsonOutput) {
129            $docsBuilder = $docsBuilder->withArgument('--json');
130        }
131
132        if ($prettyJsonOutput) {
133            $docsBuilder = $docsBuilder->withArgument('--pretty-json');
134        }
135
136        $docs = $docsBuilder->build('composer dev-tools docs --');
137
138        $coverageBuilder = $this->processBuilder
139            ->withArgument('--coverage-summary')
140            ->withArgument('--coverage', $coveragePath);
141
142        if ($progress) {
143            $coverageBuilder = $coverageBuilder->withArgument('--progress');
144        }
145
146        if ($jsonOutput) {
147            $coverageBuilder = $coverageBuilder->withArgument('--json');
148        }
149
150        if ($prettyJsonOutput) {
151            $coverageBuilder = $coverageBuilder->withArgument('--pretty-json');
152        }
153
154        $coverage = $coverageBuilder->build('composer dev-tools tests --');
155
156        $metricsBuilder = $this->processBuilder
157            ->withArgument('--junit', $coveragePath . '/junit.xml')
158            ->withArgument('--target', $metricsPath);
159
160        if ($progress) {
161            $metricsBuilder = $metricsBuilder->withArgument('--progress');
162        }
163
164        if ($jsonOutput) {
165            $metricsBuilder = $metricsBuilder->withArgument('--json');
166        }
167
168        if ($prettyJsonOutput) {
169            $metricsBuilder = $metricsBuilder->withArgument('--pretty-json');
170        }
171
172        $metrics = $metricsBuilder->build('composer dev-tools metrics --');
173
174        $this->processQueue->add(process: $docs, detached: true);
175        $this->processQueue->add(process: $coverage);
176        $this->processQueue->add(process: $metrics);
177
178        $result = $this->processQueue->run($processOutput);
179
180        if (self::SUCCESS === $result) {
181            return $this->success('Documentation reports generated successfully.', $input, [
182                'output' => $processOutput,
183            ]);
184        }
185
186        return $this->failure('Documentation reports generation failed.', $input, [
187            'output' => $processOutput,
188        ]);
189    }
190}