-
-
Notifications
You must be signed in to change notification settings - Fork 9.6k
[DotEnv] Add a new loadForEnv() method mimicking Ruby's dotenv behavior #28533
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
1000890
to
e0fecdd
Compare
/** | ||
* Loads one or several .env and the corresponding env.local, env.$env and env.$env.local files if they exist. | ||
* | ||
* The env.test.local is always ignored because tests should produce the same results for everyone. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think we should put any restriction and hardcode this. If that's really what the users want, that's on them. I'd remove it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was hesitating, but Create React App, Rails and Sinatra behave like this. Consistency is the key, it helps switching from one project to another. It especially matters when using both React and SF in a project (more and more common).
And, it's a good idea!
I really don't want to introduce something Symfony-specific here!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is .env.test.local
mentioned in the following sentence, then ? 😄
.env.dev.local, .env.test.local, .env.prod.local... - Local overrides of environment-specific settings.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@ogizanagi the comment was wrong 😁. Fixed!
6173590
to
d3b49fd
Compare
/** | ||
* Loads one or several .env and the corresponding env.local, env.$env and env.$env.local files if they exist. | ||
* | ||
* env.local is always ignored in test env because tests should produce the same results for everyone. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- env.local
+ .env.local
// or
+ $path.local
? 😄
@@ -50,6 +51,33 @@ public function load(string $path, string ...$paths): void | |||
$this->doLoad(false, $path, $paths); | |||
} | |||
|
|||
/** | |||
* Loads one or several .env and the corresponding env.local, env.$env and env.$env.local files if they exist. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Environment variables in later files override earlier files, correct?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Almost, see PR description.
I don't get what's the purpose of having I don't like the idea of this PR. It makes simple task (app configuration) much more complicated and IMO doesn't bring added value (the only one I see is configuring variables for different environments and use it only by changing But maybe I don't understand something.. |
The first use case I have is to have on a local machine the dev and test environments running at the "same" time. I mainly have a different |
@Wirone .env.prod is totally optional (for people not able to set environment variables in prod). This file will not be generated by the default skeleton (only .env.test will). However, having .env.test, .env.panther, .env.otherenv on the development machine will be very useful (and it’s my main goal, as I use Kubernetes in prod, without env files obviously). |
/** | ||
* @param bool $envMode Silently ignore not existing files in $paths (but not the one in $path) | ||
*/ | ||
private function doLoad(bool $overrideExistingVars, string $path, array $paths, bool $envMode = false): void |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
$envMode
variable name does not correspond with what it does. Should be named $silent
(as it's used internally) or $ignorePathErrors
or something like that.
PS. phpDoc is missing the other arguments
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
$silent
or $ignorePathErrors
is less accurate: an error will be thrown of the main file (usually .env) doesn’t exist. Only files for specific environments are optional.
Regarding the PHPDoc, in Symfony we don’t add the useless lines.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IMO $envMode
is not meaningful. If you don't look at implementation, only on signature, would you know what $envMode
does? Honestly, it doesn't even look like bool
variable, rather string or bitwise flag.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Wirone I agree, it's why I added a PHPDoc description :) If you have better name in mind, I'll be very happy to switch ($silent
and $ignorePathErrors
were my first thoughts, but they are more confusing than $envMode
).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What about $safe
(determines if call is safe and will not throw an exception) or $required
(determines if all paths should exist - it would require changing to $silent = !$required
).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IMO they are not more explicit, and can be confusing. environment mode
is exactly what it is, and $ignoreFilesThatNotExistExceptTheFirstOne
is a bit long. Isn't the description in the PHPDoc enough? This method is private, it will never be used by the end user, only by Symfony contributors (we may expect that they read the PHPDoc :D).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
doLoad(bool $overrideExistingVars, string $path, bool $ignoreMissingExtraPaths, string ...$extraPaths = array())
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure that using the splat operator is a good idea in this private method (we may add extra parameters at some point), also it is already used without the splat operator in other functions.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
parameter renamed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Finally! This will allow me to drop an extra class from all my enterprise projects.
👍 Thanks for raising
I think what's missing from this picture is where |
@teohhanhui the whole point of this PR is to switch from “our” conventions to the ones other projects follow. |
That sounds like a really bad thing to me. We shouldn't just switch conventions like that. What's wrong with sticking with What I'm trying to say is, we could stick with our conventions while having all the benefits of an extended .env support like in the other projects. |
This has already been discussed a lot in symfony/recipes#466 and related tickets. It actually makes it easier to deal with Docker Compose. |
95d821e
to
774a78c
Compare
Thank you @dunglas. |
…s dotenv behavior (dunglas) This PR was merged into the 4.2-dev branch. Discussion ---------- [DotEnv] Add a new loadForEnv() method mimicking Ruby's dotenv behavior | Q | A | ------------- | --- | Branch? | master | Bug fix? | no | New feature? | yes | BC breaks? | no <!-- see https://symfony.com/bc --> | Deprecations? |no <!-- don't forget to update UPGRADE-*.md and src/**/CHANGELOG.md files --> | Tests pass? | yes <!-- please add some, will be required by reviewers --> | Fixed tickets | helps for symfony/recipes#465, symfony/recipes#408 | License | MIT | Doc PR | todo This PR adds a new `loadForEnv()` method that mimics the behavior of [Create React App](https://github.com/facebook/create-react-app/blob/master/packages/react-scripts/template/README.md#what-other-env-files-can-be-used), [Rails' DotEnv](https://github.com/bkeepers/dotenv#what-other-env-files-can-i-use) and probably some other libs: `DotEnv::loadForEnv()` will load the following files, starting from the bottom. The first value set (or those already defined in the environment) take precedence: - `.env` - The Original® - `.env.dev`, `.env.test`, `.env.prod`... - Environment-specific settings. - `.env.local` - Local overrides. This file is loaded for all environments _except_ `test`. - `.env.dev.local`, `.env.test.local`, `.env.prod.local`... - Local overrides of environment-specific settings. The plan is to use this method in the default SF installation (symfony/recipes#466). Commits ------- 774a78c [DotEnv] Add a new loadForEnv() method mimicking Ruby's dotenv behavior
} | ||
|
||
/** | ||
* Loads one or several .env and the corresponding env.$env, env.local and env.$env.local files if they exist. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this seems to be missing the dots in front of the files like .env.$env
This PR was merged into the 4.2-dev branch. Discussion ---------- [DotEnv] Fix loadForEnv PHPDoc | Q | A | ------------- | --- | Branch? | master | Bug fix? | no | New feature? | no <!-- don't forget to update src/**/CHANGELOG.md files --> | BC breaks? | no <!-- see https://symfony.com/bc --> | Deprecations? | no <!-- don't forget to update UPGRADE-*.md and src/**/CHANGELOG.md files --> | Tests pass? | yes <!-- please add some, will be required by reviewers --> | Fixed tickets | #28533 (review) | License | MIT | Doc PR | n/a <!-- Write a short README entry for your feature/bugfix here (replace this comment block.) This will help people understand your PR and can be used as a start of the Doc PR. Additionally: - Bug fixes must be submitted against the lowest branch where they apply (lowest branches are regularly merged to upper ones so they get the fixes too). - Features and deprecations must be submitted against the master branch. --> Commits ------- c10710c [DotEnv] Fix loadForEnv PHPDoc
did we really need this? Why .env.prod over config/packages/prod? if you cant define real env vars those locations are effectively the same already... and you can already import a git ignored local parameter file.
so yeah.. curious if the config/packages/ convention didnt already provide such behavior in SF. |
Is there a well-defined use case for this to explain why it's useful? The only ones I can think up are already solved by using parameters and environment variables as they are in Symfony 4.1, but I could well be missing something. In my projects we have Just my 2 pence! |
This feature has a lot of options in it, but the original motivation was to help solve exactly one problem. Currently, you need to add all of your environment variables in Cheers! |
still.. there's zero difference with doing
no? |
The value can be changed without invalidating the container, that's the diff :) |
That's a VERY fair point @ro0NL :). But I think setting a default in that way is a bit less obvious than having a |
@weaverryan right!, that's the 2nd difference: flex automation! |
understood. im just skeptical if the overhaul is worth it eventually, it's quite significant. |
@weaverryan Thanks for this! We were starting to think we'd gone mad and had completely missed something. |
…nv() (nicolas-grekas) This PR was merged into the 4.2-dev branch. Discussion ---------- [Dotenv] add loadEnv(), a smoother alternative to loadForEnv() | Q | A | ------------- | --- | Branch? | 4.2 | Bug fix? | yes | New feature? | no | BC breaks? | yes (4.2-only) | Deprecations? | no | Tests pass? | yes | Fixed tickets | - | License | MIT | Doc PR | - This PR replaces the `loadForEnv()` method introduced in #28533 by a new `loadEnv()` method. - It accepts only one mandatory argument: `$path`, which is the path to the `.env` file. - The 2nd argument is optional and defines the name of the environment variable that defines the Symfony env. This plays better with the current practice of defining the env in `.env` (`loadForEnv()` requires knowing the env before being called, leading to a chicken-n-egg situation that `loadEnv()` avoids.) - the possibility to load several files at once is removed. We don't have a use case for it and those who do can call `loadEnv()` in a loop anyway. In addition to $path (.env), the following files are loaded, the latter taking precedence in this order: .env < env.local < .env.$env < .env.$env.local Note that `loadForEnv()` used to give higher precedence to .env.local vs .env.$env. The new behavior is aligned with [the order used by create-react-app](https://github.com/facebook/create-react-app/blob/master/docusaurus/docs/adding-custom-environment-variables.md#what-other-env-files-can-be-used). It also allows overriding the env in .env.local, which should be convenient for DX. Last but not least, the "test" env has this special behaviors: - `.env.local` file is skipped for the "test" env (same as before and as in create-react-app) - ~vars defined in .env files **override** real env vars (similar to what Rails' dotenv does: you don't want your tests to randomly fail because of some real env vars)~. Commits ------- 0cf9acb [Dotenv] add loadEnv(), a smoother alternative to loadForEnv()
Hi, This "Ruby's dotenv behavior" is BC for all tools using ".env traditional behaviour" which is to store a lot of command lines arguments value and store secrets. My main difficulty is with this last point. Cf. What Changed Exactly?
Check this illustration with FROM registry.access.redhat.com/rhel7/rhel
ARG PASSWORD With the following tips Cf. docker compose args
services:
web:
build:
context: docker/web
args:
- PASSWORD And command line ".env traditional behaviour"explain Cf. docker compose env
Will propose extra thoughts
|
This PR adds a new
loadForEnv()
method that mimics the behavior of Create React App, Rails' DotEnv and probably some other libs:DotEnv::loadForEnv()
will load the following files, starting from the bottom. The first value set (or those already defined in the environment) take precedence:.env
- The Original®.env.dev
,.env.test
... - Environment-specific settings..env.local
- Local overrides. This file is loaded for all environments excepttest
..env.dev.local
,.env.test.local
... - Local overrides of environment-specific settings.The plan is to use this method in the default SF installation (symfony/recipes#466).
Note: this feature can also be used in prod if the app doesn’t follow the 12factor methodology (discouraged, but sometimes mandatory in constrained hosting environments not allowing to set environment variables).