From 54de94724f6a335bc181b6cf58a18c0945a8ec5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20Lu=CC=88ckel?= Date: Tue, 27 Aug 2019 11:33:43 +0200 Subject: [PATCH 1/8] Adds mikey179/vfsstream to the dev requirements because it is needed to test the cache implementation --- composer.json | 1 + 1 file changed, 1 insertion(+) diff --git a/composer.json b/composer.json index e4ec877..a623333 100644 --- a/composer.json +++ b/composer.json @@ -22,6 +22,7 @@ "bin/sd-plugin-manager" ], "require-dev": { + "mikey179/vfsstream": "^1.6", "solutiondrive/standalone-build-tools": "^1.0" }, "config": { From b00f224442ab28d74ee4556f9e25d83437acc1ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20Lu=CC=88ckel?= Date: Tue, 27 Aug 2019 11:42:44 +0200 Subject: [PATCH 2/8] Adds a parameter to be able to define a cache directory --- spec/Service/StoreApiConnectorSpec.php | 16 ++++++++++++---- src/Resources/config/services.yml | 1 + src/Service/StoreApiConnector.php | 9 +++++++-- 3 files changed, 20 insertions(+), 6 deletions(-) diff --git a/spec/Service/StoreApiConnectorSpec.php b/spec/Service/StoreApiConnectorSpec.php index 7b8a6d6..ad3068e 100644 --- a/spec/Service/StoreApiConnectorSpec.php +++ b/spec/Service/StoreApiConnectorSpec.php @@ -12,6 +12,8 @@ use GuzzleHttp\Client; use GuzzleHttp\Psr7\Response; use GuzzleHttp\RequestOptions; +use org\bovigo\vfs\vfsStream; +use org\bovigo\vfs\vfsStreamDirectory; use PhpSpec\ObjectBehavior; use Psr\Http\Message\StreamInterface; use sd\SwPluginManager\Service\StoreApiConnector; @@ -26,6 +28,9 @@ class StoreApiConnectorSpec extends ObjectBehavior const SHOPWARE_ACCOUNT_PASSWORD = 'SuperSecurePassword'; const SHOPWARE_SHOP_DOMAIN = 'example.org'; + /** @var vfsStreamDirectory */ + private $cacheRootDir; + public function it_is_initializable(): void { $this->shouldHaveType(StoreApiConnector::class); @@ -40,9 +45,12 @@ public function let( Client $guzzleClient, StreamTranslatorInterface $streamTranslator ): void { + $this->cacheRootDir = vfsStream::setup('/tmp/'); + $this->beConstructedWith( $guzzleClient, - $streamTranslator + $streamTranslator, + $this->cacheRootDir->url() ); // Resets environment variables on every run @@ -116,7 +124,7 @@ public function it_can_load_a_plugin_only_if_domain_exists_in_partner_account( RequestOptions::HEADERS => [ 'X-Shopware-Token' => 'ABCDEF', ], - RequestOptions::SINK => '/tmp/sw-plugin-awesomePlugin0.0.2', + RequestOptions::SINK => $this->cacheRootDir->url() . '/sw-plugin-awesomePlugin0.0.2', ] ) ->shouldBeCalled() @@ -189,7 +197,7 @@ public function it_can_load_a_plugin_only_if_domain_exists_in_normal_shop( RequestOptions::HEADERS => [ 'X-Shopware-Token' => 'ABCDEF', ], - RequestOptions::SINK => '/tmp/sw-plugin-awesomePlugin0.0.2', + RequestOptions::SINK => $this->cacheRootDir->url() . '/sw-plugin-awesomePlugin0.0.2', ] ) ->shouldBeCalled() @@ -248,7 +256,7 @@ public function it_can_load_a_plugin_without_a_partner_account( RequestOptions::HEADERS => [ 'X-Shopware-Token' => 'ABCDEF', ], - RequestOptions::SINK => '/tmp/sw-plugin-awesomePlugin0.0.2', + RequestOptions::SINK => $this->cacheRootDir->url() . '/sw-plugin-awesomePlugin0.0.2', ] ) ->shouldBeCalled() diff --git a/src/Resources/config/services.yml b/src/Resources/config/services.yml index cf7dbd0..45de2a1 100644 --- a/src/Resources/config/services.yml +++ b/src/Resources/config/services.yml @@ -81,6 +81,7 @@ services: arguments: - '@sd.external.guzzle' - '@sd.service.stream_translator' + - '/tmp' sd.service.stream_translator: class: sd\SwPluginManager\Service\StreamTranslator diff --git a/src/Service/StoreApiConnector.php b/src/Service/StoreApiConnector.php index 844f98f..0ca7862 100644 --- a/src/Service/StoreApiConnector.php +++ b/src/Service/StoreApiConnector.php @@ -24,6 +24,9 @@ class StoreApiConnector implements StoreApiConnectorInterface /** @var StreamTranslatorInterface */ private $streamTranslator; + /** @var string */ + private $cacheDir; + /** @var string|null */ private $accessToken; @@ -35,10 +38,12 @@ class StoreApiConnector implements StoreApiConnectorInterface public function __construct( Client $guzzleClient, - StreamTranslatorInterface $streamTranslator + StreamTranslatorInterface $streamTranslator, + string $cacheDir ) { $this->guzzleClient = $guzzleClient; $this->streamTranslator = $streamTranslator; + $this->cacheDir = $cacheDir; } public function loadPlugin(string $pluginId, string $version): string @@ -101,7 +106,7 @@ public function loadPlugin(string $pluginId, string $version): string return $binary['version'] === $version; }))[0]; - $tmpName = '/tmp/sw-plugin-' . $pluginName . $version; + $tmpName = $this->cacheDir . DIRECTORY_SEPARATOR . 'sw-plugin-' . $pluginName . $version; $downloadUrl = self::BASE_URL . '/plugins/' . $pluginSpecificId . '/binaries/' . $binaryVersion['id'] . '/file?shopId=' . $shop['id']; $this->doRequest( $downloadUrl, From f3d5dfe4a75455e34768aab989632811bc523f36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20Lu=CC=88ckel?= Date: Tue, 27 Aug 2019 13:48:51 +0200 Subject: [PATCH 3/8] Changes the behaviour to use already downloaded plugins from the 'cache' directory instead of downloading the plugins again and again --- spec/Service/StoreApiConnectorSpec.php | 28 ++++++++++++++++++++++++++ src/Service/StoreApiConnector.php | 7 +++++-- 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/spec/Service/StoreApiConnectorSpec.php b/spec/Service/StoreApiConnectorSpec.php index ad3068e..e30e08a 100644 --- a/spec/Service/StoreApiConnectorSpec.php +++ b/spec/Service/StoreApiConnectorSpec.php @@ -15,6 +15,7 @@ use org\bovigo\vfs\vfsStream; use org\bovigo\vfs\vfsStreamDirectory; use PhpSpec\ObjectBehavior; +use Prophecy\Argument; use Psr\Http\Message\StreamInterface; use sd\SwPluginManager\Service\StoreApiConnector; use sd\SwPluginManager\Service\StoreApiConnectorInterface; @@ -270,6 +271,33 @@ public function it_cannot_connect_to_store_api_without_credentials(): void $this->shouldThrow(\RuntimeException::class)->during('loadPlugin', ['awesomePlugin', '0.0.2']); } + public function it_does_not_download_plugin_if_it_is_available_in_cache( + Client $guzzleClient, + StreamTranslatorInterface $streamTranslator + ): void { + vfsStream::newFile('sw-plugin-awesomePlugin0.0.2')->at($this->cacheRootDir); + vfsStream::newFile('sw-plugin-awesomePlugin1.2.5')->at($this->cacheRootDir); + + $guzzleClient->get(Argument::any(), Argument::any()) + ->shouldNotBeCalled(); + $guzzleClient->post(Argument::any(), Argument::any()) + ->shouldNotBeCalled(); + $guzzleClient->put(Argument::any(), Argument::any()) + ->shouldNotBeCalled(); + $guzzleClient->delete(Argument::any(), Argument::any()) + ->shouldNotBeCalled(); + $guzzleClient->patch(Argument::any(), Argument::any()) + ->shouldNotBeCalled(); + + $streamTranslator->translateToArray(Argument::any()) + ->shouldNotBeCalled(); + + $this->loadPlugin('awesomePlugin', '0.0.2') + ->shouldReturn($this->cacheRootDir->url() . '/sw-plugin-awesomePlugin0.0.2'); + $this->loadPlugin('awesomePlugin', '1.2.5') + ->shouldReturn($this->cacheRootDir->url() . '/sw-plugin-awesomePlugin1.2.5'); + } + private function prepareAccessToken( Client $guzzleClient, StreamTranslatorInterface $streamTranslator, diff --git a/src/Service/StoreApiConnector.php b/src/Service/StoreApiConnector.php index 0ca7862..0c37095 100644 --- a/src/Service/StoreApiConnector.php +++ b/src/Service/StoreApiConnector.php @@ -48,6 +48,11 @@ public function __construct( public function loadPlugin(string $pluginId, string $version): string { + $tmpName = $this->cacheDir . DIRECTORY_SEPARATOR . 'sw-plugin-' . $pluginId . $version; + if (\file_exists($tmpName)) { + return $tmpName; + } + $partnerShops = $this->getShopsFromPartnerAccount(); $shops = $this->getGeneralShops(); $shop = $this->filterShopsByDomain($shops, $partnerShops); @@ -75,7 +80,6 @@ public function loadPlugin(string $pluginId, string $version): string // Get plugin information $pluginOverallId = $plugin['id']; - $pluginName = $plugin['plugin']['name']; $pluginSpecificId = $plugin['plugin']['id']; $pluginInfoUrl = self::BASE_URL; @@ -106,7 +110,6 @@ public function loadPlugin(string $pluginId, string $version): string return $binary['version'] === $version; }))[0]; - $tmpName = $this->cacheDir . DIRECTORY_SEPARATOR . 'sw-plugin-' . $pluginName . $version; $downloadUrl = self::BASE_URL . '/plugins/' . $pluginSpecificId . '/binaries/' . $binaryVersion['id'] . '/file?shopId=' . $shop['id']; $this->doRequest( $downloadUrl, From 86714bb06a2974707b926721e3678229d78ade57 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20Lu=CC=88ckel?= Date: Tue, 27 Aug 2019 14:27:04 +0200 Subject: [PATCH 4/8] Adds a force parameter to the providers to be able to manage the behaviour if a plugin should be loaded from the cache --- spec/Provider/FilesystemProviderSpec.php | 5 +++++ spec/Provider/HttpProviderSpec.php | 15 +++++++++++++++ spec/Provider/NoneProviderSpec.php | 5 +++++ spec/Provider/S3ProviderSpec.php | 22 ++++++++++++++++++++++ spec/Provider/StoreApiProviderSpec.php | 16 ++++++++++++++++ src/Provider/FilesystemProvider.php | 2 +- src/Provider/HttpProvider.php | 2 +- src/Provider/NoneProvider.php | 2 +- src/Provider/ProviderInterface.php | 2 +- src/Provider/S3Provider.php | 2 +- src/Provider/StoreApiProvider.php | 2 +- 11 files changed, 69 insertions(+), 6 deletions(-) diff --git a/spec/Provider/FilesystemProviderSpec.php b/spec/Provider/FilesystemProviderSpec.php index 94ee93d..d20cd2c 100644 --- a/spec/Provider/FilesystemProviderSpec.php +++ b/spec/Provider/FilesystemProviderSpec.php @@ -30,6 +30,11 @@ public function it_can_load_file(): void $this->loadFile(['src' => './test/file/path.zip'])->shouldReturn('./test/file/path.zip'); } + public function it_can_force_load_file(): void + { + $this->loadFile(['src' => './test/file/path.zip'], true)->shouldReturn('./test/file/path.zip'); + } + public function it_cannot_load_with_empty_filename(): void { $this->shouldThrow(\RuntimeException::class)->during('loadFile', [[]]); diff --git a/spec/Provider/HttpProviderSpec.php b/spec/Provider/HttpProviderSpec.php index 31a5912..11f0668 100644 --- a/spec/Provider/HttpProviderSpec.php +++ b/spec/Provider/HttpProviderSpec.php @@ -48,6 +48,21 @@ public function it_can_load_simple(Client $guzzleClient, ResponseInterface $guzz $this->loadFile(['src' => $url]); } + public function it_can_force_load_simple(Client $guzzleClient, ResponseInterface $guzzleResponse): void + { + $url = 'https://sd.test/url/to/file.zip'; + + $guzzleResponse->getStatusCode()->willReturn(200); + $guzzleClient->get( + Argument::exact($url), + Argument::withKey('sink') + ) + ->willReturn($guzzleResponse) + ->shouldBeCalled(); + + $this->loadFile(['src' => $url], true); + } + public function it_can_load_with_auth(Client $guzzleClient, ResponseInterface $guzzleResponse): void { $url = 'https://sd.test/url/to/file.zip'; diff --git a/spec/Provider/NoneProviderSpec.php b/spec/Provider/NoneProviderSpec.php index e13d3d2..62651a8 100644 --- a/spec/Provider/NoneProviderSpec.php +++ b/spec/Provider/NoneProviderSpec.php @@ -30,6 +30,11 @@ public function it_can_load_file(): void $this->loadFile([])->shouldReturn(null); } + public function it_can_force_load_file(): void + { + $this->loadFile([], true)->shouldReturn(null); + } + public function it_supports(): void { $this->supports('none')->shouldReturn(true); diff --git a/spec/Provider/S3ProviderSpec.php b/spec/Provider/S3ProviderSpec.php index 7835f2c..5e23c17 100644 --- a/spec/Provider/S3ProviderSpec.php +++ b/spec/Provider/S3ProviderSpec.php @@ -59,6 +59,28 @@ public function it_can_load_simple( ]); } + public function it_can_force_load_simple( + S3ClientFactoryInterface $s3ClientFactory, + S3Client $client + ): void { + $src = 'file.zip'; + + $s3ClientFactory->createClient(Argument::any(), Argument::any()) + ->shouldBeCalled() + ->willReturn($client); + + $client->getObject( + Argument::allOf( + Argument::withEntry('Bucket', self::BUCKET), + Argument::withEntry('Key', self::BASEPATH . '/' . $src) + ) + ); + + $this->loadFile([ + 'src' => $src, + ], true); + } + public function it_can_load_from_custom_region_and_profile( S3ClientFactoryInterface $s3ClientFactory, S3Client $client diff --git a/spec/Provider/StoreApiProviderSpec.php b/spec/Provider/StoreApiProviderSpec.php index 9ef45d5..41fb5c7 100644 --- a/spec/Provider/StoreApiProviderSpec.php +++ b/spec/Provider/StoreApiProviderSpec.php @@ -55,6 +55,22 @@ public function it_can_load_a_plugin_with_correct_credentials( ->shouldReturn('/tmp/plugin'); } + public function it_can_force_load_a_plugin_with_correct_credentials( + StoreApiConnectorInterface $storeApiConnector + ): void { + $storeApiConnector->loadPlugin('awesomePlugin', '0.0.2') + ->willReturn('/tmp/plugin'); + + $this->loadFile( + [ + 'pluginId' => 'awesomePlugin', + 'version' => '0.0.2', + ], + true + ) + ->shouldReturn('/tmp/plugin'); + } + public function it_supports(): void { $this->supports('http')->shouldReturn(false); diff --git a/src/Provider/FilesystemProvider.php b/src/Provider/FilesystemProvider.php index b3e64ea..a0b4798 100644 --- a/src/Provider/FilesystemProvider.php +++ b/src/Provider/FilesystemProvider.php @@ -14,7 +14,7 @@ class FilesystemProvider implements ProviderInterface /** * {@inheritdoc} */ - public function loadFile(array $parameters): ?string + public function loadFile(array $parameters, bool $force = false): ?string { if (true === empty($parameters['src'])) { throw new \RuntimeException('src must not be empty for FilesystemProvider.'); diff --git a/src/Provider/HttpProvider.php b/src/Provider/HttpProvider.php index 468ecb6..643fb61 100644 --- a/src/Provider/HttpProvider.php +++ b/src/Provider/HttpProvider.php @@ -24,7 +24,7 @@ public function __construct(Client $guzzleClient) /** * {@inheritdoc} */ - public function loadFile(array $parameters): ?string + public function loadFile(array $parameters, bool $force = false): ?string { if (true === empty($parameters['src'])) { throw new \RuntimeException('src must not be empty for HttpProvider.'); diff --git a/src/Provider/NoneProvider.php b/src/Provider/NoneProvider.php index f94f691..d3cd49d 100644 --- a/src/Provider/NoneProvider.php +++ b/src/Provider/NoneProvider.php @@ -14,7 +14,7 @@ class NoneProvider implements ProviderInterface /** * {@inheritdoc} */ - public function loadFile(array $parameters): ?string + public function loadFile(array $parameters, bool $force = false): ?string { return null; } diff --git a/src/Provider/ProviderInterface.php b/src/Provider/ProviderInterface.php index 79dd3ff..30a8107 100644 --- a/src/Provider/ProviderInterface.php +++ b/src/Provider/ProviderInterface.php @@ -16,7 +16,7 @@ interface ProviderInterface * * @return string|null Path to the downloaded ZIP file */ - public function loadFile(array $parameters): ?string; + public function loadFile(array $parameters, bool $force = false): ?string; public function supports(string $providerName): bool; } diff --git a/src/Provider/S3Provider.php b/src/Provider/S3Provider.php index 2689014..bf54327 100644 --- a/src/Provider/S3Provider.php +++ b/src/Provider/S3Provider.php @@ -35,7 +35,7 @@ public function __construct( /** * {@inheritdoc} */ - public function loadFile(array $parameters): ?string + public function loadFile(array $parameters, bool $force = false): ?string { if (true === empty($parameters['src'])) { throw new \RuntimeException('src must not be empty for S3Provider.'); diff --git a/src/Provider/StoreApiProvider.php b/src/Provider/StoreApiProvider.php index 340f090..11dff5f 100644 --- a/src/Provider/StoreApiProvider.php +++ b/src/Provider/StoreApiProvider.php @@ -30,7 +30,7 @@ public function __construct( /** * {@inheritdoc} */ - public function loadFile(array $parameters): ?string + public function loadFile(array $parameters, bool $force = false): ?string { $name = $parameters['pluginId']; $version = $parameters['version']; From af99f9399e09d9ab492e5df37e383bff4b3fe7f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20Lu=CC=88ckel?= Date: Tue, 27 Aug 2019 14:29:52 +0200 Subject: [PATCH 5/8] Adds a force parameter to the plugin fetcher to be able to manage the behaviour if a plugin should be loading from the cache --- spec/Worker/PluginFetcherSpec.php | 29 ++++++++++++++++++++++++++- src/Worker/PluginFetcher.php | 4 ++-- src/Worker/PluginFetcherInterface.php | 2 +- 3 files changed, 31 insertions(+), 4 deletions(-) diff --git a/spec/Worker/PluginFetcherSpec.php b/spec/Worker/PluginFetcherSpec.php index 145a8f8..0e82596 100644 --- a/spec/Worker/PluginFetcherSpec.php +++ b/spec/Worker/PluginFetcherSpec.php @@ -57,12 +57,39 @@ public function it_can_fetch( ->willReturn($provider); $provider - ->loadFile($providerParameters) + ->loadFile($providerParameters, false) ->shouldBeCalled(); $this->fetch($configuredPluginState); } + public function it_can_force_fetch( + ProviderRepositoryInterface $providerRepository, + ProviderInterface $provider, + ConfiguredPluginState $configuredPluginState + ): void { + $providerParameters = []; + + $configuredPluginState + ->getProviderParameters() + ->willReturn($providerParameters); + + $configuredPluginState + ->getProvider() + ->willReturn('testType'); + + $providerRepository + ->getProviderSupporting(Argument::exact('testType')) + ->shouldBeCalled() + ->willReturn($provider); + + $provider + ->loadFile($providerParameters, true) + ->shouldBeCalled(); + + $this->fetch($configuredPluginState, true); + } + public function it_can_throw_no_suitable_provider_exception( ProviderRepositoryInterface $providerRepository, ConfiguredPluginState $configuredPluginState diff --git a/src/Worker/PluginFetcher.php b/src/Worker/PluginFetcher.php index b805bef..4a59a0e 100644 --- a/src/Worker/PluginFetcher.php +++ b/src/Worker/PluginFetcher.php @@ -24,13 +24,13 @@ public function __construct( $this->providerRepository = $providerRepository; } - public function fetch(ConfiguredPluginState $configuredPluginState): ?string + public function fetch(ConfiguredPluginState $configuredPluginState, bool $force = false): ?string { $provider = $this->providerRepository->getProviderSupporting($configuredPluginState->getProvider()); if (null === $provider) { throw new NoSuitableProviderException($configuredPluginState->getProvider()); } - return $provider->loadFile($configuredPluginState->getProviderParameters()); + return $provider->loadFile($configuredPluginState->getProviderParameters(), $force); } } diff --git a/src/Worker/PluginFetcherInterface.php b/src/Worker/PluginFetcherInterface.php index 331856c..58d0eb5 100644 --- a/src/Worker/PluginFetcherInterface.php +++ b/src/Worker/PluginFetcherInterface.php @@ -13,5 +13,5 @@ interface PluginFetcherInterface { - public function fetch(ConfiguredPluginState $configuredPluginState): ?string; + public function fetch(ConfiguredPluginState $configuredPluginState, bool $force = false): ?string; } From bd0a9f0641783ade97498cddac66004dc9cc469c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20Lu=CC=88ckel?= Date: Tue, 27 Aug 2019 14:33:54 +0200 Subject: [PATCH 6/8] Adds the force parameter to the store api connector to manage the behaviour of loading a plugin from cache --- spec/Service/StoreApiConnectorSpec.php | 62 ++++++++++++++++++++++ src/Service/StoreApiConnector.php | 4 +- src/Service/StoreApiConnectorInterface.php | 2 +- 3 files changed, 65 insertions(+), 3 deletions(-) diff --git a/spec/Service/StoreApiConnectorSpec.php b/spec/Service/StoreApiConnectorSpec.php index e30e08a..2f05696 100644 --- a/spec/Service/StoreApiConnectorSpec.php +++ b/spec/Service/StoreApiConnectorSpec.php @@ -298,6 +298,68 @@ public function it_does_not_download_plugin_if_it_is_available_in_cache( ->shouldReturn($this->cacheRootDir->url() . '/sw-plugin-awesomePlugin1.2.5'); } + public function it_does_download_plugin_if_it_is_forced_even_if_plugin_is_available_in_cache( + Client $guzzleClient, + StreamTranslatorInterface $streamTranslator, + Response $accessTokenResponse, + StreamInterface $accessCodeStream, + Response $partnerResponse, + StreamInterface $partnerStream, + Response $shopsResponse, + StreamInterface $shopsStream, + Response $licenseResponse, + StreamInterface $licenseStream, + Response $pluginInfoResponse, + StreamInterface $pluginInfoStream, + Response $pluginResponse + ): void { + \putenv('SHOPWARE_ACCOUNT_USER=' . self::SHOPWARE_ACCOUNT_USER); + \putenv('SHOPWARE_ACCOUNT_PASSWORD=' . self::SHOPWARE_ACCOUNT_PASSWORD); + \putenv('SHOPWARE_SHOP_DOMAIN=' . self::SHOPWARE_SHOP_DOMAIN); + + vfsStream::newFile('sw-plugin-awesomePlugin0.0.2')->at($this->cacheRootDir); + vfsStream::newFile('sw-plugin-awesomePlugin1.2.5')->at($this->cacheRootDir); + + // ACCESS TOKEN + $this->prepareAccessToken($guzzleClient, $streamTranslator, $accessTokenResponse, $accessCodeStream); + + // CHECK FOR PARTNER ACCOUNT + $partnerData = []; + $this->preparePartnerAccountCheck($guzzleClient, $streamTranslator, $partnerResponse, $partnerStream, $partnerData); + + // GET ALL SHOPS DIRECTLY CONNECTED TO ACCOUNT + $shopsData = [ + [ + 'id' => 7, + 'domain' => 'example.org', + ], + ]; + $this->prepareShops($guzzleClient, $streamTranslator, $shopsResponse, $shopsStream, $shopsData); + + // GET ALL LICENSES + $licenseUrl = '/shops/7/pluginlicenses'; + $this->prepareLicenseData($guzzleClient, $streamTranslator, $licenseResponse, $licenseStream, $licenseUrl); + + // GET ALL INFOS ABOUT PLUGIN + $pluginInfoUrl = '/shops/7/pluginlicenses/17'; + $this->preparePluginInfoData($guzzleClient, $streamTranslator, $pluginInfoResponse, $pluginInfoStream, $pluginInfoUrl); + + $downloadUrl = '/plugins/58/binaries/10/file?shopId=7'; + $guzzleClient->get( + self::BASE_URL . $downloadUrl, + [ + RequestOptions::HEADERS => [ + 'X-Shopware-Token' => 'ABCDEF', + ], + RequestOptions::SINK => $this->cacheRootDir->url() . '/sw-plugin-awesomePlugin0.0.2', + ] + ) + ->shouldBeCalled() + ->willReturn($pluginResponse); + + $this->loadPlugin('awesomePlugin', '0.0.2', true); + } + private function prepareAccessToken( Client $guzzleClient, StreamTranslatorInterface $streamTranslator, diff --git a/src/Service/StoreApiConnector.php b/src/Service/StoreApiConnector.php index 0c37095..079cf64 100644 --- a/src/Service/StoreApiConnector.php +++ b/src/Service/StoreApiConnector.php @@ -46,10 +46,10 @@ public function __construct( $this->cacheDir = $cacheDir; } - public function loadPlugin(string $pluginId, string $version): string + public function loadPlugin(string $pluginId, string $version, bool $force = false): string { $tmpName = $this->cacheDir . DIRECTORY_SEPARATOR . 'sw-plugin-' . $pluginId . $version; - if (\file_exists($tmpName)) { + if (false === $force && \file_exists($tmpName)) { return $tmpName; } diff --git a/src/Service/StoreApiConnectorInterface.php b/src/Service/StoreApiConnectorInterface.php index 3ce7e14..8fab8c6 100644 --- a/src/Service/StoreApiConnectorInterface.php +++ b/src/Service/StoreApiConnectorInterface.php @@ -11,5 +11,5 @@ interface StoreApiConnectorInterface { - public function loadPlugin(string $pluginId, string $version): string; + public function loadPlugin(string $pluginId, string $version, bool $force = false): string; } From ba99bb672b7bc3e841fcdcc179d8f24036db9237 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20Lu=CC=88ckel?= Date: Tue, 27 Aug 2019 14:36:57 +0200 Subject: [PATCH 7/8] Adds the force parameter to the method params --- spec/Provider/StoreApiProviderSpec.php | 4 ++-- src/Provider/StoreApiProvider.php | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/spec/Provider/StoreApiProviderSpec.php b/spec/Provider/StoreApiProviderSpec.php index 41fb5c7..e432386 100644 --- a/spec/Provider/StoreApiProviderSpec.php +++ b/spec/Provider/StoreApiProviderSpec.php @@ -43,7 +43,7 @@ public function let( public function it_can_load_a_plugin_with_correct_credentials( StoreApiConnectorInterface $storeApiConnector ): void { - $storeApiConnector->loadPlugin('awesomePlugin', '0.0.2') + $storeApiConnector->loadPlugin('awesomePlugin', '0.0.2', false) ->willReturn('/tmp/plugin'); $this->loadFile( @@ -58,7 +58,7 @@ public function it_can_load_a_plugin_with_correct_credentials( public function it_can_force_load_a_plugin_with_correct_credentials( StoreApiConnectorInterface $storeApiConnector ): void { - $storeApiConnector->loadPlugin('awesomePlugin', '0.0.2') + $storeApiConnector->loadPlugin('awesomePlugin', '0.0.2', true) ->willReturn('/tmp/plugin'); $this->loadFile( diff --git a/src/Provider/StoreApiProvider.php b/src/Provider/StoreApiProvider.php index 11dff5f..2bc0b10 100644 --- a/src/Provider/StoreApiProvider.php +++ b/src/Provider/StoreApiProvider.php @@ -35,7 +35,7 @@ public function loadFile(array $parameters, bool $force = false): ?string $name = $parameters['pluginId']; $version = $parameters['version']; - return $this->storeApiConnector->loadPlugin($name, $version); + return $this->storeApiConnector->loadPlugin($name, $version, $force); } public function supports(string $providerName): bool From 600dae76bc69d6f290938cb1dc5122e9b9c1f90c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20Lu=CC=88ckel?= Date: Tue, 27 Aug 2019 14:42:08 +0200 Subject: [PATCH 8/8] Adds a force parameter to the commands to be able to manage the behaviour from the commandline --- src/Command/AutomaticDeployCommand.php | 9 ++++++++- src/Command/FetchPluginCommand.php | 10 +++++++++- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/src/Command/AutomaticDeployCommand.php b/src/Command/AutomaticDeployCommand.php index bb36f20..6c3cd72 100644 --- a/src/Command/AutomaticDeployCommand.php +++ b/src/Command/AutomaticDeployCommand.php @@ -66,6 +66,12 @@ protected function configure(): void InputOption::VALUE_NONE, 'If set, skip download and extraction' ) + ->addOption( + 'force-download', + '', + InputOption::VALUE_NONE, + 'If set, a download will be forced (not using any cache)! Be careful: If skip-download is set, this parameter does not do anything!' + ) ->addOption( 'skip-install', '', @@ -89,6 +95,7 @@ protected function execute( OutputInterface $output ) { $skipDownload = (bool) $input->getOption('skip-download'); + $forceDownload = (bool) $input->getOption('force-download'); $skipInstall = (bool) $input->getOption('skip-install'); $environment = $input->getOption('env'); @@ -114,7 +121,7 @@ protected function execute( // Download the plugin and get the path $output->write('Downloading plugin `' . $configuredPluginState->getId() . '`...'); - $downloadPath = $this->pluginFetcher->fetch($configuredPluginState); + $downloadPath = $this->pluginFetcher->fetch($configuredPluginState, $forceDownload); $output->writeln(' done.'); // If no path was returned, it is assumed that the plugin is already in its destination path diff --git a/src/Command/FetchPluginCommand.php b/src/Command/FetchPluginCommand.php index b6d1f4f..eadd1b9 100644 --- a/src/Command/FetchPluginCommand.php +++ b/src/Command/FetchPluginCommand.php @@ -60,6 +60,12 @@ protected function configure(): void 'The current environment to use for calling shopware commands', 'production' ) + ->addOption( + 'force', + '', + InputOption::VALUE_NONE, + 'If set, no cache will be used to get the plugin' + ) ->setDescription('Fetches a plugin from its source.') ->setHelp( 'Fetches a plugin from its source configured in the given statefile.' @@ -85,7 +91,9 @@ protected function execute( throw new \RuntimeException('The given plugin was not found in the statefile.'); } - $file = $this->pluginFetcher->fetch($configuredPluginState); + $force = (bool) $input->getOption('force'); + + $file = $this->pluginFetcher->fetch($configuredPluginState, $force); $output->writeln("Downloaded plugin '$pluginId' to: ", OutputInterface::VERBOSITY_VERBOSE); $output->writeln($file);