From 11eae22dada359ae577c73775d11985983ac6573 Mon Sep 17 00:00:00 2001 From: patrickkusebauch Date: Thu, 28 Dec 2023 16:24:49 +0100 Subject: [PATCH] New command useful to limit the amount of testing in a project. --- config/services.php | 9 ++ docs/debugging.md | 19 ++++ phpunit.xml.dist | 30 ++++++ .../Console/Command/ChangedFilesCommand.php | 52 +++++++++ .../Console/Command/ChangedFilesRunner.php | 100 ++++++++++++++++++ 5 files changed, 210 insertions(+) create mode 100644 src/Supportive/Console/Command/ChangedFilesCommand.php create mode 100644 src/Supportive/Console/Command/ChangedFilesRunner.php diff --git a/config/services.php b/config/services.php index a0de735ff..a4e17b908 100644 --- a/config/services.php +++ b/config/services.php @@ -78,6 +78,8 @@ use Qossmic\Deptrac\Core\Layer\LayerResolverInterface; use Qossmic\Deptrac\Supportive\Console\Command\AnalyseCommand; use Qossmic\Deptrac\Supportive\Console\Command\AnalyseRunner; +use Qossmic\Deptrac\Supportive\Console\Command\ChangedFilesCommand; +use Qossmic\Deptrac\Supportive\Console\Command\ChangedFilesRunner; use Qossmic\Deptrac\Supportive\Console\Command\DebugDependenciesCommand; use Qossmic\Deptrac\Supportive\Console\Command\DebugDependenciesRunner; use Qossmic\Deptrac\Supportive\Console\Command\DebugLayerCommand; @@ -425,6 +427,13 @@ ->set(AnalyseCommand::class) ->autowire() ->tag('console.command'); + $services + ->set(ChangedFilesRunner::class) + ->autowire(); + $services + ->set(ChangedFilesCommand::class) + ->autowire() + ->tag('console.command'); $services ->set(DebugLayerRunner::class) ->autowire() diff --git a/docs/debugging.md b/docs/debugging.md index 8792cb6e9..dd8b7972a 100644 --- a/docs/debugging.md +++ b/docs/debugging.md @@ -76,3 +76,22 @@ $ php deptrac.phar debug:unused --limit=10 InputCollector layer is dependent File layer 3 times OutputFormatter layer is dependent DependencyInjection layer 1 times ``` + +## `changed-files` + +> [!CAUTION] +> This command in experimental and is not covered by +> the [BC policy](bc_policy.md). + +This command list the layers corresponding to the passed files. Optionally it +can also list all the layers that depend on those layers. + +```console +$ php deptrac.phar changed-files --with-dependencies src/Supportive/File/FileReader.php + + File + Console;Ast;InputCollector;Analyser;Dependency;Layer +``` + +For a discussion as to why that information might be useful, refer to +the [90DaysOfDevOps Presentation](https://github.com/MichaelCade/90DaysOfDevOps/pull/472). diff --git a/phpunit.xml.dist b/phpunit.xml.dist index bb0c56643..f5459ad69 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -4,6 +4,36 @@ ./tests/ + + ./tests/Contract + + + ./tests/Core/Analyser + + + ./tests/Core/Ast + + + ./tests/Core/Dependency + + + ./tests/Core/InputCollector + + + ./tests/Core/Layer + + + ./tests/Supportive/Console + + + ./tests/Supportive/DependencyInjection + + + ./tests/Supportive/File + + + ./tests/Supportive/OutputFormatter + diff --git a/src/Supportive/Console/Command/ChangedFilesCommand.php b/src/Supportive/Console/Command/ChangedFilesCommand.php new file mode 100644 index 000000000..be65e6c01 --- /dev/null +++ b/src/Supportive/Console/Command/ChangedFilesCommand.php @@ -0,0 +1,52 @@ +addOption('with-dependencies', null, InputOption::VALUE_NONE, 'show dependent layers'); + $this->addArgument('files', InputArgument::REQUIRED | InputArgument::IS_ARRAY, 'List of changed files'); + } + + protected function execute(InputInterface $input, OutputInterface $output): int + { + ini_set('memory_limit', '-1'); + + $symfonyOutput = new SymfonyOutput($output, new Style(new SymfonyStyle($input, $output))); + + try { + /** @var list $files */ + $files = $input->getArgument('files'); + $this->runner->run($files, (bool) $input->getOption('with-dependencies'), $symfonyOutput); + } catch (CommandRunException) { + return self::FAILURE; + } + + return self::SUCCESS; + } + +} diff --git a/src/Supportive/Console/Command/ChangedFilesRunner.php b/src/Supportive/Console/Command/ChangedFilesRunner.php new file mode 100644 index 000000000..308406222 --- /dev/null +++ b/src/Supportive/Console/Command/ChangedFilesRunner.php @@ -0,0 +1,100 @@ + $files + * + * @throws CommandRunException + */ + public function run(array $files, bool $withDependencies, OutputInterface $output): void + { + try { + $layers = []; + foreach ($files as $file) { + $matches = $this->layerForTokenAnalyser->findLayerForToken($file, TokenType::FILE); + foreach ($matches as $match) { + foreach ($match as $layer) { + $layers[$layer] = $layer; + } + } + } + $output->writeLineFormatted(implode(';', $layers)); + } catch (AnalyserException $exception) { + throw CommandRunException::analyserException($exception); + } + + if ($withDependencies) { + try { + $result = OutputResult::fromAnalysisResult($this->dependencyLayersAnalyser->analyse()); + $layersDependOnLayers = $this->calculateLayerDependencies($result->allRules()); + + $layerDependencies = []; + foreach ($layers as $layer) { + $layerDependencies += $layersDependOnLayers[$layer] ?? []; + } + do { + $size = count($layerDependencies); + $layerDependenciesCopy = $layerDependencies; + foreach ($layerDependenciesCopy as $layerDependency) { + $layerDependencies += $layersDependOnLayers[$layerDependency] ?? []; + } + } while ($size !== count($layerDependencies)); + + $output->writeLineFormatted(implode(';', $layerDependencies)); + } catch (AnalyserException $exception) { + throw CommandRunException::analyserException($exception); + } + } + } + + /** + * @param RuleInterface[] $rules + * + * @return array> + */ + private function calculateLayerDependencies(array $rules): array + { + $layersDependOnLayers = []; + + foreach ($rules as $rule) { + if (!$rule instanceof CoveredRuleInterface) { + continue; + } + + $layerA = $rule->getDependerLayer(); + $layerB = $rule->getDependentLayer(); + + if (!isset($layersDependOnLayers[$layerB])) { + $layersDependOnLayers[$layerB] = []; + } + + if (!array_key_exists($layerA, $layersDependOnLayers[$layerB])) { + $layersDependOnLayers[$layerB][$layerA] = $layerA; + } + } + + return $layersDependOnLayers; + } +}