-
-
Save rmcgibbo/6e6ed0d69d864ca220f54369f2bb3828 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import json | |
import os | |
import subprocess | |
import sys | |
from typing import Any, Dict, List | |
from .nix import Attr | |
# https://github.com/rmcgibbo/nixpkgs-review-bot/issues/26 | |
IGNORE_SUGGESTIONS_FOR_FILES = { | |
"pkgs/misc/vim-plugins/generated.nix", | |
"pkgs/misc/vim-plugins/overrides.nix", | |
"pkgs/misc/tmux-plugins/default.nix", | |
} | |
# https://github.com/jtojnar/nixpkgs-hammering/issues/73 | |
# https://github.com/jtojnar/nixpkgs-hammering/issues/77#issuecomment-786193493 | |
# https://github.com/jtojnar/nixpkgs-hammering/pull/78#pullrequestreview-599072677 | |
ATTRS_THAT_BREAK_NIXPKGS_HAMMER = { | |
"acl", | |
"attr", | |
"bash", | |
"binutils-unwrapped", | |
"bzip2", | |
"coreutils", | |
"coreutils-full", | |
"coreutils-prefixed", | |
"datadog-agent", | |
"diffutils", | |
"findutils", | |
"gawkInteractive", | |
"gcc-unwrapped", | |
"glibc", | |
"gnugrep", | |
"gnupatch", | |
"gnused", | |
"gnutar", | |
"gzip", | |
"holochain-go", | |
"javaPackages.junit_4_12", | |
"javaPackages.mavenHello_1_0", | |
"javaPackages.mavenHello_1_1", | |
"libgccjit", | |
"zfsbackup", | |
} | |
def nixpkgs_hammer(attrs: List[Attr], modified_files: List[str] = None) -> List[Attr]: | |
"""Run nixpkgs-hammer on each attr, saves the results into the | |
'check_report' field on the attr. | |
Only save checks if the 'location' of the bug flagged by the check is within | |
the set of files modified by the pr, which should be passed in `modified_files`. | |
""" | |
cmd = [ | |
"nixpkgs-hammer", | |
"-f", | |
".", | |
"--json", | |
"--exclude", | |
"attribute-ordering", | |
"--exclude", | |
"explicit-phases", | |
# Discussion here: https://github.com/jtojnar/nixpkgs-hammering/pull/38#issuecomment-778381992 | |
"--exclude", | |
"attribute-typo", | |
] + [ | |
a.name | |
for a in attrs | |
if (a.name not in ATTRS_THAT_BREAK_NIXPKGS_HAMMER) | |
and (not a.skipped) | |
and (not a.blacklisted) | |
and (not a.broken) | |
] | |
print("$" + " ".join(cmd), file=sys.stderr) | |
try: | |
proc = subprocess.run( | |
cmd, | |
stdout=subprocess.PIPE, | |
stderr=subprocess.PIPE, | |
check=True, | |
text=True, | |
) | |
except subprocess.CalledProcessError as e: | |
print(os.path.abspath(os.getcwd()), file=sys.stderr) | |
print(e.stderr, file=sys.stderr) | |
print(e.stderr, file=sys.stderr) | |
print(e.returncode, file=sys.stderr) | |
raise | |
hammer_report = json.loads(proc.stdout) | |
for name, data in hammer_report.items(): | |
for msg in data: | |
for location in msg.get("locations", []): | |
if "file" in location and isinstance(location["file"], str): | |
location["file"] = os.path.relpath(location["file"], ".") | |
attrs_by_name = {a.name: a for a in attrs} | |
for name, data in hammer_report.items(): | |
for msg in (m for m in data if is_acceptable_hammer_message(m, modified_files)): | |
attrs_by_name[name].check_report.append(stringify_message(**msg)) | |
return attrs | |
def stringify_location(file: str, line: int, column: int): | |
with open(file, "r") as opened_file: | |
all_lines = opened_file.read().splitlines() | |
line_contents = all_lines[line - 1] | |
line_spaces = " " * len(str(line)) | |
pointer = " " * (column - 1) + "^" | |
location_lines = [ | |
"Near " + file + ":" + str(line) + ":" + str(column) + ":", | |
"```", | |
line_spaces + " |", | |
str(line) + " | " + line_contents, | |
line_spaces + " | " + pointer, | |
"```", | |
"", | |
] | |
return "\n".join(location_lines) | |
def stringify_message( | |
name: str, | |
msg: str, | |
locations: List[Dict[str, Any]] = [], | |
cond: bool = True, | |
link: bool = True, | |
severity: str = "warning", | |
) -> str: | |
if link: | |
linked_name = f'<a href="https://github.com/jtojnar/nixpkgs-hammering/blob/master/explanations/{name}.md">{name}</a>' | |
else: | |
linked_name = name | |
message_lines = [ | |
f"{severity}: {linked_name}", | |
"", | |
msg, | |
] + list(map(lambda loc: stringify_location(**loc), locations)) | |
return "\n".join(message_lines) | |
def is_acceptable_hammer_message( | |
msg: Dict[str, Any], modified_files: List[str] = None | |
) -> bool: | |
predicates = [ | |
lambda: is_modified_location(msg, modified_files=modified_files), | |
lambda: not is_ignored_file(msg), | |
lambda: not is_ignored_golang_buildFlagsArray_msg(msg), | |
lambda: msg["name"] not in ("no-build-output",), | |
] | |
return all(pred() for pred in predicates) | |
def is_modified_location(msg: Dict[str, Any], modified_files: List[str] = None) -> bool: | |
if modified_files is None: | |
return True | |
for loc in msg.get("locations", []): | |
if loc["file"] in set(modified_files): | |
return True | |
return False | |
def is_ignored_file(msg: Dict[str, Any]) -> bool: | |
return any( | |
loc["file"] in IGNORE_SUGGESTIONS_FOR_FILES for loc in msg.get("locations", []) | |
) | |
def is_ignored_golang_buildFlagsArray_msg(msg: Dict[str, Any]) -> bool: | |
for loc in msg["locations"]: | |
is_golang = False | |
with open(loc["file"]) as f: | |
content = f.read() | |
is_golang = "buildGoModule" in content or "buildGoPackage" in content | |
if is_golang and msg["name"] == "no-flags-array": | |
return True | |
return False |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment