Skip to content
Open
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
18 changes: 16 additions & 2 deletions src/specify_cli/workflows/_commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -1009,14 +1009,21 @@ def workflow_catalog_list():
def workflow_catalog_add(
url: str = typer.Argument(..., help="Catalog URL to add"),
name: str | None = typer.Option(None, "--name", help="Catalog name"),
priority: int | None = typer.Option(None, "--priority", help="Priority (lower = higher priority)"),
install_allowed: bool = typer.Option(
True,
"--install-allowed/--no-install-allowed",
help="Allow workflows from this catalog to be installed",
),
description: str = typer.Option("", "--description", help="Description of the catalog"),
):
"""Add a workflow catalog source."""
from .catalog import WorkflowCatalog, WorkflowValidationError

project_root = _require_specify_project()
catalog = WorkflowCatalog(project_root)
try:
catalog.add_catalog(url, name)
catalog.add_catalog(url, name, priority, install_allowed, description)
except WorkflowValidationError as exc:
Comment on lines 1019 to 1027
console.print(f"[red]Error:[/red] {exc}")
raise typer.Exit(1)
Expand Down Expand Up @@ -1661,6 +1668,13 @@ def workflow_step_catalog_list():
def workflow_step_catalog_add(
url: str = typer.Argument(..., help="Catalog URL to add"),
name: str | None = typer.Option(None, "--name", help="Catalog name"),
priority: int | None = typer.Option(None, "--priority", help="Priority (lower = higher priority)"),
install_allowed: bool = typer.Option(
True,
"--install-allowed/--no-install-allowed",
help="Allow steps from this catalog to be installed",
),
description: str = typer.Option("", "--description", help="Description of the catalog"),
):
"""Add a step catalog source."""
from .catalog import StepCatalog, StepValidationError
Expand All @@ -1669,7 +1683,7 @@ def workflow_step_catalog_add(

catalog = StepCatalog(project_root)
try:
catalog.add_catalog(url, name)
catalog.add_catalog(url, name, priority, install_allowed, description)
except StepValidationError as exc:
Comment on lines 1678 to 1687
console.print(f"[red]Error:[/red] {exc}")
raise typer.Exit(1)
Expand Down
30 changes: 22 additions & 8 deletions src/specify_cli/workflows/catalog.py
Original file line number Diff line number Diff line change
Expand Up @@ -476,7 +476,14 @@ def get_catalog_configs(self) -> list[dict[str, Any]]:
for e in entries
]

def add_catalog(self, url: str, name: str | None = None) -> None:
def add_catalog(
self,
url: str,
name: str | None = None,
priority: int | None = None,
install_allowed: bool = True,
description: str = "",
) -> None:
"""Add a catalog source to the project-level config."""
self._validate_catalog_url(url)
config_path = self.project_root / ".specify" / "workflow-catalogs.yml"
Expand Down Expand Up @@ -530,9 +537,9 @@ def _coerce_priority(value: Any) -> int:
{
"name": name or f"catalog-{len(catalogs) + 1}",
"url": url,
"priority": max_priority + 1,
"install_allowed": True,
"description": "",
"priority": max_priority + 1 if priority is None else priority,
"install_allowed": install_allowed,
"description": description,
}
)
data["catalogs"] = catalogs
Expand Down Expand Up @@ -1086,7 +1093,14 @@ def get_catalog_configs(self) -> list[dict[str, Any]]:
for e in entries
]

def add_catalog(self, url: str, name: str | None = None) -> None:
def add_catalog(
self,
url: str,
name: str | None = None,
priority: int | None = None,
install_allowed: bool = True,
description: str = "",
) -> None:
"""Add a catalog source to the project-level config."""
self._validate_catalog_url(url)
config_path = self.project_root / ".specify" / "step-catalogs.yml"
Expand Down Expand Up @@ -1136,9 +1150,9 @@ def _coerce_priority(value: Any) -> int:
{
"name": name or f"catalog-{len(catalogs) + 1}",
"url": url,
"priority": max_priority + 1,
"install_allowed": True,
"description": "",
"priority": max_priority + 1 if priority is None else priority,
"install_allowed": install_allowed,
"description": description,
}
)
data["catalogs"] = catalogs
Expand Down
109 changes: 109 additions & 0 deletions tests/test_workflows.py
Original file line number Diff line number Diff line change
Expand Up @@ -4513,6 +4513,60 @@ def test_add_catalog(self, project_dir):
data = yaml.safe_load(config_path.read_text())
assert len(data["catalogs"]) == 1
assert data["catalogs"][0]["url"] == "https://example.com/new-catalog.json"
assert data["catalogs"][0]["priority"] == 1
assert data["catalogs"][0]["install_allowed"] is True
assert data["catalogs"][0]["description"] == ""

def test_add_catalog_accepts_metadata_overrides(self, project_dir):
from specify_cli.workflows.catalog import WorkflowCatalog

catalog = WorkflowCatalog(project_dir)
catalog.add_catalog(
"https://example.com/new-catalog.json",
"my-catalog",
priority=7,
install_allowed=False,
description="Workflow source",
)

config_path = project_dir / ".specify" / "workflow-catalogs.yml"
data = yaml.safe_load(config_path.read_text())
assert data["catalogs"][0] == {
"name": "my-catalog",
"url": "https://example.com/new-catalog.json",
"priority": 7,
"install_allowed": False,
"description": "Workflow source",
}

def test_catalog_add_cli_accepts_metadata_options(self, project_dir, monkeypatch):
from typer.testing import CliRunner
from specify_cli import app

monkeypatch.chdir(project_dir)
result = CliRunner().invoke(
app,
[
"workflow",
"catalog",
"add",
"https://example.com/new-catalog.json",
"--name",
"my-catalog",
"--priority",
"7",
"--no-install-allowed",
"--description",
"Workflow source",
],
)

assert result.exit_code == 0, result.output
config_path = project_dir / ".specify" / "workflow-catalogs.yml"
data = yaml.safe_load(config_path.read_text())
assert data["catalogs"][0]["priority"] == 7
assert data["catalogs"][0]["install_allowed"] is False
assert data["catalogs"][0]["description"] == "Workflow source"

def test_add_catalog_duplicate_rejected(self, project_dir):
from specify_cli.workflows.catalog import WorkflowCatalog, WorkflowValidationError
Expand Down Expand Up @@ -4959,6 +5013,61 @@ def test_add_catalog(self, project_dir):
data = yaml.safe_load(config_path.read_text())
assert len(data["catalogs"]) == 1
assert data["catalogs"][0]["url"] == "https://example.com/new-steps.json"
assert data["catalogs"][0]["priority"] == 1
assert data["catalogs"][0]["install_allowed"] is True
assert data["catalogs"][0]["description"] == ""

def test_add_catalog_accepts_metadata_overrides(self, project_dir):
from specify_cli.workflows.catalog import StepCatalog

catalog = StepCatalog(project_dir)
catalog.add_catalog(
"https://example.com/new-steps.json",
"my-steps",
priority=7,
install_allowed=False,
description="Step source",
)

config_path = project_dir / ".specify" / "step-catalogs.yml"
data = yaml.safe_load(config_path.read_text())
assert data["catalogs"][0] == {
"name": "my-steps",
"url": "https://example.com/new-steps.json",
"priority": 7,
"install_allowed": False,
"description": "Step source",
}

def test_catalog_add_cli_accepts_metadata_options(self, project_dir, monkeypatch):
from typer.testing import CliRunner
from specify_cli import app

monkeypatch.chdir(project_dir)
result = CliRunner().invoke(
app,
[
"workflow",
"step",
"catalog",
"add",
"https://example.com/new-steps.json",
"--name",
"my-steps",
"--priority",
"7",
"--no-install-allowed",
"--description",
"Step source",
],
)

assert result.exit_code == 0, result.output
config_path = project_dir / ".specify" / "step-catalogs.yml"
data = yaml.safe_load(config_path.read_text())
assert data["catalogs"][0]["priority"] == 7
assert data["catalogs"][0]["install_allowed"] is False
assert data["catalogs"][0]["description"] == "Step source"

def test_add_catalog_empty_yaml_file(self, project_dir):
"""An empty YAML config file should be treated as empty, not corrupted."""
Expand Down
Loading