diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 05a0c615..9698ff8d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -166,4 +166,6 @@ jobs: - name: Dogfooding codecov-cli if: ${{ !cancelled() }} run: | + codecovcli process-test-results --provider-token ${{ secrets.GITHUB_TOKEN }} + sleep 5 codecovcli process-test-results --provider-token ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file diff --git a/codecov_cli/commands/process_test_results.py b/codecov_cli/commands/process_test_results.py index 1bf4558a..6f362e3f 100644 --- a/codecov_cli/commands/process_test_results.py +++ b/codecov_cli/commands/process_test_results.py @@ -2,6 +2,7 @@ import os import pathlib from dataclasses import dataclass +from json import loads from typing import List import click @@ -15,6 +16,8 @@ from codecov_cli.helpers.request import ( log_warnings_and_errors_if_any, + send_get_request, + send_patch_request, send_post_request, ) from codecov_cli.services.upload.file_finder import select_file_finder @@ -84,8 +87,13 @@ class TestResultsNotificationPayload: @click.command() @process_test_results_options def process_test_results( - dir=None, files=None, exclude_folders=None, disable_search=None, provider_token=None + dir=None, + files=None, + exclude_folders=None, + disable_search=None, + provider_token=None, ): + if provider_token is None: raise click.ClickException( "Provider token was not provided. Make sure to pass --provider-token option with the contents of the GITHUB_TOKEN secret, so we can make a comment." @@ -119,34 +127,59 @@ def process_test_results( "No JUnit XML files were found. Make sure to specify them using the --file option." ) + # GITHUB_REF is documented here: https://docs.github.com/en/actions/learn-github-actions/variables#default-environment-variables + pr_number = ref.split("/")[2] + payload = generate_message_payload(upload_collection_results) message = build_message(payload) - + server_url = os.getenv("GITHUB_SERVER_URL") + message += f"\n\n[View checks]({server_url}/{slug}/pull/{pr_number}/checks)" + message += "\n" # write to step summary file with open(summary_file_path, "w") as f: f.write(message) - # GITHUB_REF is documented here: https://docs.github.com/en/actions/learn-github-actions/variables#default-environment-variables - pr_number = ref.split("/")[2] - - create_github_comment(provider_token, slug, pr_number, message) - + create_github_comment( + provider_token, + slug, + pr_number, + message, + ) -def create_github_comment(token, repo_slug, pr_number, message): - url = f"https://api.github.com/repos/{repo_slug}/issues/{pr_number}/comments" +def create_github_comment( + token, + repo_slug, + pr_number, + message, +): headers = { "Accept": "application/vnd.github+json", "Authorization": f"Bearer {token}", "X-GitHub-Api-Version": "2022-11-28", } - logger.info("Posting github comment") - log_warnings_and_errors_if_any( - send_post_request(url=url, data={"body": message}, headers=headers), - "Posting test results comment", - ) + url = f"https://api.github.com/repos/{repo_slug}/issues/{pr_number}/comments" + # list comments + result = send_get_request(url=url, headers=headers) + comments = loads(result.text) + for comment in comments: + if "" in comment: + logger.info("Patching github comment") + + url = comment["url"] + log_warnings_and_errors_if_any( + send_patch_request(url=url, json={"body": message}, headers=headers), + "Patching test results comment", + ) + else: + logger.info("Posting github comment") + + log_warnings_and_errors_if_any( + send_post_request(url=url, data={"body": message}, headers=headers), + "Posting test results comment", + ) def generate_message_payload(upload_collection_results): diff --git a/codecov_cli/helpers/request.py b/codecov_cli/helpers/request.py index d356eed8..12d73240 100644 --- a/codecov_cli/helpers/request.py +++ b/codecov_cli/helpers/request.py @@ -80,6 +80,16 @@ def wrapper(*args, **kwargs): return wrapper +@retry_request +def send_get_request(url: str, headers: dict = None, params: dict = None): + return request_result(get(url=url, headers=headers, params=params)) + + +@retry_request +def send_patch_request(url: str, headers: dict = None, json: dict = None): + return request_result(patch(url=url, headers=headers, json=json)) + + @retry_request def send_post_request( url: str, data: dict = None, headers: dict = None, params: dict = None diff --git a/tests/commands/test_process_test_results.py b/tests/commands/test_process_test_results.py index d0c62eb7..8e29d5af 100644 --- a/tests/commands/test_process_test_results.py +++ b/tests/commands/test_process_test_results.py @@ -1,8 +1,8 @@ -import logging import os from click.testing import CliRunner +from codecov_cli import __version__ from codecov_cli.main import cli from codecov_cli.types import RequestResult @@ -18,8 +18,9 @@ def test_process_test_results( os.environ, { "GITHUB_REPOSITORY": "fake/repo", - "GITHUB_REF": "pull/fake/pull", + "GITHUB_REF": "refs/pull/1/merge", "GITHUB_STEP_SUMMARY": tmp_file.dirname + tmp_file.basename, + "GITHUB_SERVER_URL": "https://github.com", }, ) mocked_post = mocker.patch( @@ -44,21 +45,20 @@ def test_process_test_results( assert result.exit_code == 0 - mocked_post.assert_called_with( - url="https://api.github.com/repos/fake/repo/issues/pull/comments", + url="https://api.github.com/repos/fake/repo/issues/1/comments", data={ - "body": "### :x: Failed Test Results: \nCompleted 4 tests with **`1 failed`**, 3 passed and 0 skipped.\n
View the full list of failed tests\n\n| **Test Description** | **Failure message** |\n| :-- | :-- |\n|
Testsuite:
api.temp.calculator.test_calculator::test_divide

Test name:
pytest
|
def
test_divide():
> assert Calculator.divide(1, 2) == 0.5
E assert 1.0 == 0.5
E + where 1.0 = <function Calculator.divide at 0x104c9eb90>(1, 2)
E + where <function Calculator.divide at 0x104c9eb90> = Calculator.divide
.../temp/calculator/test_calculator.py:30: AssertionError
|" + "body": "### :x: Failed Test Results: \nCompleted 4 tests with **`1 failed`**, 3 passed and 0 skipped.\n
View the full list of failed tests\n\n| **Test Description** | **Failure message** |\n| :-- | :-- |\n|
Testsuite:
api.temp.calculator.test_calculator::test_divide

Test name:
pytest
|
def
test_divide():
> assert Calculator.divide(1, 2) == 0.5
E assert 1.0 == 0.5
E + where 1.0 = <function Calculator.divide at 0x104c9eb90>(1, 2)
E + where <function Calculator.divide at 0x104c9eb90> = Calculator.divide
.../temp/calculator/test_calculator.py:30: AssertionError
|\n\n[View checks](https://github.com/fake/repo/pull/1/checks\n" }, headers={ "Accept": "application/vnd.github+json", "Authorization": "Bearer whatever", + "User-Agent": f"codecov-cli/{__version__}", "X-GitHub-Api-Version": "2022-11-28", }, ) - def test_process_test_results_non_existent_file(mocker, tmpdir): tmp_file = tmpdir.mkdir("folder").join("summary.txt") @@ -93,7 +93,7 @@ def test_process_test_results_non_existent_file(mocker, tmpdir): assert result.exit_code == 1 expected_logs = [ "ci service found", - 'Some files were not found', + "Some files were not found", ] for log in expected_logs: assert log in result.output @@ -182,7 +182,6 @@ def test_process_test_results_missing_ref(mocker, tmpdir): assert log in result.output - def test_process_test_results_missing_step_summary(mocker, tmpdir): tmp_file = tmpdir.mkdir("folder").join("summary.txt") @@ -221,4 +220,4 @@ def test_process_test_results_missing_step_summary(mocker, tmpdir): "Error: Error getting step summary file path from environment. Can't find GITHUB_STEP_SUMMARY environment variable.", ] for log in expected_logs: - assert log in result.output \ No newline at end of file + assert log in result.output