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: Support list of env files #506

Merged
merged 11 commits into from
Feb 22, 2024
8 changes: 6 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ web_modules/

# dotenv environment variables file
.env
.env.test
.env.*

# parcel-bundler cache (https://parceljs.org/)
.cache
Expand Down Expand Up @@ -385,4 +385,8 @@ archive/
_build/

# Pytest Setup
/module/
/module/

# Testing
seedfarmer.yaml
tmp-metadata
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ This project adheres to [Semantic Versioning](http://semver.org/) and [Keep a Ch

### New

- support list of env files using `--env-file`

### Changes

### Fixes
Expand Down
22 changes: 15 additions & 7 deletions seedfarmer/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@

import logging
import os
from typing import Optional
from typing import List, Optional

import click
from dotenv import load_dotenv
Expand Down Expand Up @@ -65,8 +65,10 @@ def version() -> None:
)
@click.option(
"--env-file",
default=".env",
"env_files",
default=[".env"],
help="A relative path to the .env file to load environment variables from",
multiple=True,
required=False,
)
@click.option(
Expand Down Expand Up @@ -109,7 +111,7 @@ def apply(
profile: Optional[str],
region: Optional[str],
qualifier: Optional[str],
env_file: str,
env_files: List[str],
debug: bool,
dry_run: bool,
show_manifest: bool,
Expand All @@ -121,7 +123,9 @@ def apply(
enable_debug(format=DEBUG_LOGGING_FORMAT)

# Load environment variables from .env file if it exists
load_dotenv(dotenv_path=os.path.join(config.OPS_ROOT, env_file), verbose=True, override=True)
for env_file in env_files:
_logger.info("Loading environment variables from %s", env_file)
load_dotenv(dotenv_path=os.path.join(config.OPS_ROOT, env_file), verbose=True, override=True)

_logger.info("Apply request with manifest %s", spec)
if dry_run:
Expand Down Expand Up @@ -177,8 +181,10 @@ def apply(
)
@click.option(
"--env-file",
default=".env",
"env_files",
default=[".env"],
help="A relative path to the .env file to load environment variables from",
multiple=True,
required=False,
)
@click.option(
Expand Down Expand Up @@ -208,7 +214,7 @@ def destroy(
profile: Optional[str],
region: Optional[str],
qualifier: Optional[str],
env_file: str,
env_files: List[str],
debug: bool,
enable_session_timeout: bool,
session_timeout_interval: int,
Expand All @@ -218,7 +224,9 @@ def destroy(
enable_debug(format=DEBUG_LOGGING_FORMAT)

# Load environment variables from .env file if it exists
load_dotenv(dotenv_path=os.path.join(config.OPS_ROOT, env_file), verbose=True, override=True)
for env_file in env_files:
_logger.info("Loading environment variables from %s", env_file)
load_dotenv(dotenv_path=os.path.join(config.OPS_ROOT, env_file), verbose=True, override=True)

# MUST use seedfarmer.yaml so we can initialize codeseeder configs
project = config.PROJECT
Expand Down
63 changes: 44 additions & 19 deletions seedfarmer/cli_groups/_list_group.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
import logging
import os
import sys
from typing import Optional
from typing import List, Optional

import click
from dotenv import load_dotenv
Expand Down Expand Up @@ -110,8 +110,10 @@ def list() -> None:
)
@click.option(
"--env-file",
default=".env",
"env_files",
default=[".env"],
help="A relative path to the .env file to load environment variables from",
multiple=True,
required=False,
)
@click.option(
Expand All @@ -128,7 +130,7 @@ def list_dependencies(
profile: Optional[str],
region: Optional[str],
qualifier: Optional[str],
env_file: str,
env_files: List[str],
debug: bool,
) -> None:
if debug:
Expand All @@ -137,7 +139,9 @@ def list_dependencies(

if project is None:
project = _load_project()
load_dotenv(dotenv_path=os.path.join(config.OPS_ROOT, env_file), verbose=True, override=True)

for env_file in env_files:
load_dotenv(dotenv_path=os.path.join(config.OPS_ROOT, env_file), verbose=True, override=True)

SessionManager().get_or_create(project_name=project, profile=profile, region_name=region, qualifier=qualifier)
dep_manifest = du.generate_deployed_manifest(deployment_name=deployment, skip_deploy_spec=True)
Expand Down Expand Up @@ -203,8 +207,10 @@ def list_dependencies(
)
@click.option(
"--env-file",
default=".env",
"env_files",
default=[".env"],
help="A relative path to the .env file to load environment variables from",
multiple=True,
required=False,
)
@click.option(
Expand All @@ -221,7 +227,7 @@ def list_deployspec(
profile: Optional[str],
region: Optional[str],
qualifier: Optional[str],
env_file: str,
env_files: List[str],
debug: bool,
) -> None:
if debug:
Expand All @@ -230,7 +236,9 @@ def list_deployspec(

if project is None:
project = _load_project()
load_dotenv(dotenv_path=os.path.join(config.OPS_ROOT, env_file), verbose=True, override=True)

for env_file in env_files:
load_dotenv(dotenv_path=os.path.join(config.OPS_ROOT, env_file), verbose=True, override=True)

session = SessionManager().get_or_create(
project_name=project, profile=profile, region_name=region, qualifier=qualifier
Expand Down Expand Up @@ -310,8 +318,10 @@ def list_deployspec(
)
@click.option(
"--env-file",
default=".env",
"env_files",
default=[".env"],
help="A relative path to the .env file to load environment variables from",
multiple=True,
required=False,
)
@click.option(
Expand All @@ -328,7 +338,7 @@ def list_module_metadata(
profile: Optional[str],
region: Optional[str],
qualifier: Optional[str],
env_file: str,
env_files: List[str],
export_local_env: bool,
debug: bool,
) -> None:
Expand All @@ -338,7 +348,9 @@ def list_module_metadata(

if project is None:
project = _load_project()
load_dotenv(dotenv_path=os.path.join(config.OPS_ROOT, env_file), verbose=True, override=True)

for env_file in env_files:
load_dotenv(dotenv_path=os.path.join(config.OPS_ROOT, env_file), verbose=True, override=True)

session = SessionManager().get_or_create(
project_name=project, profile=profile, region_name=region, qualifier=qualifier
Expand Down Expand Up @@ -407,8 +419,10 @@ def list_module_metadata(
)
@click.option(
"--env-file",
default=".env",
"env_files",
default=[".env"],
help="A relative path to the .env file to load environment variables from",
multiple=True,
required=False,
)
@click.option(
Expand All @@ -423,7 +437,7 @@ def list_all_module_metadata(
profile: Optional[str],
region: Optional[str],
qualifier: Optional[str],
env_file: str,
env_files: List[str],
debug: bool,
) -> None:
if debug:
Expand All @@ -432,7 +446,9 @@ def list_all_module_metadata(

if project is None:
project = _load_project()
load_dotenv(dotenv_path=os.path.join(config.OPS_ROOT, env_file), verbose=True, override=True)

for env_file in env_files:
load_dotenv(dotenv_path=os.path.join(config.OPS_ROOT, env_file), verbose=True, override=True)

session = SessionManager().get_or_create(
project_name=project, profile=profile, region_name=region, qualifier=qualifier
Expand Down Expand Up @@ -500,8 +516,10 @@ def list_all_module_metadata(
)
@click.option(
"--env-file",
default=".env",
"env_files",
default=[".env"],
help="A relative path to the .env file to load environment variables from",
multiple=True,
required=False,
)
@click.option(
Expand All @@ -516,7 +534,7 @@ def list_modules(
profile: Optional[str],
region: Optional[str],
qualifier: Optional[str],
env_file: str,
env_files: List[str],
debug: bool,
) -> None:
if debug:
Expand All @@ -525,7 +543,10 @@ def list_modules(

if project is None:
project = _load_project()
load_dotenv(dotenv_path=os.path.join(config.OPS_ROOT, env_file), verbose=True, override=True)

for env_file in env_files:
load_dotenv(dotenv_path=os.path.join(config.OPS_ROOT, env_file), verbose=True, override=True)

SessionManager().get_or_create(project_name=project, profile=profile, region_name=region, qualifier=qualifier)

dep_manifest = du.generate_deployed_manifest(deployment_name=deployment, skip_deploy_spec=True)
Expand Down Expand Up @@ -647,8 +668,10 @@ def list_deployments(
)
@click.option(
"--env-file",
default=".env",
"env_files",
default=[".env"],
help="A relative path to the .env file to load environment variables from",
multiple=True,
required=False,
)
@click.option(
Expand All @@ -666,7 +689,7 @@ def list_build_env_params(
profile: Optional[str],
region: Optional[str],
qualifier: Optional[str],
env_file: str,
env_files: List[str],
export_local_env: str,
debug: bool,
) -> None:
Expand All @@ -678,7 +701,9 @@ def list_build_env_params(

if project is None:
project = _load_project()
load_dotenv(dotenv_path=os.path.join(config.OPS_ROOT, env_file), verbose=True, override=True)

for env_file in env_files:
load_dotenv(dotenv_path=os.path.join(config.OPS_ROOT, env_file), verbose=True, override=True)

session = SessionManager().get_or_create(
project_name=project, profile=profile, region_name=region, qualifier=qualifier
Expand Down
75 changes: 75 additions & 0 deletions test/unit-test/test_cli_arg.py
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,47 @@ def test_apply_deployment(mocker):
command_output = _test_command(sub_command=apply, options=[deployment_manifest, "--debug"], exit_code=0)


@pytest.mark.first
@pytest.mark.apply_working_module
def test_apply_deployment__env_variables_no_env_file(mocker, caplog):
# Deploys a functioning module
mocker.patch("seedfarmer.__main__.commands.apply", return_value=None)
deployment_manifest = f"{_TEST_ROOT}/manifests/module-test/deployment.yaml"

_test_command(sub_command=apply, options=[deployment_manifest, "--debug"], exit_code=0)

env_messages = [msg for msg in caplog.messages if msg.startswith("Loading environment variables from ")]
assert env_messages == ["Loading environment variables from .env"]


@pytest.mark.first
@pytest.mark.apply_working_module
def test_apply_deployment__env_variables_single_env_file(mocker, caplog):
# Deploys a functioning module
mocker.patch("seedfarmer.__main__.commands.apply", return_value=None)
deployment_manifest = f"{_TEST_ROOT}/manifests/module-test/deployment.yaml"

env_file = ".env.test"
_test_command(sub_command=apply, options=[deployment_manifest, "--debug", "--env-file", env_file], exit_code=0)

env_messages = [msg for msg in caplog.messages if msg.startswith("Loading environment variables from ")]
assert env_messages == [f"Loading environment variables from {env_file}"]


@pytest.mark.first
@pytest.mark.apply_working_module
def test_apply_deployment__env_variables_multiple_env_files(mocker, caplog):
# Deploys a functioning module
mocker.patch("seedfarmer.__main__.commands.apply", return_value=None)
deployment_manifest = f"{_TEST_ROOT}/manifests/module-test/deployment.yaml"

env_files = [".env.test", ".env.test2"]
_test_command(sub_command=apply, options=[deployment_manifest, "--debug", "--env-file", env_files[0], "--env-file", env_files[1]], exit_code=0)

env_messages = [msg for msg in caplog.messages if msg.startswith("Loading environment variables from ")]
assert env_messages == [f"Loading environment variables from {env_file}" for env_file in env_files]


@pytest.mark.destroy
def test_destroy_deployment_dry_run(mocker):
# Destroy a functioning module
Expand All @@ -175,6 +216,40 @@ def test_destroy_deployment(mocker):
command_output = _test_command(sub_command=destroy, options=["myapp", "--debug"], exit_code=0)


@pytest.mark.destroy
def test_destroy__deployment_env_variables_no_env_file(mocker, caplog):
# Destroy a functioning module
mocker.patch("seedfarmer.__main__.commands.destroy", return_value=None)
_test_command(sub_command=destroy, options=["myapp", "--debug"], exit_code=0)

env_messages = [msg for msg in caplog.messages if msg.startswith("Loading environment variables from ")]
assert env_messages == ["Loading environment variables from .env"]


@pytest.mark.destroy
def test_destroy__deployment_env_variables_single_env_file(mocker, caplog):
# Destroy a functioning module
mocker.patch("seedfarmer.__main__.commands.destroy", return_value=None)

env_file = ".env.test"
_test_command(sub_command=destroy, options=["myapp", "--debug", "--env-file", env_file], exit_code=0)

env_messages = [msg for msg in caplog.messages if msg.startswith("Loading environment variables from ")]
assert env_messages == [f"Loading environment variables from {env_file}"]


@pytest.mark.destroy
def test_destroy__deployment_env_variables_multiple_env_files(mocker, caplog):
# Destroy a functioning module
mocker.patch("seedfarmer.__main__.commands.destroy", return_value=None)

env_files = [".env.test", ".env.test2"]
_test_command(sub_command=destroy, options=["myapp", "--debug", "--env-file", env_files[0], "--env-file", env_files[1]], exit_code=0)

env_messages = [msg for msg in caplog.messages if msg.startswith("Loading environment variables from ")]
assert env_messages == [f"Loading environment variables from {env_file}" for env_file in env_files]


@pytest.mark.bootstrap
def test_bootstrap_toolchain_only(mocker):
# Bootstrap an Account As Target
Expand Down
Loading