Skip to content

Commit

Permalink
Merge pull request #19 from laravel/feat/adds-env-commands
Browse files Browse the repository at this point in the history
Adds `env:pull` and `env:push` commands
  • Loading branch information
taylorotwell authored Aug 10, 2021
2 parents e598822 + 82f964e commit 92ccdab
Show file tree
Hide file tree
Showing 7 changed files with 274 additions and 0 deletions.
2 changes: 2 additions & 0 deletions app/Clients/Forge.php
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,8 @@ protected function handleRequestError(ResponseInterface $response)
Panic::abort($response->getBody());
}

abort_if($response->getStatusCode() == 403, 1, 'Forbidden.');

if ($response->getStatusCode() == 422) {
$errors = json_decode((string) $response->getBody());

Expand Down
17 changes: 17 additions & 0 deletions app/Commands/Concerns/InteractsWithEnvironmentFiles.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?php

namespace App\Commands\Concerns;

trait InteractsWithEnvironmentFiles
{
/**
* Gets the "local" environment file name.
*
* @param \Laravel\Forge\Resources\Site $site
* @return string
*/
protected function getEnvironmentFile($site)
{
return $this->argument('file') ?: (getcwd().'/.env.forge.'.$site->id);
}
}
14 changes: 14 additions & 0 deletions app/Commands/Concerns/InteractsWithIO.php
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,20 @@ public function askStep($question, $default = null)
return $this->ask('<fg=yellow>‣</> <options=bold>'.$question.'</>', $default);
}

/**
* Display a confirm "step" message.
*
* @param string|array $question
* @param bool $default
* @return bool
*/
public function confirmStep($question, $default = false)
{
$question = $this->formatStepText($question);

return $this->output->confirm('<fg=yellow>‣</> <options=bold>'.$question.'</>', $default);
}

/**
* Display a ask "step" message.
*
Expand Down
54 changes: 54 additions & 0 deletions app/Commands/EnvPullCommand.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
<?php

namespace App\Commands;

use Illuminate\Support\Facades\File;

class EnvPullCommand extends Command
{
use Concerns\InteractsWithEnvironmentFiles;

/**
* The signature of the command.
*
* @var string
*/
protected $signature = 'env:pull {site? : The site name} {file? : File to write the environment variables to}';

/**
* The description of the command.
*
* @var string
*/
protected $description = 'Download the environment file for the given site';

/**
* Execute the console command.
*
* @return int|void
*/
public function handle()
{
$siteId = $this->askForSite('Which site would you like to download the environment file from');

$server = $this->currentServer();
$file = $this->getEnvironmentFile(
$site = $this->forge->site($server->id, $siteId)
);

if (is_null($this->argument('file')) && File::exists($file) && ! $this->confirmStep(
['File already exists with the name: %s. Would you like to overwrite it?', basename($file)]
)) {
return 0;
}

File::delete($file);

File::put(
$file,
$this->forge->siteEnvironmentFile($this->currentServer()->id, $site->id),
);

$this->successfulStep(['Environment variables written to %s', basename($file)]);
}
}
66 changes: 66 additions & 0 deletions app/Commands/EnvPushCommand.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
<?php

namespace App\Commands;

use Illuminate\Support\Facades\File;

class EnvPushCommand extends Command
{
use Concerns\InteractsWithEnvironmentFiles;

/**
* The signature of the command.
*
* @var string
*/
protected $signature = 'env:push {site? : The site name} {file? : File to upload the environment variables from}';

/**
* The description of the command.
*
* @var string
*/
protected $description = 'Upload the environment file for the given site';

/**
* Execute the console command.
*
* @return int|void
*/
public function handle()
{
$siteId = $this->askForSite('Which site would you like to upload the environment file to');

$server = $this->currentServer();
$file = $this->getEnvironmentFile(
$site = $this->forge->site($server->id, $siteId)
);

abort_unless(
File::exists($file),
1,
'The environment variables for that site have not been downloaded.'
);

if (is_null($this->argument('file')) && ! $this->confirmStep(
['Would You Like Update The Site Environment File With The Contents Of The File %s', basename($file)]
)) {
return 0;
}

$this->step(['Uploading %s Environment File', basename($file)]);

$this->forge->updateSiteEnvironmentFile(
$this->currentServer()->id,
$site->id,
File::get($file)
);

$this->successfulStep(['Environment variables uploaded successfully to %s', $site->name]);
$this->step('You may need to deploy the site for the new variables to take effect.');

if (is_null($this->argument('file')) && $this->confirmStep(['Would you like to delete the environment file %s from your machine', basename($file)])) {
File::delete($file);
}
}
}
59 changes: 59 additions & 0 deletions tests/Feature/EnvPullCommandTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
<?php

use Illuminate\Support\Facades\File;

it('can pull environment variables generated file', function () {
$this->client->shouldReceive('sites')->andReturn([
(object) ['id' => 1, 'name' => 'pestphp.com'],
(object) ['id' => 2, 'name' => 'something.com'],
]);

$this->client->shouldReceive('server')->andReturn(
(object) ['id' => 1, 'name' => 'production'],
);

$this->client->shouldReceive('site')->andReturn(
(object) ['id' => 2, 'name' => 'something.com'],
);

$file = getcwd().'/.env.forge.2';

File::shouldReceive('exists')->once()->with($file)->andReturn(false);
File::shouldReceive('delete')->once()->with($file)->andReturn(false);

$content = "BAR=FOO\nFOO=BAR\n";

$this->forge->shouldReceive('siteEnvironmentFile')->once()->with(1, 2)->andReturn($content);

File::shouldReceive('put')->once()->with($file, $content);

$this->artisan('env:pull')
->expectsQuestion('<fg=yellow>‣</> <options=bold>Which Site Would You Like To Download The Environment File From</>', 2)
->expectsOutput('==> Environment Variables Written To [.env.forge.2]');
});

it('can pull environment variables specific env file', function () {
$this->client->shouldReceive('sites')->andReturn([
(object) ['id' => 1, 'name' => 'pestphp.com'],
(object) ['id' => 2, 'name' => 'something.com'],
]);

$this->client->shouldReceive('server')->andReturn(
(object) ['id' => 1, 'name' => 'production'],
);

$this->client->shouldReceive('site')->andReturn(
(object) ['id' => 1, 'name' => 'pestphp.com'],
);

File::shouldReceive('delete')->once()->with('.env')->andReturn(false);

$content = "FOO=BAR\nBAR=FOO\n";

$this->forge->shouldReceive('siteEnvironmentFile')->once()->with(1, 1)->andReturn($content);

File::shouldReceive('put')->once()->with('.env', $content);

$this->artisan('env:pull', ['site' => 'pestphp.com', 'file' => '.env'])
->expectsOutput('==> Environment Variables Written To [.env]');
});
62 changes: 62 additions & 0 deletions tests/Feature/EnvPushCommandTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
<?php

use Illuminate\Support\Facades\File;

it('can push environment variables from the generated file', function () {
$this->client->shouldReceive('sites')->andReturn([
(object) ['id' => 1, 'name' => 'pestphp.com'],
(object) ['id' => 2, 'name' => 'something.com'],
]);

$this->client->shouldReceive('server')->andReturn(
(object) ['id' => 1, 'name' => 'production'],
);

$this->client->shouldReceive('site')->andReturn(
(object) ['id' => 2, 'name' => 'something.com'],
);

$file = getcwd().'/.env.forge.2';

File::shouldReceive('exists')->once()->with($file)->andReturn(true);

$content = "BAR=FOO\nFOO=BAR\n";

File::shouldReceive('get')->once()->with($file)->andReturn($content);

$this->forge->shouldReceive('updateSiteEnvironmentFile')->once()->with(1, 2, $content);

$this->artisan('env:push')
->expectsQuestion('<fg=yellow>‣</> <options=bold>Which Site Would You Like To Upload The Environment File To</>', 2)
->expectsQuestion('<fg=yellow>‣</> <options=bold>Would You Like Update The Site Environment File With The Contents Of The File <comment>[.env.forge.2]</comment></>', 2)
->expectsQuestion('<fg=yellow>‣</> <options=bold>Would You Like To Delete The Environment File <comment>[.env.forge.2]</comment> From Your Machine</>', false)
->expectsOutput('==> Uploading [.env.forge.2] Environment File')
->expectsOutput('==> Environment Variables Uploaded Successfully To [something.com]');
});

it('can push environment variables from specific env file', function () {
$this->client->shouldReceive('sites')->andReturn([
(object) ['id' => 1, 'name' => 'pestphp.com'],
(object) ['id' => 2, 'name' => 'something.com'],
]);

$this->client->shouldReceive('server')->andReturn(
(object) ['id' => 1, 'name' => 'production'],
);

$this->client->shouldReceive('site')->andReturn(
(object) ['id' => 2, 'name' => 'something.com'],
);

File::shouldReceive('exists')->once()->with('.env')->andReturn(true);

$content = "BAR=FOO\nFOO=BAR\n";

File::shouldReceive('get')->once()->with('.env')->andReturn($content);

$this->forge->shouldReceive('updateSiteEnvironmentFile')->once()->with(1, 2, $content);

$this->artisan('env:push', ['site' => 'pestphp.com', 'file' => '.env'])
->expectsOutput('==> Uploading [.env] Environment File')
->expectsOutput('==> Environment Variables Uploaded Successfully To [something.com]');
});

0 comments on commit 92ccdab

Please sign in to comment.