Passed
Pull Request — master (#236)
by Fabien
02:07
created

ChurnCommand   A

Complexity

Total Complexity 8

Size/Duplication

Total Lines 126
Duplicated Lines 0 %

Importance

Changes 12
Bugs 3 Features 2
Metric Value
eloc 45
dl 0
loc 126
rs 10
c 12
b 3
f 2
wmc 8

5 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 9 1
A execute() 0 20 1
A configure() 0 9 1
A getDirectoriesToScan() 0 14 3
A getOnSuccessObserver() 0 10 2
1
<?php declare(strict_types = 1);
2
3
namespace Churn\Commands;
4
5
use Churn\Configuration\Config;
6
use Churn\Factories\ResultsRendererFactory;
7
use Churn\Logic\ResultsLogic;
8
use Churn\Managers\FileManager;
9
use Churn\Process\Observer\OnSuccess;
10
use Churn\Process\Observer\OnSuccessNull;
11
use Churn\Process\Observer\OnSuccessProgress;
12
use Churn\Process\ProcessFactory;
13
use Churn\Process\ProcessHandlerFactory;
14
use function count;
15
use function file_get_contents;
16
use InvalidArgumentException;
17
use Symfony\Component\Console\Command\Command;
18
use Symfony\Component\Console\Helper\ProgressBar;
19
use Symfony\Component\Console\Input\InputArgument;
20
use Symfony\Component\Console\Input\InputInterface;
21
use Symfony\Component\Console\Input\InputOption;
22
use Symfony\Component\Console\Output\OutputInterface;
23
use Symfony\Component\Yaml\Yaml;
24
25
/**
26
 * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
27
 */
28
class ChurnCommand extends Command
29
{
30
    private const LOGO ="
31
    ___  _   _  __  __  ____  _  _     ____  _   _  ____
32
   / __)( )_( )(  )(  )(  _ \( \( )___(  _ \( )_( )(  _ \
33
  ( (__  ) _ (  )(__)(  )   / )  ((___))___/ ) _ (  )___/
34
   \___)(_) (_)(______)(_)\_)(_)\_)   (__)  (_) (_)(__)";
35
36
    /**
37
     * The results logic.
38
     * @var ResultsLogic
39
     */
40
    private $resultsLogic;
41
42
    /**
43
     * The process handler factory.
44
     * @var ProcessHandlerFactory
45
     */
46
    private $processHandlerFactory;
47
48
    /**
49
     * The renderer factory.
50
     * @var ResultsRendererFactory
51
     */
52
    private $renderFactory;
53
54
    /**
55
     * ChurnCommand constructor.
56
     * @param ResultsLogic           $resultsLogic          The results logic.
57
     * @param ProcessHandlerFactory  $processHandlerFactory The process handler factory.
58
     * @param ResultsRendererFactory $renderFactory         The Results Renderer Factory.
59
     */
60
    public function __construct(
61
        ResultsLogic $resultsLogic,
62
        ProcessHandlerFactory $processHandlerFactory,
63
        ResultsRendererFactory $renderFactory
64
    ) {
65
        parent::__construct();
66
        $this->resultsLogic = $resultsLogic;
67
        $this->processHandlerFactory = $processHandlerFactory;
68
        $this->renderFactory = $renderFactory;
69
    }
70
71
    /**
72
     * Configure the command
73
     * @return void
74
     */
75
    protected function configure(): void
76
    {
77
        $this->setName('run')
78
            ->addArgument('paths', InputArgument::IS_ARRAY, 'Path to source to check.')
79
            ->addOption('configuration', 'c', InputOption::VALUE_OPTIONAL, 'Path to the configuration file', 'churn.yml')  // @codingStandardsIgnoreLine
80
            ->addOption('format', null, InputOption::VALUE_REQUIRED, 'The output format to use', 'text')
81
            ->addOption('progress', 'p', InputOption::VALUE_NONE, 'Show progress bar')
82
            ->setDescription('Check files')
83
            ->setHelp('Checks the churn on the provided path argument(s).');
84
    }
85
86
    /**
87
     * Execute the command
88
     * @param InputInterface  $input  Input.
89
     * @param OutputInterface $output Output.
90
     * @return integer
91
     */
92
    protected function execute(InputInterface $input, OutputInterface $output): int
93
    {
94
        $output->writeln(self::LOGO);
95
        $content = (string) @file_get_contents($input->getOption('configuration'));
0 ignored issues
show
Bug introduced by
It seems like $input->getOption('configuration') can also be of type string[]; however, parameter $filename of file_get_contents() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

95
        $content = (string) @file_get_contents(/** @scrutinizer ignore-type */ $input->getOption('configuration'));
Loading history...
96
        $config = Config::create(Yaml::parse($content) ?? []);
97
        $filesCollection = (new FileManager($config->getFileExtensions(), $config->getFilesToIgnore()))
98
            ->getPhpFiles($this->getDirectoriesToScan($input, $config->getDirectoriesToScan()));
99
        $completedProcesses = $this->processHandlerFactory->getProcessHandler($config)->process(
100
            $filesCollection,
101
            new ProcessFactory($config->getCommitsSince()),
102
            $this->getOnSuccessObserver($input, $output, $filesCollection->count())
103
        );
104
        $resultCollection = $this->resultsLogic->process(
105
            $completedProcesses,
106
            $config->getMinScoreToShow(),
107
            $config->getFilesToShow()
108
        );
109
        $renderer = $this->renderFactory->getRenderer($input->getOption('format'));
110
        $renderer->render($output, $resultCollection);
111
        return 0;
112
    }
113
114
    /**
115
     * Get the directories to scan.
116
     * @param InputInterface $input          Input Interface.
117
     * @param array          $dirsConfigured The directories configured to scan.
118
     * @throws InvalidArgumentException If paths argument invalid.
119
     * @return array When no directories to scan found.
120
     */
121
    private function getDirectoriesToScan(InputInterface $input, array $dirsConfigured): array
122
    {
123
        $dirsProvidedAsArgs = $input->getArgument('paths');
124
        if (count($dirsProvidedAsArgs) > 0) {
0 ignored issues
show
Bug introduced by
It seems like $dirsProvidedAsArgs can also be of type string; however, parameter $var of count() does only seem to accept Countable|array, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

124
        if (count(/** @scrutinizer ignore-type */ $dirsProvidedAsArgs) > 0) {
Loading history...
125
            return $dirsProvidedAsArgs;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $dirsProvidedAsArgs could return the type null|string which is incompatible with the type-hinted return array. Consider adding an additional type-check to rule them out.
Loading history...
126
        }
127
128
        if (count($dirsConfigured) > 0) {
129
            return $dirsConfigured;
130
        }
131
132
        throw new InvalidArgumentException(
133
            'Provide the directories you want to scan as arguments, ' .
134
            'or configure them under "directoriesToScan" in your churn.yml file.'
135
        );
136
    }
137
138
    /**
139
     * @param InputInterface  $input      Input.
140
     * @param OutputInterface $output     Output.
141
     * @param integer         $totalFiles Total number of files to process.
142
     * @return OnSuccess
143
     */
144
    private function getOnSuccessObserver(InputInterface $input, OutputInterface $output, int $totalFiles): OnSuccess
145
    {
146
        if ((bool)$input->getOption('progress')) {
147
            $output->writeln("\n");
148
            $progressBar = new ProgressBar($output, $totalFiles);
149
            $progressBar->start();
150
            return new OnSuccessProgress($progressBar);
151
        }
152
153
        return new OnSuccessNull();
154
    }
155
}
156