Skip to content
Closed
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
14 changes: 12 additions & 2 deletions src/specify_cli/workflows/overlays/_commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

import typer
import yaml
from rich.markup import escape as _escape_markup

from ..._console import console, err_console
from ...extensions import normalize_priority
Expand Down Expand Up @@ -412,14 +413,23 @@ def workflow_resolve(project_root: Path, workflow_id: str) -> dict[str, Any] | N
priority = (
"n/a" if layer.tier == "base" else str(normalize_priority(layer.priority))
)
# Escape the literal bracket (\[) so Rich renders `[<tier>]` instead of
# parsing it as a style tag: `[base]` and `[project-overlay]` were
# silently swallowed, so the tier column vanished from the output
# entirely. Layer sources and step ids are user-controlled paths/ids,
# so escape those values too.
console.print(
f" \u2022 [{layer.tier}] {layer.source} "
f" \u2022 \\[{_escape_markup(str(layer.tier))}] "
f"{_escape_markup(str(layer.source))} "
f"(priority={priority})"
)

console.print("Step attribution:")
for composed in attribution:
console.print(f" \u2022 {composed.step_id}: {composed.source}")
console.print(
f" \u2022 {_escape_markup(str(composed.step_id))}: "
f"{_escape_markup(str(composed.source))}"
Comment thread
jawwad-ali marked this conversation as resolved.
)

return {
"workflow_id": workflow_id,
Expand Down
45 changes: 45 additions & 0 deletions tests/workflows/test_overlay_commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -509,6 +509,51 @@ def test_workflow_resolve(self, project_dir, monkeypatch):
assert payload["layers"][-1]["tier"] == "base"
assert payload["layers"][-1]["priority"] is None

def test_workflow_resolve_prints_the_tier_column(self, project_dir, monkeypatch):
"""The `[<tier>]` column must survive Rich rendering.

The layer line interpolated a literal `[{layer.tier}]`, so Rich parsed
`[base]` / `[project-overlay]` as style tags and swallowed them — the
tier column disappeared from every `workflow resolve` run. A bare
`"base" in result.output` does not catch this, because the
step-attribution section prints the same word as a source; the tier has
to be asserted in bracket form on the layers line itself.
"""
monkeypatch.setattr("specify_cli._require_specify_project", lambda: project_dir)
_write_workflow(
project_dir,
"wf",
{
"schema_version": "1.0",
"workflow": {"id": "wf", "name": "WF", "version": "1.0.0"},
"steps": [{"id": "a", "type": "command", "command": "echo"}],
},
)
_write_overlay(
project_dir,
"wf",
"ov1",
{
"id": "ov1",
"extends": "wf",
"priority": 10,
"edits": [{"remove": "a"}],
},
)

result = runner.invoke(app, ["workflow", "resolve", "wf"])
assert result.exit_code == 0, result.output

layer_lines = [
line
for line in result.output.splitlines()
if "priority=" in line
]
assert layer_lines, result.output
joined = "\n".join(layer_lines)
assert "[base]" in joined, joined
assert "[project-overlay]" in joined, joined

def test_workflow_resolve_equal_priority_layers_sort_by_source(self, project_dir, monkeypatch):
"""Equal-priority overlays are listed alphabetically by source."""
monkeypatch.setattr("specify_cli._require_specify_project", lambda: project_dir)
Expand Down