diff --git a/aiidalab_launch/__main__.py b/aiidalab_launch/__main__.py index a41fe6d..6c22628 100644 --- a/aiidalab_launch/__main__.py +++ b/aiidalab_launch/__main__.py @@ -229,34 +229,39 @@ def add_profile(ctx, app_state, port, home_mount, image, profile): @click.argument("profile") @click.option("--yes", is_flag=True, help="Do not ask for confirmation.") @click.option("-f", "--force", is_flag=True, help="Proceed, ignoring any warnings.") +@click.option("--purge", is_flag=True, help="Remove all data associated with profile.") @pass_app_state -def remove_profile(app_state, profile, yes, force): +@click.pass_context +def remove_profile(ctx, app_state, profile, yes, force, purge): """Remove an AiiDAlab profile from the configuration.""" try: profile = app_state.config.get_profile(profile) except ValueError: raise click.ClickException(f"Profile with name '{profile}' does not exist.") - else: - if not force: - instance = AiidaLabInstance(client=app_state.docker_client, profile=profile) - status = asyncio.run(instance.status()) - if status not in ( - instance.AiidaLabInstanceStatus.DOWN, - instance.AiidaLabInstanceStatus.CREATED, - instance.AiidaLabInstanceStatus.EXITED, - ): - raise click.ClickException( - f"The instance associated with profile '{profile.name}' " - "is still running. Use the -f/--force option to remove the " - "profile anyways." - ) - if yes or click.confirm( - f"Are you sure you want to remove profile '{profile.name}'?" + if not force: + instance = AiidaLabInstance(client=app_state.docker_client, profile=profile) + status = asyncio.run(instance.status()) + if status not in ( + instance.AiidaLabInstanceStatus.DOWN, + instance.AiidaLabInstanceStatus.CREATED, + instance.AiidaLabInstanceStatus.EXITED, ): - app_state.config.profiles.remove(profile) - app_state.save_config() - click.echo(f"Removed profile with name '{profile.name}'.") + raise click.ClickException( + f"The instance associated with profile '{profile.name}' " + "is still running. Use the -f/--force option to remove the " + "profile anyways." + ) + + if purge: + ctx.invoke(reset, profile=profile, yes=yes) + + if yes or click.confirm( + f"Are you sure you want to remove profile '{profile.name}'?" + ): + app_state.config.profiles.remove(profile) + app_state.save_config() + click.echo(f"Removed profile with name '{profile.name}'.") @profile.command("edit") @@ -696,7 +701,7 @@ def reset(app_state, profile, yes): ) click.secho( - f"Resetting instance for profile '{profile.name}'. This action cannot be undone!", + f"Resetting instance for profile '{profile.name}'. This will remove ALL DATA, including the docker container and the associated volumes. This action cannot be undone!", err=True, fg="red", ) diff --git a/tests/test_cli.py b/tests/test_cli.py index 3bd7697..0dc7182 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -101,9 +101,13 @@ def test_add_remove_profile(): assert result.exit_code == 0 assert "Added profile 'new-profile'." in result.output + # Add second profile to be clean with delete volume + runner.invoke(cli.cli, ["profile", "add", "second-profile"], input="n\n") + # Check that new-profile exists result: Result = runner.invoke(cli.cli, ["profile", "list"]) assert "new-profile" in result.output + assert "second-profile" in result.output result: Result = runner.invoke(cli.cli, ["profile", "show", "new-profile"]) assert result.exit_code == 0 @@ -138,6 +142,15 @@ def test_add_remove_profile(): assert result.exit_code == 1 assert "Profile with name 'new-profile' does not exist." in result.output + # Remove second-profile with reset (`--purge` option) + result: Result = runner.invoke( + cli.cli, + ["profile", "remove", "--purge", "second-profile"], + input="y\nsecond-profile\n", + ) + assert result.exit_code == 0 + assert "Please enter the name of the profile to continue" in result.output + def test_add_profile_invalid_name(): runner: CliRunner = CliRunner()