1 | <?php |
||||
2 | |||||
3 | namespace Kaliop\eZMigrationBundle\Command; |
||||
4 | |||||
5 | use Symfony\Component\Console\Input\InputInterface; |
||||
6 | use Symfony\Component\Console\Output\OutputInterface; |
||||
7 | use Symfony\Component\Console\Input\InputOption; |
||||
8 | use Symfony\Component\Console\Input\InputArgument; |
||||
9 | use Kaliop\eZMigrationBundle\API\Value\Migration; |
||||
10 | use Kaliop\eZMigrationBundle\API\Value\MigrationDefinition; |
||||
11 | use Symfony\Component\Console\Question\ConfirmationQuestion; |
||||
0 ignored issues
–
show
|
|||||
12 | |||||
13 | /** |
||||
14 | * Command to manipulate the available migrations / migration definitions. |
||||
15 | * @todo should we split off the actions used to manipulate migration defs into a separate command `MigrationDefinition` ? |
||||
16 | */ |
||||
17 | class MigrationCommand extends AbstractCommand |
||||
18 | { |
||||
19 | /** |
||||
20 | * Set up the command. |
||||
21 | * |
||||
22 | * Define the name, options and help text. |
||||
23 | */ |
||||
24 | 148 | protected function configure() |
|||
25 | { |
||||
26 | 148 | parent::configure(); |
|||
27 | |||||
28 | $this |
||||
29 | 148 | ->setName('kaliop:migration:migration') |
|||
30 | 148 | ->setDescription('Manually modify or get info about migrations in the database table.') |
|||
31 | 148 | ->addOption('delete', null, InputOption::VALUE_NONE, "Delete the specified migration.") |
|||
32 | 148 | ->addOption('info', null, InputOption::VALUE_NONE, "Get info about the specified migration.") |
|||
33 | 148 | ->addOption('add', null, InputOption::VALUE_NONE, "Add the specified migration definition.") |
|||
34 | 148 | ->addOption('skip', null, InputOption::VALUE_NONE, "Mark the specified migration as skipped.") |
|||
35 | 148 | ->addOption('fail', null, InputOption::VALUE_NONE, "Mark the specified migration as failed.") |
|||
36 | 148 | ->addOption('no-interaction', 'n', InputOption::VALUE_NONE, "Do not ask any interactive question.") |
|||
37 | 148 | ->addArgument('migration', InputArgument::REQUIRED, 'The migration to add/skip (filename with full path) or detail/delete (plain migration name).', null) |
|||
38 | 148 | ->setHelp(<<<EOT |
|||
39 | 148 | The <info>kaliop:migration:migration</info> command allows you to manually manage migrations. |
|||
40 | |||||
41 | To see detailed information about a migration or migration definition: |
||||
42 | |||||
43 | <info>php bin/console kaliop:migration:migration --info migration_name</info> |
||||
44 | |||||
45 | <info>php bin/console kaliop:migration:migration --info /path/to/migration_definition.yml</info> |
||||
46 | |||||
47 | To remove a migration from the migration table, or mark it as failed: |
||||
48 | |||||
49 | <info>php bin/console kaliop:migration:migration --delete migration_name</info> |
||||
50 | |||||
51 | <info>php bin/console kaliop:migration:migration --fail migration_name</info> |
||||
52 | |||||
53 | To manually add migration definitions to the migration table, or marking them as skipped: |
||||
54 | |||||
55 | <info>php bin/console kaliop:migration:migration --add /path/to/migration_definition</info> |
||||
56 | |||||
57 | <info>php bin/console kaliop:migration:migration --skip /path/to/migration_definition</info> |
||||
58 | EOT |
||||
59 | ); |
||||
60 | 148 | } |
|||
61 | |||||
62 | /** |
||||
63 | * Execute the command. |
||||
64 | * |
||||
65 | * @param InputInterface $input |
||||
66 | * @param OutputInterface $output |
||||
67 | * @return null|int null or 0 if everything went fine, or an error code |
||||
68 | */ |
||||
69 | 107 | protected function execute(InputInterface $input, OutputInterface $output) |
|||
70 | { |
||||
71 | 107 | $this->setOutput($output); |
|||
72 | 107 | $this->setVerbosity($output->getVerbosity()); |
|||
73 | |||||
74 | 107 | if (!$input->getOption('add') && !$input->getOption('delete') && !$input->getOption('skip') && |
|||
75 | 107 | !$input->getOption('info') && !$input->getOption('fail')) { |
|||
76 | throw new \InvalidArgumentException('You must specify whether you want to --add, --delete, --skip, --fail or --info the specified migration.'); |
||||
77 | } |
||||
78 | |||||
79 | 107 | $migrationService = $this->getMigrationService(); |
|||
80 | 107 | $migrationNameOrPath = $input->getArgument('migration'); |
|||
81 | |||||
82 | 107 | if ($input->getOption('info')) { |
|||
83 | 20 | $output->writeln(''); |
|||
84 | |||||
85 | /// @todo if we are passed a path, we could give the user a more specific warning than what we get back from the storage layer |
||||
86 | 20 | $migration = $migrationService->getMigration($migrationNameOrPath); |
|||
87 | 20 | if ($migration == null) { |
|||
88 | throw new \InvalidArgumentException(sprintf('The migration "%s" does not exist in the migrations table. You can use `kaliop:migration:status --show-path` to find out more', $migrationNameOrPath)); |
||||
89 | } |
||||
90 | |||||
91 | 20 | switch ($migration->status) { |
|||
92 | case Migration::STATUS_DONE: |
||||
93 | 18 | $status = '<info>executed</info>'; |
|||
94 | 18 | break; |
|||
95 | case Migration::STATUS_STARTED: |
||||
96 | $status = '<comment>execution started</comment>'; |
||||
97 | break; |
||||
98 | case Migration::STATUS_TODO: |
||||
99 | // bold to-migrate! |
||||
100 | 1 | $status = '<error>not executed</error>'; |
|||
101 | 1 | break; |
|||
102 | case Migration::STATUS_SKIPPED: |
||||
103 | 1 | $status = '<comment>skipped</comment>'; |
|||
104 | 1 | break; |
|||
105 | case Migration::STATUS_PARTIALLY_DONE: |
||||
106 | $status = '<comment>partially executed</comment>'; |
||||
107 | break; |
||||
108 | case Migration::STATUS_SUSPENDED: |
||||
109 | $status = '<comment>suspended</comment>'; |
||||
110 | break; |
||||
111 | case Migration::STATUS_FAILED: |
||||
112 | $status = '<error>failed</error>'; |
||||
113 | break; |
||||
114 | } |
||||
115 | |||||
116 | 20 | $output->writeln('<info>Migration: ' . $migration->name . '</info>'); |
|||
117 | 20 | $output->writeln('Status: ' . $status); |
|||
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
|
|||||
118 | 20 | $output->writeln('Executed on: <info>' . ($migration->executionDate != null ? date("Y-m-d H:i:s", $migration->executionDate) : '--'). '</info>'); |
|||
119 | 20 | $output->writeln('Execution notes: <info>' . $migration->executionError . '</info>'); |
|||
120 | |||||
121 | 20 | if ($migration->status == Migration::STATUS_SUSPENDED) { |
|||
122 | /// @todo decode the suspension context: date, step, ... |
||||
123 | } |
||||
124 | |||||
125 | 20 | $output->writeln('Definition path: <info>' . $migration->path . '</info>'); |
|||
126 | 20 | $output->writeln('Definition md5: <info>' . $migration->md5 . '</info>'); |
|||
127 | |||||
128 | 20 | if ($migration->path != '') { |
|||
129 | // q: what if we have a loader which does not work with is_file? We could probably remove this check |
||||
130 | // or, better, add a method `$migrationService->migrationDefinitionExists` / use a specific exception in getMigrationsDefinitions... |
||||
131 | // Note also that $migration->path can not be used as is, as it is usually relative to the app's root dir |
||||
132 | //if (is_file($migration->path)) { |
||||
133 | try { |
||||
134 | 20 | $migrationDefinitionCollection = $migrationService->getMigrationsDefinitions(array($migration->path)); |
|||
135 | 20 | if (count($migrationDefinitionCollection)) { |
|||
136 | 20 | $migrationDefinition = $migrationDefinitionCollection->reset(); |
|||
137 | 20 | $migrationDefinition = $migrationService->parseMigrationDefinition($migrationDefinition); |
|||
138 | |||||
139 | 20 | if ($migrationDefinition->status != MigrationDefinition::STATUS_PARSED) { |
|||
140 | $output->writeln('Definition error: <error>' . $migrationDefinition->parsingError . '</error>'); |
||||
141 | } |
||||
142 | |||||
143 | 20 | if (md5($migrationDefinition->rawDefinition) != $migration->md5) { |
|||
144 | 20 | $output->writeln('Notes: <comment>The migration definition file has now a different checksum</comment>'); |
|||
145 | } |
||||
146 | } else { |
||||
147 | 20 | $output->writeln('Definition error: <error>The migration definition file can not be loaded</error>'); |
|||
148 | } |
||||
149 | } catch (\Exception $e) { |
||||
150 | /// @todo one day we should be able to limit the kind of exceptions we have to catch here... |
||||
151 | $output->writeln('Definition parsing error: <error>' . $e->getMessage() . '</error>'); |
||||
152 | } |
||||
153 | //} else { |
||||
154 | // $output->writeln('Definition error: <error>The migration definition file can not be found any more</error>'); |
||||
155 | //} |
||||
156 | } |
||||
157 | |||||
158 | 20 | $output->writeln(''); |
|||
159 | 20 | return 0; |
|||
160 | } |
||||
161 | |||||
162 | // ask user for confirmation to make changes |
||||
163 | 107 | if ($input->isInteractive() && !$input->getOption('no-interaction')) { |
|||
164 | $dialog = $this->getHelperSet()->get('question'); |
||||
165 | if (!$dialog->ask( |
||||
0 ignored issues
–
show
The method
ask() does not exist on Symfony\Component\Console\Helper\HelperInterface . It seems like you code against a sub-type of Symfony\Component\Console\Helper\HelperInterface such as Symfony\Component\Console\Helper\DialogHelper .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||
166 | $input, |
||||
167 | $output, |
||||
168 | new ConfirmationQuestion('<question>Careful, the database will be modified. Do you want to continue Y/N ?</question>', false) |
||||
169 | ) |
||||
170 | ) { |
||||
171 | $output->writeln('<error>Migration change cancelled!</error>'); |
||||
172 | return 0; |
||||
173 | } |
||||
174 | } |
||||
175 | |||||
176 | 107 | if ($input->getOption('add')) { |
|||
177 | // will throw if a file is passed and it is not found, but not if an empty dir is passed |
||||
178 | 84 | $migrationDefinitionCollection = $migrationService->getMigrationsDefinitions(array($migrationNameOrPath)); |
|||
179 | |||||
180 | 84 | if (!count($migrationDefinitionCollection)) |
|||
181 | { |
||||
182 | throw new \InvalidArgumentException(sprintf('The path "%s" does not correspond to any migration definition.', $migrationNameOrPath)); |
||||
183 | } |
||||
184 | |||||
185 | 84 | foreach ($migrationDefinitionCollection as $migrationDefinition) { |
|||
186 | 84 | $migrationName = basename($migrationDefinition->path); |
|||
187 | |||||
188 | 84 | $migration = $migrationService->getMigration($migrationNameOrPath); |
|||
189 | 84 | if ($migration != null) { |
|||
190 | throw new \InvalidArgumentException(sprintf('The migration "%s" does already exist in the migrations table.', $migrationName)); |
||||
191 | } |
||||
192 | |||||
193 | 84 | $migrationService->addMigration($migrationDefinition); |
|||
194 | 84 | $output->writeln('<info>Added migration ' . $migrationDefinition->path . '</info>'); |
|||
195 | } |
||||
196 | |||||
197 | 84 | return 0; |
|||
198 | } |
||||
199 | |||||
200 | 107 | if ($input->getOption('delete') || $input->getOption('fail')) { |
|||
201 | /// @todo if we are passed a path, we could give the user a more specific warning than what we get back from the storage layer |
||||
202 | 107 | $migration = $migrationService->getMigration($migrationNameOrPath); |
|||
203 | 107 | if ($migration == null) { |
|||
204 | 104 | throw new \InvalidArgumentException(sprintf('The migration "%s" does not exist in the migrations table.', $migrationNameOrPath)); |
|||
205 | } |
||||
206 | |||||
207 | 107 | if ($input->getOption('delete')) { |
|||
208 | 107 | $migrationService->deleteMigration($migration); |
|||
209 | } else { |
||||
210 | $errorMessage = 'Manually failed on ' . date("Y-m-d H:i:s"); |
||||
211 | if ($migration->executionError != '') { |
||||
212 | $errorMessage .= ". Previous notes: " . $migration->executionError; |
||||
213 | } |
||||
214 | $migrationService->failMigration($migration, $errorMessage); |
||||
215 | } |
||||
216 | |||||
217 | return 0; |
||||
218 | 107 | } |
|||
219 | |||||
220 | if ($input->getOption('skip')) { |
||||
221 | 1 | // will throw if a file is passed and it is not found, but not if an empty dir is passed |
|||
222 | $migrationDefinitionCollection = $migrationService->getMigrationsDefinitions(array($migrationNameOrPath)); |
||||
223 | 1 | ||||
224 | if (!count($migrationDefinitionCollection)) |
||||
225 | 1 | { |
|||
226 | throw new \InvalidArgumentException(sprintf('The path "%s" does not correspond to any migration definition.', $migrationNameOrPath)); |
||||
227 | } |
||||
228 | |||||
229 | foreach ($migrationDefinitionCollection as $migrationDefinition) { |
||||
230 | 1 | $migrationService->skipMigration($migrationDefinition); |
|||
231 | 1 | $output->writeln('<info>Migration ' . $migrationDefinition->path . ' marked as skipped</info>'); |
|||
232 | 1 | } |
|||
233 | |||||
234 | return 0; |
||||
235 | 1 | } |
|||
236 | |||||
237 | throw new \InvalidArgumentException("Please specify one action to be taken on the given migration"); |
||||
238 | } |
||||
239 | } |
||||
240 |
The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g.
excluded_paths: ["lib/*"]
, you can move it to the dependency path list as follows:For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths