diff --git a/composer.json b/composer.json index c7e1d90..2f2fba7 100644 --- a/composer.json +++ b/composer.json @@ -65,6 +65,7 @@ }, "phpmd": { "url": "http://static.phpmd.org/php/latest/phpmd.phar", + "fallback-url": "https://github.com/jakzal/phpmd/releases/download/2.6.0-jakzal-2/phpmd.phar", "force-replace": true }, "security-checker": { diff --git a/src/Factory/ToolFactory.php b/src/Factory/ToolFactory.php index b61d137..9ebbf16 100644 --- a/src/Factory/ToolFactory.php +++ b/src/Factory/ToolFactory.php @@ -24,6 +24,7 @@ public static function createTool($name, $directory, array $parameters) 'only-dev' => true, 'force-replace' => false, 'rename' => false, + 'fallback-url' => null, ]; $parameters = array_merge($defaults, $parameters); @@ -47,6 +48,10 @@ public static function createTool($name, $directory, array $parameters) $tool->setNameToToolKey(); } + if (null !== $parameters['fallback-url']) { + $tool->setFallbackUrl($parameters['fallback-url']); + } + return $tool; } diff --git a/src/Model/Tool.php b/src/Model/Tool.php index d2910d8..664fae7 100644 --- a/src/Model/Tool.php +++ b/src/Model/Tool.php @@ -42,12 +42,16 @@ class Tool */ private $rename = false; + /** + * @var string + */ + private $fallbackUrl; + /** * @param string $name * @param string $filename * @param string $url * @param string $signUrl - * * @SuppressWarnings(PHPMD.ExcessiveParameterList) */ public function __construct($name, $filename, $url, $signUrl = null) @@ -137,4 +141,22 @@ public function renameToConfigKey() { return $this->rename; } + + /** + * @param string $url + * + * @return void + */ + public function setFallbackUrl($url) + { + $this->fallbackUrl = $url; + } + + /** + * @return string + */ + public function getFallbackUrl() + { + return $this->fallbackUrl; + } } diff --git a/src/Script/Decision/IsAccessibleDecision.php b/src/Script/Decision/IsAccessibleDecision.php index dfed98d..268822e 100644 --- a/src/Script/Decision/IsAccessibleDecision.php +++ b/src/Script/Decision/IsAccessibleDecision.php @@ -17,7 +17,7 @@ class IsAccessibleDecision extends AbstractDecision public function canProceed(Tool $tool) { if (false === $this->helper->getDownloader()->isAccessible($tool->getUrl())) { - return false; + return $this->fallbackUrlIsAccessible($tool); } if (empty($tool->getSignUrl())) { @@ -38,4 +38,16 @@ public function getReason() { return 'At least one given URL are not accessible!'; } + + /** + * @param Tool $tool + * + * @return bool + */ + private function fallbackUrlIsAccessible(Tool $tool) + { + $fallbackUrl = $tool->getFallbackUrl(); + + return false === empty($fallbackUrl) && true === $this->helper->getDownloader()->isAccessible($fallbackUrl); + } } diff --git a/src/Script/Processor.php b/src/Script/Processor.php index 95a7ddc..18d48cd 100644 --- a/src/Script/Processor.php +++ b/src/Script/Processor.php @@ -9,7 +9,6 @@ use Tooly\Script\Decision\IsAccessibleDecision; use Tooly\Script\Decision\IsVerifiedDecision; use Tooly\Script\Decision\OnlyDevDecision; -use Tooly\Script\Helper; use Tooly\Model\Tool; /** @@ -80,7 +79,7 @@ public function process(Tool $tool) return; } - $data = $this->helper->getDownloader()->download($tool->getUrl()); + $data = $this->helper->getDownloader()->download($this->getDownloadUrl($tool)); $filename = $tool->getFilename(); $this->helper->getFilesystem()->createFile($filename, $data); @@ -166,4 +165,18 @@ private function removeFromDir($dir, array $excludeToolNames = []) $this->helper->getFilesystem()->remove($path); } } + + /** + * @param Tool $tool + * + * @return string + */ + private function getDownloadUrl(Tool $tool) + { + if (false === $this->helper->getDownloader()->isAccessible($tool->getUrl())) { + return $tool->getFallbackUrl(); + } + + return $tool->getUrl(); + } } diff --git a/tests/Factory/ToolFactoryTest.php b/tests/Factory/ToolFactoryTest.php index 1baf06f..79ceca4 100644 --- a/tests/Factory/ToolFactoryTest.php +++ b/tests/Factory/ToolFactoryTest.php @@ -18,14 +18,19 @@ public function testCanCreateATool() $tool = ToolFactory::createTool('test', 'vfs://root', [ 'url' => 'my-url', 'sign-url' => 'my-sign-url', - 'force-replace' => true + 'force-replace' => true, + 'only-dev' => false, + 'rename' => true, + 'fallback-url' => 'fallback-url' ]); $this->assertInstanceOf(Tool::class, $tool); $this->assertEquals('my-url', $tool->getUrl()); $this->assertEquals('my-sign-url', $tool->getSignUrl()); $this->assertTrue($tool->forceReplace()); - $this->assertTrue($tool->isOnlyDev()); + $this->assertFalse($tool->isOnlyDev()); + $this->assertTrue($tool->renameToConfigKey()); + $this->assertEquals('fallback-url', $tool->getFallbackUrl()); } public function testCanCreateMultipleTools() diff --git a/tests/Script/Decision/IsAccessibleDecisionTest.php b/tests/Script/Decision/IsAccessibleDecisionTest.php index 2f34d6b..0e99cf0 100644 --- a/tests/Script/Decision/IsAccessibleDecisionTest.php +++ b/tests/Script/Decision/IsAccessibleDecisionTest.php @@ -74,6 +74,28 @@ public function testNotAccessibleToolSignUrlReturnsFalse() ]))); } + public function testNotAccessibleToolUrlButAccessibleFallbackUrlReturnsTrue() + { + $downloader = $this + ->getMockBuilder(Downloader::class) + ->getMock(); + + $downloader + ->expects($this->exactly(2)) + ->method('isAccessible') + ->will($this->onConsecutiveCalls(false, true)); + + $this->helper + ->expects($this->exactly(2)) + ->method('getDownloader') + ->willReturn($downloader); + + $decision = new IsAccessibleDecision($this->configuration, $this->helper); + $this->assertTrue($decision->canProceed(ToolFactory::createTool('tool', __DIR__, [ + 'fallback-url' => 'fallback-url' + ]))); + } + public function testAccessibleUrlsWillReturnTrue() { $downloader = $this diff --git a/tests/Script/Processor/ProcessTest.php b/tests/Script/Processor/ProcessTest.php index 9f96469..1d09996 100644 --- a/tests/Script/Processor/ProcessTest.php +++ b/tests/Script/Processor/ProcessTest.php @@ -121,4 +121,56 @@ public function testCanSuccessfullyDownloadATool() $processor = new Processor($this->io, $this->helper, $this->configuration); $processor->process($tool); } + + public function testCanSuccessfullyDownloadAToolViaFallbackUrl() + { + vfsStream::setup('bin'); + + $downloader = $this + ->getMockBuilder(Downloader::class) + ->getMock(); + + $downloader + ->expects($this->exactly(3)) + ->method('isAccessible') + ->will($this->onConsecutiveCalls(false, true, false)); + + $filesystem = $this + ->getMockBuilder(Filesystem::class) + ->getMock(); + + $filesystem + ->method('isFileAlreadyExist') + ->willReturn(false); + + $this->helper + ->method('getFilesystem') + ->willReturn($filesystem); + + $this->helper + ->expects($this->exactly(4)) + ->method('getDownloader') + ->willReturn($downloader); + + $this->helper + ->method('isFileAlreadyExist') + ->willReturn(false); + + $this->io + ->expects($this->exactly(2)) + ->method('write'); + + $tool = $this + ->getMockBuilder(Tool::class) + ->disableOriginalConstructor() + ->getMock(); + + $tool + ->expects($this->exactly(2)) + ->method('getFallbackUrl') + ->willReturn('//test.html'); + + $processor = new Processor($this->io, $this->helper, $this->configuration); + $processor->process($tool); + } }