Last active
October 2, 2025 10:55
-
-
Save stigok/338fa5ab419f12bb11c4d47cb09d044f to your computer and use it in GitHub Desktop.
This file contains hidden or 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
#!/usr/bin/env python3 | |
# ruff: noqa: E501 | |
""" | |
Given a regular expression pattern containing certain named capture groups, | |
print a line to stdout for each match found in `infile`. The printed messages | |
is in a format that will annotate code in a GitHub pull request. | |
See the source code of this program for usage examples. | |
See GitHub command reference for more information. | |
https://docs.github.com/en/actions/reference/workflows-and-actions/workflow-commands | |
""" | |
# For example, given the following input: | |
# | |
# migrations/env.py:77: unused variable 'reflected' (100% confidence) | |
# tests/database_fixtures.py:61: unused variable 'init_database' (100% confidence) | |
# tests/object_factories/address_factories.py:54: unused variable 'ordanization_id' (100% confidence) | |
# | |
# you can use the following pattern: | |
# | |
# --pattern "^(?P<filename>[^:]+):(?P<line_number>\d+): (?P<message>.+$)" | |
# | |
# to get the following output printed to stdout: | |
# | |
# ::error file=migrations/env.py,line=77,title=Regex match::unused variable 'reflected' (100% confidence) | |
# ::error file=tests/database_fixtures.py,line=61,title=Regex match::unused variable 'init_database' (100% confidence) | |
# ::error file=tests/object_factories/address_factories.py,line=54,title=Regex match::unused variable 'ordanization_id' (100% confidence) | |
# | |
# ... which will annotate the code lines when these messages are printed in a | |
# github actions run, for example in a pull request. | |
# | |
# Be advised that GitHub UI will show at most 10 errors per run (as of Oct 2025). | |
from argparse import ArgumentParser, FileType | |
import re | |
import sys | |
# fmt: off | |
parser = ArgumentParser(description=__doc__) | |
parser.add_argument("infile", type=FileType("r"), default=(None if sys.stdin.isatty() else sys.stdin)) | |
parser.add_argument("--pattern", type=str, required=True) | |
parser.add_argument("--title", type=str, default="Regex match") | |
parser.add_argument("--outfile", type=FileType("w"), default=sys.stdout) | |
args = parser.parse_args() | |
# fmt: on | |
pattern = re.compile(args.pattern, re.MULTILINE) | |
assert "filename" in pattern.groupindex | |
assert "line_number" in pattern.groupindex | |
assert "message" in pattern.groupindex | |
haystack = args.infile.read() | |
exit_status = 0 | |
for match in pattern.finditer(haystack): | |
filename = match.group("filename") | |
line_number = match.group("line_number") | |
message = match.group("message") | |
print( | |
f"""::error file={filename},line={line_number},title={args.title}::{message}""", | |
file=args.outfile, | |
) | |
exit_status = 1 | |
sys.exit(exit_status) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment