From 8e01cf6924aa684f3308d32ecb46c617c0c12523 Mon Sep 17 00:00:00 2001 From: Anton Medvedev Date: Sat, 12 Aug 2017 20:31:19 +0300 Subject: [PATCH] Refactor environment variables handling --- CHANGELOG.md | 2 ++ UPGRADE.md | 8 ++++++++ recipe/common.php | 2 +- recipe/deploy/vendors.php | 2 +- recipe/symfony.php | 18 +++++++++++------- src/Support/helpers.php | 16 ++++++++++++++++ src/functions.php | 13 +++++++++++++ test/fixture/recipe/deploy.php | 16 +++++++++++++++- test/recipe/DeployTest.php | 7 +++++++ 9 files changed, 74 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 34b2c6cd..9efc27ec 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,10 +16,12 @@ ### Changed - Changed `branch` parameter and option behavior - Extended `task` func to support callables +- Renamed `env_vars` to `env` ### Fixed - Improved the way `ParallelExecutor` handles option parameters - Fixed no `stage` argument in parallel mode [#1299] +- Improved environment variables management ### Removed - Removed `terminate_message` option diff --git a/UPGRADE.md b/UPGRADE.md index 27765489..ac1ca346 100644 --- a/UPGRADE.md +++ b/UPGRADE.md @@ -29,6 +29,14 @@ * `run('command')->toString()` → `run('command')` * `run('if command; then echo "true"; fi;')->toBool()` → `test('command')` +4. `env_vars` renamed to `env` + + * `set('env_vars', 'FOO=bar');` → `set('env', ['FOO' => 'bar']);` + + If your are using Symfony recipe, then you need to change `env` setting: + + * `set('env', 'prod');` → `set('symfony_env', 'prod');` + # Upgrade from 4.x to 5.x 1. Servers to Hosts diff --git a/recipe/common.php b/recipe/common.php index 27e552cd..6f99c8ff 100644 --- a/recipe/common.php +++ b/recipe/common.php @@ -73,7 +73,7 @@ set('use_atomic_symlink', function () { set('composer_action', 'install'); set('composer_options', '{{composer_action}} --verbose --prefer-dist --no-progress --no-interaction --no-dev --optimize-autoloader'); -set('env_vars', ''); // Variable assignment before cmds (for example, SYMFONY_ENV={{set}}) +set('env', []); // Run command environment (for example, SYMFONY_ENV=prod) /** * Return current release path. diff --git a/recipe/deploy/vendors.php b/recipe/deploy/vendors.php index aad3e0eb..0040b96e 100644 --- a/recipe/deploy/vendors.php +++ b/recipe/deploy/vendors.php @@ -12,5 +12,5 @@ task('deploy:vendors', function () { if (!commandExist('unzip')) { writeln('To speed up composer installation setup "unzip" command with PHP zip extension https://goo.gl/sxzFcD'); } - run('cd {{release_path}} && {{env_vars}} {{bin/composer}} {{composer_options}}'); + run('cd {{release_path}} && {{bin/composer}} {{composer_options}}'); }); diff --git a/recipe/symfony.php b/recipe/symfony.php index e40aee2d..f63c6426 100644 --- a/recipe/symfony.php +++ b/recipe/symfony.php @@ -15,7 +15,7 @@ require_once __DIR__ . '/common.php'; */ // Symfony build set -set('env', 'prod'); +set('symfony_env', 'prod'); // Symfony shared dirs set('shared_dirs', ['app/logs']); @@ -36,7 +36,11 @@ set('assets', ['web/css', 'web/images', 'web/js']); set('dump_assets', false); // Environment vars -set('env_vars', 'SYMFONY_ENV={{env}}'); +set('env', function () { + return [ + 'SYMFONY_ENV' => get('symfony_env') + ]; +}); // Adding support for the Symfony3 directory structure set('bin_dir', 'app'); @@ -89,7 +93,7 @@ task('deploy:assets', function () { * Install assets from public dir of bundles */ task('deploy:assets:install', function () { - run('{{env_vars}} {{bin/php}} {{bin/console}} assets:install {{console_options}} {{release_path}}/web'); + run('{{bin/php}} {{bin/console}} assets:install {{console_options}} {{release_path}}/web'); })->desc('Install bundle assets'); @@ -98,7 +102,7 @@ task('deploy:assets:install', function () { */ task('deploy:assetic:dump', function () { if (get('dump_assets')) { - run('{{env_vars}} {{bin/php}} {{bin/console}} assetic:dump {{console_options}}'); + run('{{bin/php}} {{bin/console}} assetic:dump {{console_options}}'); } })->desc('Dump assets'); @@ -106,14 +110,14 @@ task('deploy:assetic:dump', function () { * Clear Cache */ task('deploy:cache:clear', function () { - run('{{env_vars}} {{bin/php}} {{bin/console}} cache:clear {{console_options}} --no-warmup'); + run('{{bin/php}} {{bin/console}} cache:clear {{console_options}} --no-warmup'); })->desc('Clear cache'); /** * Warm up cache */ task('deploy:cache:warmup', function () { - run('{{env_vars}} {{bin/php}} {{bin/console}} cache:warmup {{console_options}}'); + run('{{bin/php}} {{bin/console}} cache:warmup {{console_options}}'); })->desc('Warm up cache'); @@ -121,7 +125,7 @@ task('deploy:cache:warmup', function () { * Migrate database */ task('database:migrate', function () { - run('{{env_vars}} {{bin/php}} {{bin/console}} doctrine:migrations:migrate {{console_options}} --allow-no-migration'); + run('{{bin/php}} {{bin/console}} doctrine:migrations:migrate {{console_options}} --allow-no-migration'); })->desc('Migrate database'); diff --git a/src/Support/helpers.php b/src/Support/helpers.php index f04edf06..02e9bf69 100644 --- a/src/Support/helpers.php +++ b/src/Support/helpers.php @@ -73,3 +73,19 @@ function str_contains(string $haystack, string $needle) { return strpos($haystack, $needle) !== false; } + +/** + * Take array of key/value and create string of it. + * + * This function used for create environment string. + */ +function array_to_string(array $array): string +{ + return implode(' ', array_map( + function ($key, $value) { + return sprintf("%s='%s'", $key, $value); + }, + array_keys($array), + $array + )); +} diff --git a/src/functions.php b/src/functions.php index 4079774c..05786df9 100644 --- a/src/functions.php +++ b/src/functions.php @@ -22,6 +22,7 @@ use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Question\ChoiceQuestion; use Symfony\Component\Console\Question\ConfirmationQuestion; use Symfony\Component\Console\Question\Question; +use function Deployer\Support\array_to_string; // There are two types of functions: Deployer dependent and Context dependent. // Deployer dependent function uses in definition stage of recipe and may require Deployer::get() method. @@ -290,6 +291,12 @@ function run($command, $options = []) $command = "cd $workingPath && ($command)"; } + $env = get('env', []) + ($options['env'] ?? []); + if (!empty($env)) { + $env = array_to_string($env); + $command = "export $env; $command"; + } + if ($host instanceof Localhost) { $output = $process->run($hostname, $command, $options); } else { @@ -318,6 +325,12 @@ function runLocally($command, $options = []) $command = "cd $workingPath && ($command)"; } + $env = get('env', []) + ($options['env'] ?? []); + if (!empty($env)) { + $env = array_to_string($env); + $command = "export $env; $command"; + } + $output = $process->run($hostname, $command, $options); return rtrim($output); diff --git a/test/fixture/recipe/deploy.php b/test/fixture/recipe/deploy.php index 8a024fff..295017bd 100644 --- a/test/fixture/recipe/deploy.php +++ b/test/fixture/recipe/deploy.php @@ -77,5 +77,19 @@ fail('deploy_fail', 'deploy:unlock'); // Dummy task('deploy:vendors', function () { - run('echo {{env_vars}} {{bin/composer}} {{composer_options}}'); + run('echo {{bin/composer}} {{composer_options}}'); +}); + +// Environment test + +task('test_env', function () { + add('env', ['KEY' => 'env value']); + + writeln(run('echo $KEY $EXT', ['env' => [ + 'EXT' => 'ext' + ]])); + + writeln(runLocally('echo $KEY $LOCAL', ['env' => [ + 'LOCAL' => 'local' + ]])); }); diff --git a/test/recipe/DeployTest.php b/test/recipe/DeployTest.php index 9c61ab73..2643a554 100644 --- a/test/recipe/DeployTest.php +++ b/test/recipe/DeployTest.php @@ -86,4 +86,11 @@ class DeployTest extends DepCase self::assertEquals(5, exec("ls -1 releases | wc -l")); self::assertFileNotExists(self::$currentPath . '/release'); } + + public function testEnvironment() + { + $output = $this->start('test_env'); + self::assertContains('env value ext', $output); + self::assertContains('env value local', $output); + } }