1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace N98\Magento\Command\System\Setup; |
4
|
|
|
|
5
|
|
|
use N98\JUnitXml\Document as JUnitXmlDocument; |
6
|
|
|
use N98\Magento\Command\AbstractMagentoCommand; |
7
|
|
|
use N98\Util\Console\Helper\Table\Renderer\RendererFactory; |
8
|
|
|
use Symfony\Component\Console\Input\InputInterface; |
9
|
|
|
use Symfony\Component\Console\Input\InputOption; |
10
|
|
|
use Symfony\Component\Console\Output\OutputInterface; |
11
|
|
|
|
12
|
|
|
class CompareVersionsCommand extends AbstractMagentoCommand |
13
|
|
|
{ |
14
|
|
View Code Duplication |
protected function configure() |
|
|
|
|
15
|
|
|
{ |
16
|
|
|
$this |
17
|
|
|
->setName('sys:setup:compare-versions') |
18
|
|
|
->addOption('ignore-data', null, InputOption::VALUE_NONE, 'Ignore data updates') |
19
|
|
|
->addOption('log-junit', null, InputOption::VALUE_REQUIRED, 'Log output to a JUnit xml file.') |
20
|
|
|
->addOption( |
21
|
|
|
'errors-only', |
22
|
|
|
null, |
23
|
|
|
InputOption::VALUE_NONE, |
24
|
|
|
'Only display Setup resources where Status equals Error.' |
25
|
|
|
) |
26
|
|
|
->addOption( |
27
|
|
|
'format', |
28
|
|
|
null, |
29
|
|
|
InputOption::VALUE_OPTIONAL, |
30
|
|
|
'Output Format. One of [' . implode(',', RendererFactory::getFormats()) . ']' |
31
|
|
|
) |
32
|
|
|
->setDescription('Compare module version with core_resource table.'); |
33
|
|
|
$help = <<<HELP |
34
|
|
|
Compares module version with saved setup version in `core_resource` table and displays version mismatch. |
35
|
|
|
HELP; |
36
|
|
|
$this->setHelp($help); |
37
|
|
|
} |
38
|
|
|
|
39
|
|
|
/** |
40
|
|
|
* @param InputInterface $input |
41
|
|
|
* @param OutputInterface $output |
42
|
|
|
* |
43
|
|
|
* @return int|null|void |
44
|
|
|
*/ |
45
|
|
|
protected function execute(InputInterface $input, OutputInterface $output) |
46
|
|
|
{ |
47
|
|
|
$this->detectMagento($output); |
48
|
|
|
if (!$this->initMagento()) { |
49
|
|
|
return; |
50
|
|
|
} |
51
|
|
|
|
52
|
|
|
$time = microtime(true); |
53
|
|
|
$modules = \Mage::getConfig()->getNode('modules'); |
54
|
|
|
$resourceModel = $this->_getResourceSingleton('core/resource', 'Mage_Core_Model_Resource_Resource'); |
55
|
|
|
$setups = \Mage::getConfig()->getNode('global/resources')->children(); |
56
|
|
|
$ignoreDataUpdate = $input->getOption('ignore-data'); |
57
|
|
|
|
58
|
|
|
$headers = array('Setup', 'Module', 'DB', 'Data', 'Status'); |
59
|
|
|
if ($ignoreDataUpdate) { |
60
|
|
|
unset($headers[array_search('Data', $headers)]); |
61
|
|
|
} |
62
|
|
|
|
63
|
|
|
$hasStatusErrors = false; |
64
|
|
|
|
65
|
|
|
$errorCounter = 0; |
66
|
|
|
$table = array(); |
67
|
|
|
foreach ($setups as $setupName => $setup) { |
68
|
|
|
$moduleName = (string) $setup->setup->module; |
69
|
|
|
$moduleVersion = (string) $modules->{$moduleName}->version; |
70
|
|
|
$dbVersion = (string) $resourceModel->getDbVersion($setupName); |
71
|
|
|
if (!$ignoreDataUpdate) { |
72
|
|
|
$dataVersion = (string) $resourceModel->getDataVersion($setupName); |
73
|
|
|
} |
74
|
|
|
$ok = $dbVersion == $moduleVersion; |
75
|
|
|
if ($ok && !$ignoreDataUpdate) { |
76
|
|
|
$ok = $dataVersion == $moduleVersion; |
|
|
|
|
77
|
|
|
} |
78
|
|
|
if (!$ok) { |
79
|
|
|
$errorCounter++; |
80
|
|
|
} |
81
|
|
|
|
82
|
|
|
$row = array( |
83
|
|
|
'Setup' => $setupName, |
84
|
|
|
'Module' => $moduleVersion, |
85
|
|
|
'DB' => $dbVersion, |
86
|
|
|
); |
87
|
|
|
|
88
|
|
|
if (!$ignoreDataUpdate) { |
89
|
|
|
$row['Data-Version'] = $dataVersion; |
90
|
|
|
} |
91
|
|
|
$row['Status'] = $ok ? 'OK' : 'Error'; |
92
|
|
|
|
93
|
|
|
if (!$ok) { |
94
|
|
|
$hasStatusErrors = true; |
95
|
|
|
} |
96
|
|
|
|
97
|
|
|
$table[] = $row; |
98
|
|
|
} |
99
|
|
|
|
100
|
|
|
if ($input->getOption('errors-only')) { |
101
|
|
|
$table = array_filter($table, function ($row) { |
102
|
|
|
return ($row['Status'] === 'Error'); |
103
|
|
|
}); |
104
|
|
|
} |
105
|
|
|
|
106
|
|
|
//if there is no output format |
107
|
|
|
//highlight the status |
108
|
|
|
//and show error'd rows at bottom |
109
|
|
|
if (!$input->getOption('format')) { |
110
|
|
|
usort($table, function ($a, $b) { |
111
|
|
|
if ($a['Status'] !== 'OK' && $b['Status'] === 'OK') { |
112
|
|
|
return 1; |
113
|
|
|
} |
114
|
|
|
if ($a['Status'] === 'OK' && $b['Status'] !== 'OK') { |
115
|
|
|
return -1; |
116
|
|
|
} |
117
|
|
|
return strcmp($a['Setup'], $b['Setup']); |
118
|
|
|
}); |
119
|
|
|
|
120
|
|
|
array_walk($table, function (&$row) { |
121
|
|
|
$status = $row['Status']; |
122
|
|
|
$availableStatus = array('OK' => 'info', 'Error' => 'error'); |
123
|
|
|
$statusString = sprintf( |
124
|
|
|
'<%s>%s</%s>', |
125
|
|
|
$availableStatus[$status], |
126
|
|
|
$status, |
127
|
|
|
$availableStatus[$status] |
128
|
|
|
); |
129
|
|
|
$row['Status'] = $statusString; |
130
|
|
|
}); |
131
|
|
|
} |
132
|
|
|
|
133
|
|
|
if ($input->getOption('log-junit')) { |
134
|
|
|
$this->logJUnit($table, $input->getOption('log-junit'), microtime($time) - $time); |
135
|
|
|
} else { |
136
|
|
|
$this->getHelper('table') |
137
|
|
|
->setHeaders($headers) |
138
|
|
|
->renderByFormat($output, $table, $input->getOption('format')); |
139
|
|
|
|
140
|
|
|
//if no output format specified - output summary line |
141
|
|
|
if (!$input->getOption('format')) { |
142
|
|
|
if ($errorCounter > 0) { |
143
|
|
|
$this->writeSection( |
144
|
|
|
$output, |
145
|
|
|
sprintf( |
146
|
|
|
'%s error%s %s found!', |
147
|
|
|
$errorCounter, |
148
|
|
|
$errorCounter === 1 ? '' : 's', |
149
|
|
|
$errorCounter === 1 ? 'was' : 'were' |
150
|
|
|
), |
151
|
|
|
'error' |
152
|
|
|
); |
153
|
|
|
} else { |
154
|
|
|
$this->writeSection($output, 'No setup problems were found.', 'info'); |
155
|
|
|
} |
156
|
|
|
} |
157
|
|
|
} |
158
|
|
|
|
159
|
|
|
if ($hasStatusErrors) { |
160
|
|
|
//Return a non-zero status to indicate there is an error in the setup scripts. |
161
|
|
|
return 1; |
162
|
|
|
} else { |
163
|
|
|
return 0; |
164
|
|
|
} |
165
|
|
|
} |
166
|
|
|
|
167
|
|
|
/** |
168
|
|
|
* @param array $data |
169
|
|
|
* @param string $filename |
170
|
|
|
* @param float $duration |
171
|
|
|
*/ |
172
|
|
|
protected function logJUnit(array $data, $filename, $duration) |
173
|
|
|
{ |
174
|
|
|
$document = new JUnitXmlDocument(); |
175
|
|
|
$suite = $document->addTestSuite(); |
176
|
|
|
$suite->setName('n98-magerun: ' . $this->getName()); |
177
|
|
|
$suite->setTimestamp(new \DateTime()); |
178
|
|
|
$suite->setTime($duration); |
179
|
|
|
|
180
|
|
|
$testCase = $suite->addTestCase(); |
181
|
|
|
$testCase->setName('Magento Setup Version Test'); |
182
|
|
|
$testCase->setClassname('CompareVersionsCommand'); |
183
|
|
|
if (count($data) > 0) { |
184
|
|
|
foreach ($data as $moduleSetup) { |
185
|
|
|
if (stristr($moduleSetup['Status'], 'error')) { |
186
|
|
|
$testCase->addFailure( |
187
|
|
|
sprintf( |
188
|
|
|
'Setup Script Error: [Setup %s]', |
189
|
|
|
$moduleSetup['Setup'] |
190
|
|
|
), |
191
|
|
|
'MagentoSetupScriptVersionException' |
192
|
|
|
); |
193
|
|
|
} |
194
|
|
|
} |
195
|
|
|
} |
196
|
|
|
|
197
|
|
|
$document->save($filename); |
198
|
|
|
} |
199
|
|
|
} |
200
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.