Skip to content

Commit 10772e2

Browse files
committed
Merge chore/precheck-2026-09-12: skip build output in checks
2 parents 493427f + cc0644c commit 10772e2

8 files changed

Lines changed: 72 additions & 11 deletions

File tree

binder/cli/checks/concept_maps.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,11 @@
88

99
import yaml
1010

11+
try:
12+
from cli.checks.generated_paths import is_generated
13+
except ImportError: # pragma: no cover - package-relative import path
14+
from binder.cli.checks.generated_paths import is_generated
15+
1116
LIST_FIELDS = {
1217
"primary_concepts",
1318
"secondary_concepts",
@@ -134,7 +139,8 @@ def _validate_concept_map_file(
134139
def check_concept_maps(contents_dir: Path, repo_root: Path) -> List[ConceptMapIssue]:
135140
"""Validate all concept maps in contents_dir."""
136141
findings: List[ConceptMapIssue] = []
137-
qmd_files = sorted(contents_dir.glob("**/*.qmd"))
142+
# 2026-09-12: stale _build copies of chapters failed the push hook.
143+
qmd_files = sorted(p for p in contents_dir.glob("**/*.qmd") if not is_generated(p, contents_dir))
138144
qmd_frontmatter = {path: _frontmatter(path) for path in qmd_files}
139145

140146
referenced_maps: dict[Path, Path] = {}
@@ -154,7 +160,9 @@ def check_concept_maps(contents_dir: Path, repo_root: Path) -> List[ConceptMapIs
154160
findings.append(ConceptMapIssue("error", qmd_rel, f"frontmatter concepts file is not YAML: {concepts_ref}"))
155161
referenced_maps[concept_path.resolve()] = qmd_path
156162

157-
for concept_path in sorted(contents_dir.glob("**/*_concepts.y*ml")):
163+
for concept_path in sorted(
164+
p for p in contents_dir.glob("**/*_concepts.y*ml") if not is_generated(p, contents_dir)
165+
):
158166
_validate_concept_map_file(concept_path, qmd_frontmatter, repo_root, findings)
159167
if concept_path.resolve() not in referenced_maps:
160168
concept_rel = str(concept_path.relative_to(repo_root)) if concept_path.is_relative_to(repo_root) else str(concept_path)
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
"""Recognize generated trees that source checks must never scan.
2+
3+
A local render leaves build output and caches inside ``books/``: HTML and PDF
4+
output under ``_build/``, Quarto caches under ``.quarto/``, and per-chapter
5+
figure directories named ``<chapter>_files/``. Those trees hold stale copies
6+
of sources and assets, so a check that walks them reports defects that do not
7+
exist in the tracked content.
8+
"""
9+
10+
from __future__ import annotations
11+
12+
from pathlib import Path
13+
14+
GENERATED_DIRS = frozenset(
15+
{".quarto", "_build", "__pycache__", ".venv", "venv", "node_modules"}
16+
)
17+
18+
19+
def is_generated(path: Path, root: Path) -> bool:
20+
"""True when *path* lies inside a generated tree below *root*."""
21+
try:
22+
parts = path.relative_to(root).parts[:-1]
23+
except ValueError:
24+
parts = path.parts[:-1]
25+
return any(part in GENERATED_DIRS or part.endswith("_files") for part in parts)

binder/cli/commands/validate.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11636,15 +11636,19 @@ def _run_image_formats(self, root: Path) -> ValidationRunResult:
1163611636
"""Validate image file formats using Pillow."""
1163711637
try:
1163811638
from cli.checks.image_formats import check_file
11639+
from cli.checks.generated_paths import is_generated
1163911640
except ImportError:
1164011641
from binder.cli.checks.image_formats import check_file
11642+
from binder.cli.checks.generated_paths import is_generated
1164111643

1164211644
t0 = time.time()
1164311645
image_files: List[Path] = []
1164411646
for ext in ("*.png", "*.jpg", "*.jpeg", "*.gif", "*.webp"):
11647+
# 2026-09-12: stale _build copies of covers failed the push hook;
11648+
# only tracked-content trees are checked.
1164511649
image_files.extend([
1164611650
f for f in sorted(root.rglob(ext))
11647-
if "_files/mediabag/" not in str(f)
11651+
if not is_generated(f, root)
1164811652
])
1164911653

1165011654
issues: List[ValidationIssue] = []
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
"""Source checks must ignore render output and caches under books/."""
2+
3+
from pathlib import Path
4+
5+
from checks.concept_maps import check_concept_maps
6+
from checks.generated_paths import is_generated
7+
8+
9+
def test_is_generated_flags_build_trees(tmp_path: Path) -> None:
10+
assert is_generated(tmp_path / "_build" / "html-vol1" / "index.qmd", tmp_path)
11+
assert is_generated(tmp_path / ".quarto" / "idx" / "a.json", tmp_path)
12+
assert is_generated(tmp_path / "vol1" / "01_intro" / "01_intro_files" / "f.png", tmp_path)
13+
assert not is_generated(tmp_path / "vol1" / "01_intro" / "01_intro.qmd", tmp_path)
14+
15+
16+
def test_concept_maps_ignore_stale_build_copies(tmp_path: Path) -> None:
17+
books = tmp_path / "books"
18+
stale = books / "_build" / "html-vol1" / "vol1" / "conclusion" / "conclusion.qmd"
19+
stale.parent.mkdir(parents=True)
20+
stale.write_text("---\nconcepts: conclusion_concepts.yml\n---\n", encoding="utf-8")
21+
22+
findings = check_concept_maps(books, tmp_path)
23+
24+
assert not [f for f in findings if "_build" in f.path]

books/config/_quarto-html-vol1.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@ project:
1818
# collision. Mirrors _quarto-html-vol2.yml. Do NOT remove this as "stale" — it is
1919
# load-bearing for the vol1 HTML build (removing it in 3d5aa628ae broke CI for weeks).
2020
resources:
21-
- shared/assets/images/covers/*
22-
- shared/assets/downloads/*
21+
- /shared/assets/images/covers/*
22+
- /shared/assets/downloads/*
2323

2424
render:
2525
- index.qmd

books/config/_quarto-html-vol2.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@ project:
1111
execute-dir: project
1212

1313
resources:
14-
- shared/assets/images/covers/*
15-
- shared/assets/downloads/*
14+
- /shared/assets/images/covers/*
15+
- /shared/assets/downloads/*
1616

1717
# Full render manifest (vol2 HTML). An explicit list is required here: the
1818
# project index (index.qmd) and the website homepage (index-vol2.qmd) BOTH

books/config/_quarto-html-vol3.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ project:
88
execute-dir: project
99

1010
resources:
11-
- shared/assets/images/covers/*
12-
- shared/assets/downloads/*
11+
- /shared/assets/images/covers/*
12+
- /shared/assets/downloads/*
1313

1414
render:
1515
- index.qmd

books/config/_quarto-html-vol4.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@ project:
1111
execute-dir: project
1212

1313
resources:
14-
- shared/assets/images/covers/*
15-
- shared/assets/downloads/*
14+
- /shared/assets/images/covers/*
15+
- /shared/assets/downloads/*
1616

1717
render:
1818
# Generated from vol4/index.qmd. The preface is a separate page below.

0 commit comments

Comments
 (0)