diff --git a/module/CLI/src/Command/Visit/UpdateDbCommand.php b/module/CLI/src/Command/Visit/UpdateDbCommand.php index 35389260..af032e96 100644 --- a/module/CLI/src/Command/Visit/UpdateDbCommand.php +++ b/module/CLI/src/Command/Visit/UpdateDbCommand.php @@ -9,9 +9,12 @@ use Shlinkio\Shlink\Common\IpGeolocation\GeoLite2\DbUpdaterInterface; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Helper\ProgressBar; use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Style\SymfonyStyle; +use function sprintf; + class UpdateDbCommand extends Command { public const NAME = 'visit:update-db'; @@ -33,6 +36,12 @@ class UpdateDbCommand extends Command ->setHelp( 'The GeoLite2 database is updated first Tuesday every month, so this command should be ideally run ' . 'every first Wednesday' + ) + ->addOption( + 'ignoreErrors', + 'i', + InputOption::VALUE_NONE, + 'Makes the command success even iof the update fails.' ); } @@ -49,19 +58,32 @@ class UpdateDbCommand extends Command }); $progressBar->finish(); - $io->writeln(''); + $io->newLine(); $io->success('GeoLite2 database properly updated'); return ExitCodes::EXIT_SUCCESS; } catch (RuntimeException $e) { $progressBar->finish(); - $io->writeln(''); + $io->newLine(); - $io->error('An error occurred while updating GeoLite2 database'); - if ($io->isVerbose()) { - $this->getApplication()->renderException($e, $output); - } - return ExitCodes::EXIT_FAILURE; + return $this->handleError($e, $io, $input); } } + + private function handleError(RuntimeException $e, SymfonyStyle $io, InputInterface $input): int + { + $ignoreErrors = $input->getOption('ignoreErrors'); + $baseErrorMsg = 'An error occurred while updating GeoLite2 database'; + + if ($ignoreErrors) { + $io->warning(sprintf('%s, but it was ignored', $baseErrorMsg)); + return ExitCodes::EXIT_SUCCESS; + } + + $io->error($baseErrorMsg); + if ($io->isVerbose()) { + $this->getApplication()->renderException($e, $io); + } + return ExitCodes::EXIT_FAILURE; + } } diff --git a/module/CLI/test/Command/Visit/UpdateDbCommandTest.php b/module/CLI/test/Command/Visit/UpdateDbCommandTest.php index 80579513..63f87b6d 100644 --- a/module/CLI/test/Command/Visit/UpdateDbCommandTest.php +++ b/module/CLI/test/Command/Visit/UpdateDbCommandTest.php @@ -7,6 +7,7 @@ use PHPUnit\Framework\TestCase; use Prophecy\Argument; use Prophecy\Prophecy\ObjectProphecy; use Shlinkio\Shlink\CLI\Command\Visit\UpdateDbCommand; +use Shlinkio\Shlink\CLI\Util\ExitCodes; use Shlinkio\Shlink\Common\Exception\RuntimeException; use Shlinkio\Shlink\Common\IpGeolocation\GeoLite2\DbUpdaterInterface; use Symfony\Component\Console\Application; @@ -31,27 +32,45 @@ class UpdateDbCommandTest extends TestCase } /** @test */ - public function successMessageIsPrintedIfEverythingWorks() + public function successMessageIsPrintedIfEverythingWorks(): void { $download = $this->dbUpdater->downloadFreshCopy(Argument::type('callable'))->will(function () { }); $this->commandTester->execute([]); $output = $this->commandTester->getDisplay(); + $exitCode = $this->commandTester->getStatusCode(); $this->assertStringContainsString('GeoLite2 database properly updated', $output); + $this->assertEquals(ExitCodes::EXIT_SUCCESS, $exitCode); $download->shouldHaveBeenCalledOnce(); } /** @test */ - public function errorMessageIsPrintedIfAnExceptionIsThrown() + public function errorMessageIsPrintedIfAnExceptionIsThrown(): void { $download = $this->dbUpdater->downloadFreshCopy(Argument::type('callable'))->willThrow(RuntimeException::class); $this->commandTester->execute([]); $output = $this->commandTester->getDisplay(); + $exitCode = $this->commandTester->getStatusCode(); $this->assertStringContainsString('An error occurred while updating GeoLite2 database', $output); + $this->assertEquals(ExitCodes::EXIT_FAILURE, $exitCode); + $download->shouldHaveBeenCalledOnce(); + } + + /** @test */ + public function warningMessageIsPrintedIfAnExceptionIsThrownAndErrorsAreIgnored(): void + { + $download = $this->dbUpdater->downloadFreshCopy(Argument::type('callable'))->willThrow(RuntimeException::class); + + $this->commandTester->execute(['--ignoreErrors' => true]); + $output = $this->commandTester->getDisplay(); + $exitCode = $this->commandTester->getStatusCode(); + + $this->assertStringContainsString('ignored', $output); + $this->assertEquals(ExitCodes::EXIT_SUCCESS, $exitCode); $download->shouldHaveBeenCalledOnce(); } }