mirror of
https://github.com/ChristianLight/tutor.git
synced 2025-01-24 14:08:23 +00:00
feat: cleanup flag (#1086)
This will add a `-c` / `--clean` flag to the save command and ensure that the env directory is deleted if it exists. Close https://github.com/overhangio/tutor/issues/967
This commit is contained in:
parent
6cdedddd22
commit
46b401690c
1
changelog.d/20240629_120748_codewithemad_cleanup_flag.md
Normal file
1
changelog.d/20240629_120748_codewithemad_cleanup_flag.md
Normal file
@ -0,0 +1 @@
|
||||
- [Feature] Added `-c` or `--clean` option to tutor config save: For plugin developers and advanced users, this option cleans the `env/` folder before saving, ensuring a fresh environment for testing and development. (by @CodeWithEmad)
|
@ -106,7 +106,7 @@ You should then re-build the "openedx" Docker image to pick up your changes::
|
||||
|
||||
tutor images build openedx-dev
|
||||
|
||||
Then, whenever you run ``tutor dev start``, the "lms" and "cms" container should automatically hot-reload your changes.
|
||||
Then, whenever you run ``tutor dev start``, the "lms" and "cms" containers should automatically hot-reload your changes.
|
||||
|
||||
To push your changes in production, you should do the same with ``tutor local`` and the "openedx" image::
|
||||
|
||||
|
@ -17,6 +17,11 @@ class ConfigTests(unittest.TestCase, TestCommandMixin):
|
||||
self.assertFalse(result.exception)
|
||||
self.assertEqual(0, result.exit_code)
|
||||
|
||||
def test_config_save_cleanup_env_dir(self) -> None:
|
||||
result = self.invoke(["config", "save", "-c"])
|
||||
self.assertFalse(result.exception)
|
||||
self.assertEqual(0, result.exit_code)
|
||||
|
||||
def test_config_save_interactive(self) -> None:
|
||||
result = self.invoke(["config", "save", "-i"])
|
||||
self.assertFalse(result.exception)
|
||||
|
@ -48,7 +48,7 @@ class ConfigTests(unittest.TestCase):
|
||||
with patch.object(click, "prompt", new=mock_prompt):
|
||||
with patch.object(click, "confirm", new=mock_prompt):
|
||||
config = tutor_config.load_minimal(rootdir)
|
||||
interactive.ask_questions(config)
|
||||
interactive.ask_questions(config, rootdir)
|
||||
|
||||
self.assertIn("MYSQL_ROOT_PASSWORD", config)
|
||||
self.assertEqual(8, len(get_typed(config, "MYSQL_ROOT_PASSWORD", str)))
|
||||
|
@ -187,12 +187,18 @@ Press enter when you are ready to continue"""
|
||||
|
||||
|
||||
def interactive_configuration(
|
||||
context: click.Context, interactive: bool, run_for_prod: t.Optional[bool] = None
|
||||
context: click.Context,
|
||||
interactive: bool,
|
||||
run_for_prod: t.Optional[bool] = None,
|
||||
) -> None:
|
||||
click.echo(fmt.title("Interactive platform configuration"))
|
||||
config = tutor_config.load_minimal(context.obj.root)
|
||||
if interactive:
|
||||
interactive_config.ask_questions(config, run_for_prod=run_for_prod)
|
||||
click.echo(fmt.title("Interactive platform configuration"))
|
||||
interactive_config.ask_questions(
|
||||
config,
|
||||
context.obj.root,
|
||||
run_for_prod=run_for_prod,
|
||||
)
|
||||
tutor_config.save_config_file(context.obj.root, config)
|
||||
config = tutor_config.load_full(context.obj.root)
|
||||
tutor_env.save(context.obj.root, config)
|
||||
|
@ -136,6 +136,13 @@ class ConfigListKeyValParamType(ConfigKeyValParamType):
|
||||
@click.option(
|
||||
"-e", "--env-only", "env_only", is_flag=True, help="Skip updating config.yml"
|
||||
)
|
||||
@click.option(
|
||||
"-c",
|
||||
"--clean",
|
||||
"clean_env",
|
||||
is_flag=True,
|
||||
help="Remove everything in the env directory before save",
|
||||
)
|
||||
@click.pass_obj
|
||||
def save(
|
||||
context: Context,
|
||||
@ -145,10 +152,13 @@ def save(
|
||||
remove_vars: list[tuple[str, t.Any]],
|
||||
unset_vars: list[str],
|
||||
env_only: bool,
|
||||
clean_env: bool,
|
||||
) -> None:
|
||||
config = tutor_config.load_minimal(context.root)
|
||||
if interactive:
|
||||
interactive_config.ask_questions(config)
|
||||
interactive_config.ask_questions(config, context.root, clean_env_prompt=True)
|
||||
if clean_env:
|
||||
env.delete_env_dir(context.root)
|
||||
if set_vars:
|
||||
for key, value in set_vars:
|
||||
config[key] = env.render_unknown(config, value)
|
||||
|
@ -225,10 +225,10 @@ def launch(context: click.Context, non_interactive: bool) -> None:
|
||||
from_release=tutor_env.get_env_release(context.obj.root),
|
||||
)
|
||||
|
||||
click.echo(fmt.title("Interactive platform configuration"))
|
||||
config = tutor_config.load_minimal(context.obj.root)
|
||||
if not non_interactive:
|
||||
interactive_config.ask_questions(config, run_for_prod=True)
|
||||
click.echo(fmt.title("Interactive platform configuration"))
|
||||
interactive_config.ask_questions(config, context.obj.root, run_for_prod=True)
|
||||
tutor_config.save_config_file(context.obj.root, config)
|
||||
config = tutor_config.load_full(context.obj.root)
|
||||
tutor_env.save(context.obj.root, config)
|
||||
|
@ -99,7 +99,7 @@ def plugins_command() -> None:
|
||||
|
||||
@click.command(
|
||||
short_help="Print the location of file-based plugins",
|
||||
help=f"""Print the location of yaml-based plugins: nboth python v1 and yaml v0 plugins. This location can be manually
|
||||
help=f"""Print the location of yaml-based plugins: both python v1 and yaml v0 plugins. This location can be manually
|
||||
defined by setting the {PLUGINS_ROOT_ENV_VAR_NAME} environment variable""",
|
||||
)
|
||||
def printroot() -> None:
|
||||
|
14
tutor/env.py
14
tutor/env.py
@ -533,6 +533,20 @@ def root_dir(root: str) -> str:
|
||||
return os.path.abspath(root)
|
||||
|
||||
|
||||
def delete_env_dir(root: str) -> None:
|
||||
env_path = base_dir(root)
|
||||
|
||||
try:
|
||||
shutil.rmtree(env_path)
|
||||
fmt.echo_alert(f"Removed existing Tutor environment at: {env_path}")
|
||||
except PermissionError:
|
||||
raise exceptions.TutorError(
|
||||
f"Permission Denied while trying to remove existing Tutor environment at: {env_path}"
|
||||
)
|
||||
except FileNotFoundError:
|
||||
fmt.echo_info(f"No existing Tutor environment to remove at: {env_path}")
|
||||
|
||||
|
||||
@hooks.Actions.PLUGIN_UNLOADED.add()
|
||||
def _delete_plugin_templates(plugin: str, root: str, _config: Config) -> None:
|
||||
"""
|
||||
|
@ -7,7 +7,12 @@ from . import env, exceptions, fmt, hooks
|
||||
from .types import Config, get_typed
|
||||
|
||||
|
||||
def ask_questions(config: Config, run_for_prod: Optional[bool] = None) -> None:
|
||||
def ask_questions(
|
||||
config: Config,
|
||||
root: str,
|
||||
run_for_prod: Optional[bool] = None,
|
||||
clean_env_prompt: bool = False,
|
||||
) -> None:
|
||||
"""
|
||||
Interactively ask questions to collect configuration values from the user.
|
||||
|
||||
@ -15,6 +20,10 @@ def ask_questions(config: Config, run_for_prod: Optional[bool] = None) -> None:
|
||||
config: Existing (or minimal) configuration. Modified in-place.
|
||||
run_for_prod: Whether platform should be configured for production.
|
||||
If None, then ask the user.
|
||||
clean_env_prompt: Whether to show the clean environment prompt before running.
|
||||
defaults to False.
|
||||
Returns:
|
||||
None
|
||||
"""
|
||||
defaults = tutor_config.get_defaults()
|
||||
if run_for_prod is None:
|
||||
@ -148,6 +157,14 @@ def ask_questions(config: Config, run_for_prod: Optional[bool] = None) -> None:
|
||||
config,
|
||||
defaults,
|
||||
)
|
||||
if clean_env_prompt:
|
||||
run_clean = click.confirm(
|
||||
fmt.question("Remove existing Tutor environment directory?"),
|
||||
prompt_suffix=" ",
|
||||
default=True,
|
||||
)
|
||||
if run_clean:
|
||||
env.delete_env_dir(root)
|
||||
|
||||
hooks.Actions.CONFIG_INTERACTIVE.do(config)
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user