Skip to content
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
10 changes: 8 additions & 2 deletions src/specify_cli/integrations/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -1178,12 +1178,18 @@ def _render_yaml(cls, title: str, description: str, body: str, source_id: str) -
default_flow_style=False,
).strip()

# Indent the body for YAML block scalar
# Indent the body for YAML block scalar. Use an explicit indentation
# indicator ("|2") rather than a bare "|": YAML infers a plain block
# scalar's indentation from its first non-empty line, so a body whose
# first line is itself indented (e.g. a markdown code block or a nested
# list item) would make the parser expect that deeper indent for the
# whole block and reject the later, less-indented lines. Pinning the
# indent to 2 keeps the recipe parseable whatever the body looks like.
indented = "\n".join(f" {line}" for line in body.split("\n"))

lines = [
header_yaml,
"prompt: |",
"prompt: |2",
indented,
"",
f"# Source: {source_id}",
Expand Down
17 changes: 17 additions & 0 deletions tests/integrations/test_integration_base_yaml.py
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,23 @@ def test_yaml_prompt_excludes_frontmatter(self, tmp_path, monkeypatch):
assert "scripts:" not in parsed["prompt"]
assert "---" not in parsed["prompt"]

def test_yaml_prompt_with_indented_first_line_stays_valid(self):
"""A body whose first line is indented must still parse.

A bare ``|`` block scalar infers its indentation from the first
non-empty line, so a body starting with an indented line (e.g. a
markdown code block or nested list item) made the parser expect that
deeper indent for the whole block and reject the later, shallower
lines. The explicit ``|2`` indicator pins the indent so it parses."""
body = " indented first line\nback to normal\n indented again"
rendered = YamlIntegration._render_yaml("Title", "Desc", body, "src")

yaml_lines = [
ln for ln in rendered.split("\n") if not ln.startswith("# Source:")
]
parsed = yaml.safe_load("\n".join(yaml_lines))
assert parsed["prompt"].rstrip("\n") == body

def test_plan_command_has_no_context_placeholder(self, tmp_path):
"""The generated plan command must not carry a context-file placeholder.

Expand Down
Loading