Skip to content

Commit 76fe1c7

Browse files
committed
Add environment spark command
1 parent 6bacf2c commit 76fe1c7

File tree

2 files changed

+246
-0
lines changed

2 files changed

+246
-0
lines changed
Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
<?php
2+
3+
namespace CodeIgniter\Commands\Utilities;
4+
5+
use CodeIgniter\CLI\BaseCommand;
6+
use CodeIgniter\CLI\CLI;
7+
use CodeIgniter\Config\DotEnv;
8+
9+
/**
10+
* Command to display the current environment,
11+
* or set a new one in the `.env` file.
12+
*/
13+
final class Environment extends BaseCommand
14+
{
15+
/**
16+
* The group the command is lumped under
17+
* when listing commands.
18+
*
19+
* @var string
20+
*/
21+
protected $group = 'CodeIgniter';
22+
23+
/**
24+
* The Command's name
25+
*
26+
* @var string
27+
*/
28+
protected $name = 'env';
29+
30+
/**
31+
* The Command's short description
32+
*
33+
* @var string
34+
*/
35+
protected $description = 'Retrieves the current environment, or set a new one.';
36+
37+
/**
38+
* The Command's usage
39+
*
40+
* @var string
41+
*/
42+
protected $usage = 'env [<environment>]';
43+
44+
/**
45+
* The Command's arguments
46+
*
47+
* @var array<string, string>
48+
*/
49+
protected $arguments = [
50+
'environment' => '[Optional] The new environment to set. If none is provided, this will print the current environment.',
51+
];
52+
53+
/**
54+
* The Command's options
55+
*
56+
* @var array
57+
*/
58+
protected $options = [];
59+
60+
/**
61+
* Allowed values for environment. `testing` is excluded
62+
* since spark won't work on it.
63+
*
64+
* @var array<int, string>
65+
*/
66+
private static $knownTypes = [
67+
'production',
68+
'development',
69+
];
70+
71+
/**
72+
* @inheritDoc
73+
*
74+
* @param array<string, mixed> $params
75+
*
76+
* @return void
77+
*/
78+
public function run(array $params)
79+
{
80+
if ($params === [])
81+
{
82+
CLI::write(sprintf('Your environment is currently set as %s.', CLI::color(ENVIRONMENT, 'green')));
83+
CLI::newLine();
84+
85+
return;
86+
}
87+
88+
$env = strtolower(array_shift($params));
89+
90+
if ($env === 'testing')
91+
{
92+
CLI::error('The "testing" environment is reserved for PHPUnit testing.', 'light_gray', 'red');
93+
CLI::error('You will not be able to run spark under a "testing" environment.', 'light_gray', 'red');
94+
CLI::newLine();
95+
96+
return;
97+
}
98+
99+
if (! in_array($env, self::$knownTypes, true))
100+
{
101+
CLI::error(sprintf('Invalid environment type "%s". Expected one of "%s".', $env, implode('" and "', self::$knownTypes)), 'light_gray', 'red');
102+
CLI::newLine();
103+
104+
return;
105+
}
106+
107+
if (! $this->writeNewEnvironmentToEnvFile($env))
108+
{
109+
CLI::error('Error in writing new environment to .env file.', 'light_gray', 'red');
110+
CLI::newLine();
111+
112+
return;
113+
}
114+
115+
// force DotEnv to reload the new environment
116+
// however we cannot redefine the ENVIRONMENT constant
117+
putenv('CI_ENVIRONMENT');
118+
unset($_ENV['CI_ENVIRONMENT'], $_SERVER['CI_ENVIRONMENT']);
119+
(new DotEnv(ROOTPATH))->load();
120+
121+
CLI::write(sprintf('Environment is successfully changed to "%s".', $env), 'green');
122+
CLI::write('The ENVIRONMENT constant will be changed on the next script execution.');
123+
CLI::newLine();
124+
}
125+
126+
/**
127+
* @see https://regex101.com/r/4sSORp/1 for the regex in action
128+
*
129+
* @param string $newEnv
130+
*
131+
* @return boolean
132+
*/
133+
private function writeNewEnvironmentToEnvFile(string $newEnv): bool
134+
{
135+
$baseEnv = ROOTPATH . 'env';
136+
$envFile = ROOTPATH . '.env';
137+
138+
if (! is_file($envFile))
139+
{
140+
if (! is_file($baseEnv))
141+
{
142+
CLI::write('Both default shipped `env` file and custom `.env` are missing.', 'yellow');
143+
CLI::write('It is impossible to write the new environment type.', 'yellow');
144+
CLI::newLine();
145+
146+
return false;
147+
}
148+
149+
copy($baseEnv, $envFile);
150+
}
151+
152+
$pattern = preg_quote($_SERVER['CI_ENVIRONMENT'] ?? ENVIRONMENT, '/');
153+
$pattern = sprintf('/^[#\s]*CI_ENVIRONMENT[=\s]+%s$/m', $pattern);
154+
155+
return file_put_contents(
156+
$envFile,
157+
preg_replace($pattern, "\nCI_ENVIRONMENT = {$newEnv}", file_get_contents($envFile), -1, $count)
158+
) !== false && $count > 0;
159+
}
160+
}
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
<?php
2+
3+
namespace CodeIgniter\Commands;
4+
5+
use CodeIgniter\Test\CIUnitTestCase;
6+
use CodeIgniter\Test\Filters\CITestStreamFilter;
7+
8+
final class EnvironmentCommandTest extends CIUnitTestCase
9+
{
10+
private $streamFilter;
11+
12+
private $envPath = ROOTPATH . '.env';
13+
14+
private $backupEnvPath = ROOTPATH . '.env.backup';
15+
16+
protected function setUp(): void
17+
{
18+
parent::setUp();
19+
CITestStreamFilter::$buffer = '';
20+
21+
$this->streamFilter = stream_filter_append(STDOUT, 'CITestStreamFilter');
22+
$this->streamFilter = stream_filter_append(STDERR, 'CITestStreamFilter');
23+
24+
if (is_file($this->envPath))
25+
{
26+
rename($this->envPath, $this->backupEnvPath);
27+
}
28+
}
29+
30+
protected function tearDown(): void
31+
{
32+
parent::tearDown();
33+
stream_filter_remove($this->streamFilter);
34+
35+
if (is_file($this->envPath))
36+
{
37+
unlink($this->envPath);
38+
}
39+
40+
if (is_file($this->backupEnvPath))
41+
{
42+
rename($this->backupEnvPath, $this->envPath);
43+
}
44+
45+
$_SERVER['CI_ENVIRONMENT'] = $_ENV['CI_ENVIRONMENT'] = ENVIRONMENT;
46+
}
47+
48+
public function testUsingCommandWithNoArgumentsGivesCurrentEnvironment(): void
49+
{
50+
command('env');
51+
$this->assertStringContainsString('testing', CITestStreamFilter::$buffer);
52+
$this->assertStringContainsString(ENVIRONMENT, CITestStreamFilter::$buffer);
53+
}
54+
55+
public function testProvidingTestingAsEnvGivesErrorMessage(): void
56+
{
57+
command('env testing');
58+
$this->assertStringContainsString('The "testing" environment is reserved for PHPUnit testing.', CITestStreamFilter::$buffer);
59+
}
60+
61+
public function testProvidingUnknownEnvGivesErrorMessage(): void
62+
{
63+
command('env foobar');
64+
$this->assertStringContainsString('Invalid environment type "foobar".', CITestStreamFilter::$buffer);
65+
}
66+
67+
public function testDefaultShippedEnvIsMissing()
68+
{
69+
rename(ROOTPATH . 'env', ROOTPATH . 'lostenv');
70+
command('env development');
71+
rename(ROOTPATH . 'lostenv', ROOTPATH . 'env');
72+
73+
$this->assertStringContainsString('Both default shipped', CITestStreamFilter::$buffer);
74+
$this->assertStringContainsString('It is impossible to write the new environment type.', CITestStreamFilter::$buffer);
75+
}
76+
77+
public function testSettingNewEnvIsSuccess(): void
78+
{
79+
// default env file has `production` env in it
80+
$_SERVER['CI_ENVIRONMENT'] = 'production';
81+
command('env development');
82+
83+
$this->assertStringContainsString('Environment is successfully changed to', CITestStreamFilter::$buffer);
84+
$this->assertStringContainsString('CI_ENVIRONMENT = development', file_get_contents($this->envPath));
85+
}
86+
}

0 commit comments

Comments
 (0)