From 5b52aa00059ccac6c91c969e931409dba97bff5b Mon Sep 17 00:00:00 2001 From: Ivan Ogasawara Date: Thu, 14 Dec 2023 16:12:36 -0400 Subject: [PATCH] add more features --- .envers/data.lock | 22 ++++----- .envers/specs.yaml | 4 +- README.md | 4 +- src/envers/cli.py | 18 ++++---- src/envers/core.py | 111 ++++++++++++++++++++++++++++++++++++--------- 5 files changed, 112 insertions(+), 47 deletions(-) diff --git a/.envers/data.lock b/.envers/data.lock index 519715c..7bf08dd 100644 --- a/.envers/data.lock +++ b/.envers/data.lock @@ -1,8 +1,7 @@ version: 0.1 releases: - '2.0': + '1.0': spec: - status: draft docs: '' profiles: - base @@ -23,23 +22,17 @@ releases: type: string default: '1.0' encrypted: false - USE_CONTAINER: - type: bool - default: true - encrypted: false data: base: files: .env: type: dotenv vars: - ENV: dev - PROJECT_NAME: envers - VERSION: '1.0' - USE_CONTAINER: true - '1.0': + ENV: staging + PROJECT_NAME: sugar + VERSION: '1.2' + '2.0': spec: - status: draft docs: '' profiles: - base @@ -60,6 +53,10 @@ releases: type: string default: '1.0' encrypted: false + USE_CONTAINER: + type: bool + default: true + encrypted: false data: base: files: @@ -69,3 +66,4 @@ releases: ENV: dev PROJECT_NAME: envers VERSION: '1.0' + USE_CONTAINER: true diff --git a/.envers/specs.yaml b/.envers/specs.yaml index 02fb554..79f0052 100644 --- a/.envers/specs.yaml +++ b/.envers/specs.yaml @@ -1,7 +1,7 @@ version: 0.1 releases: '1.0': - status: draft + status: deployed docs: '' profiles: - base @@ -23,7 +23,7 @@ releases: default: '1.0' encrypted: false '2.0': - status: draft + status: deployed docs: '' profiles: - base diff --git a/README.md b/README.md index 7cd08a8..31e0102 100644 --- a/README.md +++ b/README.md @@ -39,10 +39,8 @@ Below are the initial subcommands for `envers`: Create a new version draft in the spec file. Some variants of this command: - `envers draft --from ` - `envers draft --from-env .env` -- `envers profile set --profile --spec `: +- `envers profile-set --profile --spec `: Add new content. -- `envers profile update --profile --spec `: - Update existing content. - `envers profile load --profile prod --spec `: Load a specific environment profile to files - `envers profile versions --profile --spec `: diff --git a/src/envers/cli.py b/src/envers/cli.py index b24dcac..85cbb20 100644 --- a/src/envers/cli.py +++ b/src/envers/cli.py @@ -77,15 +77,17 @@ def profile_set( @app.command() -def profile_update(profile_name: str, spec_version: str) -> None: - """Update existing content of a profile.""" - print(profile_name, spec_version) - - -@app.command() -def profile_load(profile: str, spec: str) -> None: +def profile_load( + profile: Annotated[ + str, typer.Option(help="The name of the profile to set values for.") + ] = "", + spec: Annotated[ + str, typer.Option(help="The version of the spec to use.") + ] = "", +) -> None: """Load a specific environment profile to files.""" - print(profile, spec) + envers = Envers() + envers.profile_load(profile, spec) @app.command() diff --git a/src/envers/core.py b/src/envers/core.py index 3ddbbf6..be5822d 100644 --- a/src/envers/core.py +++ b/src/envers/core.py @@ -156,7 +156,7 @@ def deploy(self, version: str) -> None: None """ specs_file = Path(".envers") / ENVERS_SPEC_FILENAME - data_lock_file = Path(".envers") / "data.lock" + data_file = Path(".envers") / "data.lock" if not specs_file.exists(): typer.echo("Spec file not found. Please initialize envers first.") @@ -169,11 +169,21 @@ def deploy(self, version: str) -> None: typer.echo(f"Version {version} not found in specs.yaml.") raise typer.Exit() - spec = specs["releases"][version] + spec = copy.deepcopy(specs["releases"][version]) + + # all data in the data.lock file are deployed + del spec["status"] - if data_lock_file.exists(): - with open(data_lock_file, "r") as file: + if data_file.exists(): + with open(data_file, "r") as file: data_lock = yaml.safe_load(file) or {} + + if not data_lock: + typer.echo("data.lock is not valid. Creating a new file.") + data_lock = { + "version": specs["version"], + "releases": {}, + } data_lock["releases"][version] = {"spec": spec, "data": {}} else: data_lock = { @@ -197,9 +207,13 @@ def deploy(self, version: str) -> None: profile_data["files"][file_path] = file_data data_lock["releases"][version]["data"][profile_name] = profile_data - with open(data_lock_file, "w") as file: + with open(data_file, "w") as file: yaml.dump(data_lock, file, sort_keys=False) + with open(specs_file, "w") as file: + specs["releases"][version]["status"] = "deployed" + yaml.dump(specs, file, sort_keys=False) + def profile_set(self, profile: str, spec: str) -> None: """ Set the profile values for a given spec version. @@ -215,15 +229,15 @@ def profile_set(self, profile: str, spec: str) -> None: ------- None """ - data_lock_file = Path(".envers") / "data.lock" + data_file = Path(".envers") / "data.lock" - if not data_lock_file.exists(): + if not data_file.exists(): typer.echo( "Data lock file not found. Please deploy a version first." ) raise typer.Exit() - with open(data_lock_file, "r") as file: + with open(data_file, "r") as file: data_lock = yaml.safe_load(file) or {} if not data_lock.get("releases", {}).get(spec, ""): @@ -231,28 +245,81 @@ def profile_set(self, profile: str, spec: str) -> None: raise typer.Exit() release_data = data_lock["releases"][spec] - spec_data = release_data.get("spec", {}) - profile_data = release_data.get("data", {}).get(profile, {"files": {}}) + profile_data = release_data.get("data", {}).get(profile, {}) + + if not (profile_data and profile_data.get("files", {})): + typer.echo( + f"There is no data spec for version '{spec}' " + f"and profile '{profile}'" + ) + raise typer.Exit() # Iterate over files and variables - for file_path, file_info in spec_data.get("files", {}).items(): + profile_title = f"Profile: {profile}" + typer.echo(f"{profile_title}\n{'=' * len(profile_title)}") + for file_path, file_info in profile_data.get("files", {}).items(): + file_title = f"File: {file_path}" + typer.echo(f"{file_title}\n{'-' * len(file_title)}") for var_name, var_info in file_info.get("vars", {}).items(): - current_value = ( - profile_data.get("files", {}) - .get(file_path, {}) - .get("vars", {}) - .get(var_name, var_info.get("default", "")) - ) + current_value = var_info new_value = typer.prompt( - f"Enter value for {var_name} in {file_path} " - f"(Profile: {profile})", + f"Enter value for `{var_name}`", default=current_value, ) - if not profile_data.get("files", {}).get(file_path, {}): - profile_data["files"][file_path] = {"vars": {}} profile_data["files"][file_path]["vars"][var_name] = new_value # Update data.lock file data_lock["releases"][spec]["data"][profile] = profile_data - with open(data_lock_file, "w") as file: + with open(data_file, "w") as file: yaml.dump(data_lock, file, sort_keys=False) + + def profile_load(self, profile: str, spec: str) -> None: + """ + Load a specific environment profile to files. + + Load a specific environment profile to files based on the given + spec version. + + Parameters + ---------- + profile : str + The name of the profile to load. + spec : str + The version of the spec to use. + + Returns + ------- + None + """ + data_lock_file = Path(".envers") / "data.lock" + + if not data_lock_file.exists(): + typer.echo( + "Data lock file not found. Please deploy a version first." + ) + raise typer.Exit() + + with open(data_lock_file, "r") as file: + data_lock = yaml.safe_load(file) or {} + + if not data_lock.get("releases", {}).get(spec, ""): + typer.echo(f"Version {spec} not found in data.lock.") + raise typer.Exit() + + release_data = data_lock["releases"][spec] + profile_data = release_data.get("data", {}).get(profile, {"files": {}}) + + # Iterate over files and variables + for file_path, file_info in profile_data.get("files", {}).items(): + file_content = "" + for var_name, var_value in file_info.get("vars", {}).items(): + file_content += f"{var_name}={var_value}\n" + + # Create or update the file + with open(file_path, "w") as file: + file.write(file_content) + + typer.echo( + f"Environment files for profile '{profile}' and spec version " + f"'{spec}' have been created/updated." + )