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
28 changes: 16 additions & 12 deletions ci/tools/check_release_notes.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import os
import re
import sys
from pathlib import Path

COMPONENT_TO_PACKAGE: dict[str, str] = {
"cuda-core": "cuda_core",
Expand Down Expand Up @@ -62,8 +63,8 @@ def is_post_release(version: str) -> bool:
return ".post" in version


def load_backport_branch(repo_root: str = ".") -> str | None:
path = os.path.join(repo_root, "ci", "versions.yml")
def load_backport_branch(repo_root: Path = Path(".")) -> str | None:
path = repo_root / "ci" / "versions.yml"
try:
with open(path, encoding="utf-8") as f:
for line in f:
Expand All @@ -84,13 +85,16 @@ def is_backport_version(version: str, backport_branch: str) -> bool:
return version == backport_branch


def notes_path(package: str, version: str) -> str:
return os.path.join(package, "docs", "source", "release", f"{version}-notes.rst")
def notes_path(package: str, version: str) -> Path:
return Path(package, "docs", "source", "release", f"{version}-notes.rst")


def check_release_notes(git_tag: str, component: str, repo_root: str = ".") -> list[tuple[str, str]]:
def check_release_notes(git_tag: str, component: str, repo_root: Path = Path(".")) -> list[tuple[str | Path, str]]:
"""Return a list of (path, reason) for missing or empty release notes.

``path`` is the repo-relative notes path, or a ``<placeholder>`` naming the
offending argument when the tag or component itself is the problem.

Returns an empty list when notes are present and non-empty, or when the
tag is a .post release (no new notes required).
"""
Expand All @@ -105,10 +109,10 @@ def check_release_notes(git_tag: str, component: str, repo_root: str = ".") -> l
return []

path = notes_path(COMPONENT_TO_PACKAGE[component], version)
full = os.path.join(repo_root, path)
if not os.path.isfile(full):
full = repo_root / path
if not full.is_file():
return [(path, "missing")]
if os.path.getsize(full) == 0:
if full.stat().st_size == 0:
return [(path, "empty")]
return []

Expand All @@ -123,7 +127,7 @@ def write_step_summary(message: str) -> None:
f.write("\n")


def warn_missing_backport_notes(git_tag: str, component: str, problems: list[tuple[str, str]]) -> None:
def warn_missing_backport_notes(git_tag: str, component: str, problems: list[tuple[str | Path, str]]) -> None:
print(f"WARNING: missing or empty release notes for backport tag {git_tag}:")
summary_lines = [
"## Release Notes Reminder",
Expand All @@ -147,8 +151,8 @@ def validate_backport_decision(
version: str,
backport_git_tag: str,
backport_branch: str | None,
repo_root: str,
) -> tuple[int | None, list[tuple[str, str]]]:
repo_root: Path,
) -> tuple[int | None, list[tuple[str | Path, str]]]:
if component not in BACKPORT_PLANNING_COMPONENTS or is_post_release(version):
return None, []

Expand Down Expand Up @@ -205,7 +209,7 @@ def main(argv: list[str] | None = None) -> int:
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--git-tag", required=True)
parser.add_argument("--component", required=True, choices=list(COMPONENT_TO_PACKAGE))
parser.add_argument("--repo-root", default=".")
parser.add_argument("--repo-root", default=Path("."), type=Path)
parser.add_argument("--backport-git-tag", default="")
parser.add_argument("--backport-branch", default="")
args = parser.parse_args(argv)
Expand Down
26 changes: 13 additions & 13 deletions ci/tools/tests/test_check_release_notes.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@

from __future__ import annotations

import os
import sys
from pathlib import Path

sys.path.insert(0, os.path.join(os.path.dirname(__file__), ".."))
sys.path.insert(0, str(Path(__file__).parent.parent))
from check_release_notes import (
check_release_notes,
is_post_release,
Expand Down Expand Up @@ -87,43 +87,43 @@ def _make_notes(self, tmp_path, pkg, version, content="Release notes."):

def test_present_and_nonempty(self, tmp_path):
self._make_notes(tmp_path, "cuda_core", "0.7.0")
problems = check_release_notes("cuda-core-v0.7.0", "cuda-core", str(tmp_path))
problems = check_release_notes("cuda-core-v0.7.0", "cuda-core", tmp_path)
assert problems == []

def test_missing(self, tmp_path):
problems = check_release_notes("cuda-core-v0.7.0", "cuda-core", str(tmp_path))
problems = check_release_notes("cuda-core-v0.7.0", "cuda-core", tmp_path)
assert len(problems) == 1
assert problems[0][1] == "missing"

def test_empty(self, tmp_path):
self._make_notes(tmp_path, "cuda_core", "0.7.0", content="")
problems = check_release_notes("cuda-core-v0.7.0", "cuda-core", str(tmp_path))
problems = check_release_notes("cuda-core-v0.7.0", "cuda-core", tmp_path)
assert len(problems) == 1
assert problems[0][1] == "empty"

def test_post_release_skipped(self, tmp_path):
problems = check_release_notes("v12.6.2.post1", "cuda-bindings", str(tmp_path))
problems = check_release_notes("v12.6.2.post1", "cuda-bindings", tmp_path)
assert problems == []

def test_invalid_tag(self, tmp_path):
problems = check_release_notes("not-a-tag", "cuda-core", str(tmp_path))
problems = check_release_notes("not-a-tag", "cuda-core", tmp_path)
assert len(problems) == 1
assert "cannot parse" in problems[0][1]

def test_component_prefix_mismatch(self, tmp_path):
# Pass a cuda-core tag with component=cuda-pathfinder; must be rejected.
problems = check_release_notes("cuda-core-v0.7.0", "cuda-pathfinder", str(tmp_path))
problems = check_release_notes("cuda-core-v0.7.0", "cuda-pathfinder", tmp_path)
assert len(problems) == 1
assert "cannot parse" in problems[0][1]

def test_unknown_component(self, tmp_path):
problems = check_release_notes("v13.1.0", "bogus", str(tmp_path))
problems = check_release_notes("v13.1.0", "bogus", tmp_path)
assert len(problems) == 1
assert "unknown component" in problems[0][1]

def test_plain_v_tag(self, tmp_path):
self._make_notes(tmp_path, "cuda_python", "13.1.0")
problems = check_release_notes("v13.1.0", "cuda-python", str(tmp_path))
problems = check_release_notes("v13.1.0", "cuda-python", tmp_path)
assert problems == []


Expand All @@ -133,17 +133,17 @@ def test_from_versions_yml(self, tmp_path):
d.mkdir(parents=True)
(d / "versions.yml").write_text('backport_branch: "12.9.x"\n')

assert load_backport_branch(str(tmp_path)) == "12.9.x"
assert load_backport_branch(tmp_path) == "12.9.x"

def test_from_github_ref_name_for_legacy_backport_branch(self, tmp_path, monkeypatch):
monkeypatch.setenv("GITHUB_REF_NAME", "12.9.x")

assert load_backport_branch(str(tmp_path)) == "12.9.x"
assert load_backport_branch(tmp_path) == "12.9.x"

def test_ignores_non_backport_github_ref_name(self, tmp_path, monkeypatch):
monkeypatch.setenv("GITHUB_REF_NAME", "main")

assert load_backport_branch(str(tmp_path)) is None
assert load_backport_branch(tmp_path) is None


class TestMain:
Expand Down
10 changes: 4 additions & 6 deletions toolshed/build_static_bitcode_input.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,21 +14,19 @@
"""

import binascii
import os
import sys
import textwrap
from pathlib import Path

import llvmlite.binding # HINT: pip install llvmlite

from cuda.bindings import nvvm


def get_minimal_nvvmir_txt_template():
cuda_bindings_tests_dir = os.path.normpath("cuda_bindings/tests")
assert os.path.isdir(cuda_bindings_tests_dir), (
"Please run this helper script from the cuda-python top-level directory."
)
sys.path.insert(0, os.path.abspath(cuda_bindings_tests_dir))
cuda_bindings_tests_dir = Path("cuda_bindings/tests")
assert cuda_bindings_tests_dir.is_dir(), "Please run this helper script from the cuda-python top-level directory."
sys.path.insert(0, str(cuda_bindings_tests_dir.resolve()))
import test_nvvm

return test_nvvm.MINIMAL_NVVMIR_TXT_TEMPLATE
Expand Down
3 changes: 1 addition & 2 deletions toolshed/check_generated_file_seals.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
# SPDX-License-Identifier: Apache-2.0

import hashlib
import os
import re
import subprocess
import sys
Expand Down Expand Up @@ -142,7 +141,7 @@ def main(args):

returncode = 0
for filepath in args:
if not os.path.isfile(filepath):
if not Path(filepath).is_file():
continue
if not validate_generated_file_seal(filepath, previously_sealed_paths):
returncode = 1
Expand Down
5 changes: 2 additions & 3 deletions toolshed/check_spdx.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,10 @@
# SPDX-License-Identifier: Apache-2.0

import datetime
import os
import re
import subprocess
import sys
from pathlib import PureWindowsPath
from pathlib import Path, PureWindowsPath

import pathspec

Expand Down Expand Up @@ -39,7 +38,7 @@


def load_spdx_ignore():
if os.path.exists(SPDX_IGNORE_FILENAME):
if Path(SPDX_IGNORE_FILENAME).exists():
with open(SPDX_IGNORE_FILENAME, encoding="utf-8") as f:
lines = f.readlines()
else:
Expand Down
6 changes: 3 additions & 3 deletions toolshed/dump_cutile_b64.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@
"""

import base64
import glob
import os
import sys
from pathlib import Path

import cupy

Expand Down Expand Up @@ -54,13 +54,13 @@ def main():
raise

# Find the .cutile file in current directory
cutile_files = glob.glob("./*.cutile")
cutile_files = list(Path().glob("*.cutile"))
if not cutile_files:
print("No .cutile file found in current directory", file=sys.stderr)
sys.exit(1)

# Use the most recently modified one if multiple exist
cutile_path = max(cutile_files, key=os.path.getmtime)
cutile_path = max(cutile_files, key=lambda path: path.stat().st_mtime)

# Read the binary content
with open(cutile_path, "rb") as f:
Expand Down
Loading