Skip to content

Commit

Permalink
update 20240321
Browse files Browse the repository at this point in the history
  • Loading branch information
gennadigennadigennadi committed Mar 26, 2024
1 parent 6aec38f commit c6c801f
Show file tree
Hide file tree
Showing 42 changed files with 559 additions and 136 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ https://qossmic.github.io/deptrac
You can install Deptrac via Composer. We recommend using the
[deptrac-shim](https://github.com/qossmic/deptrac-shim) package for this:

```Shell
composer require --dev qossmic/deptrac-shim
```console
$ composer require --dev qossmic/deptrac-shim
```

Alternatively, you can also use [PHIVE](docs/index.md#phive) or download the
Expand Down
2 changes: 1 addition & 1 deletion config/cache.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
return static function (ContainerConfigurator $container) : void {
$services = $container->services();
$services->defaults()->public();
$services->set(AstFileReferenceFileCache::class)->args(['%deptrac.cache_file%', Application::VERSION]);
$services->set(AstFileReferenceFileCache::class)->args(['%cache_file%', Application::VERSION]);
$services->alias(AstFileReferenceDeferredCacheInterface::class, AstFileReferenceFileCache::class);
$services->alias(AstFileReferenceCacheInterface::class, AstFileReferenceDeferredCacheInterface::class);
$services->set(CacheableFileSubscriber::class)->args([service(AstFileReferenceFileCache::class)])->tag('kernel.event_subscriber');
Expand Down
8 changes: 7 additions & 1 deletion config/services.php
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,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;
Expand All @@ -105,6 +107,7 @@
use Qossmic\Deptrac\Supportive\OutputFormatter\GraphVizOutputImageFormatter;
use Qossmic\Deptrac\Supportive\OutputFormatter\JsonOutputFormatter;
use Qossmic\Deptrac\Supportive\OutputFormatter\JUnitOutputFormatter;
use Qossmic\Deptrac\Supportive\OutputFormatter\MermaidJSOutputFormatter;
use Qossmic\Deptrac\Supportive\OutputFormatter\TableOutputFormatter;
use Qossmic\Deptrac\Supportive\OutputFormatter\XMLOutputFormatter;
use DEPTRAC_202403\Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
Expand Down Expand Up @@ -165,7 +168,7 @@
/*
* Layer
*/
$services->set(LayerResolver::class)->args(['$layers' => param('layers')]);
$services->set(LayerResolver::class)->args(['$layersConfig' => param('layers')]);
$services->alias(LayerResolverInterface::class, LayerResolver::class);
$services->set(CollectorProvider::class)->args(['$collectorLocator' => tagged_locator('collector', 'type')]);
$services->set(CollectorResolver::class);
Expand Down Expand Up @@ -227,12 +230,15 @@
$services->set(GraphVizOutputDotFormatter::class)->tag('output_formatter');
$services->set(GraphVizOutputHtmlFormatter::class)->tag('output_formatter');
$services->set(CodeclimateOutputFormatter::class)->tag('output_formatter');
$services->set(MermaidJSOutputFormatter::class)->tag('output_formatter');
/*
* Console
*/
$services->set(InitCommand::class)->autowire()->tag('console.command');
$services->set(AnalyseRunner::class)->autowire();
$services->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()->args(['$layers' => param('layers')]);
$services->set(DebugLayerCommand::class)->autowire()->tag('console.command');
$services->set(DebugTokenRunner::class)->autowire();
Expand Down
3 changes: 2 additions & 1 deletion deptrac.config.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,12 @@
use Qossmic\Deptrac\Contract\Config\DeptracConfig;
use Qossmic\Deptrac\Contract\Config\EmitterType;
use Qossmic\Deptrac\Contract\Config\Formatter\GraphvizConfig;
use Qossmic\Deptrac\Contract\Config\Formatter\MermaidJsConfig;
use Qossmic\Deptrac\Contract\Config\Layer;
use Qossmic\Deptrac\Contract\Config\Ruleset;
use DEPTRAC_202403\Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
return static function (DeptracConfig $config, ContainerConfigurator $containerConfigurator) : void {
$services = $containerConfigurator->services();
$services->set(IgnoreDependenciesOnContract::class)->tag('kernel.event_subscriber');
$config->paths('src')->analyser(AnalyserConfig::create()->internalTag('@internal')->types(EmitterType::CLASS_TOKEN, EmitterType::CLASS_SUPERGLOBAL_TOKEN, EmitterType::FILE_TOKEN, EmitterType::FUNCTION_TOKEN, EmitterType::FUNCTION_SUPERGLOBAL_TOKEN, EmitterType::FUNCTION_CALL))->layers($analyser = Layer::withName('Analyser')->collectors(DirectoryConfig::create('src/Core/Analyser/.*')), $ast = Layer::withName('Ast')->collectors(DirectoryConfig::create('src/Core/Ast/.*'), ComposerConfig::create()->addPackage('phpstan/phpdoc-parser')->addPackage('nikic/php-parser')->addPackage('phpdocumentor/type-resolver')->private()), $console = Layer::withName('Console')->collectors(DirectoryConfig::create('src/Supportive/Console/.*')), $dependency = Layer::withName('Dependency')->collectors(DirectoryConfig::create('src/Core/Dependency/.*')), $dependencyInjection = Layer::withName('DependencyInjection')->collectors(DirectoryConfig::create('src/Supportive/DependencyInjection/.*')), $contract = Layer::withName('Contract')->collectors(DirectoryConfig::create('src/Contract/.*')), $inputCollector = Layer::withName('InputCollector')->collectors(DirectoryConfig::create('src/Core/InputCollector/.*')), $layer = Layer::withName('Layer')->collectors(DirectoryConfig::create('src/Core/Layer/.*')), $outputFormatter = Layer::withName('OutputFormatter')->collectors(DirectoryConfig::create('src/Supportive/OutputFormatter/.*'), ComposerConfig::create('composer.json', 'composer.lock')->addPackage('phpdocumentor/graphviz')->private()), $file = Layer::withName('File')->collectors(DirectoryConfig::create('src/Supportive/File/.*')), $time = Layer::withName('Time')->collectors(DirectoryConfig::create('src/Supportive/Time/.*')), $supportive = Layer::withName('Supportive')->collectors(BoolConfig::create()->mustNot(DirectoryConfig::create('src/Supportive/.*/.*'))->must(DirectoryConfig::create('src/Supportive/.*'))), $symfony = Layer::withName('Symfony')->collectors(ComposerConfig::create()->addPackage('symfony/config')->addPackage('symfony/console')->addPackage('symfony/dependency-injection')->addPackage('symfony/event-dispatcher')->addPackage('symfony/filesystem')->addPackage('symfony/finder')->addPackage('symfony/yaml')))->rulesets(Ruleset::forLayer($layer)->accesses($ast, $symfony), Ruleset::forLayer($console)->accesses($analyser, $outputFormatter, $dependencyInjection, $file, $time, $symfony), Ruleset::forLayer($dependency)->accesses($ast), Ruleset::forLayer($analyser)->accesses($layer, $dependency, $ast, $symfony), Ruleset::forLayer($outputFormatter)->accesses($dependencyInjection, $symfony), Ruleset::forLayer($ast)->accesses($file, $inputCollector, $symfony), Ruleset::forLayer($inputCollector)->accesses($file, $symfony), Ruleset::forLayer($supportive)->accesses($file), Ruleset::forLayer($contract)->accesses($symfony), Ruleset::forLayer($file)->accesses($symfony), Ruleset::forLayer($dependencyInjection)->accesses($symfony))->formatters(GraphvizConfig::create()->pointsToGroup(\true)->groups('Contract', $contract)->groups('Supportive', $supportive, $file, $symfony, $console, $dependencyInjection, $outputFormatter, $time)->groups('Core', $analyser, $ast, $dependency, $inputCollector, $layer));
$config->paths('src')->cacheFile('.cache/deptrac.cache')->analyser(AnalyserConfig::create()->internalTag('@internal')->types(EmitterType::CLASS_TOKEN, EmitterType::CLASS_SUPERGLOBAL_TOKEN, EmitterType::FILE_TOKEN, EmitterType::FUNCTION_TOKEN, EmitterType::FUNCTION_SUPERGLOBAL_TOKEN, EmitterType::FUNCTION_CALL))->layers($analyser = Layer::withName('Analyser')->collectors(DirectoryConfig::create('src/Core/Analyser/.*')), $ast = Layer::withName('Ast')->collectors(DirectoryConfig::create('src/Core/Ast/.*'), ComposerConfig::create()->addPackage('phpstan/phpdoc-parser')->addPackage('nikic/php-parser')->addPackage('phpdocumentor/type-resolver')->private()), $console = Layer::withName('Console')->collectors(DirectoryConfig::create('src/Supportive/Console/.*')), $dependency = Layer::withName('Dependency')->collectors(DirectoryConfig::create('src/Core/Dependency/.*')), $dependencyInjection = Layer::withName('DependencyInjection')->collectors(DirectoryConfig::create('src/Supportive/DependencyInjection/.*')), $contract = Layer::withName('Contract')->collectors(DirectoryConfig::create('src/Contract/.*')), $inputCollector = Layer::withName('InputCollector')->collectors(DirectoryConfig::create('src/Core/InputCollector/.*')), $layer = Layer::withName('Layer')->collectors(DirectoryConfig::create('src/Core/Layer/.*')), $outputFormatter = Layer::withName('OutputFormatter')->collectors(DirectoryConfig::create('src/Supportive/OutputFormatter/.*'), ComposerConfig::create('composer.json', 'composer.lock')->addPackage('phpdocumentor/graphviz')->private()), $file = Layer::withName('File')->collectors(DirectoryConfig::create('src/Supportive/File/.*')), $time = Layer::withName('Time')->collectors(DirectoryConfig::create('src/Supportive/Time/.*')), $supportive = Layer::withName('Supportive')->collectors(BoolConfig::create()->mustNot(DirectoryConfig::create('src/Supportive/.*/.*'))->must(DirectoryConfig::create('src/Supportive/.*'))), $symfony = Layer::withName('Symfony')->collectors(ComposerConfig::create()->addPackage('symfony/config')->addPackage('symfony/console')->addPackage('symfony/dependency-injection')->addPackage('symfony/event-dispatcher')->addPackage('symfony/filesystem')->addPackage('symfony/finder')->addPackage('symfony/yaml')))->rulesets(Ruleset::forLayer($layer)->accesses($ast, $symfony), Ruleset::forLayer($console)->accesses($analyser, $outputFormatter, $dependencyInjection, $file, $time, $symfony), Ruleset::forLayer($dependency)->accesses($ast), Ruleset::forLayer($analyser)->accesses($layer, $dependency, $ast, $symfony), Ruleset::forLayer($outputFormatter)->accesses($dependencyInjection, $symfony), Ruleset::forLayer($ast)->accesses($file, $inputCollector, $symfony), Ruleset::forLayer($inputCollector)->accesses($file, $symfony), Ruleset::forLayer($supportive)->accesses($file), Ruleset::forLayer($contract)->accesses($symfony), Ruleset::forLayer($file)->accesses($symfony), Ruleset::forLayer($dependencyInjection)->accesses($symfony))->formatters(GraphvizConfig::create()->pointsToGroup(\true)->groups('Contract', $contract)->groups('Supportive', $supportive, $file, $symfony, $console, $dependencyInjection, $outputFormatter, $time)->groups('Core', $analyser, $ast, $dependency, $inputCollector, $layer), MermaidJsConfig::create()->direction('TD')->groups('Contract', $contract)->groups('Supportive', $supportive, $file, $symfony, $console, $dependencyInjection, $outputFormatter, $time)->groups('Core', $analyser, $ast, $dependency, $inputCollector, $layer));
};
Binary file modified deptrac.phar
Binary file not shown.
10 changes: 5 additions & 5 deletions deptrac.phar.asc
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
-----BEGIN PGP SIGNATURE-----

iJMEABYKADsWIQRXy1VvJC/I1P1IPCxHQ2WH2CxKOQUCZfLQwh0cZ2VubmFkaS5t
Y2tlbHZleUBxb3NzbWljLmNvbQAKCRBHQ2WH2CxKOYVRAP0crfIO32Tt9G1U2QI5
ebOmFt3wvPWx+eA2yl4aQ2BtfQEAuFRE9CsTgXubdKi7pTNIqTX3HdLCgI2YwiXm
ZBXuIg8=
=58M9
iJMEABYKADsWIQRXy1VvJC/I1P1IPCxHQ2WH2CxKOQUCZfyQKB0cZ2VubmFkaS5t
Y2tlbHZleUBxb3NzbWljLmNvbQAKCRBHQ2WH2CxKOSlPAQCCRiLJA/cxv5ipQjgG
9xLIfhjMT6X04wcIbpmmqemJBAD+I8LXdRbE3T9mC8Z00xHXkXmgBQnP8jKShWqx
YrX3WQM=
=+7Ga
-----END PGP SIGNATURE-----
4 changes: 2 additions & 2 deletions docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -300,8 +300,8 @@ Deptrac provides parameters that can be user in your configuration.

* `%currentWorkingDirectory%` The path Deptrac runs in
* `%projectDirectory%` The path where the configuration is stored.
* `%deptrac.cache_file%` contains the filename and path for the cache file.
Note: This parameter is set by `--cache-file=` and will be overwritten.
* `%cache_file%` contains the filename and path for the cache file.
Note: This parameter is overwritten by `--cache-file=` if it is set.

You can specify your own parameters and reuse them in your configuration:

Expand Down
38 changes: 33 additions & 5 deletions docs/debugging.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,20 @@ With the `debug:layer`-command you can list all tokens which are matched in
a specific layer. This command only shows tokens that would be emitted by your analyser configuration.

```console
$ php deptrac.phar debug:layer --config-file=examples/DirectoryLayer.depfile.yaml Layer1

examples\Layer1\AnotherClassLikeAController
examples\Layer1\SomeClass
examples\Layer1\SomeClass2
$ php deptrac.phar debug:layer --config-file=deptrac.config.php Time

---------------------------------------------------- ------------
Time Token Type
---------------------------------------------------- ------------
/src/Supportive/Time/Period.php file
/src/Supportive/Time/StartedPeriod.php file
/src/Supportive/Time/Stopwatch.php file
/src/Supportive/Time/StopwatchException.php file
Qossmic\Deptrac\Supportive\Time\Period class-like
Qossmic\Deptrac\Supportive\Time\StartedPeriod class-like
Qossmic\Deptrac\Supportive\Time\Stopwatch class-like
Qossmic\Deptrac\Supportive\Time\StopwatchException class-like
---------------------------------------------------- ------------
```

## `debug:token`
Expand Down Expand Up @@ -80,3 +89,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).
81 changes: 81 additions & 0 deletions docs/formatters.md
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,87 @@ Will produce the following graph:
#### Pointing to groups instead of nodes
With `formatters.graphviz.pointToGroups` set to `true`, when you have a node inside a groups with the same name as the group itself, edges pointing to that node will point to the group instead. This might be useful for example if you want to provide a "public API" for a module defined by a group.

## MermaidJS Formatter

The MermaidJS formatter is a console formatter, which generates a mermaid.js compatible graph definition. It can be activated with `--formatter=mermaidjs`.
With the -o option you can specify the output file.

Available options:

```
--formatter=mermaidjs
--output= path to a dumped file
```
With this example
Yaml Config:

```yaml
deptrac:
layers:
- User Frontend
- User Backend
- Admin Frontend
- Admin Backend
formatters:
mermaidjs:
direction: TD
groups:
User:
- User Frontend
- User Backend
Admin:
- Admin Frontend
- Admin Backend
```

This will produce the following graph:

```mermaid
flowchart TD;
subgraph ContractGroup;
Contract;
end;
subgraph SupportiveGroup;
Supportive;
File;
end;
subgraph SymfonyGroup;
Console;
DependencyInjection;
OutputFormatter;
end;
subgraph CoreGroup;
Analyser;
Ast;
Dependency;
InputCollector;
Layer;
end;
Contract -->|6| Symfony;
InputCollector -->|3| File;
InputCollector -->|7| Symfony;
Dependency -->|36| Ast;
Layer -->|68| Ast;
Layer -->|8| Symfony;
Analyser -->|18| Ast;
Analyser -->|23| Dependency;
Analyser -->|6| Layer;
Analyser -->|10| Symfony;
Ast -->|3| Symfony;
Ast -->|3| InputCollector;
Ast -->|7| File;
OutputFormatter -->|5| Symfony;
OutputFormatter -->|1| DependencyInjection;
File -->|9| Symfony;
DependencyInjection -->|37| Symfony;
Console -->|66| Symfony;
Console -->|2| DependencyInjection;
Console -->|16| Analyser;
Console -->|5| File;
Console -->|4| OutputFormatter;
Console -->|4| Time;
```

## JSON Formatter

By default, Json formatter dumps information to *STDOUT*. It can be activated
Expand Down
18 changes: 18 additions & 0 deletions src/Contract/Ast/DependencyContext.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?php

declare (strict_types=1);
namespace Qossmic\Deptrac\Contract\Ast;

/**
* @psalm-immutable
*
* Context of the dependency.
*
* Any additional info about where the dependency occurred.
*/
final class DependencyContext
{
public function __construct(public readonly \Qossmic\Deptrac\Contract\Ast\FileOccurrence $fileOccurrence, public readonly \Qossmic\Deptrac\Contract\Ast\DependencyType $dependencyType)
{
}
}
7 changes: 7 additions & 0 deletions src/Contract/Config/DeptracConfig.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ final class DeptracConfig implements ConfigBuilderInterface
private array $skipViolations = [];
/** @var array<string> */
private array $excludeFiles = [];
private ?string $cacheFile = null;
/**
* @deprecated use analyser(AnalyserConfig::create()) instead
*/
Expand Down Expand Up @@ -84,6 +85,11 @@ public function rulesets(\Qossmic\Deptrac\Contract\Config\Ruleset ...$rulesetCon
}
return $this;
}
public function cacheFile(string $path) : self
{
$this->cacheFile = $path;
return $this;
}
/** @return array<mixed> */
public function toArray() : array
{
Expand All @@ -110,6 +116,7 @@ public function toArray() : array
$config['skip_violations'] = $this->skipViolations;
}
$config['ignore_uncovered_internal_classes'] = $this->ignoreUncoveredInternalClasses;
$config['cache_file'] = $this->cacheFile;
return $config;
}
public function getExtensionAlias() : string
Expand Down
42 changes: 42 additions & 0 deletions src/Contract/Config/Formatter/MermaidJsConfig.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<?php

declare (strict_types=1);
namespace Qossmic\Deptrac\Contract\Config\Formatter;

use Qossmic\Deptrac\Contract\Config\Layer;
final class MermaidJsConfig implements \Qossmic\Deptrac\Contract\Config\Formatter\FormatterConfigInterface
{
private string $name = 'mermaidjs';
private string $direction = 'TD';
/** @var array<string, Layer[]> */
private array $groups = [];
public static function create() : self
{
return new self();
}
public function getName() : string
{
return $this->name;
}
public function direction(string $direction) : self
{
$this->direction = $direction;
return $this;
}
public function groups(string $name, Layer ...$layerConfigs) : self
{
foreach ($layerConfigs as $layerConfig) {
$this->groups[$name][] = $layerConfig;
}
return $this;
}
public function toArray() : array
{
$output = [];
if ([] !== $this->groups) {
$output['groups'] = \array_map(static fn(array $configs) => \array_map(static fn(Layer $layer) => $layer->name, $configs), $this->groups);
}
$output['direction'] = $this->direction;
return $output;
}
}
6 changes: 2 additions & 4 deletions src/Contract/Dependency/DependencyInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,7 @@
declare (strict_types=1);
namespace Qossmic\Deptrac\Contract\Dependency;

use Qossmic\Deptrac\Contract\Ast\DependencyType;
use Qossmic\Deptrac\Contract\Ast\FileOccurrence;
use Qossmic\Deptrac\Contract\Ast\DependencyContext;
use Qossmic\Deptrac\Contract\Ast\TokenInterface;
/**
* Represents a dependency between 2 tokens (depender and dependent).
Expand All @@ -13,10 +12,9 @@ interface DependencyInterface
{
public function getDepender() : TokenInterface;
public function getDependent() : TokenInterface;
public function getFileOccurrence() : FileOccurrence;
public function getContext() : DependencyContext;
/**
* @return array<array{name:string, line:int}>
*/
public function serialize() : array;
public function getType() : DependencyType;
}
Loading

0 comments on commit c6c801f

Please sign in to comment.