Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add retry for installation #38

Merged
merged 1 commit into from
Dec 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 57 additions & 2 deletions .github/workflows/integration.yml
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,62 @@ jobs:
run: ./vendor/bin/shopware-deployment-helper run

- name: Start Webserver
run: symfony server:start -d
run: symfony server:start -d --no-tls --allow-all-ip

- name: PayPal plugin should be installed
run: ./bin/console plugin:list | grep SwagPayPal

- name: Default Storefront should be available
run: curl -q --fail http://localhost:8000

installation-with-retry:
name: Install a Shopware Shop with Retry
runs-on: ubuntu-latest
env:
SHOPWARE_DEPLOYMENT_FORCE_REINSTALL: 1
steps:
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: '8.3'
tools: symfony-cli

- name: Start Default MySQL
run: |
sudo mv /var/lib/mysql /var/lib/mysql-old
sudo mkdir /var/lib/mysql
sudo mount -t tmpfs tmpfs /var/lib/mysql -o size=1G
sudo -u mysql mysqld --datadir=/var/lib/mysql --default-time-zone=SYSTEM --initialize-insecure
sudo systemctl start mysql

- name: Create new Shopware Project
run: composer create-project shopware/production . --no-interaction

- name: Checkout
uses: actions/checkout@v4
with:
path: ./custom/plugins/deployment-helper

- name: Set fake version into deployment helper
run: composer -d custom/plugins/deployment-helper config version 999.9.9

- name: Install Deployment Helper
run: composer require --dev 'shopware/deployment-helper:*'

- name: Install PayPal
run: composer require 'swag/paypal:*'

- name: Install Shopware and kill it after some seconds
run: timeout 10 ./vendor/bin/shopware-deployment-helper run || true

- name: Retry the Installation
run: ./vendor/bin/shopware-deployment-helper run

- name: Ensure the admin user exists
run: ./bin/console user:list | grep [email protected]

- name: Start Webserver
run: symfony server:start -d --no-tls --allow-all-ip

- name: PayPal plugin should be installed
run: ./bin/console plugin:list | grep SwagPayPal
Expand Down Expand Up @@ -98,7 +153,7 @@ jobs:
run: ./vendor/bin/shopware-deployment-helper run

- name: Start Webserver
run: symfony server:start -d
run: symfony server:start -d --no-tls --allow-all-ip

- name: PayPal plugin should be installed
run: ./bin/console plugin:list | grep SwagPayPal
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/php.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ jobs:
uses: shivammathur/setup-php@v2
with:
php-version: '${{ matrix.php }}'
tools: composer:2.8.3
coverage: xdebug

- name: Install dependencies
Expand Down
6 changes: 6 additions & 0 deletions src/Command/RunCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
namespace Shopware\Deployment\Command;

use Shopware\Deployment\Event\PostDeploy;
use Shopware\Deployment\Helper\EnvironmentHelper;
use Shopware\Deployment\Services\HookExecutor;
use Shopware\Deployment\Services\InstallationManager;
use Shopware\Deployment\Services\ShopwareState;
Expand Down Expand Up @@ -46,10 +47,15 @@ protected function execute(InputInterface $input, OutputInterface $output): int
skipThemeCompile: (bool) $input->getOption('skip-theme-compile'),
skipAssetsInstall: ((bool) $input->getOption('skip-asset-install') || (bool) $input->getOption('skip-assets-install')),
timeout: is_numeric($timeout) ? (float) $timeout : null,
forceReinstallation: EnvironmentHelper::getVariable('SHOPWARE_DEPLOYMENT_FORCE_REINSTALL', '0') === '1',
);

$installed = $this->state->isInstalled();

if ($config->forceReinstallation && $this->state->getPreviousVersion() === 'unknown') {
$installed = false;
}

$this->hookExecutor->execute(HookExecutor::HOOK_PRE);

if ($installed) {
Expand Down
7 changes: 6 additions & 1 deletion src/Services/InstallationManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,10 @@ public function run(RunConfiguration $configuration, OutputInterface $output): v
$additionalInstallParameters[] = '--skip-assets-install';
}

if ($configuration->forceReinstallation) {
$additionalInstallParameters[] = '--drop-database';
}

$this->processHelper->console(['system:install', '--create-database', '--shop-locale=' . $shopLocale, '--shop-currency=' . $shopCurrency, '--force', ...$additionalInstallParameters]);
$this->processHelper->console(['user:create', $adminUser, '--password=' . $adminPassword]);

Expand All @@ -76,7 +80,6 @@ public function run(RunConfiguration $configuration, OutputInterface $output): v
}

$this->state->disableFirstRunWizard();
$this->state->setVersion($this->state->getCurrentVersion());

$this->processHelper->console(['plugin:refresh']);
$this->pluginHelper->installPlugins($configuration->skipAssetsInstall);
Expand All @@ -93,6 +96,8 @@ public function run(RunConfiguration $configuration, OutputInterface $output): v
$this->appHelper->deactivateApps();
$this->appHelper->removeApps();

$this->state->setVersion($this->state->getCurrentVersion());

$this->hookExecutor->execute(HookExecutor::HOOK_POST_INSTALL);
}

Expand Down
6 changes: 5 additions & 1 deletion src/Services/ShopwareState.php
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,11 @@ public function isStorefrontInstalled(): bool

public function getPreviousVersion(): string
{
$data = $this->connection->fetchOne('SELECT configuration_value FROM system_config WHERE configuration_key = "deployment.version" AND sales_channel_id IS NULL');
try {
$data = $this->connection->fetchOne('SELECT configuration_value FROM system_config WHERE configuration_key = "deployment.version" AND sales_channel_id IS NULL');
} catch (\Throwable) {
return 'unknown';
}

if ($data === false) {
return 'unknown';
Expand Down
1 change: 1 addition & 0 deletions src/Struct/RunConfiguration.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ public function __construct(
public bool $skipThemeCompile = false,
public bool $skipAssetsInstall = false,
public ?float $timeout = 60,
public bool $forceReinstallation = false,
) {
}
}
41 changes: 41 additions & 0 deletions tests/Command/RunCommandTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
use Shopware\Deployment\Services\UpgradeManager;
use Symfony\Component\Console\Tester\CommandTester;
use Symfony\Component\EventDispatcher\EventDispatcher;
use Zalas\PHPUnit\Globals\Attribute\Env;

#[CoversClass(RunCommand::class)]
class RunCommandTest extends TestCase
Expand Down Expand Up @@ -101,4 +102,44 @@ public function testUpdate(): void
'--timeout' => 600,
]);
}

#[Env('SHOPWARE_DEPLOYMENT_FORCE_REINSTALL', '1')]
public function testRunWithoutFullyInstalled(): void
{
$state = $this->createMock(ShopwareState::class);
$state
->expects($this->once())
->method('isInstalled')
->willReturn(true);
$state
->expects($this->once())
->method('getPreviousVersion')
->willReturn('unknown');

$hookExecutor = $this->createMock(HookExecutor::class);
$hookExecutor
->expects($this->exactly(2))
->method('execute');

$installationManager = $this->createMock(InstallationManager::class);
$installationManager
->expects($this->once())
->method('run')
->with(self::callback(function ($config) {
static::assertTrue($config->forceReinstallation);

return true;
}));

$command = new RunCommand(
$state,
$installationManager,
$this->createMock(UpgradeManager::class),
$hookExecutor,
new EventDispatcher()
);

$tester = new CommandTester($command);
$tester->execute([]);
}
}
31 changes: 31 additions & 0 deletions tests/Services/InstallationManagerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -131,4 +131,35 @@ public function testRunWithLicenseDomain(): void

$manager->run(new RunConfiguration(), $this->createMock(OutputInterface::class));
}

public function testRunWithForceReinstall(): void
{
$processHelper = $this->createMock(ProcessHelper::class);
$consoleCommands = [];

$processHelper
->method('console')
->willReturnCallback(function (array $command) use (&$consoleCommands): void {
$consoleCommands[] = $command;
});

$accountService = $this->createMock(AccountService::class);
$accountService->expects(static::never())->method('refresh');

$manager = new InstallationManager(
$this->createMock(ShopwareState::class),
$this->createMock(Connection::class),
$processHelper,
$this->createMock(PluginHelper::class),
$this->createMock(AppHelper::class),
$this->createMock(HookExecutor::class),
new ProjectConfiguration(),
$accountService,
);

$manager->run(new RunConfiguration(true, true, forceReinstallation: true), $this->createMock(OutputInterface::class));

static::assertCount(4, $consoleCommands);
static::assertSame(['system:install', '--create-database', '--shop-locale=en-GB', '--shop-currency=EUR', '--force', '--no-assign-theme', '--skip-assets-install', '--drop-database'], $consoleCommands[0]);
}
}
9 changes: 9 additions & 0 deletions tests/Services/ShopwareStateTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,15 @@ public function testStorefrontInstalled(): void
InstalledVersions::reload($before);
}

public function testGetPreviousVersionTableDoesNotExistYet(): void
{
$this->connection
->expects($this->once())
->method('fetchOne')
->willThrowException(new \Exception());
static::assertSame('unknown', $this->state->getPreviousVersion());
}

public function testGetPreviousVersionNotExisting(): void
{
$this->connection
Expand Down
Loading