kaliop-uk /
ezmigrationbundle
| 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); |
|||
| 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
Loading history...
|
|||||
| 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