-
-
Notifications
You must be signed in to change notification settings - Fork 9.6k
Description
Symfony version(s) affected
5.4
Description
We're currently in the process of automating some of our more cumbersome tasks when doing deployments (updating the deployed Jira issues to reflect the most recent status). So we've created a small Symfony\Component\Console\Application
-based standalone application, which we wanted to install globally on our dev machines (composer global require becklyn/deploy-message-generator
). And since it's a new tool, we wanted to spend the time having a closer look at the awesome new runtime component.
Installing the tool within an existing Symfony application works exactly as expected. However, installing it globally is where the headache began:
1) Runtime selection
Following the official docs (https://symfony.com/doc/current/components/runtime.html#selecting-runtimes), there are two ways of selecting which runtime is being used to bootstrap the application: Either via an environment variable or by specifying the extra.runtime.class
key within our composer.json
(which we did).
Trying to just execute our tool resulted in a very strange behaviour where it was instantiating SymfonyRuntime
, even though our configuration did specify to use the GenericRuntime
(see https://github.com/Becklyn/deploy-message-generator/blob/1.0.0/composer.json#L26-L30).
2) Unable to pass $runtimeOptions
to any runtime via CLI arguments
Currently, the SymfonyRuntime
(and most likely others) are configurable by passing in an array, which is generated by parsing the $_SERVER
and $_ENV
super globals (see
$runtime = new $runtime(($_SERVER['APP_RUNTIME_OPTIONS'] ?? $_ENV['APP_RUNTIME_OPTIONS'] ?? []) + %runtime_options%); |
autoload_runtime.php
, there is actually a single semi-hardcoded value, which defines the project_dir
option.
If I'd now go ahead and try to use some options, I cannot possibly figure out how to turn my regular CLI arguments into a proper PHP array, which is expected to make checks such as this
if (!($options['disable_dotenv'] ?? false) && isset($options['project_dir']) && !class_exists(MissingDotenv::class, false)) { |
3) SymfonyRuntime
always loads DotEnv
variables
This is more or less a follow-up from the previous problem since I can't configure the default behaviour of the SymfonyRuntime
.
Since our console application also makes use of the DotEnv
(with a different path on where to look for the .env
file), the SymfonyRuntime
just tries to load a .env
file within my global composer folder, which causes in an error since the file doesn't exist.
How to reproduce
(Assuming the global composer directory is within your shell's $PATH
)
composer global require becklyn/deploy-message-generator
deploy-message-generator deployment:send-deploy-message staging a81842dc..9368c076
You should see a stacktrace that looks like this:
Possible Solution
One workaround for us would be to no longer require autoload_runtime.php
(and load autoload.php
again) and copy over some of the logic from it to ultimately end up with something like this:
<?php declare(strict_types=1);
use Becklyn\DeployMessageGenerator\Commands\SendDeployMessageCommand;
use Composer\InstalledVersions;
use Symfony\Component\Console\Application;
use Symfony\Component\Dotenv\Dotenv;
use Symfony\Component\Runtime\GenericRuntime;
// Regular project installation
if (is_file($autoloader = dirname(__DIR__) . "/vendor/autoload.php"))
{
require_once $autoloader;
}
// Composer global install
else if (is_file($autoloader = dirname(__DIR__, 3) . "/autoload.php"))
{
require_once $autoloader;
}
$app = static function (array $context) : Application {
$home = "Windows" === \PHP_OS_FAMILY ? $context["USERPROFILE"] : $context["HOME"];
(new Dotenv())->load("{$home}/.deploy-message-generator.env");
$context += $_ENV;
$name = "becklyn/deploy-message-generator";
$version = InstalledVersions::getVersion($name) ?? "UNKNOWN";
$application = new Application($name, $version);
$application->add(new SendDeployMessageCommand($context));
return $application;
};
$runtime = new GenericRuntime(($_SERVER['APP_RUNTIME_OPTIONS'] ?? $_ENV['APP_RUNTIME_OPTIONS'] ?? []) + [
"disable_dotenv" => true,
"project_dir" => dirname(__DIR__, 1),
]);
[$app, $args] = $runtime
->getResolver($app)
->resolve();
$app = $app(...$args);
exit(
$runtime
->getRunner($app)
->run()
);
This would work for us for now, but this is most likely not how this component has been envisioned :) Surely it sounds like I've found an edge case :D
Additional Context
No response