Failed Conditions
Push — master ( 5d2ea6...f862f5 )
by Alexander
12:15
created

BackwardsCompatibilityCommand::getTargetPath()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 1
dl 0
loc 3
ccs 0
cts 0
cp 0
crap 2
rs 10
c 0
b 0
f 0
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\BreakFilter;
16
use ConsoleHelpers\CodeInsight\BackwardsCompatibility\Checker\AbstractChecker;
17
use ConsoleHelpers\CodeInsight\BackwardsCompatibility\Checker\CheckerFactory;
18
use ConsoleHelpers\CodeInsight\BackwardsCompatibility\Reporter\ReporterFactory;
19
use ConsoleHelpers\CodeInsight\KnowledgeBase\KnowledgeBaseFactory;
20
use Stecman\Component\Symfony\Console\BashCompletion\CompletionContext;
21
use Symfony\Component\Console\Exception\RuntimeException;
22
use Symfony\Component\Console\Input\ArgvInput;
23
use Symfony\Component\Console\Input\InputArgument;
24
use Symfony\Component\Console\Input\InputInterface;
25
use Symfony\Component\Console\Input\InputOption;
26
use Symfony\Component\Console\Output\OutputInterface;
27
28
class BackwardsCompatibilityCommand extends AbstractCommand
29
{
30
31
	/**
32
	 * Knowledge base factory.
33
	 *
34
	 * @var KnowledgeBaseFactory
35
	 */
36
	private $_knowledgeBaseFactory;
37
38
	/**
39
	 * Backwards compatibility checker factory.
40
	 *
41
	 * @var CheckerFactory
42
	 */
43
	private $_checkerFactory;
44
45
	/**
46
	 * Backwards compatibility reporter factory.
47
	 *
48
	 * @var ReporterFactory
49
	 */
50
	private $_reporterFactory;
51
52
	/**
53
	 * Backwards compatibility break filter.
54
	 *
55
	 * @var BreakFilter
56
	 */
57
	private $_breakFilter;
58
59
	/**
60
	 * {@inheritdoc}
61
	 */
62
	protected function configure()
63
	{
64
		$this
65
			->setName('bc')
66
			->setDescription('Detects backwards compatibility breaks between 2 project versions')
67
			->addArgument(
68
				'source-project-path',
69
				InputArgument::OPTIONAL,
70
				'Path to source project root folder (where <comment>.code-insight.json</comment> is located)'
71
			)
72
			->addArgument(
73
				'target-project-path',
74
				InputArgument::OPTIONAL,
75
				'Path to target project root folder (where <comment>.code-insight.json</comment> is located)',
76
				'.'
77
			)
78
			->addOption(
79
				'source-project-fork',
80
				null,
81
				InputOption::VALUE_REQUIRED,
82
				'Source project fork name'
83
			)
84
			->addOption(
85
				'target-project-fork',
86
				null,
87
				InputOption::VALUE_REQUIRED,
88
				'Target project fork name'
89
			)
90
			->addOption(
91
				'format',
92
				null,
93
				InputOption::VALUE_REQUIRED,
94
				'Output format, e.g. <comment>text</comment>, <comment>html</comment>, <comment>json</comment>',
95
				'text'
96
			);
97
	}
98
99
	/**
100
	 * Prepare dependencies.
101
	 *
102
	 * @return void
103
	 */
104
	protected function prepareDependencies()
105
	{
106
		parent::prepareDependencies();
107
108
		$container = $this->getContainer();
109
110
		$this->_knowledgeBaseFactory = $container['knowledge_base_factory'];
111
		$this->_checkerFactory = $container['bc_checker_factory'];
112
		$this->_reporterFactory = $container['bc_reporter_factory'];
113
		$this->_breakFilter = $container['bc_break_filter'];
114
	}
115
116
	/**
117
	 * Return possible values for the named option
118
	 *
119
	 * @param string            $optionName Option name.
120
	 * @param CompletionContext $context    Completion context.
121
	 *
122
	 * @return array
123
	 */
124
	public function completeOptionValues($optionName, CompletionContext $context)
125
	{
126
		$ret = parent::completeOptionValues($optionName, $context);
127
128
		if ( $optionName === 'source-project-fork' ) {
129
			$input = $this->getInputFromCompletionContext($context);
130
131
			return $this->_knowledgeBaseFactory->getForks($this->getSourcePath($input, true));
132
		}
133
134
		if ( $optionName === 'target-project-fork' ) {
135
			$input = $this->getInputFromCompletionContext($context);
136
137
			return $this->_knowledgeBaseFactory->getForks($this->getTargetPath($input));
138
		}
139
140
		if ( $optionName === 'format' ) {
141
			return $this->_reporterFactory->getNames();
142
		}
143
144
		return $ret;
145
	}
146
147
	/**
148
	 * {@inheritdoc}
149
	 */
150
	protected function execute(InputInterface $input, OutputInterface $output)
151
	{
152
		// Get reporter upfront so that we can error out early for invalid reporters.
153
		$reporter = $this->_reporterFactory->get($this->io->getOption('format'));
0 ignored issues
show
Bug introduced by
It seems like $this->io->getOption('format') can also be of type string[]; however, parameter $name of ConsoleHelpers\CodeInsig...\ReporterFactory::get() 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

153
		$reporter = $this->_reporterFactory->get(/** @scrutinizer ignore-type */ $this->io->getOption('format'));
Loading history...
154
155
		$source_path = $this->getSourcePath($input, false);
156
		$target_path = $this->getTargetPath($input);
157
158
		$source_knowledge_base = $this->_knowledgeBaseFactory->getKnowledgeBase(
159
			$source_path,
160
			$this->io->getOption('source-project-fork'),
0 ignored issues
show
Bug introduced by
It seems like $this->io->getOption('source-project-fork') can also be of type string[]; however, parameter $fork of ConsoleHelpers\CodeInsig...ory::getKnowledgeBase() does only seem to accept null|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

160
			/** @scrutinizer ignore-type */ $this->io->getOption('source-project-fork'),
Loading history...
161
			$this->io
162
		);
163
		$target_knowledge_base = $this->_knowledgeBaseFactory->getKnowledgeBase(
164
			$target_path,
165
			$this->io->getOption('target-project-fork'),
166
			$this->io
167
		);
168
169
		$bc_breaks = $this->getBackwardsCompatibilityBreaks(
170
			$source_knowledge_base->getDatabase(),
171
			$target_knowledge_base->getDatabase(),
172
			$target_knowledge_base->getBackwardsCompatibilityCheckers($this->_checkerFactory)
173
		);
174
		$bc_breaks = $this->_breakFilter->removeMatching(
175
			$bc_breaks,
176
			$target_knowledge_base->getBackwardsCompatibilityIgnoreRules()
177
		);
178
179
		$this->io->writeln($reporter->generate($bc_breaks));
180
	}
181
182
	/**
183
	 * Returns source path.
184
	 *
185
	 * @param InputInterface $input        Input.
186
	 * @param boolean        $autocomplete Autocomplete.
187
	 *
188
	 * @return string
189
	 * @throws RuntimeException When source project path is missing.
190
	 */
191
	protected function getSourcePath(InputInterface $input, $autocomplete)
192
	{
193
		$source_path = $this->getPath($input->getArgument('source-project-path'));
0 ignored issues
show
Bug introduced by
It seems like $input->getArgument('source-project-path') can also be of type string[]; however, parameter $raw_path of ConsoleHelpers\CodeInsig...tractCommand::getPath() 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

193
		$source_path = $this->getPath(/** @scrutinizer ignore-type */ $input->getArgument('source-project-path'));
Loading history...
194
195
		if ( $source_path ) {
196
			return $source_path;
197
		}
198
199
		// Single code base, but comparing with fork OR autocompleting forks.
200
		if ( $autocomplete || $input->getOption('source-project-fork') ) {
201
			return $this->getTargetPath($input);
202
		}
203
204
		// Not using fork, then need to specify project path.
205
		throw new RuntimeException('Not enough arguments (missing: "source-project-path").');
206
	}
207
208
	/**
209
	 * Returns target path.
210
	 *
211
	 * @param InputInterface $input Input.
212
	 *
213
	 * @return string
214
	 */
215
	protected function getTargetPath(InputInterface $input)
216
	{
217
		return $this->getPath($input->getArgument('target-project-path'));
0 ignored issues
show
Bug introduced by
It seems like $input->getArgument('target-project-path') can also be of type string[]; however, parameter $raw_path of ConsoleHelpers\CodeInsig...tractCommand::getPath() 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

217
		return $this->getPath(/** @scrutinizer ignore-type */ $input->getArgument('target-project-path'));
Loading history...
218
	}
219
220
	/**
221
	 * Finds backward compatibility breaks.
222
	 *
223
	 * @param ExtendedPdoInterface $source_db Source database.
224
	 * @param ExtendedPdoInterface $target_db Target database.
225
	 * @param AbstractChecker[]    $checkers  Checkers.
226
	 *
227
	 * @return array
228
	 */
229
	protected function getBackwardsCompatibilityBreaks(
230
		ExtendedPdoInterface $source_db,
231
		ExtendedPdoInterface $target_db,
232
		array $checkers
233
	) {
234
		$breaks = array();
235
236
		foreach ( $checkers as $checker ) {
237
			$breaks = array_merge($breaks, $checker->check($source_db, $target_db));
238
		}
239
240
		return $breaks;
241
	}
242
243
}
244