From 8cabfd46bbcddafa7ce077faf5dac33081ca4955 Mon Sep 17 00:00:00 2001 From: Timon de Groot Date: Tue, 1 Oct 2024 13:11:40 +0200 Subject: [PATCH 1/5] DeployRunner: Add full support for roles/stage selection - If a configuration has a stage configured, it will select hosts with that stage - If a configuration has roles configured, it will select hosts with any of those roles - If a configuration has both stage and roles configured, they will be combined together with AND. --- src/DeployRunner.php | 81 +++++++++++++++++++++++++++++++++++++------- 1 file changed, 69 insertions(+), 12 deletions(-) diff --git a/src/DeployRunner.php b/src/DeployRunner.php index aa0fda3..454949a 100644 --- a/src/DeployRunner.php +++ b/src/DeployRunner.php @@ -20,10 +20,12 @@ use Hypernode\DeployConfiguration\Configuration; use Hypernode\DeployConfiguration\Server; use Hypernode\DeployConfiguration\Stage; +use Hypernode\DeployConfiguration\TaskConfigurationInterface; use Psr\Log\LoggerInterface; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; use Throwable; +use Webmozart\Assert\Assert; use function Deployer\host; use function Deployer\localhost; @@ -51,6 +53,10 @@ class DeployRunner private array $deployedHostnames = []; private string $deployedStage = ''; + /** + * @var Host[] + */ + private array $configuredHosts = []; public function __construct( TaskFactory $taskFactory, @@ -75,8 +81,14 @@ public function __construct( * @throws Throwable * @throws Exception */ - public function run(OutputInterface $output, string $stage, string $task, bool $configureBuildStage, bool $configureServers, bool $reuseBrancher): int - { + public function run( + OutputInterface $output, + string $stage, + string $task, + bool $configureBuildStage, + bool $configureServers, + bool $reuseBrancher + ): int { $deployer = $this->deployerLoader->getOrCreateInstance($output); try { @@ -97,8 +109,12 @@ public function run(OutputInterface $output, string $stage, string $task, bool $ * @throws InvalidConfigurationException * @throws Throwable */ - private function prepare(bool $configureBuildStage, bool $configureServers, string $stage, bool $reuseBrancher): void - { + private function prepare( + bool $configureBuildStage, + bool $configureServers, + string $stage, + bool $reuseBrancher + ): void { $this->recipeLoader->load('common.php'); $tasks = $this->taskFactory->loadAll(); $config = $this->configurationLoader->load( @@ -150,20 +166,54 @@ private function initializeConfigurableTask(ConfigurableTaskInterface $task, Con if ($task->supports($taskConfig)) { $deployerTask = $task->configureWithTaskConfig($taskConfig); - if ($deployerTask && $taskConfig instanceof StageConfigurableInterface) { - $this->configureTaskOnStage($deployerTask, $taskConfig); + if ($deployerTask) { + $this->configureDeployerTask($deployerTask, $taskConfig); } } } } - private function configureTaskOnStage(Task $task, StageConfigurableInterface $taskConfiguration) + private function configureDeployerTask(Task $deployerTask, TaskConfigurationInterface $taskConfig): void { - if (!$taskConfiguration->getStage()) { - return; + $rolesConfigured = false; + foreach ($this->configuredHosts as $host) { + $roles = $host->get('roles', []); + if ($roles) { + $rolesConfigured = true; + break; + } } - $task->select('stage=' . $taskConfiguration->getStage()->getName()); + $roles = $taskConfig instanceof ServerRoleConfigurableInterface + ? $taskConfig->getServerRoles() + : []; + $stage = $taskConfig instanceof StageConfigurableInterface + ? $taskConfig->getStage()->getName() + : null; + + if ($roles) { + if (!$rolesConfigured) { + throw new InvalidConfigurationException( + sprintf( + 'No roles configured for task %s, skipping role selection', + get_class($taskConfig) + ) + ); + } + + if ($stage) { + $deployerTask->select( + sprintf( + "stage=${stage}&roles=%s", + implode(",stage=${stage}&roles=", $roles) + ) + ); + } else { + $deployerTask->select('roles=' . implode(',roles=', $roles)); + } + } elseif ($stage) { + $deployerTask->select("stage={$stage}"); + } } private function configureServers(Configuration $config, string $stage, bool $reuseBrancher): void @@ -179,8 +229,12 @@ private function configureServers(Configuration $config, string $stage, bool $re } } - private function configureStageServer(Stage $stage, Server $server, Configuration $config, bool $reuseBrancher): void - { + private function configureStageServer( + Stage $stage, + Server $server, + Configuration $config, + bool $reuseBrancher + ): void { $this->maybeConfigureBrancherServer($server, $reuseBrancher); $host = host($stage->getName() . ':' . $server->getHostname()); @@ -232,6 +286,9 @@ private function configureStageServer(Stage $stage, Server $server, Configuratio ); $host->set($key, $value); } + + Assert::isInstanceOf($host, Host::class); + $this->configuredHosts[] = $host; } private function maybeConfigureBrancherServer(Server $server, bool $reuseBrancher): void From decdad065d379556afbfe4417f9fc2dac0287e6b Mon Sep 17 00:00:00 2001 From: Timon de Groot Date: Tue, 1 Oct 2024 13:12:30 +0200 Subject: [PATCH 2/5] PlatformConfiguration: return deployer task By returning the deployer task, it can be configured later on to have roles/stage selection --- src/Deployer/Task/PlatformConfiguration/CronTask.php | 10 +++------- .../PlatformConfiguration/NginxManageVHostTask.php | 7 +++---- src/Deployer/Task/PlatformConfiguration/NginxTask.php | 6 +++--- src/Deployer/Task/PlatformConfiguration/RedisTask.php | 6 +++--- .../Task/PlatformConfiguration/SupervisorTask.php | 6 +++--- .../Task/PlatformConfiguration/VarnishTask.php | 6 +++--- 6 files changed, 18 insertions(+), 23 deletions(-) diff --git a/src/Deployer/Task/PlatformConfiguration/CronTask.php b/src/Deployer/Task/PlatformConfiguration/CronTask.php index a894608..f75af91 100644 --- a/src/Deployer/Task/PlatformConfiguration/CronTask.php +++ b/src/Deployer/Task/PlatformConfiguration/CronTask.php @@ -2,19 +2,15 @@ namespace Hypernode\Deploy\Deployer\Task\PlatformConfiguration; -use Hypernode\Deploy\Deployer\Task\IncrementedTaskTrait; use Deployer\Task\Task; use Hypernode\Deploy\Deployer\Task\ConfigurableTaskInterface; +use Hypernode\Deploy\Deployer\Task\IncrementedTaskTrait; use Hypernode\Deploy\Deployer\Task\TaskBase; -use Hypernode\DeployConfiguration\Configuration; use Hypernode\DeployConfiguration\PlatformConfiguration\CronConfiguration; use Hypernode\DeployConfiguration\TaskConfigurationInterface; use function Deployer\before; -use function Deployer\get; -use function Deployer\set; use function Deployer\task; -use function Deployer\writeln; class CronTask extends TaskBase implements ConfigurableTaskInterface { @@ -27,14 +23,14 @@ protected function getIncrementalNamePrefix(): string public function configureWithTaskConfig(TaskConfigurationInterface $config): ?Task { - task('deploy:cron', [ + $task = task('deploy:cron', [ 'deploy:cron:render', 'deploy:cron:sync', ]); before('deploy:symlink', 'deploy:cron'); - return null; + return $task; } public function supports(TaskConfigurationInterface $config): bool diff --git a/src/Deployer/Task/PlatformConfiguration/NginxManageVHostTask.php b/src/Deployer/Task/PlatformConfiguration/NginxManageVHostTask.php index faf551e..1091126 100644 --- a/src/Deployer/Task/PlatformConfiguration/NginxManageVHostTask.php +++ b/src/Deployer/Task/PlatformConfiguration/NginxManageVHostTask.php @@ -2,11 +2,10 @@ namespace Hypernode\Deploy\Deployer\Task\PlatformConfiguration; -use Hypernode\Deploy\Deployer\Task\IncrementedTaskTrait; use Deployer\Task\Task; use Hypernode\Deploy\Deployer\Task\ConfigurableTaskInterface; +use Hypernode\Deploy\Deployer\Task\IncrementedTaskTrait; use Hypernode\Deploy\Deployer\Task\TaskBase; -use Hypernode\DeployConfiguration\Configuration; use Hypernode\DeployConfiguration\PlatformConfiguration\NginxConfiguration; use Hypernode\DeployConfiguration\TaskConfigurationInterface; @@ -29,10 +28,10 @@ public function supports(TaskConfigurationInterface $config): bool public function configureWithTaskConfig(TaskConfigurationInterface $config): ?Task { - task('deploy:nginx:manage_vhost', function () { + $task = task('deploy:nginx:manage_vhost', function () { run('hypernode-manage-vhosts {{domain}} --webroot {{current_path}}/{{public_folder}} --no'); }); - return null; + return $task; } } diff --git a/src/Deployer/Task/PlatformConfiguration/NginxTask.php b/src/Deployer/Task/PlatformConfiguration/NginxTask.php index 67262c4..1280130 100644 --- a/src/Deployer/Task/PlatformConfiguration/NginxTask.php +++ b/src/Deployer/Task/PlatformConfiguration/NginxTask.php @@ -2,9 +2,9 @@ namespace Hypernode\Deploy\Deployer\Task\PlatformConfiguration; -use Hypernode\Deploy\Deployer\Task\IncrementedTaskTrait; use Deployer\Task\Task; use Hypernode\Deploy\Deployer\Task\ConfigurableTaskInterface; +use Hypernode\Deploy\Deployer\Task\IncrementedTaskTrait; use Hypernode\Deploy\Deployer\Task\TaskBase; use Hypernode\DeployConfiguration\PlatformConfiguration\NginxConfiguration; use Hypernode\DeployConfiguration\TaskConfigurationInterface; @@ -35,7 +35,7 @@ public function configureWithTaskConfig(TaskConfigurationInterface $config): ?Ta return '/tmp/nginx-config-' . get('domain'); }); - task('deploy:nginx', [ + $task = task('deploy:nginx', [ 'deploy:nginx:prepare', 'deploy:nginx:upload', 'deploy:nginx:sync', @@ -49,6 +49,6 @@ public function configureWithTaskConfig(TaskConfigurationInterface $config): ?Ta after('deploy:nginx:prepare', $taskName); } - return null; + return $task; } } diff --git a/src/Deployer/Task/PlatformConfiguration/RedisTask.php b/src/Deployer/Task/PlatformConfiguration/RedisTask.php index 6d07126..e069179 100644 --- a/src/Deployer/Task/PlatformConfiguration/RedisTask.php +++ b/src/Deployer/Task/PlatformConfiguration/RedisTask.php @@ -2,9 +2,9 @@ namespace Hypernode\Deploy\Deployer\Task\PlatformConfiguration; -use Hypernode\Deploy\Deployer\Task\IncrementedTaskTrait; use Deployer\Task\Task; use Hypernode\Deploy\Deployer\Task\ConfigurableTaskInterface; +use Hypernode\Deploy\Deployer\Task\IncrementedTaskTrait; use Hypernode\Deploy\Deployer\Task\TaskBase; use Hypernode\DeployConfiguration\PlatformConfiguration\RedisConfiguration; use Hypernode\DeployConfiguration\TaskConfigurationInterface; @@ -30,11 +30,11 @@ public function supports(TaskConfigurationInterface $config): bool public function configureWithTaskConfig(TaskConfigurationInterface $config): ?Task { - task('deploy:redis', [ + $task = task('deploy:redis', [ 'deploy:redis:enable', ]); before('deploy:symlink', self::TASK_NAME); - return null; + return $task; } } diff --git a/src/Deployer/Task/PlatformConfiguration/SupervisorTask.php b/src/Deployer/Task/PlatformConfiguration/SupervisorTask.php index cd154f6..f2aa255 100644 --- a/src/Deployer/Task/PlatformConfiguration/SupervisorTask.php +++ b/src/Deployer/Task/PlatformConfiguration/SupervisorTask.php @@ -2,9 +2,9 @@ namespace Hypernode\Deploy\Deployer\Task\PlatformConfiguration; -use Hypernode\Deploy\Deployer\Task\IncrementedTaskTrait; use Deployer\Task\Task; use Hypernode\Deploy\Deployer\Task\ConfigurableTaskInterface; +use Hypernode\Deploy\Deployer\Task\IncrementedTaskTrait; use Hypernode\Deploy\Deployer\Task\TaskBase; use Hypernode\DeployConfiguration\PlatformConfiguration\SupervisorConfiguration; use Hypernode\DeployConfiguration\TaskConfigurationInterface; @@ -35,7 +35,7 @@ public function configureWithTaskConfig(TaskConfigurationInterface $config): ?Ta return '/tmp/supervisor-config-' . get('domain'); }); - task('deploy:supervisor', [ + $task = task('deploy:supervisor', [ 'deploy:supervisor:prepare', 'deploy:supervisor:upload', 'deploy:supervisor:sync', @@ -47,6 +47,6 @@ public function configureWithTaskConfig(TaskConfigurationInterface $config): ?Ta after('deploy:supervisor:prepare', $taskName); } - return null; + return $task; } } diff --git a/src/Deployer/Task/PlatformConfiguration/VarnishTask.php b/src/Deployer/Task/PlatformConfiguration/VarnishTask.php index 15ea0e3..0a17ab1 100644 --- a/src/Deployer/Task/PlatformConfiguration/VarnishTask.php +++ b/src/Deployer/Task/PlatformConfiguration/VarnishTask.php @@ -2,9 +2,9 @@ namespace Hypernode\Deploy\Deployer\Task\PlatformConfiguration; -use Hypernode\Deploy\Deployer\Task\IncrementedTaskTrait; use Deployer\Task\Task; use Hypernode\Deploy\Deployer\Task\ConfigurableTaskInterface; +use Hypernode\Deploy\Deployer\Task\IncrementedTaskTrait; use Hypernode\Deploy\Deployer\Task\TaskBase; use Hypernode\DeployConfiguration\PlatformConfiguration\VarnishConfiguration; use Hypernode\DeployConfiguration\TaskConfigurationInterface; @@ -31,7 +31,7 @@ public function supports(TaskConfigurationInterface $config): bool public function configureWithTaskConfig(TaskConfigurationInterface $config): ?Task { - task('deploy:varnish', [ + $task = task('deploy:varnish', [ 'deploy:varnish:enable', 'deploy:varnish:prepare', 'deploy:varnish:upload', @@ -46,6 +46,6 @@ public function configureWithTaskConfig(TaskConfigurationInterface $config): ?Ta after('deploy:varnish:prepare', $taskName); } - return null; + return $task; } } From 03aa8ac609e1887e126614dc11679c77a209b30b Mon Sep 17 00:00:00 2001 From: Timon de Groot Date: Tue, 1 Oct 2024 13:20:09 +0200 Subject: [PATCH 3/5] ci/test/run-general: Fix docker-compose installation The pypi version of docker-compose is very old and becomes less likely to be compatible with Docker as time passes. --- ci/test/run-general.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ci/test/run-general.sh b/ci/test/run-general.sh index b293098..7cb8dd6 100755 --- a/ci/test/run-general.sh +++ b/ci/test/run-general.sh @@ -46,7 +46,8 @@ function end_task() { # Install docker-compose if it's not installed if ! [ -x "$(command -v docker-compose)" ]; then - pip install docker-compose + curl -sSL https://github.com/docker/compose/releases/download/v2.29.7/docker-compose-linux-x86_64 -o /usr/local/bin/docker-compose + chmod +x /usr/local/bin/docker-compose fi # Clear up env From f0cbdf8aeff738cfc6c1a5391c657907fe523674 Mon Sep 17 00:00:00 2001 From: Timon de Groot Date: Tue, 1 Oct 2024 13:27:18 +0200 Subject: [PATCH 4/5] DeployRunner: Fix null error for task config stage selection --- src/DeployRunner.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/DeployRunner.php b/src/DeployRunner.php index 454949a..2ca5e48 100644 --- a/src/DeployRunner.php +++ b/src/DeployRunner.php @@ -187,7 +187,7 @@ private function configureDeployerTask(Task $deployerTask, TaskConfigurationInte $roles = $taskConfig instanceof ServerRoleConfigurableInterface ? $taskConfig->getServerRoles() : []; - $stage = $taskConfig instanceof StageConfigurableInterface + $stage = $taskConfig instanceof StageConfigurableInterface && $taskConfig->getStage() ? $taskConfig->getStage()->getName() : null; From 569d390e5e581250ef458f411eaf38c516f29a05 Mon Sep 17 00:00:00 2001 From: Timon de Groot Date: Tue, 1 Oct 2024 14:32:04 +0200 Subject: [PATCH 5/5] DeployRunner: Don't check for hosts with no roles --- src/DeployRunner.php | 26 -------------------------- 1 file changed, 26 deletions(-) diff --git a/src/DeployRunner.php b/src/DeployRunner.php index 2ca5e48..9307eb0 100644 --- a/src/DeployRunner.php +++ b/src/DeployRunner.php @@ -25,7 +25,6 @@ use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; use Throwable; -use Webmozart\Assert\Assert; use function Deployer\host; use function Deployer\localhost; @@ -53,10 +52,6 @@ class DeployRunner private array $deployedHostnames = []; private string $deployedStage = ''; - /** - * @var Host[] - */ - private array $configuredHosts = []; public function __construct( TaskFactory $taskFactory, @@ -175,15 +170,6 @@ private function initializeConfigurableTask(ConfigurableTaskInterface $task, Con private function configureDeployerTask(Task $deployerTask, TaskConfigurationInterface $taskConfig): void { - $rolesConfigured = false; - foreach ($this->configuredHosts as $host) { - $roles = $host->get('roles', []); - if ($roles) { - $rolesConfigured = true; - break; - } - } - $roles = $taskConfig instanceof ServerRoleConfigurableInterface ? $taskConfig->getServerRoles() : []; @@ -192,15 +178,6 @@ private function configureDeployerTask(Task $deployerTask, TaskConfigurationInte : null; if ($roles) { - if (!$rolesConfigured) { - throw new InvalidConfigurationException( - sprintf( - 'No roles configured for task %s, skipping role selection', - get_class($taskConfig) - ) - ); - } - if ($stage) { $deployerTask->select( sprintf( @@ -286,9 +263,6 @@ private function configureStageServer( ); $host->set($key, $value); } - - Assert::isInstanceOf($host, Host::class); - $this->configuredHosts[] = $host; } private function maybeConfigureBrancherServer(Server $server, bool $reuseBrancher): void