Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Registry management commands have been updated to handle namespaces. #220

Merged
merged 1 commit into from
Sep 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 14 additions & 6 deletions dem/cli/command/add_reg_cmd.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,29 @@
# dem/cli/command/add_reg_cmd.py

from dem.core.platform import Platform
from dem.cli.console import stdout
from dem.core.exceptions import RegistryError
from dem.cli.console import stdout, stderr

def execute(platform: Platform, name: str, url:str) -> None:
def execute(platform: Platform, name: str, url: str, namespace: str) -> None:
""" Add a new registry.

Args:
name -- name or IP address of the registry
name -- Unique name of the registry
url -- API URL of the registry
namespace -- Namespace of the registry
"""

registry = {
"name": name,
"namespace": namespace,
"url": url
}
if registry not in platform.registries.list_registry_configs():
for registry_config in platform.registries.list_registry_configs():
if registry_config["name"] == name:
stderr.print("[red]Error: The input registry name is already in use![/]")
return
try:
platform.registries.add_registry(registry)
else:
stdout.print("[yellow]The input registry is already added.[/]")
stdout.print(f"[green]The {name} registry has been successfully added![/]")
except RegistryError as e:
stderr.print(f"[red]Error: {str(e)}[/]")
2 changes: 2 additions & 0 deletions dem/cli/command/del_reg_cmd.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@

def execute(platform: Platform, registry_name: str) -> None:
""" Delete the registry.

Args:
platform -- the Platform
registry_name -- name of the registry to delete
"""
for registry in platform.registries.list_registry_configs():
Expand Down
9 changes: 7 additions & 2 deletions dem/cli/command/list_reg_cmd.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,19 @@
from rich.table import Table

def execute(platform: Platform) -> None:
""" List available registries."""
""" List available registries.

Args:
platform -- the Platform
"""
registry = None
table = Table()
table.add_column("name")
table.add_column("url")
table.add_column("namespace")

for registry in platform.registries.list_registry_configs():
table.add_row(registry["name"], registry["url"])
table.add_row(registry["name"], registry["url"], registry["namespace"])

if registry is None:
stdout.print("[yellow]No available registries![/]")
Expand Down
16 changes: 8 additions & 8 deletions dem/cli/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -369,21 +369,21 @@ def run(dev_env_name: Annotated[str, typer.Argument(help="Name of the Developmen
raise InternalError("Error: The platform hasn't been initialized properly!")

@typer_cli.command()
def add_reg(name: Annotated[str, typer.Argument(help="Name of the registry to add")],
url: Annotated[str, typer.Argument(help="API URL of the registry")]) -> None:
def add_reg(name: Annotated[str, typer.Argument(help="Unique name for the registry")],
url: Annotated[str, typer.Argument(help="API URL of the registry")],
namespace: Annotated[str, typer.Argument(help="Namespace inside the registry")] = "")-> None:
"""
Add a new registry.

The name of the registry is what you would normally use to pull an image.
Examples:
- If the full image tag: repository/image:tag -> the name should be repository.
- If the full image tag: 192.168.1.1:5000/image:tag -> the name should be 192.168.1.1:5000
The name of the registry must be unique.

The namespace is only mandatory for Docker Hub registries.

The URL should point to the registry's REST API. For the Docker Hub its
https://registry.hub.docker.com, or it can be http://localhost:5000 for a self-hosted one.
"""
if platform:
add_reg_cmd.execute(platform, name, url)
add_reg_cmd.execute(platform, name, url, namespace)
else:
raise InternalError("Error: The platform hasn't been initialized properly!")

Expand All @@ -398,7 +398,7 @@ def list_reg() -> None:
raise InternalError("Error: The platform hasn't been initialized properly!")

@typer_cli.command()
def del_reg(registry_name: Annotated[str, typer.Argument(help="Name or IP address of the registry to delete.",
def del_reg(registry_name: Annotated[str, typer.Argument(help="Name of the registry to delete.",
autocompletion=autocomplete_reg_name)]) -> None:
"""
Delete a registry.
Expand Down
2 changes: 2 additions & 0 deletions dem/core/registry.py
Original file line number Diff line number Diff line change
Expand Up @@ -247,8 +247,10 @@ def add_registry(self, registry_config: dict) -> None:
Args:
registry_config -- the registry to add
"""
# Create the registry instance
self._add_registry_instance(registry_config)

# Add the registry config to the config file
self.config_file.registries.append(registry_config)
self.config_file.flush()

Expand Down
28 changes: 19 additions & 9 deletions docs/commands.md
Original file line number Diff line number Diff line change
Expand Up @@ -482,31 +482,41 @@ List the available catalogs.
# Registry management


## **`dem add-reg NAME URL`**
## **`dem add-reg NAME URL [NAMESPACE]`**

**Description:**

Add a new registry.

The name of the registry is what you would normally use to pull an image.
The name of the registry must be unique. The URL must point to the registry's API.

The namespace is only required for the Docker Hub.

Examples:

*Add a Docker Hub registry called `axem` with the namespace `axemsolutions`*

```bash
dem add-reg axem https://registry.hub.docker.com axemsolutions
```

| Full image tag | Name |
|----------------------------------|-------------------|
| `repository/image:tag` | repository |
| `192.168.1.1:5000/image:tag` | 192.168.1.1:5000 |
*Add a self-hosted registry called `local`*

```bash
dem add-reg local http://localhost:5000
```

!!! Note

The URL should point to the registry's API. For the Docker Hub https://registry.hub.docker.com,
or it can be http://localhost:5000 for a self-hosted one.
The Docker Hub API URL is https://registry.hub.docker.com.

**Arguments:**

| Argument | Description | Required |
|------------------|---------------------------------------------------------|----------------:|
| `NAME` | Name of the registry to add. | :material-check:|
| `NAME` | Unique name for the registry. | :material-check:|
| `URL` | API URL of the registry. | :material-check:|
| `NAMESPACE` | Namespace inside the registry. | |

---

Expand Down
43 changes: 37 additions & 6 deletions tests/cli/test_add_reg_cmd.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

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

# Test framework
from typer.testing import CliRunner
Expand All @@ -14,48 +15,78 @@
runner = CliRunner(mix_stderr=False)

## Test cases
def test_add_reg():
@patch("dem.cli.command.add_reg_cmd.stdout.print")
def test_add_reg(mock_stdout_print: MagicMock) -> None:
# Test setup
mock_platform = MagicMock()
main.platform = mock_platform

test_name = "test_name"
test_url = "test_url"
test_namespace = "test_namespace"

mock_platform.registries.list_registry_configs.return_value = []

# Run unit under test
runner_result = runner.invoke(main.typer_cli, ["add-reg", test_name, test_url], color=True)
runner_result = runner.invoke(main.typer_cli, ["add-reg", test_name, test_url, test_namespace],
color=True)

# Check expectations
assert runner_result.exit_code == 0

mock_platform.registries.list_registry_configs.assert_called_once()
expected_registry = {
"name": test_name,
"namespace": test_namespace,
"url": test_url
}
mock_platform.registries.add_registry.assert_called_once_with(expected_registry)
mock_stdout_print.assert_called_once_with(f"[green]The {test_name} registry has been successfully added![/]")

@patch("dem.cli.command.add_reg_cmd.stdout.print")
def test_add_reg_already_added(mock_stdout_print: MagicMock):
@patch("dem.cli.command.add_reg_cmd.stderr.print")
def test_add_reg_name_taken(mock_stderr_print: MagicMock) -> None:
# Test setup
mock_platform = MagicMock()
main.platform = mock_platform

test_name = "test_name"
test_url = "test_url"
test_namespace = "test_namespace"

mock_platform.registries.list_registry_configs.return_value = [{
"name": test_name,
"namespace": test_namespace,
"url": test_url
}]

# Run unit under test
runner_result = runner.invoke(main.typer_cli, ["add-reg", test_name, test_url], color=True)
runner_result = runner.invoke(main.typer_cli, ["add-reg", test_name, test_url, test_namespace],
color=True)

# Check expectations
assert runner_result.exit_code == 0

mock_platform.registries.list_registry_configs.assert_called_once()
mock_stdout_print.assert_called_once_with("[yellow]The input registry is already added.[/]")
mock_stderr_print.assert_called_once_with("[red]Error: The input registry name is already in use![/]")

@patch("dem.cli.command.add_reg_cmd.stderr.print")
def test_add_reg_registry_error(mock_stderr_print: MagicMock) -> None:
# Test setup
mock_platform = MagicMock()
main.platform = mock_platform

test_name = "test_name"
test_url = "test_url"
test_namespace = "test_namespace"

mock_platform.registries.list_registry_configs.return_value = []

mock_platform.registries.add_registry.side_effect = add_reg_cmd.RegistryError("test_error")

# Run unit under test
add_reg_cmd.execute(mock_platform, test_name, test_url, test_namespace)

# Check expectations
mock_platform.registries.list_registry_configs.assert_called_once()
mock_platform.registries.add_registry.assert_called_once()
mock_stderr_print.assert_called_once_with("[red]Error: Registry error: test_error[/]")
8 changes: 5 additions & 3 deletions tests/cli/test_list_reg_cmd.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,12 @@ def test_list_reg(mock_stdout_print: MagicMock, mock_Table: MagicMock):
test_registries = [
{
"name": "test_name1",
"namespace": "test_namespace1",
"url": "test_url1"
},
{
"name": "test_name2",
"namespace": "",
"url": "test_url2"
},
]
Expand All @@ -42,14 +44,14 @@ def test_list_reg(mock_stdout_print: MagicMock, mock_Table: MagicMock):
assert runner_result.exit_code == 0

mock_Table.assert_called_once()
calls = [call("name"), call("url")]
calls = [call("name"), call("url"), call("namespace")]
mock_table.add_column.assert_has_calls(calls)

mock_platform.registries.list_registry_configs.assert_called_once()

calls = []
for registry in test_registries:
calls.append(call(registry["name"], registry["url"]))
calls.append(call(registry["name"], registry["url"], registry["namespace"]))
mock_table.add_row.assert_has_calls(calls)

mock_stdout_print.assert_called_once_with(mock_table)
Expand All @@ -71,7 +73,7 @@ def test_list_reg_non_available(mock_stdout_print: MagicMock, mock_Table):
assert runner_result.exit_code == 0

mock_Table.assert_called_once()
calls = [call("name"), call("url")]
calls = [call("name"), call("url"), call("namespace")]
mock_table.add_column.assert_has_calls(calls)

mock_platform.registries.list_registry_configs.assert_called_once()
Expand Down
3 changes: 2 additions & 1 deletion tests/cli/test_main.py
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,7 @@ def test_platform_not_initialized() -> None:
test_dev_env_name = "test_dev_env_name"
test_path = "test_path"
test_name = "test_name"
test_namespace = "test_namespace"
test_url = "test_url"
test_command = "test_command"
test_task_name = "test_task_name"
Expand All @@ -250,7 +251,7 @@ def test_platform_not_initialized() -> None:
main.assign: [test_dev_env_name, test_path],
main.init: [test_path],
main.run: [test_dev_env_name, test_task_name],
main.add_reg: [test_name, test_url],
main.add_reg: [test_name, test_url, test_namespace],
main.list_reg: [],
main.del_reg: [test_name],
main.add_cat: [test_name, test_url],
Expand Down
Loading