diff --git a/changelog.d/20230926_172753_codewithemad_config_loaded_action.md b/changelog.d/20230926_172753_codewithemad_config_loaded_action.md new file mode 100644 index 0000000..588d4da --- /dev/null +++ b/changelog.d/20230926_172753_codewithemad_config_loaded_action.md @@ -0,0 +1 @@ +- 💥[Feature] New action introduced: CONFIG_LOADED. This actions is called whenever the config is loaded. (by @CodeWithEmad) \ No newline at end of file diff --git a/tutor/commands/config.py b/tutor/commands/config.py index abcdc03..58e1833 100644 --- a/tutor/commands/config.py +++ b/tutor/commands/config.py @@ -114,7 +114,7 @@ class ConfigListKeyValParamType(ConfigKeyValParamType): type=ConfigListKeyValParamType(), multiple=True, metavar="KEY=VAL", - help="Append an item to a configuration value of type list. The value will only be added it it is not already present. (can be used multiple times)", + help="Append an item to a configuration value of type list. The value will only be added if it is not already present. (can be used multiple times)", ) @click.option( "-A", @@ -147,16 +147,18 @@ def save( env_only: bool, ) -> None: config = tutor_config.load_minimal(context.root) - config_full = tutor_config.load_full(context.root) if interactive: interactive_config.ask_questions(config) if set_vars: for key, value in set_vars: config[key] = env.render_unknown(config, value) if append_vars: + config_defaults = tutor_config.load_defaults() for key, value in append_vars: if key not in config: - config[key] = config_full.get(key, []) + config[key] = config[key] = config.get( + key, config_defaults.get(key, []) + ) values = config[key] if not isinstance(values, list): raise exceptions.TutorError( diff --git a/tutor/config.py b/tutor/config.py index a5e1eca..d343394 100644 --- a/tutor/config.py +++ b/tutor/config.py @@ -1,4 +1,5 @@ from __future__ import annotations +from copy import deepcopy import os @@ -26,6 +27,15 @@ def load(root: str) -> Config: return load_full(root) +def load_defaults() -> Config: + """ + Load default configuration. + """ + config: Config = {} + update_with_defaults(config) + return config + + def load_minimal(root: str) -> Config: """ Load a minimal configuration composed of the user and the base config. @@ -51,6 +61,7 @@ def load_full(root: str) -> Config: update_with_base(config) update_with_defaults(config) render_full(config) + hooks.Actions.CONFIG_LOADED.do(deepcopy(config)) return config @@ -319,3 +330,19 @@ def _update_enabled_plugins_on_unload(_plugin: str, _root: str, config: Config) Note that this action must be performed after the plugin has been unloaded, hence the low priority. """ save_enabled_plugins(config) + + +@hooks.Actions.CONFIG_LOADED.add() +def _check_preview_lms_host(config: Config) -> None: + """ + This will check if the PREVIEW_LMS_HOST is a subdomain of LMS_HOST. + if not, prints a warning to notify the user. + """ + + lms_host = get_typed(config, "LMS_HOST", str, "") + preview_lms_host = get_typed(config, "PREVIEW_LMS_HOST", str, "") + if not preview_lms_host.endswith("." + lms_host): + fmt.echo_alert( + f'Warning: PREVIEW_LMS_HOST="{preview_lms_host}" is not a subdomain of LMS_HOST="{lms_host}". ' + "This configuration is not typically recommended and may lead to unexpected behavior." + ) diff --git a/tutor/hooks/catalog.py b/tutor/hooks/catalog.py index 2f62810..66ed97a 100644 --- a/tutor/hooks/catalog.py +++ b/tutor/hooks/catalog.py @@ -57,6 +57,13 @@ class Actions: #: :parameter str name: docker-compose project name. COMPOSE_PROJECT_STARTED: Action[[str, Config, str]] = Action() + #: This action is called at the end of the tutor.config.load_full function. + #: Modifying this object will not trigger changes in the configuration. + #: For all purposes, it should be considered read-only. + #: + #: :parameter dict config: project configuration. + CONFIG_LOADED: Action[[Config]] = Action() + #: Called whenever the core project is ready to run. This action is called as soon #: as possible. This is the right time to discover plugins, for instance. In #: particular, we auto-discover the following plugins: