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
27 changes: 0 additions & 27 deletions great_docs/assets/post-render.py
Original file line number Diff line number Diff line change
Expand Up @@ -4380,11 +4380,6 @@ def generate_markdown_pages():
if not html_file.endswith(".html"):
continue

# Skip skill.html as the raw skill.md is served directly as a resource
# and should not be overwritten by a generated .md from rendered HTML
if rel == "skill.html" or rel == os.path.join("skill.html"):
continue

try:
with open(html_file, "r", encoding="utf-8") as f:
content = f.read()
Expand Down Expand Up @@ -4735,28 +4730,6 @@ def _param_dl_to_html(m):
print("##GD:PASS:Markdown pages generated", flush=True)


# ── Clean up skill.html ──────────────────────────────────────────────────────
# Quarto renders skill.md → skill.html despite the !skill.md exclusion in
# project.render when skill.md is also in project.resources. The raw skill.md
# is served as-is; the rendered skills.html page is the intended viewer.
# Delete the spurious skill.html so it doesn't confuse users or agents.
_skill_html = os.path.join("_site", "skill.html")
if os.path.exists(_skill_html):
os.remove(_skill_html)
print("Removed spurious _site/skill.html (raw skill.md is served directly)")

# Fix links in skills.html that Quarto rewrote from skill.md → skill.html
_skills_page = os.path.join("_site", "skills.html")
if os.path.exists(_skills_page):
with open(_skills_page, "r", encoding="utf-8") as f:
_skills_content = f.read()
_fixed = _skills_content.replace('href="./skill.html"', 'href="skill.md"')
if _fixed != _skills_content:
with open(_skills_page, "w", encoding="utf-8") as f:
f.write(_fixed)
print("Fixed skill.md link in skills.html")


# ══════════════════════════════════════════════════════════════════════════════
# STRIP COLGROUP TAGS FROM TABLES
# ══════════════════════════════════════════════════════════════════════════════
Expand Down
25 changes: 21 additions & 4 deletions great_docs/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,21 @@
from .config import Config
from ._subprocess import TEXT_MODE_KWARGS

# Quarto's default input file types, enumerated as render globs. Used to seed
# `project.render` whenever we also add `!` exclusions. A recursive `**` glob
# overpowers any negation that follows it (so `!skill.md` would be ignored),
# whereas these per-extension globs still match recursively while letting the
# exclusions take effect.
_QUARTO_RENDER_GLOBS = [
"*.qmd",
"*.md",
"*.markdown",
"*.rmd",
"*.Rmd",
"*.rmarkdown",
"*.ipynb",
]


def _patch_griffe():
"""Ensure griffe has CyclicAliasError and AliasResolutionError at top level.
Expand Down Expand Up @@ -3602,7 +3617,7 @@ def _add_project_resources(

if render_excludes:
if "render" not in project:
project["render"] = ["**"]
project["render"] = list(_QUARTO_RENDER_GLOBS)
render = project["render"]
if isinstance(render, str):
render = [render] # pragma: no cover
Expand Down Expand Up @@ -11164,10 +11179,12 @@ def _update_quarto_config(self) -> None:
if "skill.md" not in config["project"]["resources"]:
config["project"]["resources"].append("skill.md")

# Exclude skill.md from rendering (Quarto renders .md by default)
# The render list needs "**" first (render everything), then exclusions
# Exclude skill.md from rendering (Quarto renders .md by default).
# The render list enumerates Quarto's default input globs before the
# exclusions; a recursive `**` would overpower the `!skill.md`
# negation and render skill.md anyway (see issue #228).
if "render" not in config["project"]:
config["project"]["render"] = ["**"]
config["project"]["render"] = list(_QUARTO_RENDER_GLOBS)
if "!skill.md" not in config["project"]["render"]:
config["project"]["render"].append("!skill.md")

Expand Down
32 changes: 32 additions & 0 deletions tests/test_great_docs.py
Original file line number Diff line number Diff line change
Expand Up @@ -3256,6 +3256,34 @@ def test_assets_config_update_only_when_copied():
assert "assets/**" not in config["project"]["resources"]


def test_skill_render_exclusion_uses_enumerated_globs():
"""_update_quarto_config() excludes skill.md without a recursive ** glob.

A recursive "**" in the render list overpowers any "!" negation, so Quarto
would render skill.md → skill.html anyway (see issue #228). The render list
must enumerate Quarto's default input globs instead.
"""
with tempfile.TemporaryDirectory() as tmp_dir:
project_path = Path(tmp_dir)

pyproject = project_path / "pyproject.toml"
pyproject.write_text('[project]\nname = "test"\nversion = "0.1.0"')

docs = GreatDocs(project_path=tmp_dir)
docs.project_path.mkdir(parents=True, exist_ok=True)
docs._update_quarto_config()

quarto_yml = docs.project_path / "_quarto.yml"
with open(quarto_yml, "r") as f:
config = read_yaml(f)

render = config["project"]["render"]
assert "!skill.md" in render
assert "**" not in render
assert "*.qmd" in render
assert "*.md" in render


def test_user_guide_config_option_overrides_default_dir():
"""Test that user_guide config option takes precedence over user_guide/ directory."""
with tempfile.TemporaryDirectory() as tmp_dir:
Expand Down Expand Up @@ -9416,6 +9444,10 @@ def test_process_custom_pages_passthrough_and_raw():
assert "custom/app.js" in resources
assert "custom/widget.html" in resources
assert "!custom/widget.html" in render
# The render list must enumerate Quarto's default input globs rather
# than a recursive "**", which would overpower the "!" exclusions.
assert "**" not in render
assert "*.qmd" in render


def test_process_custom_pages_missing_dir():
Expand Down