Skip to content

Commit

Permalink
The del-task command implemented.
Browse files Browse the repository at this point in the history
  • Loading branch information
janosmurai committed Apr 30, 2024
1 parent 80fe6ae commit 7b0633c
Show file tree
Hide file tree
Showing 10 changed files with 252 additions and 2 deletions.
3 changes: 3 additions & 0 deletions dem/cli/command/add_task_cmd.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
"""add-task CLI command implementation."""
# dem/cli/command/add_task_cmd.py

from dem.core.platform import Platform
from dem.cli.console import stderr

Expand Down
26 changes: 26 additions & 0 deletions dem/cli/command/del_task_cmd.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
"""del-task CLI command implementation."""
# dem/cli/command/del_task_cmd.py

from dem.core.platform import Platform
from dem.cli.console import stderr

def execute(platform: Platform, dev_env_name: str, task_name: str) -> None:
""" Delete a task from a Development Environment.
Args:
platform -- the Platform
dev_env_name -- the Development Environment name
task_name -- the task name
"""
dev_env = platform.get_dev_env_by_name(dev_env_name)
if dev_env is None:
stderr.print(f"[red]Error: Development Environment '{dev_env_name}' not found![/]")
return

try:
dev_env.del_task(task_name)
except KeyError as e:
stderr.print(f"[red] Error: {str(e)}[/]")
return

platform.flush_dev_env_properties()
34 changes: 33 additions & 1 deletion dem/cli/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@
delete_cmd, rename_cmd, run_cmd, export_cmd, clone_cmd, add_reg_cmd, \
list_reg_cmd, del_reg_cmd, add_cat_cmd, list_cat_cmd, del_cat_cmd, \
add_host_cmd, set_default_cmd, uninstall_cmd, install_cmd, assign_cmd, \
init_cmd, list_host_cmd, del_host_cmd, list_tools_cmd, add_task_cmd
init_cmd, list_host_cmd, del_host_cmd, list_tools_cmd, add_task_cmd, \
del_task_cmd
from dem.cli.console import stdout
from dem.core.platform import Platform
from dem.core.exceptions import InternalError
Expand Down Expand Up @@ -89,6 +90,23 @@ def autocomplete_host_name(incomplete: str) -> Generator:
if host_config["name"].startswith(incomplete) or (incomplete == ""):
yield host_config["name"]

def autocomplete_task_name(ctx: typer.Context, incomplete: str) -> Generator:
"""
Autocomplete the input Task name with the available matching Task names.
Return with the matching Task name by a Generator.
Args:
incomplete -- the parameter the user supplied so far when the tab was pressed
"""
dev_env_name = ctx.params.get("dev_env_name", None)
if platform is not None and dev_env_name is not None:
for dev_env in platform.local_dev_envs:
if dev_env.name == dev_env_name:
for task_name in dev_env.tasks:
if task_name.startswith(incomplete) or (incomplete == ""):
yield task_name

# DEM commands
@typer_cli.command()
def add_task(dev_env_name: Annotated[str, typer.Argument(help="Name of the Development Environment to add the task to.",
Expand All @@ -105,6 +123,20 @@ def add_task(dev_env_name: Annotated[str, typer.Argument(help="Name of the Devel
add_task_cmd.execute(platform, dev_env_name, task_name, command)
else:
raise InternalError("Error: The platform hasn't been initialized properly!")

@typer_cli.command()
def del_task(dev_env_name: Annotated[str, typer.Argument(help="Name of the Development Environment to delete the task from.",
autocompletion=autocomplete_dev_env_name)],
task_name: Annotated[str, typer.Argument(help="Name of the task to delete.",
autocompletion=autocomplete_task_name)]) -> None:
"""
Delete a task from the Development Environment.
"""
if platform:
del_task_cmd.execute(platform, dev_env_name, task_name)
else:
raise InternalError("Error: The platform hasn't been initialized properly!")

@typer_cli.command()
def set_default(dev_env_name: Annotated[str,
typer.Argument(help="The name of the Development Environment to set as default.",
Expand Down
22 changes: 22 additions & 0 deletions dem/core/dev_env.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,30 @@ def assign_tool_image_instances(self, tool_images: ToolImages) -> None:
self.tool_images.append(tool_image)

def add_task(self, task_name: str, command: str) -> None:
""" Add a task to the Development Environment.
If the task already exists, it will be overwritten.
Args:
task_name -- the task name
command -- the command
"""
self.tasks[task_name] = command

def del_task(self, task_name: str) -> None:
""" Delete a task from the Development Environment.
Args:
task_name -- the task name
Exceptions:
KeyError -- if the task doesn't exist
"""
if task_name in self.tasks:
del self.tasks[task_name]
else:
raise KeyError(f"Task [bold]{task_name}[/] not found.")

def get_tool_image_status(self) -> Status:
""" Get the status of the Tool Images.
Expand Down
15 changes: 15 additions & 0 deletions docs/commands.md
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,21 @@ Delete the Dev Env descriptor from the local descriptor storage. If the Dev Env

---

## **`dem del-task DEV_ENV_NAME TASK_NAME`**

**Description:**

Delete a task from the Development Environment.

**Arguments:**

| Argument | Description | Required |
|------------------|---------------------------------------------------------|:---------------:|
| `DEV_ENV_NAME` | Name of the Development Environment. | :material-check:|
| `TASK_NAME` | Name of the task to delete. | :material-check:|

---

## **`dem export DEV_ENV_NAME [PATH_TO_EXPORT]`**

**Description:**
Expand Down
2 changes: 2 additions & 0 deletions mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -94,11 +94,13 @@ nav:
- 'basics.md'
- Commands:
- 'DevEnv Management':
- 'add-task': 'commands/#dem-add-task-dev_env_name-task_name-command'
- 'assign': 'commands/#dem-assign-dev_env_name-project_path'
- 'clone': 'commands/#dem-clone-dev_env_name'
- 'cp': 'commands/#dem-cp-dev_env_name-new_dev_env_name'
- 'create': 'commands/#dem-create-dev_env_name'
- 'delete': 'commands/#dem-delete-dev_env_name'
- 'del-task': 'commands/#dem-del-task-dev_env_name-task_name'
- 'export': 'commands/#dem-export-dev_env_name-path_to_export'
- 'import': 'commands/#dem-import-path_to_dev_env'
- 'info': 'commands/#dem-info-dev_env_name-options-catalog_names'
Expand Down
2 changes: 1 addition & 1 deletion tests/cli/test_add_task_cmd.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

# Test framework
from typer.testing import CliRunner
from unittest.mock import patch, MagicMock, call
from unittest.mock import patch, MagicMock

## Global test variables

Expand Down
71 changes: 71 additions & 0 deletions tests/cli/test_del_task_cmd.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
"""Unit tests for the del-task CLI command."""
# tests/cli/test_del_task_cmd.py

# Unit under test:
import dem.cli.main as main
import dem.cli.command.del_task_cmd as del_task_cmd

# Test framework
from typer.testing import CliRunner
from unittest.mock import patch, MagicMock, call

## Global test variables

# In order to test stdout and stderr separately, the stderr can't be mixed into
# the stdout.
runner = CliRunner(mix_stderr=False)

def test_del_task_cmd() -> None:
# Setup
mock_platform = MagicMock()
main.platform = mock_platform

mock_dev_env = MagicMock()
mock_platform.get_dev_env_by_name.return_value = mock_dev_env

# Run
result = runner.invoke(main.typer_cli, ["del-task", "my-dev-env", "my-task"])

# Check
assert result.exit_code == 0

mock_platform.get_dev_env_by_name.assert_called_once_with("my-dev-env")
mock_dev_env.del_task.assert_called_once_with("my-task")
mock_platform.flush_dev_env_properties.assert_called_once()

@patch("dem.cli.command.del_task_cmd.stderr")
def test_del_task_cmd_dev_env_not_found(mock_stderr: MagicMock) -> None:
# Setup
mock_platform = MagicMock()
main.platform = mock_platform

mock_platform.get_dev_env_by_name.return_value = None

# Run
result = runner.invoke(main.typer_cli, ["del-task", "my-dev-env", "my-task"])

# Check
assert result.exit_code == 0

mock_platform.get_dev_env_by_name.assert_called_once_with("my-dev-env")
mock_stderr.print.assert_called_once_with("[red]Error: Development Environment 'my-dev-env' not found![/]")

@patch("dem.cli.command.del_task_cmd.stderr")
def test_del_task_cmd_task_not_found(mock_stderr: MagicMock) -> None:
# Setup
mock_platform = MagicMock()
main.platform = mock_platform

mock_dev_env = MagicMock()
mock_platform.get_dev_env_by_name.return_value = mock_dev_env
mock_dev_env.del_task.side_effect = KeyError("Task [bold]my-task[/] not found.")

# Run
result = runner.invoke(main.typer_cli, ["del-task", "my-dev-env", "my-task"])

# Check
assert result.exit_code == 0

mock_platform.get_dev_env_by_name.assert_called_once_with("my-dev-env")
mock_dev_env.del_task.assert_called_once_with("my-task")
mock_stderr.print.assert_called_once_with("[red] Error: \'Task [bold]my-task[/] not found.\'[/]")
34 changes: 34 additions & 0 deletions tests/cli/test_main.py
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,39 @@ def test_autocomplete_host_name() -> None:

mock_platform.hosts.list_host_configs.assert_called_once()

def test_autocomplete_task_name() -> None:
# Test setup
mock_platform = MagicMock()
mock_dev_env1 = MagicMock()
mock_dev_env1.name = "dev_env_1"
mock_dev_env1.tasks = {
"test": "test",
"task": "command"
}
mock_dev_env2 = MagicMock()
mock_dev_env2.name = "dev_env_2"
mock_platform.local_dev_envs = [
mock_dev_env1,
mock_dev_env2
]

mock_ctx = MagicMock()
mock_ctx.params = {
"dev_env_name": "dev_env_1"
}

main.platform = mock_platform

expected_completions = [mock_dev_env1.tasks["test"]]

# Run unit under test
actual_completions = []
for result in main.autocomplete_task_name(mock_ctx, "tes"):
actual_completions.append(result)

# Check expectations
assert expected_completions == actual_completions

@patch("dem.cli.main.__app_name__", "axem-dem")
@patch("dem.cli.main.stdout.print")
@patch("dem.cli.main.importlib.metadata.version")
Expand Down Expand Up @@ -199,6 +232,7 @@ def test_platform_not_initialized() -> None:

units_to_test = {
main.add_task: [test_dev_env_name, test_name, test_command],
main.del_task: [test_dev_env_name, test_name],
main.set_default: [test_dev_env_name],
main.list_: [],
main.list_tools: [],
Expand Down
45 changes: 45 additions & 0 deletions tests/core/test_dev_env.py
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,51 @@ def test_DevEnv_add_task() -> None:
# Check expectations
assert test_dev_env.tasks[test_task_name] == test_command

def test_DevEnv_del_task() -> None:
# Test setup
test_descriptor = {
"name": "test_name",
"installed": "True",
"tools": [MagicMock()],
"tasks": {
"test_task_name1": "test_task_command1",
"test_task_name2": "test_task_command2",
"test_task_name3": "test_task_command3"
}
}
test_dev_env = dev_env.DevEnv(test_descriptor)

test_task_name = "test_task_name2"

# Run unit under test
test_dev_env.del_task(test_task_name)

# Check expectations
assert test_task_name not in test_dev_env.tasks

def test_DevEnv_del_task_not_existing() -> None:
# Test setup
test_descriptor = {
"name": "test_name",
"installed": "True",
"tools": [MagicMock()],
"tasks": {
"test_task_name1": "test_task_command1",
"test_task_name2": "test_task_command2",
"test_task_name3": "test_task_command3"
}
}
test_dev_env = dev_env.DevEnv(test_descriptor)

test_task_name = "test_task_name4"

# Run unit under test
with pytest.raises(KeyError) as exc_info:
test_dev_env.del_task(test_task_name)

# Check expectations
assert str(exc_info.value) == f"\'Task [bold]{test_task_name}[/] not found.\'"

@patch.object(dev_env.DevEnv, "__init__")
def test_DevEnv_get_tool_image_status(mock___init__: MagicMock) -> None:
# Test setup
Expand Down

0 comments on commit 7b0633c

Please sign in to comment.