Skip to content

Commit

Permalink
Improve markdown comment formatting library and update PR comment format
Browse files Browse the repository at this point in the history
Signed-off-by: Jose R. Gonzalez <komish@flutes.dev>
  • Loading branch information
komish committed Oct 23, 2023
1 parent 1bd75c6 commit b44d0b1
Showing 1 changed file with 166 additions and 54 deletions.
220 changes: 166 additions & 54 deletions scripts/src/pullrequest/prepare_pr_comment.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,13 @@ def get_verifier_errors_comment():


def get_verifier_errors_trailer():
return "Please create a valid report with the [chart-verifier](https://github.com/redhat-certification/chart-verifier) \
and ensure all mandatory checks pass."
return " ".join(
[
"Please create a valid report with the",
"[chart-verifier](https://github.com/redhat-certification/chart-verifier)",
"and ensure all mandatory checks pass.",
]
)


def get_look_at_job_output_comment():
Expand All @@ -38,138 +43,245 @@ def get_look_at_job_output_comment():


def prepare_failure_comment():
msg = f"""\
{get_failure_comment()}
{get_look_at_job_output_comment()}"""
"""assembles the comment for certification failures
Will attempt to read a file with error messaging from the filesystem
and included that information in its content. (e.g. ./pr/errors)
"""
msg = get_failure_comment()
msg = append_to(msg, get_look_at_job_output_comment())
if os.path.exists("./pr/errors"):
errors = open("./pr/errors").read()
msg += f"""
{get_verifier_errors_comment()}
{errors}
{get_verifier_errors_trailer()}
"""
msg = append_to(msg, get_verifier_errors_comment())
msg = append_to(msg, errors)
msg = append_to(msg, get_verifier_errors_trailer())
gitutils.add_output("error-message", errors)
else:
gitutils.add_output("error-message", get_failure_comment())
return msg


def prepare_success_comment():
msg = f"{get_success_coment()}.\n\n"
return msg
def prepare_pr_content_failure_comment():
"""Generate a message for PR Content Check Failures
This function reaches into the environment for known variables
that contain error messages.
def prepare_pr_content_failure_comment():
msg = f"{get_content_failure_message()} \n"
Error messages are then passed into the GITHUB_OUTPUT.
Returns a formatted string containing error message contents.
"""
msg = f"{get_content_failure_message()}"
pr_content_error_msg = os.environ.get("PR_CONTENT_ERROR_MESSAGE", "")
owners_error_msg = os.environ.get("OWNERS_ERROR_MESSAGE", "")
if pr_content_error_msg:
gitutils.add_output("error-message", pr_content_error_msg)
msg += f"{pr_content_error_msg}\n\n"
msg = append_to(msg, f"{pr_content_error_msg}")
if owners_error_msg:
gitutils.add_output("error-message", owners_error_msg)
msg += f"{owners_error_msg}\n\n"
msg = append_to(msg, f"{owners_error_msg}")
return msg


def prepare_run_verifier_failure_comment():
verifier_error_msg = os.environ.get("VERIFIER_ERROR_MESSAGE", "")
gitutils.add_output("error-message", verifier_error_msg)
msg = f"""
{verifier_error_msg}
{get_look_at_job_output_comment()}
"""
msg = verifier_error_msg
msg = append_to(msg, get_look_at_job_output_comment())
return msg


def prepare_community_comment():
msg = f"{get_community_review_message()}\n\n"
msg = f"{get_community_review_message()}"
if os.path.exists("./pr/errors"):
errors = open("./pr/errors").read()
msg += "However, please note that one or more errors were found while building and verifying your pull request:\n\n"
msg += f"{errors}\n\n"
msg = append_to(
msg,
"However, **please note** that one or more errors were found while building and verifying your pull request:",
)
msg = append_to(msg, f"{errors}")
return msg


def prepare_generic_fail_comment():
msg = ""
if os.path.exists("./pr/errors"):
errors = open("./pr/errors").read()
msg += "One or more errors were found while building and verifying your pull request:\n\n"
msg += f"{errors}\n\n"
msg = append_to(
msg,
"One or more errors were found while building and verifying your pull request:",
)
msg = append_to(msg, f"{errors}")
else:
msg += "An unspecified error has occured while building and verifying your pull request.\n\n"
msg = append_to(
msg,
"An unspecified error has occured while building and verifying your pull request.",
)
return msg


def prepare_oc_install_fail_comment():
msg = "Unfortunately the certification process failed to install OpenShift Client and could not complete.\n\n"
msg += "This problem will be addressed by maintainers and no further action is required from the submitter at this time.\n\n"
return msg
return " ".join(
[
"Unfortunately the certification process failed to install OpenShift Clientand could not complete.",
"This problem will be addressed by maintainers and no further action is required from the submitter at this time.",
]
)


def get_comment_header(issue_number):
msg = (
f"Thank you for submitting PR #{issue_number} for Helm Chart Certification!\n\n"
def append_to(msg, new_content, use_horizontal_divider=False):
"""Appends new_content to the msg.
This utility function helps simplify the building of our PR comment
template. msg and new_content are joined with either a newline separator, or
a horizontal line (if the keyword argument is provided).
It should be used in cases where the caller needs to join semi-related
ideas. Callers should instead use the join string method in cases where the
msg being constructed is a part of the same 'idea', or 'paragraph'.
Developer Note: The use of the strip method is a developer optimization.
It's intended to allow us to use a multi-line string but work entirely at
the same indentation level in source code.
Args:
msg: The original message to which we should append new_content.
new_content: the new string to add. use_horizontal_divider: Whether to
divide the content
with a horizontal line (in markdown.) Horizontal lines are surrounded
in newlines to ensure that it doesn not inadvertently cause preceding
content to become a Header.
Returns the msg containing the new content.
"""
divider_string = ""
if use_horizontal_divider:
divider_string = "\n---\n"

return f"""
{msg}
{divider_string}
{new_content}
""".strip()


def get_support_information():
reqs_doc_link = "https://github.com/redhat-certification/chart-verifier/blob/main/docs/helm-chart-checks.md#types-of-helm-chart-checks"
support_link = "https://redhat-connect.gitbook.io/red-hat-partner-connect-general-guide/managing-your-account/getting-help/technology-partner-success-desk"
return "\n".join(
[
"For information on the certification process see:",
f"- [Red Hat certification requirements and process for Kubernetes applications that are deployed using Helm charts.]({reqs_doc_link}).",
f"- For support, connect with our [Technology Partner Acceleration Desk]({support_link}).",
]
)
return msg


def get_comment_footer(vendor_label, chart_name):
msg = "\n---\n\n"
msg += "For information on the certification process see:\n"
msg += "- [Red Hat certification requirements and process for Kubernetes applications that are deployed using Helm charts.](https://redhat-connect.gitbook.io/partner-guide-for-red-hat-openshift-and-container/helm-chart-certification/overview).\n\n"
msg += "For support, connect with our [Technology Partner Success Desk](https://redhat-connect.gitbook.io/red-hat-partner-connect-general-guide/managing-your-account/getting-help/technology-partner-success-desk).\n\n"
msg += f'/metadata {{"vendor_label": "{vendor_label}", "chart_name": "{chart_name}"}}\n\n'
def metadata_label(vendor_label, chart_name):
"""Returns the metadata context that must suffix PR comments."""
return (
f'/metadata {{"vendor_label": "{vendor_label}", "chart_name": "{chart_name}"}}'
)


def task_table(task_tuples):
"""returns a markdown table containing tasks and their outcome
Args:
task_tuples: a list of two-length tuples where index 0 is the task
and index 1 is the outcome. These values should be short.
"""
sorted(task_tuples)
msg = "|task|outcome|" + "\n|---|---|"
for task_tuple in task_tuples:
msg += f"\n|{task_tuple[0]}|{task_tuple[1]}|"
return msg


def overall_outcome(outcome):
return append_to("### Outcome:", "**{outcome}**")


def main():
pr_content_result = sys.argv[1]
run_verifier_result = sys.argv[2]
verify_result = sys.argv[3]
issue_number = open("./pr/NR").read().strip()
vendor_label = open("./pr/vendor").read().strip()
chart_name = open("./pr/chart").read().strip()
msg = get_comment_header(issue_number)

community_manual_review = os.environ.get("COMMUNITY_MANUAL_REVIEW", False)
oc_install_result = os.environ.get("OC_INSTALL_RESULT", False)

msg = f"Thank you for submitting PR #{issue_number} for Helm Chart Certification!"

# Assemble the detail separately to control order in which it is added to
# the overall output.
detail_message = "### Detail"

outcome = "Failed"

# Handle success explicitly
if (
pr_content_result == "success"
and run_verifier_result == "success"
and verify_result == "success"
and oc_install_result == "success"
):
msg += prepare_success_comment()
outcome = "Passed"
detail_message = append_to(detail_message, get_success_coment())
gitutils.add_output("pr_passed", "true")
else: # Handle various failure scenarios.
if pr_content_result == "failure":
msg += prepare_pr_content_failure_comment()
detail_message = append_to(
detail_message, prepare_pr_content_failure_comment()
)
gitutils.add_output("pr_passed", "false")
elif run_verifier_result == "failure":
msg += prepare_run_verifier_failure_comment()
detail_message = append_to(
detail_message, prepare_run_verifier_failure_comment()
)
gitutils.add_output("pr_passed", "false")
elif verify_result == "failure":
community_manual_review = os.environ.get("COMMUNITY_MANUAL_REVIEW", False)
if community_manual_review:
msg += prepare_community_comment()
outcome = "Pending Manual Review"
detail_message = append_to(detail_message, prepare_community_comment())
gitutils.add_output("pr_passed", "true")
else:
msg += prepare_failure_comment()
detail_message = append_to(detail_message, prepare_failure_comment())
gitutils.add_output("pr_passed", "false")
elif oc_install_result == "failure":
msg += prepare_oc_install_fail_comment()
detail_message = append_to(
detail_message, prepare_oc_install_fail_comment()
)
gitutils.add_output("pr_passed", "false")
else:
msg += prepare_generic_fail_comment()
detail_message = append_to(detail_message, prepare_generic_fail_comment())
gitutils.add_output("pr_passed", "false")

msg += get_comment_footer(vendor_label, chart_name)
msg = append_to(msg, overall_outcome(outcome))
msg = append_to(msg, detail_message)
if outcome != "Passed":
table = task_table(
[
("PR Content Check", pr_content_result),
("Run Chart Verifier", run_verifier_result),
("Result Verification", verify_result),
("OpenShift Client Installation", oc_install_result),
]
)
msg = append_to(msg, "### Task Insights")
msg = append_to(msg, "Here are the outcomes of tasks driving this result.")
msg = append_to(msg, table)

# All comments get helpful links and a metadata
msg = append_to(msg, get_support_information(), use_horizontal_divider=True)
msg = append_to(msg, metadata_label(vendor_label, chart_name))

# Print to the console so it's easily visible from CI.
print("*" * 30)
print(msg)
print("*" * 30)

with open("./pr/comment", "w") as fd:
fd.write(msg)
Expand Down

0 comments on commit b44d0b1

Please sign in to comment.