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
19 changes: 16 additions & 3 deletions scripts/tooling/cli/misc/html_report.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@

from jinja2 import Environment, FileSystemLoader, select_autoescape

from scripts.tooling.lib.github import fetch_compare
from scripts.tooling.lib.github import fetch_compare, resolve_ref_sha
from scripts.tooling.lib.known_good import KnownGood, load_known_good

_LOG = logging.getLogger(__name__)
Expand Down Expand Up @@ -73,9 +73,22 @@ def _collect_entries(known_good: KnownGood) -> list[dict[str, Any]]:

def _enrich_with_compare_data(entries: list[dict[str, Any]], token: str) -> None:
for entry in entries:
if not entry.get("owner_repo") or not entry.get("hash") or entry.get("version"):
if not entry.get("owner_repo"):
continue
result = fetch_compare(entry["owner_repo"], entry["hash"], entry["branch"], token)

# Modules are pinned either by commit hash or by release version. A version
# pin (e.g. "0.2.9") is resolved to its tag's commit so it can be compared
# against the branch HEAD just like a hash pin.
base_ref = entry.get("hash")
if not base_ref and entry.get("version"):
base_ref = resolve_ref_sha(entry["owner_repo"], entry["version"], token)
if base_ref:
# Surface the resolved commit as the pinned hash for display/linking.
entry["hash"] = base_ref
if not base_ref:
continue

result = fetch_compare(entry["owner_repo"], base_ref, entry["branch"], token)
if result:
entry["current_hash"] = result.head_sha
entry["behind_by"] = result.ahead_by
Expand Down
44 changes: 42 additions & 2 deletions scripts/tooling/lib/github.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,12 @@
_LOG = logging.getLogger(__name__)


def _get_repo(owner_repo: str, token: Optional[str]):
"""Return the PyGithub ``Repository`` for *owner_repo*, authenticated if *token* is set."""
gh = Github(token) if token else Github()
return gh.get_repo(owner_repo)


@dataclass
class CompareResult:
"""Result of comparing a pinned commit against a branch HEAD."""
Expand Down Expand Up @@ -54,8 +60,7 @@ def fetch_compare(
Without a token requests are unauthenticated (60 req/h rate limit).
"""
try:
gh = Github(token) if token else Github()
repo = gh.get_repo(owner_repo)
repo = _get_repo(owner_repo, token)
comparison = repo.compare(base_hash, branch)
commits = list(comparison.commits)
head_sha = commits[-1].sha if commits else base_hash
Expand All @@ -69,3 +74,38 @@ def fetch_compare(
except Exception as exc: # noqa: BLE001
_LOG.debug("Unexpected error comparing %s: %s", owner_repo, exc)
return None


def resolve_ref_sha(
owner_repo: str,
ref: str,
token: Optional[str] = None,
) -> Optional[str]:
"""Resolve a git ref (tag, branch or SHA) to a commit SHA.

Modules pinned by ``version`` store the bare release string (e.g. ``"0.2.9"``)
while the git tag is usually prefixed with ``v`` (``"v0.2.9"``). Both spellings
are tried so a version pin resolves to the tag's commit.

Args:
owner_repo: GitHub ``owner/repo`` slug (e.g. ``"eclipse-score/baselibs"``).
ref: The tag/branch/version string to resolve.
token: Optional GitHub PAT or ``GITHUB_TOKEN``.

Returns:
The resolved commit SHA, or ``None`` if no candidate ref could be resolved.
"""
candidates = [ref]
if not ref.startswith("v"):
candidates.append(f"v{ref}")
try:
repo = _get_repo(owner_repo, token)
for candidate in candidates:
try:
return repo.get_commit(candidate).sha
except GithubException:
continue
_LOG.debug("Could not resolve ref %r for %s (tried %s)", ref, owner_repo, candidates)
except Exception as exc: # noqa: BLE001
_LOG.debug("Unexpected error resolving ref %s for %s: %s", ref, owner_repo, exc)
return None
Loading