Skip to content

Commit

Permalink
v1.0.2
Browse files Browse the repository at this point in the history
  • Loading branch information
lucacastelnuovo committed Jan 4, 2024
1 parent 71d7e5e commit 4d61f95
Show file tree
Hide file tree
Showing 2 changed files with 75 additions and 32 deletions.
6 changes: 5 additions & 1 deletion phpstan.neon.dist
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,14 @@ includes:
- phpstan-baseline.neon

parameters:
level: 5
level: 9
paths:
- src
tmpDir: build/phpstan
checkOctaneCompatibility: true
checkModelProperties: true
checkMissingIterableValueType: false
ignoreErrors:
- '#^Parameter \$options of function Laravel\\Prompts\\select expects array\<int\|string, string\>\|Illuminate\\Support\\Collection\<int\|string, string\>, array given\.$#'
- '#^Method Castelnuovo\\LaravelEnv\\Commands\\LaravelEnvCommand\:\:envs\(\) return type with generic class Illuminate\\Support\\Collection does not specify its types\: TKey, TValue$#'
- '#^Parameter \#1 \$callback of method Illuminate\\Support\\Collection\<\(int\|string\),mixed\>\:\:filter\(\) expects \(callable\(mixed, int\|string\)\: bool\)\|null, Closure\(mixed\)\: \(0\|1\|false\) given\.$#'
101 changes: 70 additions & 31 deletions src/Commands/LaravelEnvCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,91 +4,130 @@

use Illuminate\Console\Command;
use Illuminate\Contracts\Console\PromptsForMissingInput;
use Illuminate\Contracts\Filesystem\Filesystem;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Process;
use Illuminate\Support\Facades\Storage;

use function Laravel\Prompts\confirm;
use function Laravel\Prompts\error;
use function Laravel\Prompts\info;
use function Laravel\Prompts\note;
use function Laravel\Prompts\password;
use function Laravel\Prompts\select;
use function Laravel\Prompts\warning;

class LaravelEnvCommand extends Command implements PromptsForMissingInput
{
protected $signature = 'env:edit
{env : The environment to edit .env file for}
{key : The decryption key for the .env file}
{--c|code : Open the decrypted .env file in VS Code}';

protected $description = 'Decrypt, Edit and Encrypt .env files';

protected function promptForMissingArgumentsUsing()
{
return [
'env' => [
'Which environment do you want to edit the .env file for?',
'E.g. production',
],
'env' => fn () => select(
label: 'Which encrypted env do you want to edit?',
options: $this->envs()->toArray(),
required: true,
),
'key' => fn () => password(
label: 'What is the decryption key for the encrypted env?',
required: true,
),
];
}

public function handle(): int
{
$disk = Storage::build(['driver' => 'local', 'root' => base_path()]);
$env = $this->argument('env');
$encEnvFile = ".env.{$this->argument('env')}.encrypted";

$encryptedEnv = ".env.{$env}.encrypted";
$decryptedEnv = ".env.{$env}";
if (! $this->envs()->contains($this->argument('env'))) {
error("{$encEnvFile} does not exist!");

$key = password("What is the decryption key for {$encryptedEnv}?", required: true);
return self::FAILURE;
}

if (! $this->decryptEnv($env, $key)) {
error("{$encryptedEnv} could not be decrypted");
if (! $this->decrypt()) {
error("{$encEnvFile} could not be decrypted!");

return self::FAILURE;
}

info("Please open, edit and save {$decryptedEnv}.");
note($disk->path($decryptedEnv));
$envFile = ".env.{$this->argument('env')}";
$envFilePath = base_path($envFile);

info("Please open, edit and save: {$envFilePath}");

if ($this->option('code')) {
Process::quietly()->run("code {$disk->path($decryptedEnv)}");
Process::quietly()->run("code {$envFilePath}");
}

if (confirm("Store changes made to {$decryptedEnv}?")) {
if (! $this->encryptEnv($env, $key)) {
error("{$decryptedEnv} could not be encrypted");
if (confirm("Store changes made to {$envFile}?")) {
if (! $this->encrypt()) {
error("{$envFile} could not be encrypted!");

return self::FAILURE;
}

info('Changes were saved and encrypted!');
info('The changes were saved and encrypted!');
} else {
warning('Changes were discarded!');
warning('The changes were discarded!');
}

$disk->delete($decryptedEnv);
$this->disk()->delete($envFile);

return self::SUCCESS;
}

protected function decryptEnv(string $env, string $key): bool
/**
* Get the disk for the encrypted .env files.
*/
protected function disk(): Filesystem
{
return Storage::build(['driver' => 'local', 'root' => base_path()]);
}

/**
* Get environments of the encrypted .env files.
*/
protected function envs(): Collection
{
return $this->call('env:decrypt', [
'--key' => $key,
'--env' => $env,
return collect($this->disk()->files())
->filter(fn ($file) => preg_match('/\.env\..*\.encrypted/', $file))
->map(fn ($file) => preg_replace('/\.env\.(.*)\.encrypted/', '$1', $file))
->flatten();
}

/**
* Decrypt the .env file for the given environment.
*/
protected function decrypt(): bool
{
$result = $this->call('env:decrypt', [
'--env' => $this->argument('env'),
'--key' => $this->argument('key'),
'--force' => true,
'--quiet' => true,
]) === self::SUCCESS;
]);

return $result === Command::SUCCESS;
}

protected function encryptEnv(string $env, string $key): bool
/**
* Encrypt the .env file for the given environment.
*/
protected function encrypt(): bool
{
return $this->call('env:encrypt', [
'--key' => $key,
'--env' => $env,
$result = $this->call('env:encrypt', [
'--env' => $this->argument('env'),
'--key' => $this->argument('key'),
'--force' => true,
'--quiet' => true,
]) === self::SUCCESS;
]);

return $result === Command::SUCCESS;
}
}

0 comments on commit 4d61f95

Please sign in to comment.