-
Notifications
You must be signed in to change notification settings - Fork 1.9k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
6bacf2c
commit 76fe1c7
Showing
2 changed files
with
246 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,160 @@ | ||
<?php | ||
|
||
namespace CodeIgniter\Commands\Utilities; | ||
|
||
use CodeIgniter\CLI\BaseCommand; | ||
use CodeIgniter\CLI\CLI; | ||
use CodeIgniter\Config\DotEnv; | ||
|
||
/** | ||
* Command to display the current environment, | ||
* or set a new one in the `.env` file. | ||
*/ | ||
final class Environment extends BaseCommand | ||
{ | ||
/** | ||
* The group the command is lumped under | ||
* when listing commands. | ||
* | ||
* @var string | ||
*/ | ||
protected $group = 'CodeIgniter'; | ||
|
||
/** | ||
* The Command's name | ||
* | ||
* @var string | ||
*/ | ||
protected $name = 'env'; | ||
|
||
/** | ||
* The Command's short description | ||
* | ||
* @var string | ||
*/ | ||
protected $description = 'Retrieves the current environment, or set a new one.'; | ||
|
||
/** | ||
* The Command's usage | ||
* | ||
* @var string | ||
*/ | ||
protected $usage = 'env [<environment>]'; | ||
|
||
/** | ||
* The Command's arguments | ||
* | ||
* @var array<string, string> | ||
*/ | ||
protected $arguments = [ | ||
'environment' => '[Optional] The new environment to set. If none is provided, this will print the current environment.', | ||
]; | ||
|
||
/** | ||
* The Command's options | ||
* | ||
* @var array | ||
*/ | ||
protected $options = []; | ||
|
||
/** | ||
* Allowed values for environment. `testing` is excluded | ||
* since spark won't work on it. | ||
* | ||
* @var array<int, string> | ||
*/ | ||
private static $knownTypes = [ | ||
'production', | ||
'development', | ||
]; | ||
|
||
/** | ||
* @inheritDoc | ||
* | ||
* @param array<string, mixed> $params | ||
* | ||
* @return void | ||
*/ | ||
public function run(array $params) | ||
{ | ||
if ($params === []) | ||
{ | ||
CLI::write(sprintf('Your environment is currently set as %s.', CLI::color(ENVIRONMENT, 'green'))); | ||
CLI::newLine(); | ||
|
||
return; | ||
} | ||
|
||
$env = strtolower(array_shift($params)); | ||
|
||
if ($env === 'testing') | ||
{ | ||
CLI::error('The "testing" environment is reserved for PHPUnit testing.', 'light_gray', 'red'); | ||
CLI::error('You will not be able to run spark under a "testing" environment.', 'light_gray', 'red'); | ||
CLI::newLine(); | ||
|
||
return; | ||
} | ||
|
||
if (! in_array($env, self::$knownTypes, true)) | ||
{ | ||
CLI::error(sprintf('Invalid environment type "%s". Expected one of "%s".', $env, implode('" and "', self::$knownTypes)), 'light_gray', 'red'); | ||
CLI::newLine(); | ||
|
||
return; | ||
} | ||
|
||
if (! $this->writeNewEnvironmentToEnvFile($env)) | ||
{ | ||
CLI::error('Error in writing new environment to .env file.', 'light_gray', 'red'); | ||
CLI::newLine(); | ||
|
||
return; | ||
} | ||
|
||
// force DotEnv to reload the new environment | ||
// however we cannot redefine the ENVIRONMENT constant | ||
putenv('CI_ENVIRONMENT'); | ||
unset($_ENV['CI_ENVIRONMENT'], $_SERVER['CI_ENVIRONMENT']); | ||
(new DotEnv(ROOTPATH))->load(); | ||
|
||
CLI::write(sprintf('Environment is successfully changed to "%s".', $env), 'green'); | ||
CLI::write('The ENVIRONMENT constant will be changed on the next script execution.'); | ||
CLI::newLine(); | ||
} | ||
|
||
/** | ||
* @see https://regex101.com/r/4sSORp/1 for the regex in action | ||
* | ||
* @param string $newEnv | ||
* | ||
* @return boolean | ||
*/ | ||
private function writeNewEnvironmentToEnvFile(string $newEnv): bool | ||
{ | ||
$baseEnv = ROOTPATH . 'env'; | ||
$envFile = ROOTPATH . '.env'; | ||
|
||
if (! is_file($envFile)) | ||
{ | ||
if (! is_file($baseEnv)) | ||
{ | ||
CLI::write('Both default shipped `env` file and custom `.env` are missing.', 'yellow'); | ||
CLI::write('It is impossible to write the new environment type.', 'yellow'); | ||
CLI::newLine(); | ||
|
||
return false; | ||
} | ||
|
||
copy($baseEnv, $envFile); | ||
} | ||
|
||
$pattern = preg_quote($_SERVER['CI_ENVIRONMENT'] ?? ENVIRONMENT, '/'); | ||
$pattern = sprintf('/^[#\s]*CI_ENVIRONMENT[=\s]+%s$/m', $pattern); | ||
|
||
return file_put_contents( | ||
$envFile, | ||
preg_replace($pattern, "\nCI_ENVIRONMENT = {$newEnv}", file_get_contents($envFile), -1, $count) | ||
) !== false && $count > 0; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
<?php | ||
|
||
namespace CodeIgniter\Commands; | ||
|
||
use CodeIgniter\Test\CIUnitTestCase; | ||
use CodeIgniter\Test\Filters\CITestStreamFilter; | ||
|
||
final class EnvironmentCommandTest extends CIUnitTestCase | ||
{ | ||
private $streamFilter; | ||
|
||
private $envPath = ROOTPATH . '.env'; | ||
|
||
private $backupEnvPath = ROOTPATH . '.env.backup'; | ||
|
||
protected function setUp(): void | ||
{ | ||
parent::setUp(); | ||
CITestStreamFilter::$buffer = ''; | ||
|
||
$this->streamFilter = stream_filter_append(STDOUT, 'CITestStreamFilter'); | ||
$this->streamFilter = stream_filter_append(STDERR, 'CITestStreamFilter'); | ||
|
||
if (is_file($this->envPath)) | ||
{ | ||
rename($this->envPath, $this->backupEnvPath); | ||
} | ||
} | ||
|
||
protected function tearDown(): void | ||
{ | ||
parent::tearDown(); | ||
stream_filter_remove($this->streamFilter); | ||
|
||
if (is_file($this->envPath)) | ||
{ | ||
unlink($this->envPath); | ||
} | ||
|
||
if (is_file($this->backupEnvPath)) | ||
{ | ||
rename($this->backupEnvPath, $this->envPath); | ||
} | ||
|
||
$_SERVER['CI_ENVIRONMENT'] = $_ENV['CI_ENVIRONMENT'] = ENVIRONMENT; | ||
} | ||
|
||
public function testUsingCommandWithNoArgumentsGivesCurrentEnvironment(): void | ||
{ | ||
command('env'); | ||
$this->assertStringContainsString('testing', CITestStreamFilter::$buffer); | ||
$this->assertStringContainsString(ENVIRONMENT, CITestStreamFilter::$buffer); | ||
} | ||
|
||
public function testProvidingTestingAsEnvGivesErrorMessage(): void | ||
{ | ||
command('env testing'); | ||
$this->assertStringContainsString('The "testing" environment is reserved for PHPUnit testing.', CITestStreamFilter::$buffer); | ||
} | ||
|
||
public function testProvidingUnknownEnvGivesErrorMessage(): void | ||
{ | ||
command('env foobar'); | ||
$this->assertStringContainsString('Invalid environment type "foobar".', CITestStreamFilter::$buffer); | ||
} | ||
|
||
public function testDefaultShippedEnvIsMissing() | ||
{ | ||
rename(ROOTPATH . 'env', ROOTPATH . 'lostenv'); | ||
command('env development'); | ||
rename(ROOTPATH . 'lostenv', ROOTPATH . 'env'); | ||
|
||
$this->assertStringContainsString('Both default shipped', CITestStreamFilter::$buffer); | ||
$this->assertStringContainsString('It is impossible to write the new environment type.', CITestStreamFilter::$buffer); | ||
} | ||
|
||
public function testSettingNewEnvIsSuccess(): void | ||
{ | ||
// default env file has `production` env in it | ||
$_SERVER['CI_ENVIRONMENT'] = 'production'; | ||
command('env development'); | ||
|
||
$this->assertStringContainsString('Environment is successfully changed to', CITestStreamFilter::$buffer); | ||
$this->assertStringContainsString('CI_ENVIRONMENT = development', file_get_contents($this->envPath)); | ||
} | ||
} |