Skip to content
Closed
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
207 changes: 182 additions & 25 deletions scripts/check_codeql_alerts.py

Large diffs are not rendered by default.

30 changes: 28 additions & 2 deletions scripts/codeql_reset_dismissed_alerts.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
import urllib.parse
import urllib.request
from dataclasses import dataclass
from typing import Iterator, List, Optional
from typing import Any, Iterator, List, Optional

API_ROOT = "https://api.github.com"
API_VERSION = "2022-11-28"
Expand All @@ -45,7 +45,7 @@ def _request(
*,
params: Optional[dict] = None,
payload: Optional[dict] = None,
) -> dict:
) -> Any:
url = urllib.parse.urljoin(API_ROOT, path)
if params:
query = urllib.parse.urlencode(params)
Expand Down Expand Up @@ -99,6 +99,8 @@ def _paginate_alerts(owner: str, repo: str) -> Iterator[dict]:

@dataclass
class Alert:
"""Represents a dismissed CodeQL alert."""

number: int
html_url: str
rule_id: str
Expand All @@ -123,6 +125,14 @@ def _to_alert(raw: dict) -> Alert:


def reopen_alert(owner: str, repo: str, alert: Alert, *, dry_run: bool) -> None:
"""Reopens a dismissed CodeQL alert.

Args:
owner: The GitHub organization or user.
repo: The repository name.
alert: The alert to reopen.
dry_run: If True, print the action without executing it.
"""
if dry_run:
print(f"DRY RUN: would reopen alert #{alert.number} ({alert.rule_id})")
return
Expand All @@ -135,6 +145,14 @@ def reopen_alert(owner: str, repo: str, alert: Alert, *, dry_run: bool) -> None:


def parse_args(argv: Optional[List[str]] = None) -> argparse.Namespace:
"""Parses command-line arguments.

Args:
argv: The command-line arguments to parse.

Returns:
The parsed arguments.
"""
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--owner", required=True, help="GitHub organization or user")
parser.add_argument("--repo", required=True, help="Repository name")
Expand All @@ -147,6 +165,14 @@ def parse_args(argv: Optional[List[str]] = None) -> argparse.Namespace:


def main(argv: Optional[List[str]] = None) -> int:
"""The main entry point of the script.

Args:
argv: The command-line arguments.

Returns:
The exit code.
"""
args = parse_args(argv)
try:
alerts = [_to_alert(raw) for raw in _paginate_alerts(args.owner, args.repo)]
Expand Down
38 changes: 38 additions & 0 deletions scripts/create_coverage_symlinks.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,14 @@


def should_link(path: pathlib.Path) -> bool:
"""Checks if a file should be symlinked for coverage analysis.

Args:
path: The path to the file.

Returns:
True if the file should be symlinked, False otherwise.
"""
if not path.is_file():
return False
suffix = path.suffix
Expand All @@ -49,6 +57,14 @@ def should_link(path: pathlib.Path) -> bool:


def iter_source_files(build_root: pathlib.Path) -> Iterable[pathlib.Path]:
"""Iterates over all source files in a directory.

Args:
build_root: The root directory to search.

Yields:
Paths to the source files.
"""
for root, _dirs, files in os.walk(build_root):
root_path = pathlib.Path(root)
for filename in files:
Expand All @@ -58,6 +74,12 @@ def iter_source_files(build_root: pathlib.Path) -> Iterable[pathlib.Path]:


def create_symlinks(build_root: pathlib.Path, output_root: pathlib.Path) -> None:
"""Creates symlinks for all source files in a directory.

Args:
build_root: The root directory containing the source files.
output_root: The directory where the symlinks will be created.
"""
if output_root.exists():
shutil.rmtree(output_root)
output_root.mkdir(parents=True, exist_ok=True)
Expand All @@ -79,13 +101,29 @@ def create_symlinks(build_root: pathlib.Path, output_root: pathlib.Path) -> None


def parse_args(argv: Iterable[str]) -> argparse.Namespace:
"""Parses command-line arguments.

Args:
argv: The command-line arguments to parse.

Returns:
The parsed arguments.
"""
parser = argparse.ArgumentParser(description="Create coverage symlink tree")
parser.add_argument("--build-root", required=True)
parser.add_argument("--output-root", required=True)
return parser.parse_args(list(argv)[1:])


def main(argv: Iterable[str]) -> int:
"""The main entry point of the script.

Args:
argv: The command-line arguments.

Returns:
The exit code.
"""
args = parse_args(argv)
build_root = pathlib.Path(args.build_root).resolve()
output_root = pathlib.Path(args.output_root).resolve()
Expand Down
13 changes: 13 additions & 0 deletions scripts/export_llvm_lcov.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,11 @@


def build_parser() -> argparse.ArgumentParser:
"""Builds the command-line argument parser.

Returns:
The argument parser.
"""
parser = argparse.ArgumentParser(
description="Run llvm-cov export and write the LCOV data to a file."
)
Expand All @@ -28,6 +33,14 @@ def build_parser() -> argparse.ArgumentParser:


def main(argv: list[str] | None = None) -> int:
"""The main entry point of the script.

Args:
argv: The command-line arguments.

Returns:
The exit code.
"""
parser = build_parser()
args = parser.parse_args(argv)

Expand Down
15 changes: 10 additions & 5 deletions scripts/normalize_coverage_xml.py
Original file line number Diff line number Diff line change
Expand Up @@ -208,12 +208,17 @@ def _usable_prefix(prefix: Path | None) -> Path | None:

absolute_candidate = (repo_root_resolved / relative).resolve()

cls.set("filename", relative.as_posix())
if relative is not None:
cls.set("filename", relative.as_posix())

candidate = repo_root / relative
candidate_resolved = absolute_candidate
if not candidate.exists() and not candidate_resolved.exists():
missing.append(relative.as_posix())
candidate = repo_root / relative
if absolute_candidate is not None:
candidate_resolved = absolute_candidate
else:
candidate_resolved = candidate.resolve()

if not candidate.exists() and not candidate_resolved.exists():
missing.append(relative.as_posix())

tree.write(report_path)
return missing, external
Expand Down
9 changes: 9 additions & 0 deletions scripts/sarif-alerts.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
"""A simple tool to print SARIF results from one or more SARIF files."""
import argparse
import json
from pathlib import Path
Expand Down Expand Up @@ -26,6 +27,14 @@ def _process_sarif(path: Path) -> Iterable[str]:


def main(argv=None) -> int:
"""The main entry point of the script.

Args:
argv: The command-line arguments.

Returns:
The exit code.
"""
parser = argparse.ArgumentParser(
description="Print SARIF results from one or more SARIF files"
)
Expand Down
1 change: 1 addition & 0 deletions test/python/adder.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
"""This module defines a simple C++ function using cppyy."""
import cppyy

cppyy.cppdef("""\
Expand Down
6 changes: 6 additions & 0 deletions test/python/pyphlex.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,12 @@
# `with` is a keyword in Python, so can not be the name of a method; fix this
# by renaming it to `with_` for all phlex classes
def fixwith(klass, name):
"""A cppyy pythonization to rename the 'with' method to 'with_'.

Args:
klass: The class to pythonize.
name: The name of the class.
"""
try:
klass.with_ = getattr(klass, "with")
except AttributeError:
Expand Down
5 changes: 4 additions & 1 deletion test/python/registry.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
"""This module provides a function to register Python algorithms with the Phlex framework."""
import types

import cppyy
import pyphlex # noqa: F401

Expand All @@ -7,7 +10,7 @@

cppyy.include("Python.h")

_registered_modules = dict()
_registered_modules: dict[str, types.ModuleType] = {}


def register(m, config):
Expand Down
10 changes: 8 additions & 2 deletions test/python/test_phlex.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,18 @@
"""This module contains tests for the pyphlex module."""


class TestPYPHLEX:
"""Tests for the pyphlex module."""

@classmethod
def setup_class(cls):
"""Set up the test class."""
import pyphlex # noqa: F401

__all__ = ["pyphlex"] # For CodeQL
__all__ = ["pyphlex"] # noqa: F841 # For CodeQL

def test01_phlex_existence(self):
"""Test existence of the phlex namespace"""
"""Test existence of the phlex namespace."""
import cppyy

assert cppyy.gbl.phlex
Loading