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
8 changes: 4 additions & 4 deletions docs/examples/report.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,16 @@ The example is rebuilt from the same tree that produces the published
documentation, so the HTML, canonical JSON, and SARIF artifacts stay aligned.

<p>
<a class="md-button md-button--primary" href="live/index.html" target="_blank" rel="noopener">
<a class="md-button md-button--primary" href="https://orenlab.github.io/codeclone/examples/report/live/index.html" target="_blank" rel="noopener">
Open interactive HTML report
</a>
<a class="md-button" href="live/report.json" target="_blank" rel="noopener">
<a class="md-button" href="https://orenlab.github.io/codeclone/examples/report/live/report.json" target="_blank" rel="noopener">
Open canonical JSON
</a>
<a class="md-button" href="live/report.sarif" target="_blank" rel="noopener">
<a class="md-button" href="https://orenlab.github.io/codeclone/examples/report/live/report.sarif" target="_blank" rel="noopener">
Open SARIF
</a>
<a class="md-button" href="live/manifest.json" target="_blank" rel="noopener">
<a class="md-button" href="https://orenlab.github.io/codeclone/examples/report/live/manifest.json" target="_blank" rel="noopener">
View generation manifest
</a>
</p>
Expand Down
56 changes: 40 additions & 16 deletions scripts/build_docs_example_report.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
"report.sarif",
"manifest.json",
)
_RELATIVE_LIVE_HREF = re.compile(r'href="live/([a-zA-Z0-9_.-]+)"')
_RELATIVE_LIVE_HREF = re.compile(r'href=(["\'])(?:\./)?live/([a-zA-Z0-9_.-]+)\1')


@dataclass(frozen=True)
Expand Down Expand Up @@ -81,6 +81,9 @@ def _run_codeclone(scan_root: Path, artifacts: ReportArtifacts) -> None:
str(artifacts.json),
"--sarif",
str(artifacts.sarif),
# Docs preview is report generation, not the structural CI gate.
"--no-fail-on-new",
"--no-fail-on-new-metrics",
"--no-progress",
"--quiet",
]
Expand Down Expand Up @@ -160,8 +163,30 @@ def _published_artifact_href(site_url: str, artifact_name: str) -> str:
return f"{parsed.scheme}://{parsed.netloc}{artifact_path}"


def _sample_report_page_path(output_dir: Path) -> Path:
return output_dir.parent / "index.html"
def _sample_report_page_paths(output_dir: Path) -> list[Path]:
site_root = output_dir.parent.parent.parent
candidates = (
output_dir.parent / "index.html",
site_root / "examples" / "report.html",
)
return [path for path in candidates if path.is_file()]


def _patch_page_links(page: Path, site_url: str) -> None:
text = page.read_text(encoding="utf-8")

def _replace(match: re.Match[str]) -> str:
quote = match.group(1)
artifact_name = match.group(2)
href = _published_artifact_href(site_url, artifact_name)
return f"href={quote}{href}{quote}"

patched = _RELATIVE_LIVE_HREF.sub(_replace, text)
if _RELATIVE_LIVE_HREF.search(patched):
msg = f"relative live/* artifact links remain in {page}"
raise RuntimeError(msg)
if patched != text:
page.write_text(patched, encoding="utf-8")


def _patch_sample_report_links(*, output_dir: Path, site_url: str) -> None:
Expand All @@ -171,19 +196,18 @@ def _patch_sample_report_links(*, output_dir: Path, site_url: str) -> None:
trailing slash (common with navigation.instant), resolving to
``/examples/live/...`` instead of ``/examples/report/live/...``.
"""
report_page = _sample_report_page_path(output_dir)
if not report_page.is_file():
return
text = report_page.read_text(encoding="utf-8")

def _replace(match: re.Match[str]) -> str:
artifact_name = match.group(1)
href = _published_artifact_href(site_url, artifact_name)
return f'href="{href}"'

patched = _RELATIVE_LIVE_HREF.sub(_replace, text)
if patched != text:
report_page.write_text(patched, encoding="utf-8")
pages = _sample_report_page_paths(output_dir)
if not pages:
site_root = output_dir.parent.parent.parent
expected_index = output_dir.parent / "index.html"
expected_report = site_root / "examples" / "report.html"
msg = (
"sample report HTML page not found under built site; expected "
f"{expected_index} or {expected_report}"
)
raise FileNotFoundError(msg)
for page in pages:
_patch_page_links(page, site_url)


def _verify_report_artifacts(destination: ReportArtifacts) -> None:
Expand Down
31 changes: 31 additions & 0 deletions tests/test_docs_build_contract.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,3 +46,34 @@ def test_docs_build_strict() -> None:
timeout=120,
)
assert result.returncode == 0, result.stderr or result.stdout


def test_sample_report_built_page_has_absolute_artifact_links() -> None:
site_root = _REPO_ROOT / "site"
build = subprocess.run(
[
"uv",
"run",
"--with",
"zensical==0.0.46",
"zensical",
"build",
"--clean",
"--strict",
],
cwd=_REPO_ROOT,
capture_output=True,
text=True,
timeout=120,
)
assert build.returncode == 0, build.stderr or build.stdout
candidates = (
site_root / "examples" / "report" / "index.html",
site_root / "examples" / "report.html",
)
page = next((path for path in candidates if path.is_file()), None)
assert page is not None, "expected built sample report HTML page"
text = page.read_text(encoding="utf-8")
assert 'href="live/' not in text
assert 'href="./live/' not in text
assert "examples/report/live/index.html" in text
36 changes: 36 additions & 0 deletions tests/test_docs_example_report.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,23 @@ def test_published_artifact_href_uses_site_url_path_prefix() -> None:
assert href == "https://orenlab.github.io/codeclone/examples/report/live/index.html"


def test_sample_report_markdown_links_match_zensical_site_url() -> None:
module = _load_docs_report_namespace()
read_site_url = module["_read_site_url"]
published_artifact_href = module["_published_artifact_href"]
assert callable(read_site_url)
assert callable(published_artifact_href)
repo_root = Path(__file__).resolve().parents[1]
site_url = read_site_url(repo_root)
report_md = (repo_root / "docs" / "examples" / "report.md").read_text(
encoding="utf-8"
)
artifact_names = module["_ARTIFACT_NAMES"]
assert isinstance(artifact_names, tuple)
for artifact in artifact_names:
assert published_artifact_href(site_url, str(artifact)) in report_md


def test_patch_sample_report_links_rewrites_relative_live_hrefs(
tmp_path: Path,
) -> None:
Expand Down Expand Up @@ -67,6 +84,23 @@ def test_patch_sample_report_links_rewrites_relative_live_hrefs(
)


def test_patch_sample_report_links_requires_built_page(tmp_path: Path) -> None:
module = _load_docs_report_namespace()
patch_sample_report_links = module["_patch_sample_report_links"]
assert callable(patch_sample_report_links)
output_dir = tmp_path / "examples" / "report" / "live"
output_dir.mkdir(parents=True)
try:
patch_sample_report_links(
output_dir=output_dir,
site_url="https://orenlab.github.io/codeclone/",
)
except FileNotFoundError as exc:
assert "sample report HTML page not found" in str(exc)
else:
raise AssertionError("expected FileNotFoundError when page is missing")


def test_docs_example_report_uses_main_entrypoint(
tmp_path: Path,
) -> None:
Expand Down Expand Up @@ -109,6 +143,8 @@ def _fake_run(
str(artifacts.json),
"--sarif",
str(artifacts.sarif),
"--no-fail-on-new",
"--no-fail-on-new-metrics",
"--no-progress",
"--quiet",
],
Expand Down
Loading