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
37 changes: 31 additions & 6 deletions docs/scripts/build_versioned_docs.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,27 @@ def _run_capture(command: list[str], *, cwd: Path | None = None) -> str:
return result.stdout.strip()


def _resolve_git_ref(repo_root: Path, ref: str) -> str:
"""Return a git ref that exists in the local clone.

Tag-triggered CI checkouts are often detached HEAD with ``origin/main`` but
no local ``main`` branch. Branch-like refs try ``ref`` then ``origin/ref``.
"""
candidates = [ref]
if not ref.startswith("refs/") and "/" not in ref:
candidates.append(f"origin/{ref}")
for candidate in candidates:
probe = subprocess.run(
["git", "rev-parse", "--verify", f"{candidate}^{{commit}}"],
cwd=repo_root,
capture_output=True,
text=True,
)
if probe.returncode == 0:
return candidate
return ref


def _repo_root(docs_dir: Path) -> Path:
return docs_dir.parent

Expand Down Expand Up @@ -123,13 +144,15 @@ def _conf_ref_for(version_name: str) -> str | None:

def _release_date_for_ref(repo_root: Path, ref: str) -> str:
# ISO-style date (YYYY-MM-DD) for deterministic display in docs headers.
return _run_capture(["git", "log", "-1", "--format=%cs", ref], cwd=repo_root)
resolved = _resolve_git_ref(repo_root, ref)
return _run_capture(["git", "log", "-1", "--format=%cs", resolved], cwd=repo_root)


def _version_for_ref(repo_root: Path, ref: str, fallback: str) -> str:
# Resolve display version from the VERSION file in the selected ref.
resolved = _resolve_git_ref(repo_root, ref)
try:
raw = _run_capture(["git", "show", f"{ref}:VERSION"], cwd=repo_root)
raw = _run_capture(["git", "show", f"{resolved}:VERSION"], cwd=repo_root)
value = raw.splitlines()[0].strip().lstrip("v")
return value or fallback
except Exception:
Expand Down Expand Up @@ -178,8 +201,9 @@ def _ensure_worktree(
path = worktrees_root / name
if path.exists():
return path
resolved = _resolve_git_ref(repo_root, ref)
try:
_run(["git", "worktree", "add", "--detach", str(path), ref], cwd=repo_root)
_run(["git", "worktree", "add", "--detach", str(path), resolved], cwd=repo_root)
except subprocess.CalledProcessError:
# Recover from a previous run that deleted the dir without unregistering.
subprocess.run(
Expand All @@ -189,7 +213,7 @@ def _ensure_worktree(
capture_output=True,
)
_run(
["git", "worktree", "add", "--force", "--detach", str(path), ref],
["git", "worktree", "add", "--force", "--detach", str(path), resolved],
cwd=repo_root,
)
return path
Expand Down Expand Up @@ -319,7 +343,8 @@ def main() -> None:
worktrees_root.mkdir(parents=True, exist_ok=True)

tags = _selected_tags(repo_root)
versions: list[dict[str, str]] = [{"name": "current", "ref": "main"}]
main_ref = _resolve_git_ref(repo_root, "main")
versions: list[dict[str, str]] = [{"name": "current", "ref": main_ref}]
versions.extend({"name": t, "ref": t} for t in tags)
if args.preview:
preview_branch = _current_branch(repo_root)
Expand Down Expand Up @@ -415,7 +440,7 @@ def main() -> None:
(output_root / "index.html").write_text(index_html, encoding="utf-8")

# Basic crawl artifacts for search engines.
sitemap_entries: list[tuple[str, str]] = [("", _release_date_for_ref(repo_root, "main"))]
sitemap_entries: list[tuple[str, str]] = [("", _release_date_for_ref(repo_root, main_ref))]
for item in links:
sitemap_entries.append((f"{item['name']}/index.html", item.get("release_date", "")))

Expand Down
29 changes: 28 additions & 1 deletion tests/test_select_versions.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,46 @@

from __future__ import annotations

import subprocess
import sys
from pathlib import Path

sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "docs" / "scripts"))

from build_versioned_docs import _superset_versions
from build_versioned_docs import _resolve_git_ref, _superset_versions
from select_versions import MIN_MINOR_MAJOR_0, select_versions


def _tags(*versions: str) -> list[str]:
return [f"v{version}" if not version.startswith("v") else version for version in versions]


def test_resolve_git_ref_uses_origin_main_when_local_main_missing(tmp_path):
origin = tmp_path / "origin.git"
work = tmp_path / "work"
work.mkdir()
subprocess.run(["git", "init", "--bare", str(origin)], check=True, capture_output=True)
subprocess.run(["git", "init"], cwd=work, check=True, capture_output=True)
subprocess.run(["git", "config", "user.email", "test@example.com"], cwd=work, check=True)
subprocess.run(["git", "config", "user.name", "Test User"], cwd=work, check=True)
(work / "VERSION").write_text("0.21.0\n", encoding="utf-8")
subprocess.run(["git", "add", "VERSION"], cwd=work, check=True, capture_output=True)
subprocess.run(["git", "commit", "-m", "init"], cwd=work, check=True, capture_output=True)
subprocess.run(["git", "branch", "-M", "main"], cwd=work, check=True, capture_output=True)
subprocess.run(
["git", "remote", "add", "origin", str(origin)],
cwd=work,
check=True,
capture_output=True,
)
subprocess.run(["git", "push", "-u", "origin", "main"], cwd=work, check=True, capture_output=True)
subprocess.run(["git", "checkout", "--detach", "HEAD"], cwd=work, check=True, capture_output=True)
subprocess.run(["git", "branch", "-D", "main"], cwd=work, check=True, capture_output=True)

assert _resolve_git_ref(work, "main") == "origin/main"
assert _resolve_git_ref(work, "v9.9.9") == "v9.9.9"


def test_major_0_includes_minors_back_to_0_12_latest_patch_only():
tags = _tags(
"0.16.0",
Expand Down
Loading