Completed
Push — master ( bc9a8a...77231c )
by Alexander
04:23
created

BackwardsCompatibilityCommand::groupByType()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 16
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 12

Importance

Changes 0
Metric Value
dl 0
loc 16
ccs 0
cts 12
cp 0
rs 9.4285
c 0
b 0
f 0
cc 3
eloc 8
nc 3
nop 1
crap 12
1
<?php
2
/**
3
 * This file is part of the Code-Insight library.
4
 * For the full copyright and license information, please view
5
 * the LICENSE file that was distributed with this source code.
6
 *
7
 * @copyright Alexander Obuhovich <[email protected]>
8
 * @link      https://github.com/console-helpers/code-insight
9
 */
10
11
namespace ConsoleHelpers\CodeInsight\Command;
12
13
14
use Aura\Sql\ExtendedPdoInterface;
15
use ConsoleHelpers\CodeInsight\BackwardsCompatibility\AbstractChecker;
16
use ConsoleHelpers\CodeInsight\BackwardsCompatibility\CheckerFactory;
17
use ConsoleHelpers\CodeInsight\KnowledgeBase\KnowledgeBaseFactory;
18
use Symfony\Component\Console\Input\InputArgument;
19
use Symfony\Component\Console\Input\InputInterface;
20
use Symfony\Component\Console\Input\InputOption;
21
use Symfony\Component\Console\Output\OutputInterface;
22
23
class BackwardsCompatibilityCommand extends AbstractCommand
24
{
25
26
	/**
27
	 * Knowledge base factory.
28
	 *
29
	 * @var KnowledgeBaseFactory
30
	 */
31
	private $_knowledgeBaseFactory;
32
33
	/**
34
	 * Backwards compatibility checker factory.
35
	 *
36
	 * @var CheckerFactory
37
	 */
38
	private $_checkerFactory;
39
40
	/**
41
	 * {@inheritdoc}
42
	 */
43
	protected function configure()
44
	{
45
		$this
46
			->setName('bc')
47
			->setDescription('Detects backwards compatibility breaks between 2 project versions')
48
			->addArgument(
49
				'source-project-path',
50
				InputArgument::REQUIRED,
51
				'Path to source project root folder (where <comment>.code-insight.json</comment> is located)'
52
			)
53
			->addArgument(
54
				'target-project-path',
55
				InputArgument::OPTIONAL,
56
				'Path to target project root folder (where <comment>.code-insight.json</comment> is located)',
57
				'.'
58
			)
59
			->addOption(
60
				'source-project-fork',
61
				null,
62
				InputOption::VALUE_REQUIRED,
63
				'Source project fork name'
64
			)
65
			->addOption(
66
				'target-project-fork',
67
				null,
68
				InputOption::VALUE_REQUIRED,
69
				'Target project fork name'
70
			);
71
	}
72
73
	/**
74
	 * Prepare dependencies.
75
	 *
76
	 * @return void
77
	 */
78
	protected function prepareDependencies()
79
	{
80
		parent::prepareDependencies();
81
82
		$container = $this->getContainer();
83
84
		$this->_knowledgeBaseFactory = $container['knowledge_base_factory'];
85
		$this->_checkerFactory = $container['bc_checker_factory'];
86
	}
87
88
	/**
89
	 * {@inheritdoc}
90
	 */
91
	protected function execute(InputInterface $input, OutputInterface $output)
92
	{
93
		$source_knowledge_base = $this->_knowledgeBaseFactory->getKnowledgeBase(
94
			$this->getPath('source-project-path'),
95
			$this->io->getOption('source-project-fork'),
96
			$this->io
97
		);
98
		$target_knowledge_base = $this->_knowledgeBaseFactory->getKnowledgeBase(
99
			$this->getPath('target-project-path'),
100
			$this->io->getOption('target-project-fork'),
101
			$this->io
102
		);
103
104
		$bc_breaks = $this->getBackwardsCompatibilityBreaks(
105
			$source_knowledge_base->getDatabase(),
106
			$target_knowledge_base->getDatabase(),
107
			$target_knowledge_base->getBackwardsCompatibilityCheckers($this->_checkerFactory)
108
		);
109
110
		if ( !$bc_breaks ) {
111
			$this->io->writeln('No backwards compatibility breaks detected.');
112
113
			return;
114
		}
115
116
		$this->io->writeln('Backward compatibility breaks:');
117
118
		foreach ( $this->groupByType($bc_breaks) as $bc_break => $incidents ) {
119
			$bc_break = ucwords(str_replace(array('.', '_'), ' ', $bc_break));
120
			$this->io->writeln('<fg=red>=== ' . $bc_break . ' (' . count($incidents) . ') ===</>');
121
122
			foreach ( $incidents as $incident_data ) {
123
				if ( array_key_exists('old', $incident_data) ) {
124
					$this->io->writeln(' * <fg=white;options=bold>' . $incident_data['element'] . '</>');
125
					$this->io->writeln('   OLD: ' . $incident_data['old']);
126
					$this->io->writeln('   NEW: ' . $incident_data['new']);
127
				}
128
				else {
129
					$this->io->writeln(' * ' . $incident_data['element']);
130
				}
131
			}
132
133
			$this->io->writeln('');
134
		}
135
	}
136
137
	/**
138
	 * Finds backward compatibility breaks.
139
	 *
140
	 * @param ExtendedPdoInterface $source_db Source database.
141
	 * @param ExtendedPdoInterface $target_db Target database.
142
	 * @param AbstractChecker[]    $checkers  Checkers.
143
	 *
144
	 * @return array
145
	 */
146
	protected function getBackwardsCompatibilityBreaks(
147
		ExtendedPdoInterface $source_db,
148
		ExtendedPdoInterface $target_db,
149
		array $checkers
150
	) {
151
		$breaks = array();
152
153
		foreach ( $checkers as $checker ) {
154
			$breaks = array_merge($breaks, $checker->check($source_db, $target_db));
155
		}
156
157
		return $breaks;
158
	}
159
160
	/**
161
	 * Groups BC breaks by type.
162
	 *
163
	 * @param array $bc_breaks BC breaks.
164
	 *
165
	 * @return array
166
	 */
167
	protected function groupByType(array $bc_breaks)
168
	{
169
		$ret = array();
170
171
		foreach ( $bc_breaks as $bc_break_data ) {
172
			$type = $bc_break_data['type'];
173
174
			if ( !isset($ret[$type]) ) {
175
				$ret[$type] = array();
176
			}
177
178
			$ret[$type][] = $bc_break_data;
179
		}
180
181
		return $ret;
182
	}
183
184
}
185