Skip to content

Commit

Permalink
Rename files to not clash with any other recipe file named the same
Browse files Browse the repository at this point in the history
  • Loading branch information
loevgaard committed Mar 31, 2023
1 parent 12b9d14 commit fbd8ed5
Show file tree
Hide file tree
Showing 6 changed files with 197 additions and 182 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ In your `deploy.php` file require the recipe:

namespace Deployer;

require_once 'recipe/dotenv.php';
require_once 'recipe/setono_dotenv.php';

// ...
```
Expand Down
11 changes: 3 additions & 8 deletions psalm-baseline.xml
Original file line number Diff line number Diff line change
@@ -1,12 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<files psalm-version="4.7.3@38c452ae584467e939d55377aaf83b5a26f19dd1">
<file src="src/autoload.php">
<UnusedFunctionCall occurrences="1">
<code>set_include_path</code>
</UnusedFunctionCall>
</file>
<file src="src/recipe/dotenv.php">
<PossiblyInvalidMethodCall occurrences="1">
<files psalm-version="5.9.0@8b9ad1eb9e8b7d3101f949291da2b9f7767cd163">
<file src="src/recipe/setono_dotenv.php">
<PossiblyInvalidMethodCall>
<code>has</code>
</PossiblyInvalidMethodCall>
</file>
Expand Down
22 changes: 2 additions & 20 deletions src/recipe/dotenv.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,25 +4,7 @@

namespace Setono\Deployer\DotEnv;

use function Deployer\after;
use function Deployer\before;
use Deployer\Deployer;

require_once 'task/dotenv.php';

after('deploy:update_code', 'dotenv:prepare');

$deployer = Deployer::get();

/**
* The task deploy:cache:clear is defined in Symfony related recipes and both the cache clear
* and cache warmup tasks sometimes depend on environment variables. Therefore it's a good idea
* to have environment variables defined before running these tasks.
* @deprecated Do not include this file. It will be removed in 2.0
*/
if ($deployer->tasks->has('deploy:cache:clear')) {
before('deploy:cache:clear', 'dotenv:update');
} else {
before('deploy:symlink', 'dotenv:update');
}

before('dotenv:update', 'dotenv:generate');
require_once __DIR__ . '/setono_dotenv.php';
28 changes: 28 additions & 0 deletions src/recipe/setono_dotenv.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?php

declare(strict_types=1);

namespace Setono\Deployer\DotEnv;

use function Deployer\after;
use function Deployer\before;
use Deployer\Deployer;

require_once __DIR__ . '/../task/setono_dotenv.php';

after('deploy:update_code', 'dotenv:prepare');

$deployer = Deployer::get();

/**
* The task deploy:cache:clear is defined in Symfony related recipes and both the cache clear
* and cache warmup tasks sometimes depend on environment variables. Therefore it's a good idea
* to have environment variables defined before running these tasks.
*/
if ($deployer->tasks->has('deploy:cache:clear')) {
before('deploy:cache:clear', 'dotenv:update');
} else {
before('deploy:symlink', 'dotenv:update');
}

before('dotenv:update', 'dotenv:generate');
155 changes: 2 additions & 153 deletions src/task/dotenv.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,158 +4,7 @@

namespace Setono\Deployer\DotEnv;

use function Deployer\ask;
use function Deployer\askConfirmation;
use function Deployer\has;
use function Deployer\input;
use function Deployer\invoke;
use function Deployer\output;
use function Deployer\run;
use function Deployer\set;
use function Deployer\task;
use function Deployer\test;
use Symfony\Component\Console\Helper\Table;
use Symfony\Component\Console\Helper\TableSeparator;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Dotenv\Dotenv;
use Webmozart\Assert\Assert;

/**
* This step has to come AFTER the deploy:update_code step because
*
* 1. We use the parameter previous_release which is set during the deploy:release step
*
* 2. The deploy:update_code step uses git clone to create the release directory and that command expects an empty dir
*/
task('dotenv:prepare', static function (): void {
if (!has('stage')) {
// if a stage isn't set then we presume the stage to be prod since you are only deploying to one place
set('stage', 'prod');
}

// this small trick will make sure the environment (i.e. for the console) is set to the expected environment
// when running commands before the generation of the .env.local.php is run
if (!test('[ -f {{release_path}}/.env.local ]')) {
run('echo "APP_ENV={{stage}}" > {{release_path}}/.env.local');
}

if (has('previous_release') && test('[ -f {{previous_release}}/.env.{{stage}}.local ]')) {
run('cp {{previous_release}}/.env.{{stage}}.local {{release_path}}');
} else {
run('touch {{release_path}}/.env.{{stage}}.local');
}
})->desc('Copies .env.[stage].local from previous release folder or creates a new one');

/**
* This task should be called BEFORE dotenv:update because that task needs the .env.local.php file
*/
task('dotenv:generate', static function (): void {
run('cd {{release_path}} && {{bin/composer}} symfony:dump-env {{stage}}');
})->desc('Generates the .env.local.php file');

/**
* This task should be called BEFORE deploy:symlink
* @deprecated Do not include this file. It will be removed in 2.0
*/
task('dotenv:update', static function (): void {
if (!input()->isInteractive()) {
return;
}

$output = output();

$outputVariablesFunction = static function (OutputInterface $output, array $variables): void {
ksort($variables);

$table = new Table($output);
$table->setRows([
['Variable', 'Value'],
new TableSeparator(),
]);

/**
* @var string $key
* @var string $val
*/
foreach ($variables as $key => $val) {
$table->addRow([$key, $val]);
}

$table->render();
};

$evalEnv = static function (string $envContents): array {
/** @var array<string, scalar> $res */
$res = eval('?>' . $envContents);
Assert::isArray($res);
Assert::allScalar($res);

return $res;
};

/**
* We want two arrays to begin with. This allows us to easily compare the two arrays later on
* when the $variables may have been changed by the user
*/
$variables = $initialVariables = $evalEnv(run('cat {{release_path}}/.env.local.php'));

while (true) {
$outputVariablesFunction($output, $variables);

$confirmation = askConfirmation('Do you want to update ' . (isset($confirmation) ? 'more' : 'any') . ' environment variables?');
if (false === $confirmation) {
break;
}

while (true) {
$newValue = ask('Input environment variable and value (ENV_VAR=value). Press <return> when you are finished adding', '', array_keys($variables));
if ('' === $newValue) {
break;
}

/** @psalm-suppress PossiblyUndefinedArrayOffset */
[$key, $val] = explode('=', $newValue, 2);

// Here we add/overwrite the value from the user
$variables[$key] = $val;
}
}

/**
* Notice that this comparison will return false if the two arrays have different key/value pairs
* See https://www.php.net/manual/en/language.operators.array.php
*/
if ($initialVariables != $variables) {
/**
* This array contains the environment variables already overridden
*
* @var array<string, string> $overriddenValues
*/
$overriddenValues = (new Dotenv())->parse(run('cat {{release_path}}/.env.{{stage}}.local'));

/**
* The difference between the $variables array and the $initialVariables array
* are the variables that the user has overridden in the dialog above
*/
$newOverriddenValues = array_diff_assoc($variables, $initialVariables);

/**
* Now we merge the new overridden values with the old ones which will
* give us the values we need to save to the .env.[stage].local file
*/
$overriddenValues = array_merge($overriddenValues, $newOverriddenValues);

/**
* This will generate a $command variable that will save a multiline text into a file
* See https://stackoverflow.com/questions/10969953/how-to-output-a-multiline-string-in-bash
*/
$command = "cat <<EOT > {{release_path}}/.env.{{stage}}.local\n";
foreach ($overriddenValues as $key => $val) {
$command .= $key . '=' . $val . "\n";
}
$command .= 'EOT';
run($command);

// Now we rerun the generation because we changed the environment variables
invoke('dotenv:generate');
}
})->desc('Allows the user to update environment variables');
require_once __DIR__ . '/setono_dotenv.php';
Loading

0 comments on commit fbd8ed5

Please sign in to comment.