From cf0f7541f0d99af852e94c518d2ef7849331b852 Mon Sep 17 00:00:00 2001 From: Adam Lewis <23342526+Adam-D-Lewis@users.noreply.github.com> Date: Mon, 17 Jun 2024 14:19:34 -0500 Subject: [PATCH] Explicit config (#2294) Co-authored-by: Fangchen Li <fangchen.li@outlook.com> Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Amit Kumar <dtu.amit@gmail.com> Co-authored-by: Vinicius D. Cerutti <51954708+viniciusdc@users.noreply.github.com> --- src/_nebari/config.py | 3 ++- src/_nebari/subcommands/init.py | 19 ++++++++++++++++- src/nebari/plugins.py | 2 +- src/nebari/schema.py | 4 +++- tests/tests_unit/test_cli_init.py | 34 +++++++++++++++++++------------ 5 files changed, 45 insertions(+), 17 deletions(-) diff --git a/src/_nebari/config.py b/src/_nebari/config.py index 7c27274f36..9d7dec4bd4 100644 --- a/src/_nebari/config.py +++ b/src/_nebari/config.py @@ -103,7 +103,8 @@ def write_configuration( """Write the nebari configuration file to disk""" with config_filename.open(mode) as f: if isinstance(config, pydantic.BaseModel): - yaml.dump(config.model_dump(), f) + config_dict = config.model_dump() + yaml.dump(config_dict, f) else: config = dump_nested_model(config) yaml.dump(config, f) diff --git a/src/_nebari/subcommands/init.py b/src/_nebari/subcommands/init.py index 9040f3d201..8c3de6d5b2 100644 --- a/src/_nebari/subcommands/init.py +++ b/src/_nebari/subcommands/init.py @@ -106,6 +106,7 @@ class InitInputs(schema.Base): ssl_cert_email: Optional[schema.email_pydantic] = None disable_prompt: bool = False output: pathlib.Path = pathlib.Path("nebari-config.yaml") + explicit: int = 0 def enum_to_list(enum_cls): @@ -152,7 +153,7 @@ def handle_init(inputs: InitInputs, config_schema: BaseModel): try: write_configuration( inputs.output, - config, + config if not inputs.explicit else config_schema(**config), mode="x", ) except FileExistsError: @@ -565,6 +566,13 @@ def init( "-o", help="Output file path for the rendered config file.", ), + explicit: int = typer.Option( + 0, + "--explicit", + "-e", + count=True, + help="Write explicit nebari config file (advanced users only).", + ), ): """ Create and initialize your [purple]nebari-config.yaml[/purple] file. @@ -604,6 +612,7 @@ def init( inputs.ssl_cert_email = ssl_cert_email inputs.disable_prompt = disable_prompt inputs.output = output + inputs.explicit = explicit from nebari.plugins import nebari_plugin_manager @@ -894,6 +903,14 @@ def guided_init_wizard(ctx: typer.Context, guided_init: str): ) inputs.kubernetes_version = kubernetes_version + # EXPLICIT CONFIG + inputs.explicit = questionary.confirm( + "Would you like the nebari config to show all available options? (recommended for advanced users only)", + default=False, + qmark=qmark, + auto_enter=False, + ).unsafe_ask() + from nebari.plugins import nebari_plugin_manager config_schema = nebari_plugin_manager.config_schema diff --git a/src/nebari/plugins.py b/src/nebari/plugins.py index c5148e9e1d..a523c0324f 100644 --- a/src/nebari/plugins.py +++ b/src/nebari/plugins.py @@ -128,7 +128,7 @@ def config_schema(self): classes = [schema.Main] + [ _.input_schema for _ in self.ordered_stages if _.input_schema is not None ] - return type("ConfigSchema", tuple(classes), {}) + return type("ConfigSchema", tuple(classes[::-1]), {}) nebari_plugin_manager = NebariPluginManager() diff --git a/src/nebari/schema.py b/src/nebari/schema.py index 70b9589e6f..2cc1c1ea3f 100644 --- a/src/nebari/schema.py +++ b/src/nebari/schema.py @@ -25,7 +25,9 @@ class Base(pydantic.BaseModel): model_config = ConfigDict( - extra="forbid", validate_assignment=True, populate_by_name=True + extra="forbid", + validate_assignment=True, + populate_by_name=True, ) diff --git a/tests/tests_unit/test_cli_init.py b/tests/tests_unit/test_cli_init.py index 0cd0fe03d2..9afab5ddc5 100644 --- a/tests/tests_unit/test_cli_init.py +++ b/tests/tests_unit/test_cli_init.py @@ -51,6 +51,8 @@ (["--ssl-cert-email"], 2, ["requires an argument"]), (["--output"], 2, ["requires an argument"]), (["-o"], 2, ["requires an argument"]), + (["--explicit"], 2, ["Missing option"]), + (["-e"], 2, ["Missing option"]), ], ) def test_cli_init_stdout(args: List[str], exit_code: int, content: List[str]): @@ -90,20 +92,22 @@ def generate_test_data_test_cli_init_happy_path(): ) in get_kubernetes_versions(provider) + [ "latest" ]: - test_data.append( - ( - provider, - region, - project_name, - domain_name, - namespace, - auth_provider, - ci_provider, - terraform_state, - email, - kubernetes_version, + for explicit in [True, False]: + test_data.append( + ( + provider, + region, + project_name, + domain_name, + namespace, + auth_provider, + ci_provider, + terraform_state, + email, + kubernetes_version, + explicit, + ) ) - ) keys = [ "provider", @@ -116,6 +120,7 @@ def generate_test_data_test_cli_init_happy_path(): "terraform_state", "email", "kubernetes_version", + "explicit", ] return {"keys": keys, "test_data": test_data} @@ -131,6 +136,7 @@ def test_cli_init_happy_path( terraform_state: str, email: str, kubernetes_version: str, + explicit: bool, ): app = create_cli() args = [ @@ -159,6 +165,8 @@ def test_cli_init_happy_path( "--region", region, ] + if explicit: + args += ["--explicit"] expected_yaml = f""" provider: {provider}