diff --git a/.flake8 b/.flake8 index efde3a0..2bd90f7 100644 --- a/.flake8 +++ b/.flake8 @@ -10,3 +10,4 @@ ignore = W503 max-complexity = 10 max-line-length = 120 select = E,W,F,C,N +exclude = .env,env,venv,.venv diff --git a/.gitignore b/.gitignore index b9597c0..4891504 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,8 @@ __pycache__/ .coverage /coverage.xml +.env/ +.venv/ +venv/ +env/ +.vscode/ diff --git a/.prettierignore b/.prettierignore index 79bae62..d53f2d6 100644 --- a/.prettierignore +++ b/.prettierignore @@ -4,3 +4,8 @@ .licenses/ __pycache__/ node_modules/ +.env/ +.venv/ +env/ +venv/ +.mypy_cache/ diff --git a/action.yml b/action.yml index d241747..4031d4c 100644 --- a/action.yml +++ b/action.yml @@ -7,6 +7,9 @@ inputs: github-token: description: "GitHub access token used to comment the memory usage comparison results to the PR thread" default: ${{ github.token }} + update-comment: + description: "when posting a report, set this to true to only update the previous report (if one exists)" + default: false runs: using: "docker" image: "Dockerfile" diff --git a/poetry.lock b/poetry.lock index c017ba0..82aae93 100644 --- a/poetry.lock +++ b/poetry.lock @@ -383,5 +383,5 @@ files = [ [metadata] lock-version = "2.0" -python-versions = "3.11.*" -content-hash = "727fe6621b0ce97f6eed00740ac11c7a4044c82801454741f939ef9dba1f02df" +python-versions = ">=3.11" +content-hash = "cb55a683208f96b6de70cd1163468b28f3290866c04e5082beee4707ce22dc38" diff --git a/pyproject.toml b/pyproject.toml index 4d5a444..a23ac3f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -8,7 +8,7 @@ description = "" authors = ["Arduino "] [tool.poetry.dependencies] -python = "3.11.*" +python = ">=3.11" [tool.poetry.group.dev.dependencies] black = "24.3.0" diff --git a/reportsizedeltas/reportsizedeltas.py b/reportsizedeltas/reportsizedeltas.py index b9be40c..c626e91 100644 --- a/reportsizedeltas/reportsizedeltas.py +++ b/reportsizedeltas/reportsizedeltas.py @@ -31,6 +31,7 @@ def main() -> None: repository_name=os.environ["GITHUB_REPOSITORY"], sketches_reports_source=os.environ["INPUT_SKETCHES-REPORTS-SOURCE"], token=os.environ["INPUT_GITHUB-TOKEN"], + update_comment=os.environ["INPUT_UPDATE-COMMENT"] == "true", ) report_size_deltas.report_size_deltas() @@ -47,7 +48,7 @@ def set_verbosity(enable_verbosity: bool) -> None: # INFO: manually specified output and all higher log level output verbose_logging_level = logging.DEBUG - if type(enable_verbosity) is not bool: + if not isinstance(enable_verbosity, bool): raise TypeError if enable_verbosity: logger.setLevel(level=verbose_logging_level) @@ -86,10 +87,11 @@ class ReportKeys: sketches = "sketches" compilation_success = "compilation_success" - def __init__(self, repository_name: str, sketches_reports_source: str, token: str) -> None: + def __init__(self, repository_name: str, sketches_reports_source: str, token: str, update_comment: bool) -> None: self.repository_name = repository_name self.sketches_reports_source = sketches_reports_source self.token = token + self.update_comment = update_comment def report_size_deltas(self) -> None: """Comment a report of memory usage change to pull request(s).""" @@ -167,19 +169,32 @@ def report_size_deltas_from_workflow_artifacts(self) -> None: page_number += 1 page_count = api_data["page_count"] - def report_exists(self, pr_number: int, pr_head_sha: str) -> bool: + def report_exists(self, pr_number: int, pr_head_sha: str = "") -> str | None: """Return whether a report has already been commented to the pull request thread for the latest workflow run. - Keyword arguments: - pr_number -- number of the pull request to check - pr_head_sha -- PR's head branch hash + If `pr_head_sha` is a blank str, then all thread comments are traversed. Additionally, + any report comment found will be deleted if it is not the first report comment found. + This is designed to support the action input `update-comment` when asserted. + + If `pr_head_sha` is not a blank str, then thread comments are traversed + until a report comment that corresponds to the commit is found. + No comments are deleted in this scenario. + + Arguments: + pr_number: number of the pull request to check + pr_head_sha: PR's head branch hash + Returns: + - A URL str to use for PATCHing the first applicable report comment. + - None if no applicable report comments exist. """ - # Get the pull request's comments + comment_url: str | None = None + request_uri = f"repos/{self.repository_name}/issues/{pr_number}/comments" page_number = 1 page_count = 1 while page_number <= page_count: + # Get the pull request's comments api_data = self.api_request( - request="repos/" + self.repository_name + "/issues/" + str(pr_number) + "/comments", + request=request_uri, page_number=page_number, ) @@ -187,13 +202,20 @@ def report_exists(self, pr_number: int, pr_head_sha: str) -> bool: for comment_data in comments_data: # Check if the comment is a report for the PR's head SHA if comment_data["body"].startswith(self.report_key_beginning + pr_head_sha): - return True + if pr_head_sha: + return comment_data["url"] + # else: pr_head_sha == "" + if comment_url is None: + comment_url = comment_data["url"] + else: # found another report + # delete report comment if it is not the first report found + self.http_request(url=comment_data["url"], method="DELETE") page_number += 1 page_count = api_data["page_count"] # No reports found for the PR's head SHA - return False + return comment_url def get_artifacts_data_for_sha(self, pr_user_login: str, pr_head_ref: str, pr_head_sha: str): """Return the list of data objects for the report artifacts associated with the given head commit hash. @@ -534,7 +556,10 @@ def comment_report(self, pr_number: int, report_markdown: str) -> None: report_data = json.dumps(obj={"body": report_markdown}).encode(encoding="utf-8") url = "https://api.github.com/repos/" + self.repository_name + "/issues/" + str(pr_number) + "/comments" - self.http_request(url=url, data=report_data) + comment_url = None if not self.update_comment else self.report_exists(pr_number=pr_number) + method = "PATCH" if comment_url else None + + self.http_request(url=comment_url or url, data=report_data, method=method) def api_request(self, request: str, request_parameters: str = "", page_number: int = 1): """Do a GitHub API request. Return a dictionary containing: @@ -594,7 +619,7 @@ def get_json_response(self, url: str): except Exception as exception: raise exception - def http_request(self, url: str, data: bytes | None = None): + def http_request(self, url: str, data: bytes | None = None, method: str | None = None): """Make a request and return a dictionary: read -- the response info -- headers @@ -604,28 +629,32 @@ def http_request(self, url: str, data: bytes | None = None): url -- the URL to load data -- data to pass with the request (default value: None) + method -- the HTTP request method to use + (default is None which means ``'GET' if data is None else 'POST'``). """ - with self.raw_http_request(url=url, data=data) as response_object: + with self.raw_http_request(url=url, data=data, method=method) as response_object: return { "body": response_object.read().decode(encoding="utf-8", errors="ignore"), "headers": response_object.info(), "url": response_object.geturl(), } - def raw_http_request(self, url: str, data: bytes | None = None): + def raw_http_request(self, url: str, data: bytes | None = None, method: str | None = None): """Make a request and return an object containing the response. Keyword arguments: url -- the URL to load data -- data to pass with the request (default value: None) + method -- the HTTP request method to use + (default is None which means ``'GET' if data is None else 'POST'``). """ # Maximum times to retry opening the URL before giving up maximum_urlopen_retries = 3 logger.info("Opening URL: " + url) - request = urllib.request.Request(url=url, data=data) + request = urllib.request.Request(url=url, data=data, method=method) request.add_unredirected_header(key="Accept", val="application/vnd.github+json") request.add_unredirected_header(key="Authorization", val="Bearer " + self.token) request.add_unredirected_header(key="User-Agent", val=self.repository_name.split("/")[0]) diff --git a/reportsizedeltas/tests/data/test_delete_previous_comment/comments.json b/reportsizedeltas/tests/data/test_delete_previous_comment/comments.json new file mode 100644 index 0000000..627b000 --- /dev/null +++ b/reportsizedeltas/tests/data/test_delete_previous_comment/comments.json @@ -0,0 +1,22 @@ +[ + { + "url": "https://api.github.com/repos/test-user/test-repo/issues/comments/1953679626", + "body": "**Memory usage change @ 525def8e855e5f227a4b4a0b6f84c34cd288a5ea**\n\nBoard|flash|%|RAM for global variables|%\n-|-|-|-|-\n`arduino:avr:nano`|0 - 0|0.0 - 0.0|0 - 0|0.0 - 0.0\n`arduino:samd:mkrzero`|0 - 0|0.0 - 0.0|0 - 0|0.0 - 0.0\n\n
\nClick for full report table\n\nBoard|`examples/Getting_Started_SimpleClient_Mesh`
flash|%|`examples/Getting_Started_SimpleClient_Mesh`
RAM for global variables|%|`examples/Getting_Started_SimpleServer_Mesh`
flash|%|`examples/Getting_Started_SimpleServer_Mesh`
RAM for global variables|%|`examples/InteractiveServer_Mesh`
flash|%|`examples/InteractiveServer_Mesh`
RAM for global variables|%|`examples/MQTT/mqtt_basic`
flash|%|`examples/MQTT/mqtt_basic`
RAM for global variables|%|`examples/MQTT/mqtt_basic_2`
flash|%|`examples/MQTT/mqtt_basic_2`
RAM for global variables|%|`examples/SimpleClient_Mesh`
flash|%|`examples/SimpleClient_Mesh`
RAM for global variables|%\n-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-\n`arduino:avr:nano`|0|0.0|0|0.0|0|0.0|0|0.0|0|0.0|0|0.0|0|0.0|0|0.0|0|0.0|0|0.0|0|0.0|0|0.0\n`arduino:samd:mkrzero`|0|0.0|0|0.0|0|0.0|0|0.0|0|0.0|0|0.0|0|0.0|0|0.0|0|0.0|0|0.0|0|0.0|0|0.0\n\n
\n\n
\nClick for full report CSV\n\n```\nBoard,examples/Getting_Started_SimpleClient_Mesh
flash,%,examples/Getting_Started_SimpleClient_Mesh
RAM for global variables,%,examples/Getting_Started_SimpleServer_Mesh
flash,%,examples/Getting_Started_SimpleServer_Mesh
RAM for global variables,%,examples/InteractiveServer_Mesh
flash,%,examples/InteractiveServer_Mesh
RAM for global variables,%,examples/MQTT/mqtt_basic
flash,%,examples/MQTT/mqtt_basic
RAM for global variables,%,examples/MQTT/mqtt_basic_2
flash,%,examples/MQTT/mqtt_basic_2
RAM for global variables,%,examples/SimpleClient_Mesh
flash,%,examples/SimpleClient_Mesh
RAM for global variables,%\narduino:avr:nano,0,0.0,0,0.0,0,0.0,0,0.0,0,0.0,0,0.0,0,0.0,0,0.0,0,0.0,0,0.0,0,0.0,0,0.0\narduino:samd:mkrzero,0,0.0,0,0.0,0,0.0,0,0.0,0,0.0,0,0.0,0,0.0,0,0.0,0,0.0,0,0.0,0,0.0,0,0.0\n```\n
" + }, + { + "url": "https://api.github.com/repos/test-user/test-repo/issues/comments/1953996601", + "body": "**Memory usage change @ 862a917fe24c6f737abc336b681b7326c0fcceec**\n\nBoard|flash|%|RAM for global variables|%\n-|-|-|-|-\n`arduino:avr:nano`|0 - 0|0.0 - 0.0|0 - 0|0.0 - 0.0\n`arduino:samd:mkrzero`|0 - 0|0.0 - 0.0|0 - 0|0.0 - 0.0\n\n
\nClick for full report table\n\nBoard|`examples/Getting_Started_SimpleClient_Mesh`
flash|%|`examples/Getting_Started_SimpleClient_Mesh`
RAM for global variables|%|`examples/Getting_Started_SimpleServer_Mesh`
flash|%|`examples/Getting_Started_SimpleServer_Mesh`
RAM for global variables|%|`examples/InteractiveServer_Mesh`
flash|%|`examples/InteractiveServer_Mesh`
RAM for global variables|%|`examples/MQTT/mqtt_basic`
flash|%|`examples/MQTT/mqtt_basic`
RAM for global variables|%|`examples/MQTT/mqtt_basic_2`
flash|%|`examples/MQTT/mqtt_basic_2`
RAM for global variables|%|`examples/SimpleClient_Mesh`
flash|%|`examples/SimpleClient_Mesh`
RAM for global variables|%\n-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-\n`arduino:avr:nano`|0|0.0|0|0.0|0|0.0|0|0.0|0|0.0|0|0.0|0|0.0|0|0.0|0|0.0|0|0.0|0|0.0|0|0.0\n`arduino:samd:mkrzero`|0|0.0|0|0.0|0|0.0|0|0.0|0|0.0|0|0.0|0|0.0|0|0.0|0|0.0|0|0.0|0|0.0|0|0.0\n\n
\n\n
\nClick for full report CSV\n\n```\nBoard,examples/Getting_Started_SimpleClient_Mesh
flash,%,examples/Getting_Started_SimpleClient_Mesh
RAM for global variables,%,examples/Getting_Started_SimpleServer_Mesh
flash,%,examples/Getting_Started_SimpleServer_Mesh
RAM for global variables,%,examples/InteractiveServer_Mesh
flash,%,examples/InteractiveServer_Mesh
RAM for global variables,%,examples/MQTT/mqtt_basic
flash,%,examples/MQTT/mqtt_basic
RAM for global variables,%,examples/MQTT/mqtt_basic_2
flash,%,examples/MQTT/mqtt_basic_2
RAM for global variables,%,examples/SimpleClient_Mesh
flash,%,examples/SimpleClient_Mesh
RAM for global variables,%\narduino:avr:nano,0,0.0,0,0.0,0,0.0,0,0.0,0,0.0,0,0.0,0,0.0,0,0.0,0,0.0,0,0.0,0,0.0,0,0.0\narduino:samd:mkrzero,0,0.0,0,0.0,0,0.0,0,0.0,0,0.0,0,0.0,0,0.0,0,0.0,0,0.0,0,0.0,0,0.0,0,0.0\n```\n
" + }, + { + "url": "https://api.github.com/repos/test-user/test-repo/issues/comments/1954284300", + "body": "**Memory usage change @ 0098017901c516c6cd49e248f1aabd6b30c91aa9**\n\nBoard|flash|%|RAM for global variables|%\n-|-|-|-|-\n`arduino:avr:nano`|0 - 0|0.0 - 0.0|0 - 0|0.0 - 0.0\n`arduino:samd:mkrzero`|0 - 0|0.0 - 0.0|0 - 0|0.0 - 0.0\n\n
\nClick for full report table\n\nBoard|`examples/Getting_Started_SimpleClient_Mesh`
flash|%|`examples/Getting_Started_SimpleClient_Mesh`
RAM for global variables|%|`examples/Getting_Started_SimpleServer_Mesh`
flash|%|`examples/Getting_Started_SimpleServer_Mesh`
RAM for global variables|%|`examples/InteractiveServer_Mesh`
flash|%|`examples/InteractiveServer_Mesh`
RAM for global variables|%|`examples/MQTT/mqtt_basic`
flash|%|`examples/MQTT/mqtt_basic`
RAM for global variables|%|`examples/MQTT/mqtt_basic_2`
flash|%|`examples/MQTT/mqtt_basic_2`
RAM for global variables|%|`examples/SimpleClient_Mesh`
flash|%|`examples/SimpleClient_Mesh`
RAM for global variables|%\n-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-\n`arduino:avr:nano`|0|0.0|0|0.0|0|0.0|0|0.0|0|0.0|0|0.0|0|0.0|0|0.0|0|0.0|0|0.0|0|0.0|0|0.0\n`arduino:samd:mkrzero`|0|0.0|0|0.0|0|0.0|0|0.0|0|0.0|0|0.0|0|0.0|0|0.0|0|0.0|0|0.0|0|0.0|0|0.0\n\n
\n\n
\nClick for full report CSV\n\n```\nBoard,examples/Getting_Started_SimpleClient_Mesh
flash,%,examples/Getting_Started_SimpleClient_Mesh
RAM for global variables,%,examples/Getting_Started_SimpleServer_Mesh
flash,%,examples/Getting_Started_SimpleServer_Mesh
RAM for global variables,%,examples/InteractiveServer_Mesh
flash,%,examples/InteractiveServer_Mesh
RAM for global variables,%,examples/MQTT/mqtt_basic
flash,%,examples/MQTT/mqtt_basic
RAM for global variables,%,examples/MQTT/mqtt_basic_2
flash,%,examples/MQTT/mqtt_basic_2
RAM for global variables,%,examples/SimpleClient_Mesh
flash,%,examples/SimpleClient_Mesh
RAM for global variables,%\narduino:avr:nano,0,0.0,0,0.0,0,0.0,0,0.0,0,0.0,0,0.0,0,0.0,0,0.0,0,0.0,0,0.0,0,0.0,0,0.0\narduino:samd:mkrzero,0,0.0,0,0.0,0,0.0,0,0.0,0,0.0,0,0.0,0,0.0,0,0.0,0,0.0,0,0.0,0,0.0,0,0.0\n```\n
" + }, + { + "url": "https://api.github.com/repos/test-user/test-repo/issues/comments/1955441026", + "body": "**Memory usage change @ f9881f578cf28800a2076ae709434249e9cb9d67**\n\nBoard|flash|%|RAM for global variables|%\n-|-|-|-|-\n`arduino:avr:nano`|0 - 0|0.0 - 0.0|0 - 0|0.0 - 0.0\n`arduino:samd:mkrzero`|0 - 0|0.0 - 0.0|0 - 0|0.0 - 0.0\n\n
\nClick for full report table\n\nBoard|`examples/Getting_Started_SimpleClient_Mesh`
flash|%|`examples/Getting_Started_SimpleClient_Mesh`
RAM for global variables|%|`examples/Getting_Started_SimpleServer_Mesh`
flash|%|`examples/Getting_Started_SimpleServer_Mesh`
RAM for global variables|%|`examples/InteractiveServer_Mesh`
flash|%|`examples/InteractiveServer_Mesh`
RAM for global variables|%|`examples/MQTT/mqtt_basic`
flash|%|`examples/MQTT/mqtt_basic`
RAM for global variables|%|`examples/MQTT/mqtt_basic_2`
flash|%|`examples/MQTT/mqtt_basic_2`
RAM for global variables|%|`examples/SimpleClient_Mesh`
flash|%|`examples/SimpleClient_Mesh`
RAM for global variables|%\n-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-\n`arduino:avr:nano`|0|0.0|0|0.0|0|0.0|0|0.0|0|0.0|0|0.0|0|0.0|0|0.0|0|0.0|0|0.0|0|0.0|0|0.0\n`arduino:samd:mkrzero`|0|0.0|0|0.0|0|0.0|0|0.0|0|0.0|0|0.0|0|0.0|0|0.0|0|0.0|0|0.0|0|0.0|0|0.0\n\n
\n\n
\nClick for full report CSV\n\n```\nBoard,examples/Getting_Started_SimpleClient_Mesh
flash,%,examples/Getting_Started_SimpleClient_Mesh
RAM for global variables,%,examples/Getting_Started_SimpleServer_Mesh
flash,%,examples/Getting_Started_SimpleServer_Mesh
RAM for global variables,%,examples/InteractiveServer_Mesh
flash,%,examples/InteractiveServer_Mesh
RAM for global variables,%,examples/MQTT/mqtt_basic
flash,%,examples/MQTT/mqtt_basic
RAM for global variables,%,examples/MQTT/mqtt_basic_2
flash,%,examples/MQTT/mqtt_basic_2
RAM for global variables,%,examples/SimpleClient_Mesh
flash,%,examples/SimpleClient_Mesh
RAM for global variables,%\narduino:avr:nano,0,0.0,0,0.0,0,0.0,0,0.0,0,0.0,0,0.0,0,0.0,0,0.0,0,0.0,0,0.0,0,0.0,0,0.0\narduino:samd:mkrzero,0,0.0,0,0.0,0,0.0,0,0.0,0,0.0,0,0.0,0,0.0,0,0.0,0,0.0,0,0.0,0,0.0,0,0.0\n```\n
" + }, + { + "url": "https://api.github.com/repos/test-user/test-repo/issues/comments/1955465432", + "body": "NOT A BOT COMMENT" + } +] diff --git a/reportsizedeltas/tests/test_reportsizedeltas.py b/reportsizedeltas/tests/test_reportsizedeltas.py index 4fe96cd..6d8f3dd 100644 --- a/reportsizedeltas/tests/test_reportsizedeltas.py +++ b/reportsizedeltas/tests/test_reportsizedeltas.py @@ -1,4 +1,4 @@ -import distutils.dir_util +import shutil import filecmp import json import os @@ -22,6 +22,7 @@ def get_reportsizedeltas_object( repository_name: str = "FooOwner/BarRepository", sketches_reports_source: str = "foo-artifact-pattern", token: str = "foo token", + update_comment: bool = False, ) -> reportsizedeltas.ReportSizeDeltas: """Return a reportsizedeltas.ReportSizeDeltas object to use in tests. @@ -32,7 +33,10 @@ def get_reportsizedeltas_object( token -- GitHub access token """ return reportsizedeltas.ReportSizeDeltas( - repository_name=repository_name, sketches_reports_source=sketches_reports_source, token=token + repository_name=repository_name, + sketches_reports_source=sketches_reports_source, + token=token, + update_comment=update_comment, ) @@ -106,10 +110,12 @@ class ActionInputs: repository_name = "GoldenOwner/GoldenRepository" sketches_reports_source = "golden-source-pattern" token = "golden-github-token" + update_comment = "false" monkeypatch.setenv("GITHUB_REPOSITORY", ActionInputs.repository_name) monkeypatch.setenv("INPUT_SKETCHES-REPORTS-SOURCE", ActionInputs.sketches_reports_source) monkeypatch.setenv("INPUT_GITHUB-TOKEN", ActionInputs.token) + monkeypatch.setenv("INPUT_UPDATE-COMMENT", ActionInputs.update_comment) return ActionInputs() @@ -132,6 +138,7 @@ def report_size_deltas(self): repository_name=setup_environment_variables.repository_name, sketches_reports_source=setup_environment_variables.sketches_reports_source, token=setup_environment_variables.token, + update_comment=setup_environment_variables.update_comment == "true", ) ReportSizeDeltas.report_size_deltas.assert_called_once() @@ -360,18 +367,47 @@ def test_report_exists(): report_size_deltas = get_reportsizedeltas_object(repository_name=repository_name) - json_data = [{"body": "foo123"}, {"body": report_size_deltas.report_key_beginning + pr_head_sha + "foo"}] + json_data = [ + {"body": "foo123"}, + {"body": report_size_deltas.report_key_beginning + pr_head_sha + "foo", "url": "some/url"}, + ] report_size_deltas.api_request = unittest.mock.MagicMock( return_value={"json_data": json_data, "additional_pages": False, "page_count": 1} ) - assert report_size_deltas.report_exists(pr_number=pr_number, pr_head_sha=pr_head_sha) + assert json_data[1]["url"] == report_size_deltas.report_exists(pr_number=pr_number, pr_head_sha=pr_head_sha) report_size_deltas.api_request.assert_called_once_with( request="repos/" + repository_name + "/issues/" + str(pr_number) + "/comments", page_number=1 ) - assert not report_size_deltas.report_exists(pr_number=pr_number, pr_head_sha="asdf") + assert report_size_deltas.report_exists(pr_number=pr_number, pr_head_sha="asdf") is None + + +def test_delete_previous_comment(): + pr_number = 42 + repository_name = "test_user/test_repo" + + report_size_deltas = get_reportsizedeltas_object(repository_name=repository_name) + + json_comments = json.loads((test_data_path / "test_delete_previous_comment" / "comments.json").read_bytes()) + + report_size_deltas.http_request = unittest.mock.Mock() + report_size_deltas.get_json_response = unittest.mock.Mock( + return_value={"json_data": json_comments, "page_count": 1}, + ) + + comment_url = report_size_deltas.report_exists(pr_number=pr_number) + assert comment_url == json_comments[0]["url"] + + for comment in json_comments[1:4]: + if comment["body"].startswith(report_size_deltas.report_key_beginning): + report_size_deltas.http_request.assert_any_call(url=comment["url"], method="DELETE") + + # It would be nicer to assert that a call has not been made. + # Here, we just assert that only the last 3 out of 4 bot comments were deleted. + # Implicitly, this also means the non-bot comment (`json_comment[4]`) was not deleted. + assert report_size_deltas.http_request.call_count == 3 def test_get_artifacts_data_for_sha(): @@ -526,8 +562,8 @@ def test_get_sketches_reports(test_data_folder_name): artifacts_folder_object = tempfile.TemporaryDirectory(prefix="test_reportsizedeltas-") try: - distutils.dir_util.copy_tree( - src=str(current_test_data_path.joinpath("artifacts")), dst=artifacts_folder_object.name + shutil.copytree( + src=str(current_test_data_path.joinpath("artifacts")), dst=artifacts_folder_object.name, dirs_exist_ok=True ) except Exception: # pragma: no cover artifacts_folder_object.cleanup() @@ -730,7 +766,7 @@ def test_generate_report(): artifacts_folder_object = tempfile.TemporaryDirectory(prefix="test_reportsizedeltas-") try: - distutils.dir_util.copy_tree(src=str(sketches_report_path), dst=artifacts_folder_object.name) + shutil.copytree(src=str(sketches_report_path), dst=artifacts_folder_object.name, dirs_exist_ok=True) except Exception: # pragma: no cover artifacts_folder_object.cleanup() raise @@ -778,6 +814,7 @@ def test_comment_report(): report_size_deltas.http_request.assert_called_once_with( url="https://api.github.com/repos/" + repository_name + "/issues/" + str(pr_number) + "/comments", data=report_data, + method=None, ) @@ -868,7 +905,7 @@ def test_http_request(): report_size_deltas.http_request(url=url, data=data) - report_size_deltas.raw_http_request.assert_called_once_with(url=url, data=data) + report_size_deltas.raw_http_request.assert_called_once_with(url=url, data=data, method=None) def test_raw_http_request(mocker): @@ -896,6 +933,7 @@ def add_unredirected_header(self): urllib.request.Request.assert_called_once_with( url=url, data=data, + method=None, ) request.add_unredirected_header.assert_has_calls( calls=[