From 9263cfdf5616644578dce04f11633dee0b9af255 Mon Sep 17 00:00:00 2001 From: Jami Cogswell Date: Thu, 19 Oct 2023 19:14:23 -0400 Subject: [PATCH 1/5] CI: save and upload comment id (if it exists) --- .../workflows/csv-coverage-pr-artifacts.yml | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/.github/workflows/csv-coverage-pr-artifacts.yml b/.github/workflows/csv-coverage-pr-artifacts.yml index 48c55b2a630..2f818713a1b 100644 --- a/.github/workflows/csv-coverage-pr-artifacts.yml +++ b/.github/workflows/csv-coverage-pr-artifacts.yml @@ -89,9 +89,25 @@ jobs: - name: Save PR number run: | mkdir -p pr - echo ${{ github.event.pull_request.number }} > pr/NR + echo ${PR_NUMBER} > pr/NR + env: + PR_NUMBER: ${{ github.event.pull_request.number }} - name: Upload PR number uses: actions/upload-artifact@v3 with: name: pr path: pr/ + - name: Save comment ID (if it exists) + run: | + mkdir -p comment + # Find the latest comment starting with COMMENT_PREFIX + COMMENT_PREFIX=":warning: The head of this PR and the base branch were compared for differences in the framework coverage reports." + gh api "repos/${GITHUB_REPOSITORY}/issues/${PR_NUMBER}/comments" --paginate | jq --arg prefix "${COMMENT_PREFIX}" '[.[] | select(.body|startswith($prefix)) | .id] | max' > comment/ID + env: + GITHUB_TOKEN: ${{ github.token }} + PR_NUMBER: ${{ github.event.pull_request.number }} + - name: Upload comment ID (if it exists) + uses: actions/upload-artifact@v3 + with: + name: comment + path: comment/ From 6e29b701007ff881e56ad74a63375b76117fed7d Mon Sep 17 00:00:00 2001 From: Jami Cogswell Date: Thu, 19 Oct 2023 19:19:25 -0400 Subject: [PATCH 2/5] CI: update comment (if it exists) --- misc/scripts/library-coverage/comment-pr.py | 42 ++++++++++++++++++++- 1 file changed, 40 insertions(+), 2 deletions(-) diff --git a/misc/scripts/library-coverage/comment-pr.py b/misc/scripts/library-coverage/comment-pr.py index 28e3855abb2..06d33cd0a99 100644 --- a/misc/scripts/library-coverage/comment-pr.py +++ b/misc/scripts/library-coverage/comment-pr.py @@ -56,6 +56,21 @@ def comment_pr(repo, run_id): if os.path.isdir("pr"): shutil.rmtree("pr") + utils.download_artifact(repo, "comment", "comment", run_id) + + try: + with open("comment/ID") as file: + raw_comment_id = int(file.read()) + except Exception as e: + # If there is no existing comment, comment/ID will contain just a + # newline (due to jq & gh behaviour). This will cause `int(file.read())` + # to fail, so we catch that and set `raw_comment_id` to `None`. + print("Could not retrieve an existing comment ID. \n", e) + raw_comment_id = None + finally: + if os.path.isdir("comment"): + shutil.rmtree("comment") + # Try storing diff for previous run: prev_run_id = 0 prev_diff_exists = False @@ -95,14 +110,37 @@ def comment_pr(repo, run_id): comment = comment_first_line + \ "A recent commit removed the previously reported differences." - post_comment(comment, repo, pr_number) + + if raw_comment_id is None: + post_initial_comment(comment, repo, pr_number) + else: + update_existing_comment(comment, repo, pr_number, raw_comment_id) -def post_comment(comment, repo, pr_number): +def post_initial_comment(comment, repo, pr_number): print(f"Posting comment to PR #{pr_number}") utils.subprocess_run(["gh", "pr", "comment", str(pr_number), "--repo", repo, "--body", comment]) +def update_existing_comment(comment, repo, pr_number, raw_comment_id): + # Fetch existing comment, and validate: + # - comment belongs to the PR with number `pr_number` + # - comment starts with the expected prefix `comment_first_line` + # - comment author is github-actions[bot] + comment_author = "github-actions[bot]" + filter = f"select(.issue_url | endswith(\"{repo}/issues/{pr_number}\")) " + \ + f"| select(.body | startswith(\"{comment_first_line}\")) " + \ + f"| select(.user.login == \"{comment_author}\") " + \ + "| .id" + comment_id = utils.subprocess_check_output(["gh", "api", f"repos/{repo}/issues/comments/{raw_comment_id}", + "--jq", filter]).strip() + + if comment_id: + print(f"Updating comment {comment_id} on PR #{pr_number}") + utils.subprocess_run(["gh", "api", f"repos/{repo}/issues/comments/{comment_id}", + "-X", "PATCH", "-f", f"body={comment}"]) + else: + print(f"Comment {raw_comment_id} did not pass validations: not editing.") def get_previous_run_id(repo, run_id, pr_number): """ From ee4a9c3f8d7f4962884727a3dc7e7083b49caa19 Mon Sep 17 00:00:00 2001 From: Jami Cogswell Date: Thu, 19 Oct 2023 19:23:14 -0400 Subject: [PATCH 3/5] CI: remove extraneous quotes that were causing 'get_previous_run_id' to always fail with a 'list index out of bounds' error --- misc/scripts/library-coverage/comment-pr.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/misc/scripts/library-coverage/comment-pr.py b/misc/scripts/library-coverage/comment-pr.py index 06d33cd0a99..9a35d230a35 100644 --- a/misc/scripts/library-coverage/comment-pr.py +++ b/misc/scripts/library-coverage/comment-pr.py @@ -156,7 +156,7 @@ def get_previous_run_id(repo, run_id, pr_number): pr_repo = this_run["head_repository"] # Get all previous runs that match branch, repo and workflow name: - output = utils.subprocess_check_output(["gh", "api", "-X", "GET", f"repos/{repo}/actions/runs", "-f", "event=pull_request", "-f", "status=success", "-f", f"branch='{pr_branch}'", "--paginate", + output = utils.subprocess_check_output(["gh", "api", "-X", "GET", f"repos/{repo}/actions/runs", "-f", "event=pull_request", "-f", "status=success", "-f", f"branch={pr_branch}", "--paginate", "--jq", f'[.workflow_runs.[] | select(.head_repository.full_name=="{pr_repo}" and .name=="{artifacts_workflow_name}")] | sort_by(.id) | reverse | [.[].id]']) ids = [] From 687ecffe71acf17ca8901f434d2fff854ab2788d Mon Sep 17 00:00:00 2001 From: Jami Cogswell Date: Sun, 22 Oct 2023 15:24:15 -0400 Subject: [PATCH 4/5] CI: don't upload comment/ID artifact if no existing comment --- .github/workflows/csv-coverage-pr-artifacts.yml | 11 +++++++++-- misc/scripts/library-coverage/comment-pr.py | 7 +++---- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/.github/workflows/csv-coverage-pr-artifacts.yml b/.github/workflows/csv-coverage-pr-artifacts.yml index 2f818713a1b..8e2df456260 100644 --- a/.github/workflows/csv-coverage-pr-artifacts.yml +++ b/.github/workflows/csv-coverage-pr-artifacts.yml @@ -99,10 +99,16 @@ jobs: path: pr/ - name: Save comment ID (if it exists) run: | - mkdir -p comment # Find the latest comment starting with COMMENT_PREFIX COMMENT_PREFIX=":warning: The head of this PR and the base branch were compared for differences in the framework coverage reports." - gh api "repos/${GITHUB_REPOSITORY}/issues/${PR_NUMBER}/comments" --paginate | jq --arg prefix "${COMMENT_PREFIX}" '[.[] | select(.body|startswith($prefix)) | .id] | max' > comment/ID + COMMENT_ID=$(gh api "repos/${GITHUB_REPOSITORY}/issues/${PR_NUMBER}/comments" --paginate | jq --arg prefix "${COMMENT_PREFIX}" 'map(select(.body|startswith($prefix)) | .id) | max // empty') + if [[ -z ${COMMENT_ID} ]] + then + echo "Comment not found. Not uploading 'comment/ID' artifact." + else + mkdir -p comment + echo ${COMMENT_ID} > comment/ID + fi env: GITHUB_TOKEN: ${{ github.token }} PR_NUMBER: ${{ github.event.pull_request.number }} @@ -111,3 +117,4 @@ jobs: with: name: comment path: comment/ + if-no-files-found: ignore diff --git a/misc/scripts/library-coverage/comment-pr.py b/misc/scripts/library-coverage/comment-pr.py index 9a35d230a35..51c837be9e8 100644 --- a/misc/scripts/library-coverage/comment-pr.py +++ b/misc/scripts/library-coverage/comment-pr.py @@ -56,14 +56,13 @@ def comment_pr(repo, run_id): if os.path.isdir("pr"): shutil.rmtree("pr") - utils.download_artifact(repo, "comment", "comment", run_id) - try: + utils.download_artifact(repo, "comment", "comment", run_id) with open("comment/ID") as file: raw_comment_id = int(file.read()) except Exception as e: - # If there is no existing comment, comment/ID will contain just a - # newline (due to jq & gh behaviour). This will cause `int(file.read())` + # If there is no existing comment, the `comment/ID` artifact + # will not exist. This will cause `utils.download_artifact` # to fail, so we catch that and set `raw_comment_id` to `None`. print("Could not retrieve an existing comment ID. \n", e) raw_comment_id = None From 7c053ed42874f26a7eb7c927339be2925bbad76f Mon Sep 17 00:00:00 2001 From: Jami <57204504+jcogs33@users.noreply.github.com> Date: Tue, 24 Oct 2023 17:48:38 -0400 Subject: [PATCH 5/5] CI: add .strip() to comment/ID file read Co-authored-by: Aditya Sharad <6874315+adityasharad@users.noreply.github.com> --- misc/scripts/library-coverage/comment-pr.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/misc/scripts/library-coverage/comment-pr.py b/misc/scripts/library-coverage/comment-pr.py index 51c837be9e8..543b576b1bd 100644 --- a/misc/scripts/library-coverage/comment-pr.py +++ b/misc/scripts/library-coverage/comment-pr.py @@ -59,7 +59,7 @@ def comment_pr(repo, run_id): try: utils.download_artifact(repo, "comment", "comment", run_id) with open("comment/ID") as file: - raw_comment_id = int(file.read()) + raw_comment_id = int(file.read().strip()) except Exception as e: # If there is no existing comment, the `comment/ID` artifact # will not exist. This will cause `utils.download_artifact`