diff --git a/CHANGELOG.md b/CHANGELOG.md index 7e26ffa2..8ca4c9b5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com), and this #### Added * [#153](https://github.com/shlinkio/shlink/issues/153) Updated to [doctrine/migrations](https://github.com/doctrine/migrations) version 2.0.0 +* [#376](https://github.com/shlinkio/shlink/issues/376) Allowed `visit:update-db` command to not return an error exit code even if download fails, by passing the `-i` flag. #### Changed diff --git a/composer.json b/composer.json index dbb97d98..b529ae8f 100644 --- a/composer.json +++ b/composer.json @@ -55,7 +55,7 @@ "filp/whoops": "^2.0", "infection/infection": "^0.12.2", "phpstan/phpstan": "^0.11.2", - "phpunit/phpcov": "^6.0@dev || ^5.0", + "phpunit/phpcov": "^6.0 || ^5.0", "phpunit/phpunit": "^8.0 || ^7.5", "roave/security-advisories": "dev-master", "shlinkio/php-coding-standard": "~1.1.0", 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(); } }