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

feat(unstable): deno run --env #20300

Merged
merged 24 commits into from
Nov 1, 2023
Merged

feat(unstable): deno run --env #20300

merged 24 commits into from
Nov 1, 2023

Conversation

iuioiua
Copy link
Contributor

@iuioiua iuioiua commented Aug 27, 2023

This change adds the --env=[FILE] flag to the run, compile, eval, install and repl subcommands. Environment variables set in the CLI overwrite those defined in the .env file.

@iuioiua iuioiua marked this pull request as ready for review August 27, 2023 06:41
Copy link
Member

@bartlomieju bartlomieju left a comment

Choose a reason for hiding this comment

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

Good start 👍 can you add some integration tests that check that the file is actually loaded?

cli/args/flags.rs Outdated Show resolved Hide resolved
cli/args/flags.rs Outdated Show resolved Hide resolved
cli/tools/run.rs Outdated Show resolved Hide resolved
cli/tools/run.rs Outdated Show resolved Hide resolved
@bartlomieju bartlomieju added this to the 1.37 milestone Aug 27, 2023
@cknight
Copy link
Contributor

cknight commented Aug 27, 2023

How does this change fit in with the dotenv std module? There is obviously overlap, loading from a .env file. Some thoughts:

  • Is this needed if all this functionality and more can be achieved with a single line of code (import of std/dotenv/load.ts)?
  • Is it confusing having this functionality available in both CLI flag and std module?
  • Conversely, with a .env.example and .env.defaults files and the ability to access the key/value pairs without exporting to the process environment there is an argument for keeping the std dotenv module as it provides added value which dotenvy doesn't offer
  • Do dotenvy and std/dotenv parse a .env file in the same way with the same rules and capabilities? (Does it matter?)
  • I do like the explicit command line reference to loading a .env file, this makes it more explicit that you are dependent on env variables

@bartlomieju
Copy link
Member

bartlomieju commented Aug 27, 2023

How does this change fit in with the dotenv std module? There is obviously overlap, loading from a .env file.
Some thoughts:

  • Is this needed if all this functionality and more can be achieved with a single line of code (import of std/dotenv/load.ts)?

There is some overlap, however with std/dotenv you can't influence any of DENO_* env vars without spawning a subprocess, while with --env flag these env variables will be applied before Deno checks for values of these env vars.

  • Is it confusing having this functionality available in both CLI flag and std module?

Probably yes, however --env is way more convenient than having to import module from the standard library, plus see previous comment.

  • Conversely, with a .env.example and .env.defaults files and the ability to access the key/value pairs without exporting to the process environment there is an argument for keeping the std dotenv module as it provides added value which dotenvy doesn't offer

We would certainly keep the std/dotenv module for people who need more control or flexibility. The --env flag is meant to serve the 80-90% use case.

  • Do dotenvy and std/dotenv parse a .env file in the same way with the same rules and capabilities? (Does it matter?)

Not sure, and I'm not sure if that matters. We will need to check that. It's not 100% agreed that we'll use dotenvy crate - AFAIK it can't do variable substitution which is one of the requirements for the --env flag. We already have some infrastructure for dealing with env vars in deno_task_shell and we might go with fork/inspired implementation there instead of using a 3rd part crate.

  • I do like the explicit command line reference to loading a .env file, this makes it more explicit that you are dependent on env variables

That was also one of the requirements for this feature - no magic discovery, not walking up the file system. In more detail the requirements for this feature are as follows:

  • require --env flag, don't traverse up the CWD if the file is not found
  • multiline variables support
  • variable substitution
  • conflict handling - this is the least specified, I think we just need to decide if the conflicting env var should raise an error or overrwrite (or make it configurable via a flag)

@cknight
Copy link
Contributor

cknight commented Aug 27, 2023

Thanks @bartlomieju, makes sense.

@iuioiua iuioiua changed the title feat: --env-file feat: --env Aug 28, 2023
@iuioiua
Copy link
Contributor Author

iuioiua commented Aug 28, 2023

Changes made. Still, work to do. Regarding the requirements:

  • Don't traverse up the CWD - does this just mean throw when an env file with a path above the CWD is defined?
  • Multiline support - not working with dotenvy for some reason
  • Variable substitution - need to test, dotenvy should do that automatically
  • Conflict handling - let me see if dotenvy does that automatically

TL;DR dotenvy should take care of the last 3 requirements automatically, but I need to confirm. Do we want to use deno_task_shell? If so, able to provide direction?

@iuioiua iuioiua requested a review from bartlomieju August 28, 2023 08:34
@bartlomieju
Copy link
Member

Changes made. Still, work to do. Regarding the requirements:

  • Don't traverse up the CWD - does this just mean throw when an env file with a path above the CWD is defined?

No, we should return an error if the value of the --env flag can't be loaded.

  • Multiline support - not working with dotenvy for some reason

That's a bummer :/

  • Variable substitution - need to test, dotenvy should do that automatically

That's good to hear 👍

  • Conflict handling - let me see if dotenvy does that automatically

👍

TL;DR dotenvy should take care of the last 3 requirements automatically, but I need to confirm. Do we want to use deno_task_shell? If so, able to provide direction?

If that's the case we should consider dotenvy for this purpose. If not, we can land the first pass as is and we can update deno_task_shell to be able to to handle these. Let's leave it for a follow up.

We also floated the idea that env vars defined in the dotenv file wouldn't require --allow-env permission to access, but that involves some more changes. @nayeemrmn thoughts on this?

@nayeemrmn
Copy link
Collaborator

We also floated the idea that env vars defined in the dotenv file wouldn't require --allow-env permission to access

Couldn't there be secrets there? Like API keys to non-production resources.

@bartlomieju
Copy link
Member

Good point. I guess we can skip that part for now and reevaluate in the future.

@bartlomieju
Copy link
Member

@iuioiua did you have a chance to verify if variable substitution and conflict handling is working in dotenvy?

@iuioiua
Copy link
Contributor Author

iuioiua commented Aug 30, 2023

Not yet. I should have a chance within the next couple of days. That cool?

@iuioiua
Copy link
Contributor Author

iuioiua commented Aug 31, 2023

  • Conflict handling - let me see if dotenvy does that automatically

dotenvy doesn't throw on conflicting environment variables. Instead, only the first value is used. I think this behaviour is fine, as long as it's explained, which I included. WDYT?

@cknight
Copy link
Contributor

cknight commented Aug 31, 2023

I think the more common use case would be if the env variable set in .env was already in the process environment, rather than the use case of duplication in the .env file. I think the behaviour is the same (the process env value is not overwritten), but it might be worth explicitly stating this in the docs.

@@ -391,6 +391,7 @@ pub struct Flags {
pub ext: Option<String>,
pub ignore: Vec<PathBuf>,
pub import_map_path: Option<String>,
pub env_file: Option<String>,
Copy link
Member

Choose a reason for hiding this comment

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

That was also one of the requirements for this feature - no magic discovery, not walking up the file system.

Generally a .env file would be stored right beside a deno.json. If a deno.json exists, maybe we should traverse up and stop at the deno.json directory when someone provides --env with no path?

@dsherret
Copy link
Member

I looked into this a bit and started extracting out some of the code from deno_task_shell, which will help us get this feature exactly how we like it and improve future integration. It's not too complicated, but there are some differences between the variable expansion (see https://github.com/motdotla/dotenv-expand/blob/master/tests/.env). Let's push this off to the next release.

@dsherret dsherret modified the milestones: 1.37, 1.38 Sep 18, 2023
@iuioiua iuioiua changed the title feat: --env feat: deno <run> --env Sep 28, 2023
@iuioiua iuioiua changed the title feat: deno <run> --env feat: deno run --env Sep 28, 2023
@iuioiua
Copy link
Contributor Author

iuioiua commented Sep 28, 2023

I think the more common use case would be if the env variable set in .env was already in the process environment, rather than the use case of duplication in the .env file. I think the behaviour is the same (the process env value is not overwritten), but it might be worth explicitly stating this in the docs.

I've updated the command description.

It's not too complicated, but there are some differences between the variable expansion (see https://github.com/motdotla/dotenv-expand/blob/master/tests/.env).

I've updated tests to match those, which are expectedly now failing. Is that what you'd like us to aim towards, @dsherret?

I looked into this a bit and started extracting out some of the code from deno_task_shell, which will help us get this feature exactly how we like it and improve future integration.

Can you elaborate on how this is done?

@dsherret
Copy link
Member

dsherret commented Oct 3, 2023

I looked into this a bit and started extracting out some of the code from deno_task_shell, which will help us get this feature exactly how we like it and improve future integration.

Can you elaborate on how this is done?

Extracted out some of the parsing functions and repurposed them. I haven't worked on it for a few weeks and it currently doesn't compile.

I've updated tests to match those, which are expectedly now failing. Is that what you'd like us to aim towards, @dsherret?

I think we can just merge this with dotenvy as a first pass.

cli/args/mod.rs Outdated
Comment on lines 655 to 663
if let Some(env_file_name) = &flags.env_file {
from_filename(env_file_name).unwrap_or_else(|_| {
panic!(
"Unable to load '{}' environment variable file",
env_file_name.as_str()
)
});
}

Copy link
Contributor Author

@iuioiua iuioiua Oct 31, 2023

Choose a reason for hiding this comment

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

Panicking seems wrong to me. How would we like to handle the error?

Copy link
Member

Choose a reason for hiding this comment

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

Use bail! instead which will return an error

@iuioiua
Copy link
Contributor Author

iuioiua commented Nov 1, 2023

Alright, I think this is ready. I've completed up to what I can, for now. I'm unsure how to do the present and missing env file tests for the compile and install sub-commands or if they're even needed. If they are needed, please go ahead and make any changes necessary. Hopefully, we can land this for the next release.

@dsherret dsherret changed the title feat: deno run --env feat(unstable): deno run --env Nov 1, 2023
Copy link
Member

@dsherret dsherret left a comment

Choose a reason for hiding this comment

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

LGTM. Thanks @iuioiua!

Let's land this as unstable then circle back with other fixes and improvements in the coming releases.

@dsherret dsherret enabled auto-merge (squash) November 1, 2023 14:05
@dsherret dsherret merged commit f8f4e77 into denoland:main Nov 1, 2023
@iuioiua iuioiua deleted the env-file branch November 1, 2023 18:47
@iuioiua
Copy link
Contributor Author

iuioiua commented Nov 1, 2023

Nice! Thanks for making the finishing touches. Sorry it took so long 😅

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.

5 participants