Skip to content

Commit

Permalink
feat: clean up env directory before save
Browse files Browse the repository at this point in the history
This will add a `-c` `--clean` flag to the save command and ensure that the env directory is deleted if it exists.

Close #967
  • Loading branch information
CodeWithEmad committed Jul 9, 2024
1 parent cbd20d3 commit 1a1aa05
Show file tree
Hide file tree
Showing 8 changed files with 48 additions and 5 deletions.
1 change: 1 addition & 0 deletions changelog.d/20240629_120748_codewithemad_cleanup_flag.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
- 💥[Feature] Enhance your workflow with the new `-c` or `--clean` option for the `tutor config save` command! This feature allows you to clean your environment before each save, ensuring that all files and directories within the `env/` folder are deleted, providing you with a fresh environment each time. (by @CodeWithEmad)
5 changes: 5 additions & 0 deletions tests/commands/test_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,11 @@ def test_config_save(self) -> None:
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)
Expand Down
2 changes: 1 addition & 1 deletion tests/test_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ def mock_prompt(*_args: None, **kwargs: str) -> str:
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)))
Expand Down
4 changes: 3 additions & 1 deletion tutor/commands/compose.py
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,9 @@ def interactive_configuration(
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)
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)
Expand Down
12 changes: 11 additions & 1 deletion tutor/commands/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,13 @@ def _candidate_config_items(self) -> t.Iterable[tuple[str, ConfigValue]]:
@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,
Expand All @@ -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)
if clean_env and not interactive:
env.delete_env_dir(context.root)
if set_vars:
for key, value in set_vars:
config[key] = env.render_unknown(config, value)
Expand Down
2 changes: 1 addition & 1 deletion tutor/commands/k8s.py
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,7 @@ def launch(context: click.Context, non_interactive: bool) -> None:
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)
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)
Expand Down
13 changes: 13 additions & 0 deletions tutor/env.py
Original file line number Diff line number Diff line change
Expand Up @@ -533,6 +533,19 @@ def root_dir(root: str) -> str:
return os.path.abspath(root)


def delete_env_dir(root: str) -> None:
env_path = base_dir(root)

if os.path.exists(env_path):
try:
shutil.rmtree(env_path)
fmt.echo_alert("All files in the env directory are deleted.")
except PermissionError:
raise exceptions.TutorError(
"Could not delete the env directory. Permission Denied."
)


@hooks.Actions.PLUGIN_UNLOADED.add()
def _delete_plugin_templates(plugin: str, root: str, _config: Config) -> None:
"""
Expand Down
14 changes: 13 additions & 1 deletion tutor/interactive.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@
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
) -> None:
"""
Interactively ask questions to collect configuration values from the user.
Expand Down Expand Up @@ -148,6 +150,16 @@ def ask_questions(config: Config, run_for_prod: Optional[bool] = None) -> None:
config,
defaults,
)
run_clean = click.confirm(
fmt.question(
"Do you want to start in a fresh environment? "
"Type 'n' if you want to keep your current changes"
),
prompt_suffix=" ",
default=False,
)
if run_clean:
env.delete_env_dir(root)

hooks.Actions.CONFIG_INTERACTIVE.do(config)

Expand Down

0 comments on commit 1a1aa05

Please sign in to comment.