brintos

brintos / llvm-project-archived public Read only

0
0
Text · 5.7 KiB · 155e91b Raw
159 lines · python
1# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.2# See https://llvm.org/LICENSE.txt for license information.3# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception4"""Script for getting explanations from the premerge advisor."""5 6import argparse7import platform8import sys9import json10 11# TODO(boomanaiden154): Remove the optional call once we can require Python12# 3.10.13from typing import Optional14 15import requests16import github17import github.PullRequest18 19import generate_test_report_lib20 21PREMERGE_ADVISOR_URL = (22    "http://premerge-advisor.premerge-advisor.svc.cluster.local:5000/explain"23)24COMMENT_TAG = "<!--PREMERGE ADVISOR COMMENT: {platform}-->"25 26 27def get_comment_id(platform: str, pr: github.PullRequest.PullRequest) -> Optional[int]:28    platform_comment_tag = COMMENT_TAG.format(platform=platform)29    for comment in pr.as_issue().get_comments():30        if platform_comment_tag in comment.body:31            return comment.id32    return None33 34 35def get_comment(36    github_token: str,37    pr_number: int,38    body: str,39) -> dict[str, str]:40    repo = github.Github(github_token).get_repo("llvm/llvm-project")41    pr = repo.get_issue(pr_number).as_pull_request()42    body = COMMENT_TAG.format(platform=platform.system()) + "\n" + body43    comment = {"body": body}44    comment_id = get_comment_id(platform.system(), pr)45    if comment_id:46        comment["id"] = comment_id47    return comment48 49 50def main(51    commit_sha: str,52    build_log_files: list[str],53    github_token: str,54    pr_number: int,55    return_code: int,56):57    """The main entrypoint for the script.58 59    This function parses failures from files, requests information from the60    premerge advisor, and may write a Github comment depending upon the output.61    There are four different scenarios:62    1. There has never been a previous failure and the job passes - We do not63       create a comment. We write out an empty file to the comment path so the64       issue-write workflow knows not to create anything.65    2. There has never been a previous failure and the job fails - We create a66       new comment containing the failure information and any possible premerge67       advisor findings.68    3. There has been a previous failure and the job passes - We update the69       existing comment by passing its ID and a passed message to the70       issue-write workflow.71    4. There has been a previous failure and the job fails - We update the72       existing comment in the same manner as above, but generate the comment73       as if we have a failure.74 75    Args:76      commit_sha: The base commit SHA for this PR run.77      build_log_files: The list of JUnit XML files and ninja logs.78      github_token: The token to use to access the Github API.79      pr_number: The number of the PR associated with this run.80      return_code: The numerical return code of ninja/CMake.81    """82    junit_objects, ninja_logs = generate_test_report_lib.load_info_from_files(83        build_log_files84    )85    test_failures = generate_test_report_lib.get_failures(junit_objects)86    current_platform = f"{platform.system()}-{platform.machine()}".lower()87    explanation_request = {88        "base_commit_sha": commit_sha,89        "platform": current_platform,90        "failures": [],91    }92    if test_failures:93        for _, failures in test_failures.items():94            for name, failure_messsage in failures:95                explanation_request["failures"].append(96                    {"name": name, "message": failure_messsage}97                )98    elif return_code != 0:99        ninja_failures = generate_test_report_lib.find_failure_in_ninja_logs(ninja_logs)100        for name, failure_message in ninja_failures:101            explanation_request["failures"].append(102                {"name": name, "message": failure_message}103            )104    comments = []105    advisor_explanations = []106    if return_code != 0:107        advisor_response = requests.get(108            PREMERGE_ADVISOR_URL, json=explanation_request, timeout=5109        )110        if advisor_response.status_code == 200:111            print(advisor_response.json())112            advisor_explanations = advisor_response.json()113        else:114            print(advisor_response.reason)115    comments.append(116        get_comment(117            github_token,118            pr_number,119            generate_test_report_lib.generate_report(120                generate_test_report_lib.compute_platform_title(),121                return_code,122                junit_objects,123                ninja_logs,124                failure_explanations_list=advisor_explanations,125            ),126        )127    )128    if return_code == 0 and "id" not in comments[0]:129        # If the job succeeds and there is not an existing comment, we130        # should not write one to reduce noise.131        comments = []132    with open("comments", "w") as comment_file_handle:133        json.dump(comments, comment_file_handle)134 135 136if __name__ == "__main__":137    parser = argparse.ArgumentParser()138    parser.add_argument("commit_sha", help="The base commit SHA for the test.")139    parser.add_argument("return_code", help="The build's return code", type=int)140    parser.add_argument("github_token", help="Github authentication token", type=str)141    parser.add_argument("pr_number", help="The PR number", type=int)142    parser.add_argument(143        "build_log_files", help="Paths to JUnit report files and ninja logs.", nargs="*"144    )145    args = parser.parse_args()146 147    # Skip looking for results on AArch64 for now because the premerge advisor148    # service is not available on AWS currently.149    if platform.machine() == "arm64" or platform.machine() == "aarch64":150        sys.exit(0)151 152    main(153        args.commit_sha,154        args.build_log_files,155        args.github_token,156        args.pr_number,157        args.return_code,158    )159