-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathentrypoint.py
158 lines (135 loc) · 5.41 KB
/
entrypoint.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
import os
import sys
from case_utils.case_validate import validate
from case_utils.case_validate.validate_types import ValidationResult
from case_utils.ontology.version_info import CURRENT_CASE_VERSION
from github import Github
# Get the environment variables as the settings for the validation
case_version: str = os.environ.get("CASE_VERSION", CURRENT_CASE_VERSION)
abort_on_failure: bool = (
os.environ.get("CASE_VALIDATE_ABORT", "false").lower() == "true"
)
case_path: str = os.environ.get("CASE_PATH", "/opt/json/")
extension_filter: str = os.environ.get("CASE_EXTENSION_FILTER", "")
report_in_pr = os.getenv("REPORT_IN_PR", "false").lower() == "true"
github_repo = os.getenv("GITHUB_REPOSITORY")
github_token = os.getenv("GITHUB_TOKEN")
github_pull_request = os.getenv("GITHUB_PULL_REQUEST", 0)
# Convert the github_pull_request to an int if it's numeric, otherwise set it to an empty string
github_pull_request = int(github_pull_request) if github_pull_request.isnumeric() else 0
# Print the variables with their keys for debugging
print(f"CASE_VERSION: {case_version}")
print(f"CASE_VALIDATE_ABORT: {abort_on_failure}")
print(f"CASE_PATH: {case_path}")
print(f"CASE_EXTENSION_FILTER: {extension_filter}")
print(f"REPORT_IN_PR: {report_in_pr}")
print(f"GITHUB_REPOSITORY: {github_repo}")
print(f"GITHUB_TOKEN: {'******' if github_token else ''}")
print(f"GITHUB_PULL_REQUEST: {github_pull_request}")
results: list[dict] = []
success: bool = True
def generate_html_report(reports: list[dict]) -> str:
"""
Generate an HTML report of the validation results for use in GitHub comments
:param reports: The list of validation results
:return: The HTML report
"""
html = "<!--AUTOMATED VALIDATION RESULTS-->"
html += "<h1>CASE Validation Results</h1>"
html += "<h2>Summary</h2>"
html += "<table>"
html += "<tr><th>File</th><th>Valid</th></tr>"
for report in reports:
html += f'<tr><td>{report["file"]}</td><td>'
html += (
"<span>✓</span>" if report["conforms"] else "<span>✗</span>"
)
html += "</td></tr>"
html += "</table>"
html += "<h2>Details</h2>"
for report in reports:
html += f'<details><summary><h3>{report["file"]} '
html += (
"<span>✓</span>" if report["conforms"] else "<span>✗</span>"
)
html += f'</h3></summary><pre>{report["output"]}</pre></details>'
return html
def annotate_pr(message: str) -> None:
"""
Annotate the GitHub Pull Request with the given message
:param message: The message to annotate the PR with
:return: None
"""
# If we're not reporting in the PR, just print the message and return
if not report_in_pr:
print("Not reporting in pull request")
return
# Get the GitHub values from the environment
if not github_repo:
print("No GitHub repository provided")
exit(1)
if not github_token:
print("No GitHub token provided")
exit(1)
if not github_pull_request or github_pull_request == 0:
print("No GitHub pull request provided; not reporting in pull request")
return
# Login to GitHub and get the PR object
client = Github(github_token)
repo = client.get_repo(github_repo)
pr = repo.get_pull(github_pull_request)
# Delete all existing comments that start with
# "<!--AUTOMATED VALIDATION RESULTS-->" to avoid duplicates
for comment in pr.get_issue_comments():
if comment.body.startswith("<!--AUTOMATED VALIDATION RESULTS-->"):
comment.delete()
# Create a new comment with the message
pr.create_issue_comment(message)
# Determine if the provided path is a directory. If so, then there is filtering
# and other handling to address. If it is a file, then it is assumed it should
# be validated.
if os.path.isdir(case_path):
# Get the list of files that end with the provided extension
files: list = [
os.path.join(case_path, f)
for f in os.listdir(case_path)
if f.endswith(extension_filter)
]
print(f"Validating {len(files)} files at: {case_path}")
# Loop through each file and validate it
has_failure: bool = False
for f in files:
result: ValidationResult = validate(
f, case_version=case_version, abort_on_first=abort_on_failure
)
print(f"Validating file at: {f}")
print(result.text)
results.append(
{"file": f, "conforms": result.conforms, "output": result.text}
) # noqa: E501
if not result.conforms:
has_failure = True
if abort_on_failure:
sys.exit(1)
# If there was a failure, then exit with a non-zero exit code
success = not has_failure
elif os.path.isfile(case_path):
# If the path is a file, then it is assumed it should be validated
# and ignore the filter
result: ValidationResult = validate(
case_path, case_version=case_version, abort_on_first=abort_on_failure
)
print(f"Validating file at: {case_path}")
print(result.text)
success = result.conforms
results.append(
{"file": case_path, "conforms": result.conforms, "output": result.text}
)
else:
print(f"${case_path} is not a valid path and the validation cannot continue")
sys.exit(1)
# Annotate the PR
annotate_pr(generate_html_report(results))
# Exit with a non-zero exit code if there were any failures
if not success:
exit(1)