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
7 changes: 7 additions & 0 deletions .coderabbit.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,13 @@ early_access: false
reviews:
profile: chill
request_changes_workflow: true
# Repository-owned checks validate deliberately invalid static-analysis fixtures.
path_filters:
- "!tests/semgrep/**"
pre_merge_checks:
# Ruff owns docstring policy without treating fixtures as public APIs.
docstrings:
mode: off
# Publish the legacy commit status consumed by the main-branch ruleset.
# Keep review_progress off until CodeRabbit can publish the required check run.
review_progress: false
Expand Down
33 changes: 17 additions & 16 deletions justfile
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,13 @@ cargo_nextest_version := "0.9.143"
cargo_update_version := "22.1.1"
clippy_sarif_version := "0.8.0"
dprint_version := "0.57.0"
git_cliff_version := "2.13.1"
git_cliff_version := "2.14.1"
just_version := "1.58.0"
rumdl_version := "0.2.62"
rumdl_version := "0.2.63"
sarif_fmt_version := "0.8.0"
taplo_version := "0.10.0"
typos_version := "1.50.0"
uv_version := "0.12.7"
typos_version := "1.50.1"
uv_version := "0.12.9"
zizmor_version := "1.30.0"

# Internal helpers: ensure external tooling is installed
Expand Down Expand Up @@ -209,11 +209,9 @@ _ensure-uv-available:
_ensure-stable-uv-version: _ensure-uv-available
#!/usr/bin/env bash
set -euo pipefail
version_output="$(uv --version 2>&1)"
if [[ ! "$version_output" =~ ^uv[[:space:]]+([0-9]+\.[0-9]+\.[0-9]+)([[:space:]]|$) ]]; then
echo "❌ 'uv --version' must report a stable X.Y.Z version; got: $version_output" >&2
exit 1
fi
uv_executable="$(command -v uv)"
version_output="$("$uv_executable" --version)"
"$uv_executable" run --locked update-cargo-tool-pins "--check-uv-version=$version_output"

_ensure-yamllint: _ensure-uv
#!/usr/bin/env bash
Expand Down Expand Up @@ -396,7 +394,7 @@ check-fast:
# CI simulation: flat GitHub-equivalent union of leaf validators.
# Keep this dependency list explicit so each validation surface runs once without
# re-entering broad check/test bundles. All Cargo targets match the SARIF lint scope.
ci: action-lint zizmor markdown-check spell-check docs-version-check toml-parse-check toml-fmt-check toml-lint yaml-fmt-check yaml-lint citation-check validate-json justfile-fmt-check python-format-check python-lint python-typecheck test-python cargo-lock-check fmt-check clippy-all-targets doc-check semgrep semgrep-test unused-deps shell-check test-rust-ci test-doc test-doc-exact bench-compile examples
ci: action-lint zizmor markdown-check spell-check docs-version-check toml-parse-check toml-fmt-check toml-lint yaml-fmt-check yaml-lint citation-check validate-json justfile-fmt-check python-format-check python-lint python-fixture-lint python-typecheck test-python cargo-lock-check fmt-check clippy-all-targets doc-check semgrep semgrep-test unused-deps shell-check test-rust-ci test-doc test-doc-exact bench-compile examples
@echo "🎯 CI checks complete!"

# Validate CITATION.cff against the Citation File Format schema.
Expand Down Expand Up @@ -702,26 +700,29 @@ plot-vs-linalg metric="lu_solve" stat="median" sample="new" log_y="false" allow_
uv run --locked criterion-dim-plot "${args[@]}"

# Python tooling (uv)
python-check: python-format-check python-lint python-typecheck
python-check: python-format-check python-lint python-fixture-lint python-typecheck

python-ci: python-format-check python-lint python-typecheck test-python
python-ci: python-format-check python-lint python-fixture-lint python-typecheck test-python
@echo "✅ Python checks complete!"

python-fix: python-sync
uv run --locked ruff check scripts/ --fix
uv run --locked ruff format scripts/
uv run --locked ruff format scripts/ tests/semgrep/scripts/

python-format-check: python-sync
uv run --locked ruff format --check scripts/
uv run --locked ruff format --check scripts/ tests/semgrep/scripts/

python-lint: python-sync
uv run --locked ruff check scripts/

python-fixture-lint: python-sync
uv run --locked ruff check tests/semgrep/scripts/

python-sync: _ensure-uv
uv sync --locked --group dev

python-typecheck: python-sync
uv run --locked ty check scripts/ --error all
uv run --locked ty check scripts/ tests/semgrep/scripts/ --error all

rust-core-check: cargo-lock-check fmt-check clippy-core doc-check semgrep semgrep-test unused-deps
@echo "✅ Rust core checks complete!"
Expand Down Expand Up @@ -1115,7 +1116,7 @@ update-cargo-tools: _ensure-stable-uv-version _ensure-cargo-install-update

# Advance Cargo and exact Python development requirements plus their lockfiles.
[doc('Update Cargo and Python development requirements plus all Cargo/uv locked dependencies.')]
update-dependencies: _ensure-cargo-edit _ensure-uv-available update-cargo-dependencies update-python-dependencies
update-dependencies: _ensure-cargo-edit _ensure-stable-uv-version update-cargo-dependencies update-python-dependencies

# Advance Cargo dependency declarations and lockfile entries.
[doc('Update Cargo.toml dependency requirements and Cargo.lock.')]
Expand Down
7 changes: 5 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ line-length = 160
src = [ "scripts" ]

[tool.ruff.lint]
select = [ "E", "F", "W", "ANN201", "ANN202", "ANN204", "C90", "I", "N", "UP", "YTT", "ASYNC", "S", "BLE", "FBT", "B", "A", "COM", "C4", "DTZ", "FA", "T10", "EM", "EXE", "FIX", "FLY", "FURB", "ISC", "ICN", "LOG", "G", "INP", "PERF", "PIE", "T20", "PYI", "PT", "Q", "RSE", "RET", "SLF", "SIM", "SLOT", "TC", "TID", "TD", "ARG", "PTH", "ERA", "PD", "PGH", "PL", "TRY", "NPY", "RUF", "D100", "D101", "D102", "D103", "D104", "D105", "D106", "D107" ]
select = [ "E", "F", "W", "ANN001", "ANN002", "ANN003", "ANN201", "ANN202", "ANN204", "ANN205", "ANN206", "C90", "I", "N", "UP", "YTT", "ASYNC", "S", "BLE", "FBT", "B", "A", "COM", "C4", "DTZ", "FA", "T10", "EM", "EXE", "FIX", "FLY", "FURB", "ISC", "ICN", "LOG", "G", "INP", "PERF", "PIE", "T20", "PYI", "PT", "Q", "RSE", "RET", "SLF", "SIM", "SLOT", "TC", "TID", "TD", "ARG", "PTH", "ERA", "PD", "PGH", "PL", "TRY", "NPY", "RUF", "D100", "D101", "D102", "D103", "D104", "D105", "D106", "D107" ]
fixable = [ "ALL" ]
unfixable = [ ]
ignore = [
Expand Down Expand Up @@ -83,6 +83,9 @@ ignore = [

[tool.ruff.lint.per-file-ignores]
"**/tests/test_*.py" = [ "S101", "SLF001", "D101", "D102", "D103" ]
# Static-analysis fixtures intentionally contain the patterns these rules reject.
"tests/semgrep/scripts/python_portability.py" = [ "D103", "INP001", "N813", "PLW1510", "S603", "S607", "SIM115", "UP020", "UP021" ]
"tests/semgrep/scripts/tests/python_exceptions.py" = [ "BLE001", "D100", "D103", "EM101", "INP001", "S110", "S607", "SIM105", "TRY002" ]

[tool.ruff.lint.mccabe]
max-complexity = 10
Expand Down Expand Up @@ -152,7 +155,7 @@ dev = [
"actionlint-py==1.7.12.24",
"pytest==9.1.1",
"ruff==0.16.5",
"semgrep==1.175.0",
"semgrep==1.176.0",
"shellcheck-py==0.11.0.1",
"shfmt-py==4.1.0",
"ty==0.0.77",
Expand Down
1 change: 1 addition & 0 deletions scripts/archive_changelog.py
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,7 @@ def _stage_text(path: Path, text: str) -> Path:
with tempfile.NamedTemporaryFile(
"w",
encoding="utf-8",
newline="",
dir=path.parent,
prefix=f".{path.name}.",
suffix=".tmp",
Expand Down
1 change: 1 addition & 0 deletions scripts/archive_performance.py
Original file line number Diff line number Diff line change
Expand Up @@ -435,6 +435,7 @@ def _write_text(path: Path, text: str) -> None:
with tempfile.NamedTemporaryFile(
"w",
encoding="utf-8",
newline="",
dir=path.parent,
prefix=f".{path.name}.",
suffix=".tmp",
Expand Down
1 change: 1 addition & 0 deletions scripts/bench_compare.py
Original file line number Diff line number Diff line change
Expand Up @@ -2129,6 +2129,7 @@ def _write_text_atomic(path: Path, text: str) -> None:
with tempfile.NamedTemporaryFile(
"w",
encoding="utf-8",
newline="",
dir=path.parent,
prefix=f".{path.name}.",
suffix=".tmp",
Expand Down
8 changes: 4 additions & 4 deletions scripts/criterion_dim_plot.py
Original file line number Diff line number Diff line change
Expand Up @@ -402,7 +402,7 @@ def _require_confidence_interval(lo: float, hi: float, context: str) -> None:

def _write_csv(out_csv: Path, rows: list[Row]) -> None:
out_csv.parent.mkdir(parents=True, exist_ok=True)
with out_csv.open("w", encoding="utf-8") as f:
with out_csv.open("w", encoding="utf-8", newline="\n") as f:
f.write("D,la_stack,la_lo,la_hi,nalgebra,na_lo,na_hi,faer,fa_lo,fa_hi\n")
for row in rows:
f.write(f"{row.dim},{row.la_time},{row.la_lo},{row.la_hi},{row.na_time},{row.na_lo},{row.na_hi},{row.fa_time},{row.fa_lo},{row.fa_hi}\n")
Expand Down Expand Up @@ -461,7 +461,7 @@ def _update_readme_table(readme_path: Path, marker_begin: str, marker_end: str,
if new_lines == lines:
return False

readme_path.write_text("".join(new_lines), encoding="utf-8")
readme_path.write_text("".join(new_lines), encoding="utf-8", newline="\n")
return True


Expand Down Expand Up @@ -1095,7 +1095,7 @@ def _capture_performance_provenance(
def _write_provenance(path: Path, provenance: dict[str, object]) -> None:
"""Write stable, sorted JSON provenance beside generated benchmark assets."""
path.parent.mkdir(parents=True, exist_ok=True)
path.write_text(json.dumps(provenance, indent=2, sort_keys=True) + "\n", encoding="utf-8")
path.write_text(json.dumps(provenance, indent=2, sort_keys=True) + "\n", encoding="utf-8", newline="\n")


def _validate_readme_target(root: Path, args: PlotCliArgs) -> int: # noqa: C901, PLR0911, PLR0912
Expand Down Expand Up @@ -1283,7 +1283,7 @@ def _update_staged_readme_publication(
stat=args.stat,
version=package_version,
)
staged_readme.write_text(updated_readme, encoding="utf-8")
staged_readme.write_text(updated_readme, encoding="utf-8", newline="\n")


def _stage_and_publish_outputs( # noqa: PLR0913
Expand Down
1 change: 1 addition & 0 deletions scripts/postprocess_changelog.py
Original file line number Diff line number Diff line change
Expand Up @@ -904,6 +904,7 @@ def _write_text_atomic(path: Path, text: str) -> None:
with tempfile.NamedTemporaryFile(
"w",
encoding="utf-8",
newline="",
dir=path.parent,
prefix=f".{path.name}.",
suffix=".tmp",
Expand Down
7 changes: 6 additions & 1 deletion scripts/subprocess_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,12 @@ def run_safe_command(
def _darwin_cpu_model() -> str:
try:
return run_safe_command("sysctl", ["-n", "machdep.cpu.brand_string"]).stdout.strip()
except ExecutableNotFoundError, OSError, subprocess.CalledProcessError, subprocess.TimeoutExpired:
except (
ExecutableNotFoundError,
OSError,
subprocess.CalledProcessError,
subprocess.TimeoutExpired,
):
return ""


Expand Down
99 changes: 84 additions & 15 deletions scripts/tests/test_justfile_discoverability.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,15 @@
import json
import os
import re
import shlex
import shutil
import stat
import subprocess
from pathlib import Path
from typing import Any

import pytest

import update_cargo_tool_pins

REPO_ROOT = Path(__file__).resolve().parents[2]
Expand Down Expand Up @@ -40,6 +43,49 @@ def just_recipes() -> dict[str, dict[str, Any]]:
return recipes


def write_fake_uv(directory: Path, version_output: str, *, windows_lookup_output: str | None = None) -> None:
"""Write a Bash uv shim and an optional conflicting native Windows shim."""
real_uv = shutil.which("uv")
assert real_uv is not None
posix_shim = directory / "uv"
posix_shim.write_text(
f"""#!/bin/sh
if [ "$1" = "--version" ]; then
printf '%s\\n' {shlex.quote(version_output)}
else
exec {shlex.quote(real_uv)} "$@"
fi
""",
encoding="utf-8",
newline="\n",
)
posix_shim.chmod(posix_shim.stat().st_mode | stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH)

if os.name == "nt":
native_output = windows_lookup_output or version_output
if re.fullmatch(r"[A-Za-z0-9 ._-]+", native_output) is None:
msg = f"unsupported native uv version fixture output: {native_output!r}"
raise ValueError(msg)
windows_shim = directory / "uv.cmd"
real_uv_command = subprocess.list2cmdline([real_uv])
script = "\r\n".join(
(
"@echo off",
'if "%~1"=="--version" (',
f" echo({native_output}",
" exit /b 0",
")",
f"{real_uv_command} %*",
"",
)
)
windows_shim.write_text(
script,
encoding="utf-8",
newline="",
)


def test_uv_backed_helpers_reuse_pinned_guard() -> None:
"""Local uv consumers should share one exact-version implementation."""
recipes = just_recipes()
Expand All @@ -59,9 +105,7 @@ def test_uv_guard_reports_expected_and_actual_versions(tmp_path: Path) -> None:
"""A mismatched uv executable should fail with actionable version details."""
fake_bin = tmp_path / "bin"
fake_bin.mkdir()
fake_uv = fake_bin / "uv"
fake_uv.write_text("#!/bin/sh\nprintf '%s\\n' 'uv 9.9.9'\n", encoding="utf-8")
fake_uv.chmod(fake_uv.stat().st_mode | stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH)
write_fake_uv(fake_bin, "uv 9.9.9")

environment = os.environ.copy()
environment["CARGO_HOME"] = str(tmp_path / "cargo")
Expand All @@ -74,21 +118,35 @@ def test_uv_guard_reports_expected_and_actual_versions(tmp_path: Path) -> None:
assert f"version '9.9.9', expected '{expected}'" in result.stderr


def test_stable_uv_preflight_rejects_nonstable_or_embedded_versions(tmp_path: Path) -> None:
@pytest.mark.parametrize(
"output",
["uv 9.9.9 using runtime 3.14.0", "uv version unknown", "uv 9.9.9-beta.1", "uv 9.9.9.1", "uv release-9.9.9"],
)
def test_stable_uv_preflight_rejects_unstorable_versions(tmp_path: Path, output: str) -> None:
"""Update preflights should reject uv versions the pin reconciler cannot store."""
fake_bin = tmp_path / "bin"
fake_bin.mkdir()
fake_uv = fake_bin / "uv"
write_fake_uv(fake_bin, output, windows_lookup_output="uv 7.7.7")
environment = os.environ.copy()
environment["PATH"] = f"{fake_bin}{os.pathsep}{environment['PATH']}"

result = run_just("_ensure-stable-uv-version", check=False, env=environment)

assert result.returncode != 0
assert "must report exactly one stable X.Y.Z version" in result.stderr


def test_stable_uv_preflight_accepts_newer_stable_version(tmp_path: Path) -> None:
"""Update reconciliation may advance the repository's active uv pin."""
fake_bin = tmp_path / "bin"
fake_bin.mkdir()
write_fake_uv(fake_bin, "uv 9.9.9")
environment = os.environ.copy()
environment["PATH"] = f"{fake_bin}{os.pathsep}{environment['PATH']}"

for output in ("uv 9.9.9-beta.1", "uv 9.9.9.1", "uv release-9.9.9"):
fake_uv.write_text(f"#!/bin/sh\nprintf '%s\\n' '{output}'\n", encoding="utf-8")
fake_uv.chmod(fake_uv.stat().st_mode | stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH)
result = run_just("_ensure-stable-uv-version", check=False, env=environment)
result = run_just("_ensure-stable-uv-version", check=False, env=environment)

assert result.returncode != 0
assert "must report a stable X.Y.Z version" in result.stderr
assert result.returncode == 0


def test_update_workflow_composes_scoped_dependency_and_tool_updates() -> None:
Expand All @@ -107,14 +165,14 @@ def test_update_workflow_composes_scoped_dependency_and_tool_updates() -> None:
aggregate_update = aggregate_result.stdout + aggregate_result.stderr
cargo_upgrade = "cargo upgrade --incompatible allow --exclude num-bigint --exclude num-rational"
assert aggregate_update.index("command -v cargo-install-update") < aggregate_update.index(cargo_upgrade)
assert aggregate_update.index("must report a stable X.Y.Z version") < aggregate_update.index(cargo_upgrade)
assert aggregate_update.index("--check-uv-version") < aggregate_update.index(cargo_upgrade)

dependency_result = run_just("--dry-run", "update-dependencies")
dependency_update = dependency_result.stdout + dependency_result.stderr
dependency_preflights = [dependency["recipe"] for dependency in recipes["update-dependencies"]["dependencies"]]
assert dependency_preflights[:2] == ["_ensure-cargo-edit", "_ensure-uv-available"]
assert dependency_preflights[:2] == ["_ensure-cargo-edit", "_ensure-stable-uv-version"]
assert dependency_update.index("cargo upgrade --version") < dependency_update.index(cargo_upgrade)
assert dependency_update.index("uv --version") < dependency_update.index(cargo_upgrade)
assert dependency_update.index("--check-uv-version") < dependency_update.index(cargo_upgrade)
assert cargo_upgrade in dependency_update
assert "cargo update" in dependency_update
assert "uv run --locked update-python-dev-pins" in dependency_update
Expand All @@ -128,7 +186,7 @@ def test_update_workflow_composes_scoped_dependency_and_tool_updates() -> None:
tool_update = tool_result.stdout + tool_result.stderr
assert "command -v cargo-install-update" in tool_update
assert "cargo install-update --locked" in tool_update
assert tool_update.index("must report a stable X.Y.Z version") < tool_update.index("cargo install-update --locked")
assert tool_update.index("--check-uv-version") < tool_update.index("cargo install-update --locked")
assert "update-cargo-tool-pins" in tool_update
assert "cargo install-update --all" not in tool_update
assert "uv tool upgrade" not in tool_update
Expand All @@ -152,3 +210,14 @@ def test_managed_tool_pins_exist_once_in_root_justfile() -> None:

for pin in update_cargo_tool_pins.PIN_TO_TOOL:
assert len(re.findall(rf'(?m)^{re.escape(pin)}\s*:=\s*"[^"]+"\s*$', justfile_text)) == 1


def test_ci_enforces_full_python_fixture_lint_policy() -> None:
"""Canonical CI should lint fixtures without narrowing the Ruff configuration."""
recipes = just_recipes()
ci_dependencies = {dependency["recipe"] for dependency in recipes["ci"]["dependencies"]}
fixture_lint_body = json.dumps(recipes["python-fixture-lint"]["body"])

assert "python-fixture-lint" in ci_dependencies
assert "ruff check tests/semgrep/scripts/" in fixture_lint_body
assert "--select" not in fixture_lint_body
Loading
Loading