Skip to content

Commit 1b3b67e

Browse files
committed
Start preparing annotations by the script itself
1 parent a833766 commit 1b3b67e

File tree

4 files changed

+139
-20
lines changed

4 files changed

+139
-20
lines changed

.pre-commit-config.yaml

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,15 @@ repos:
88
hooks:
99
- id: mdformat
1010
name: Format Markdown
11-
entry: mdformat # Executable to run, with fixed options
11+
entry: mdformat
1212
language: python
1313
types: [markdown]
1414
args: [--wrap, '75', --number]
1515
additional_dependencies:
1616
- mdformat-toc
1717
- mdformat-beautysh
18-
# -mdformat-shfmt
19-
# -mdformat-tables
18+
# - mdformat-shfmt
19+
# - mdformat-tables
2020
- mdformat-config
2121
- mdformat-black
2222
- mdformat-web
@@ -118,6 +118,7 @@ repos:
118118
- id: pylint
119119
additional_dependencies:
120120
- regex
121+
- requests
121122
- repo: https://github.com/pre-commit/mirrors-mypy
122123
rev: v1.7.1
123124
hooks:
@@ -130,4 +131,4 @@ repos:
130131
- --show-error-codes
131132
- --show-error-context
132133
- --disable-error-code=name-defined
133-
additional_dependencies: [tkcalendar>=1.5.0, types-pytz, regex]
134+
additional_dependencies: [tkcalendar>=1.5.0, types-pytz, regex,types-requests]

action.yml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,14 @@ inputs:
1414
description: Prefix to remove from paths in log
1515
required: false
1616
default:
17+
annotate:
18+
description: Turn annotation off/on (default = true in github workflow)
19+
required: false
20+
default:
1721
# outputs:
1822
# outpath: # id of output
1923
# description: The output path
2024
runs:
2125
using: docker
2226
image: Dockerfile
23-
args: ['${{ inputs.in }}', '${{ inputs.out }}', '${{ inputs.root }}']
27+
args: ['${{ inputs.in }}', '${{ inputs.out }}', '${{ inputs.root }}', '${{ inputs.annotate }}' ]

entrypoint.sh

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
11
#!/bin/bash -l
2+
ANNOTATE=""
3+
[ "$3" = "true" ] && ANNOTATE="--github-annotate"
4+
[ "$3" = "false" ] && ANNOTATE="--no-github-annotate"
25
[ "$3" = "" ] && python /logToCs.py "$1" "$2" --root "$PWD" && exit 0
36
[ "$3" != "" ] && python /logToCs.py "$1" "$2" --root "$3" && exit 0

logToCs.py

Lines changed: 126 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -47,11 +47,15 @@
4747
"""
4848

4949
import argparse
50+
import datetime as dt
51+
import json
5052
import os
5153
import re
5254
import sys
5355
import xml.etree.ElementTree as ET # nosec
5456

57+
import requests
58+
5559

5660
def remove_prefix(string, prefix):
5761
"""
@@ -64,27 +68,122 @@ def remove_prefix(string, prefix):
6468
return string
6569

6670

67-
def convert_to_checkstyle(messages, root_path=None):
71+
def convert_annotations_to_checkstyle(annotations, root_path=None):
6872
"""
69-
Convert provided message to CheckStyle format.
73+
Convert annotation list to CheckStyle xml string
7074
"""
7175
root = ET.Element("checkstyle")
72-
for message in messages:
73-
fields = parse_message(message)
74-
if fields:
75-
add_error_entry(root, **fields, root_path=root_path)
76+
for fields in annotations:
77+
add_error_entry(root, **fields, root_path=root_path)
7678
return ET.tostring(root, encoding="utf_8").decode("utf_8")
7779

7880

79-
def convert_text_to_checkstyle(text, root_path=None):
81+
def convert_lines_to_annotations(lines):
8082
"""
8183
Convert provided message to CheckStyle format.
8284
"""
83-
root = ET.Element("checkstyle")
84-
for fields in parse_file(text):
85+
annotations = []
86+
for line in lines:
87+
fields = parse_message(line)
8588
if fields:
86-
add_error_entry(root, **fields, root_path=root_path)
87-
return ET.tostring(root, encoding="utf_8").decode("utf_8")
89+
annotations.append(fields)
90+
return annotations
91+
92+
93+
def convert_text_to_annotations(text):
94+
"""
95+
Convert provided message to CheckStyle format.
96+
"""
97+
return parse_file(text)
98+
99+
100+
# Initial version for Checkrun from:
101+
# https://github.com/tayfun/flake8-your-pr/blob/50a175cde4dd26a656734c5b64ba1e5bb27151cb/src/main.py#L7C1-L123C36
102+
# MIT Licence
103+
class CheckRun:
104+
"""
105+
Represents the check run
106+
"""
107+
108+
GITHUB_TOKEN = os.environ.get("GITHUB_TOKEN", None)
109+
GITHUB_EVENT_PATH = os.environ.get("GITHUB_EVENT_PATH", None)
110+
111+
URI = "https://api.github.com"
112+
API_VERSION = "2022-11-28"
113+
ACCEPT_HEADER_VALUE = f"application/vnd.github.{API_VERSION}+json"
114+
AUTH_HEADER_VALUE = f"token {GITHUB_TOKEN}"
115+
# This is the max annotations Github API accepts in one go.
116+
MAX_ANNOTATIONS = 50
117+
118+
def __init__(self):
119+
"""
120+
Initialise Check Run object with information from checkrun
121+
"""
122+
self.read_event_file()
123+
self.read_meta_data()
124+
125+
def read_event_file(self):
126+
"""
127+
Read the event file to get the event information later.
128+
"""
129+
if self.GITHUB_EVENT_PATH is None:
130+
raise ValueError("Not running in github workflow")
131+
with open(self.GITHUB_EVENT_PATH, encoding="utf_8") as event_file:
132+
self.event = json.loads(event_file.read())
133+
134+
def read_meta_data(self):
135+
"""
136+
Get meta data from event information
137+
"""
138+
self.repo_full_name = self.event["repository"]["full_name"]
139+
pull_request = self.event.get("pull_request")
140+
if pull_request:
141+
self.head_sha = pull_request["head"]["sha"]
142+
else:
143+
check_suite = self.event["check_suite"]
144+
self.head_sha = check_suite["pull_requests"][0]["base"]["sha"]
145+
146+
def submit( # pylint: disable=too-many-arguments
147+
self,
148+
annotations,
149+
title=None,
150+
summary=None,
151+
text=None,
152+
conclusion=None,
153+
):
154+
"""
155+
Submit annotations to github
156+
157+
:param conclusion: success, failure
158+
"""
159+
output = {
160+
"annotations": annotations[: CheckRun.MAX_ANNOTATIONS],
161+
}
162+
if title is not None:
163+
output["title"] = title
164+
output["summary"] = summary
165+
output["text"] = text
166+
167+
payload = {
168+
"name": "log-to-pr-annotation",
169+
"head_sha": self.head_sha,
170+
"status": "completed",
171+
"conclusion": conclusion,
172+
"completed_at": dt.datetime.now(dt.timezone.utc).isoformat(),
173+
"output": output,
174+
}
175+
176+
response = requests.post(
177+
f"{self.URI}/repos/{self.repo_full_name}/check-runs",
178+
headers={
179+
"Accept": self.ACCEPT_HEADER_VALUE,
180+
"Authorization": self.AUTH_HEADER_VALUE,
181+
},
182+
json=payload,
183+
timeout=30,
184+
)
185+
print(response.content)
186+
response.raise_for_status()
88187

89188

90189
ANY_REGEX = r".*?"
@@ -405,6 +504,12 @@ def main():
405504
" Defaults to working directory.",
406505
default=os.getcwd(),
407506
)
507+
parser.add_argument(
508+
"--github-annotate",
509+
action=argparse.BooleanOptionalAction,
510+
help="Annotate when in Github workflow.",
511+
default=(os.environ.get("GITHUB_EVENT_PATH", None) is not None),
512+
)
408513

409514
args = parser.parse_args()
410515

@@ -424,11 +529,13 @@ def main():
424529
root_path = os.path.join(args.root, "")
425530

426531
try:
427-
checkstyle_xml = convert_text_to_checkstyle(text, root_path=root_path)
532+
annotations = convert_text_to_annotations(text)
428533
except ImportError:
429-
checkstyle_xml = convert_to_checkstyle(
430-
re.split(r"[\r\n]+", text), root_path=root_path
431-
)
534+
annotations = convert_lines_to_annotations(re.split(r"[\r\n]+", text))
535+
536+
checkstyle_xml = convert_annotations_to_checkstyle(
537+
annotations, root_path=root_path
538+
)
432539

433540
if args.output == "-" and args.output_named:
434541
with open(args.output_named, "w", encoding="utf_8") as output_file:
@@ -439,6 +546,10 @@ def main():
439546
else:
440547
print(checkstyle_xml)
441548

549+
if args.github_annotate:
550+
checkrun = CheckRun()
551+
checkrun.submit(annotations)
552+
442553

443554
if __name__ == "__main__":
444555
main()

0 commit comments

Comments
 (0)