Skip to content

Commit

Permalink
Make envfile global and task level options also accept a list of values
Browse files Browse the repository at this point in the history
  • Loading branch information
nat-n committed Jun 18, 2022
1 parent e8159be commit 2e249c3
Show file tree
Hide file tree
Showing 10 changed files with 80 additions and 9 deletions.
25 changes: 21 additions & 4 deletions README.rst
Expand Up @@ -410,7 +410,10 @@ set by replacing the last line with the following:
serve.env.PORT.default = "9001"
You can also specify an env file (with bash-like syntax) to load per task like so:
Loading env vars from an env file
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

You can also specify one or more env files (with bash-like syntax) to load per task like so:

.. code-block:: bash
Expand All @@ -424,17 +427,29 @@ You can also specify an env file (with bash-like syntax) to load per task like s
serve.script = "myapp:run"
serve.envfile = ".env"
It it also possible to reference existing env vars when defining a new env var for a
The envfile option accepts the name (or relative path) to a single envfile as shown
above but can also by given a list of such paths like so:

.. code-block:: toml
serve.envfile = [".env", "local.env"]
In this case the referenced files will be loaded in the given order.

Defining env vars in terms of other env vars
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

It is also possible to reference existing env vars when defining a new env var for a
task. This may be useful for aliasing or extending a variable already defined in the
host environment, globally in the config, or in a referencd envfile. In the following
host environment, globally in the config, or in a referenced envfile. In the following
example the value from $TF_VAR_service_port on the host environment is also made
available as $FLASK_RUN_PORT within the task.

.. code-block:: toml
[tool.poe.tasks.serve]
serve.cmd = "flask run"
serve.env = { FLASK_RUN_PORT = "${TF_VAR_service_port}" }
serve.env = { FLASK_RUN_PORT = "${TF_VAR_service_port}" }
Declaring CLI arguments
Expand Down Expand Up @@ -711,6 +726,8 @@ You can also specify an env file (with bash-like syntax) to load for all tasks l
[tool.poe]
envfile = ".env"
The envfile global option also accepts a list of env files.

Default command verbosity
-------------------------

Expand Down
2 changes: 1 addition & 1 deletion poethepoet/config.py
Expand Up @@ -28,7 +28,7 @@ class PoeConfig:
"default_array_task_type": str,
"default_array_item_task_type": str,
"env": dict,
"envfile": str,
"envfile": (str, list),
"executor": dict,
"include": (str, list),
"poetry_command": str,
Expand Down
13 changes: 10 additions & 3 deletions poethepoet/env/manager.py
Expand Up @@ -42,8 +42,12 @@ def __init__(

if parent_env is None:
# Get env vars from envfile referenced in global options
if self._config.global_envfile is not None:
self._vars.update(self.envfiles.get(self._config.global_envfile))
global_envfile = self._config.global_envfile
if isinstance(global_envfile, str):
self._vars.update(self.envfiles.get(global_envfile))
elif isinstance(global_envfile, list):
for task_envfile_path in global_envfile:
self._vars.update(self.envfiles.get(task_envfile_path))

# Get env vars from global options
self._apply_env_config(self._config.global_env)
Expand Down Expand Up @@ -80,8 +84,11 @@ def for_task(
result = EnvVarsManager(self._config, self._ui, parent_env=self)

# Include env vars from envfile referenced in task options
if task_envfile is not None:
if isinstance(task_envfile, str):
result.update(self.envfiles.get(task_envfile))
elif isinstance(task_envfile, list):
for task_envfile_path in task_envfile:
result.update(self.envfiles.get(task_envfile_path))

# Include env vars from task options
if task_env is not None:
Expand Down
2 changes: 1 addition & 1 deletion poethepoet/task/base.py
Expand Up @@ -60,7 +60,7 @@ class PoeTask(metaclass=MetaPoeTask):
"capture_stdout": (str),
"deps": list,
"env": dict,
"envfile": str,
"envfile": (str, list),
"executor": dict,
"help": str,
"uses": dict,
Expand Down
6 changes: 6 additions & 0 deletions tests/fixtures/envfile_project/first.env
@@ -0,0 +1,6 @@
VAR_A=VAL_A
VAR_B=NOT_B
VAR_C=NOT_C
VAR_D=NOT_D
VAR_E=NOT_E
VAR_F=NOT_F
2 changes: 2 additions & 0 deletions tests/fixtures/envfile_project/fourth.env
@@ -0,0 +1,2 @@
VAR_E=VAL_E
VAR_F=NOT_F
10 changes: 10 additions & 0 deletions tests/fixtures/envfile_project/multiple_envfiles.toml
@@ -0,0 +1,10 @@
[tool.poe]
envfile = ["first.env", "second.env"]
env = { VAR_C = "VAL_C" }

[tool.poe.tasks.show_me_the_vals]
cmd = """
poe_test_echo "${VAR_A}-${VAR_B}-${VAR_C}-${VAR_D}-${VAR_E}-${VAR_F}!!"
"""
envfile = ["third.env", "fourth.env"]
env = { VAR_F = "VAL_F" }
5 changes: 5 additions & 0 deletions tests/fixtures/envfile_project/second.env
@@ -0,0 +1,5 @@
VAR_B=VAL_B
VAR_C=NOT_C
VAR_D=NOT_D
VAR_E=NOT_E
VAR_F=NOT_F
3 changes: 3 additions & 0 deletions tests/fixtures/envfile_project/third.env
@@ -0,0 +1,3 @@
VAR_D=VAL_D
VAR_E=NOT_E
VAR_F=NOT_F
21 changes: 21 additions & 0 deletions tests/test_envfile.py
Expand Up @@ -38,3 +38,24 @@ def test_task_envfile_and_default(run_poe_subproc, is_windows):
)
assert result.stdout == "deploying to admin:12345@prod.example.com/app\n"
assert result.stderr == ""


def test_multiple_envfiles(run_poe_subproc, projects, is_windows):
result = run_poe_subproc(
f'--root={projects["envfile/multiple_envfiles"]}', "show_me_the_vals"
)

if is_windows:
assert (
'Poe => poe_test_echo "VAL_A-VAL_B-VAL_C-VAL_D-VAL_E-VAL_F!!"\n'
in result.capture
)
assert result.stdout == '"VAL_A-VAL_B-VAL_C-VAL_D-VAL_E-VAL_F!!"\n'
assert result.stderr == ""
else:
assert (
"Poe => poe_test_echo VAL_A-VAL_B-VAL_C-VAL_D-VAL_E-VAL_F!!\n"
in result.capture
)
assert result.stdout == "VAL_A-VAL_B-VAL_C-VAL_D-VAL_E-VAL_F!!\n"
assert result.stderr == ""

0 comments on commit 2e249c3

Please sign in to comment.