Skip to content
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

Adding test bootstrap.php file so .env vars are read #366

Closed
wants to merge 2 commits into from
Closed

Adding test bootstrap.php file so .env vars are read #366

wants to merge 2 commits into from

Conversation

weaverryan
Copy link
Member

Q A
License MIT

Fixes symfony/flex#251

The problem is that currently, environment variables must be completely duplicated between .env and phpunit.xml.dist. That's just unacceptable DX to put in the user... which includes me - I don't want to do that :).

This is an easy win:

  • .env is read in the same way as bin/console and public/index.php
  • Environment variables in phpunit.xml.dist WIN over .env. This is used to set the environment to test.

This works particularly well, because any env vars set in
phpunit.xml.dist WIN over .env. This means that .env can
contain default values, but can then be easily overridden
for the test environment.
Copy link

@ghost ghost left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request passes validation.

* Environment variables can also be specified in phpunit.xml.dist.
* Those variables will override any defined in .env.
*/
if (!isset($_SERVER['APP_ENV'])) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just by curiosity, why do we use this condition, also in the console? This disallow from having a generic bash script with a conditional behavior depending of the APP_ENV, and then launch specific commands based on this. It does not make sense in my opinion that APP_ENV=dev ./bin/console s:r launches the server without reading the .env file while ./bin/console s:r does. I will have the same issue here as I may set the APP_ENV var to test before launching the tests (I actually do) ; it won't load the .env file consequently...

I would expect that the .env file is always loaded (except if APP_ENV is defined and set to prod so we can prevent misuses of .env files), if it exists. The DotEnv component already takes care to avoid overriding already defined variables.

@fabpot
Copy link
Member

fabpot commented Feb 11, 2018

@weaverryan You should also create a companion PR on symfony/flex to remove the addition of env vars in phpunit.xml.dist.

@ogizanagi
Copy link
Member

@weaverryan: That's already a great improvement, but this doesn't solve another linked issue that should also be considered to me: running a command in another env, including test one, which is sometimes handy to debug your test suite, or even simply to init the database/other stuff (despite it can also be done from the test suite bootstrap file).

If it can be of any help, here is what I'm using currently on flex projects: A DotEnvLoader class allows to load an extra .env.[env] file (in addition to the .env one), where "[env]" is the symfony env. Other patches inside the gist shows how to use it.

This is tough: we're getting WTF moments when someone tries to set,
for example, APP_ENV=test or some other environment, and suddenly
the .env file isn't loaded.

This is to hopefully make things work in a more predictable way: .env
is always loaded, except in the prod environment. This works because
DotEnv does not override any existing variables, so there's no risk
in loading it.
@weaverryan
Copy link
Member Author

Hey guys!

I've just made this PR more complicated :). I've change to load the .env file even if the APP_ENV. The only time we don't load it is in the prod environment.

I think this is important: we continue to see users confused about why the .env variable suddenly isn't read if they set APP_ENV. The previous situation also made this PR strange: the phpunit.xml.dist env vars are loaded FIRST, and then bootstrap.php is executed. But, the phpunit.xml.dist env vars are ONLY added to $_ENV, not $_SERVER. So, .env was still loaded (which I liked). But if you suddenly started setting true env vars, you'd get a different behavior.

So the goal is simple: load the .env file in the least WTF kind of way. Because it doesn't override existing env vars, I think this makes sense.

Also, @ogizanagi brings up another point in his comment. There's not an easy way, for example, to set a different DATABASE_URL in test, and be able to use it in your tests and in bin/console. He suggests the possibility of having a .env.[env] file that would override the normal one, and I agree. It's also what Laravel does, which I think is important, because they've been using the .env idea longer so have probably learned a few things.

So.... I think we need to make several changes to our .env handling.... and so possibly some sort of bootstrap.php file that's used by all entry points - index.php, console, testing.

Cheers!

Copy link

@ghost ghost left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request passes validation.

@quentinus95
Copy link

I guess the possibility to use .env.[env] files is mitigated by the fact that we can now load the .env file even if some environment files are already loaded. One could easily create custom .env.test file (for instance) and load those using a source + allexport in a bash script and then run the tests normally.

@ogizanagi
Copy link
Member

ogizanagi commented Feb 12, 2018

What about symfony/flex providing something like the DotEnvLoader class mentioned earlier (or whatever name we use for it) and use it here ?

@SergeC
Copy link

SergeC commented Feb 16, 2018

Maybe we should have a .env.[env].dist which will be updated by SF Flex the same way as .env.dist? The .env.[env].dist will be pushed to GIT while .env.[env] will be ignored. If env=prod the use .env.

@bocharsky-bw
Copy link
Contributor

* Those variables will override any defined in .env.
*/

if (!isset($_SERVER['APP_ENV']) || 'prod' !== $_SERVER['APP_ENV']) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why don't we use getenv('APP_ENV') instead of $_SERVER['APP_ENV']. Are there any reasons behind? Symfony recommends to use getenv() in docs but has $_SERVER[] in code which is not consistent as for me.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See #156 about that. It should probably be updated in the docs then.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

getenv is an issue because of not being thread safe (probably less an issue in the PHPUnit bootstrap as this is used only in the CLI)

Copy link
Member

@Nyholm Nyholm left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great. I like this. Just had a minor question

* Environment variables can also be specified in phpunit.xml.dist.
* Those variables will override any defined in .env.
*/
if (!isset($_SERVER['APP_ENV'])) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouln't this be the same as for version 4.7?

if (!isset($_SERVER['APP_ENV']) || 'prod' !== $_SERVER['APP_ENV']) {


/*
* Environment variables can also be specified in phpunit.xml.dist.
* Those variables will override any defined in .env.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good!

@@ -8,7 +8,7 @@
require __DIR__.'/../vendor/autoload.php';

// The check is to ensure we don't use .env in production
if (!isset($_SERVER['APP_ENV'])) {
if (!isset($_SERVER['APP_ENV']) || 'prod' !== $_SERVER['APP_ENV']) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just had an issue trying to warm-up my cache on the CI.
My APP_ENV was test and I was overriding the env with the --env option like so :

bin/console --env=prod cache:clear --no-warmup
[08-Mar-2018 16:54:49 Europe/Paris] PHP Fatal error:  Uncaught RuntimeException: APP_ENV environment variable is not defined. You need to define environment variables for configuration or add "symfony/dotenv" as a Composer dependency to load variables from a .env file. in /app/bin/console:20

I can see that my case is kind of weird and I am going to change the way I ran the command but we could do something to improve DX in that case perhaps ?

@sstok
Copy link
Contributor

sstok commented Mar 11, 2018

To be clear phpunit follows the same convention as the DotEnv component, if an env is already set it will not overwrite, unless you provide force="true".

@joshlopes
Copy link

A DotEnvLoader from @ogizanagi seems what SF needs - why isn't this shown any love? Is there a workaround for this already implemented?

@weaverryan
Copy link
Member Author

It’s just waiting on me to find some time to finish it. I have some agreement that this is probably the right approach

@joshlopes joshlopes mentioned this pull request May 15, 2018
@weaverryan
Copy link
Member Author

Closing in favor of #408

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet