From 0e34b92cec1ea1a521d1dd0b17a27225d847d574 Mon Sep 17 00:00:00 2001 From: joseph-sentry Date: Fri, 29 Dec 2023 11:28:32 -0500 Subject: [PATCH 01/16] feat: add test result file finding in FileFinder --- codecov_cli/services/upload/__init__.py | 4 +- ...coverage_file_finder.py => file_finder.py} | 51 +++++++++++-------- .../services/upload/upload_collector.py | 6 +-- .../upload/test_coverage_file_finder.py | 38 +++++--------- tests/services/upload/test_upload_service.py | 32 ++++++------ 5 files changed, 64 insertions(+), 67 deletions(-) rename codecov_cli/services/upload/{coverage_file_finder.py => file_finder.py} (80%) diff --git a/codecov_cli/services/upload/__init__.py b/codecov_cli/services/upload/__init__.py index c012beb4..f62fcac9 100644 --- a/codecov_cli/services/upload/__init__.py +++ b/codecov_cli/services/upload/__init__.py @@ -9,7 +9,7 @@ from codecov_cli.helpers.request import log_warnings_and_errors_if_any from codecov_cli.helpers.versioning_systems import VersioningSystemInterface from codecov_cli.plugins import select_preparation_plugins -from codecov_cli.services.upload.coverage_file_finder import select_coverage_file_finder +from codecov_cli.services.upload.file_finder import select_file_finder from codecov_cli.services.upload.legacy_upload_sender import LegacyUploadSender from codecov_cli.services.upload.network_finder import select_network_finder from codecov_cli.services.upload.upload_collector import UploadCollector @@ -52,7 +52,7 @@ def do_upload_logic( disable_file_fixes: bool = False, ): preparation_plugins = select_preparation_plugins(cli_config, plugin_names) - coverage_file_selector = select_coverage_file_finder( + coverage_file_selector = select_file_finder( coverage_files_search_root_folder, coverage_files_search_exclude_folders, coverage_files_search_explicitly_listed_files, diff --git a/codecov_cli/services/upload/coverage_file_finder.py b/codecov_cli/services/upload/file_finder.py similarity index 80% rename from codecov_cli/services/upload/coverage_file_finder.py rename to codecov_cli/services/upload/file_finder.py index 555df796..e8ecf5a3 100644 --- a/codecov_cli/services/upload/coverage_file_finder.py +++ b/codecov_cli/services/upload/file_finder.py @@ -35,6 +35,11 @@ "test_cov.xml", ] +test_results_files_patterns = [ + "*junit*", +] + +test_results_files_excluded_patterns = [] coverage_files_excluded_patterns = [ "*.am", @@ -170,49 +175,53 @@ ] -class CoverageFileFinder(object): +class FileFinder(object): def __init__( self, project_root: Path = None, folders_to_ignore: typing.List[str] = None, explicitly_listed_files: typing.List[Path] = None, disable_search: bool = False, + report_type: str = "coverage", ): self.project_root = project_root or Path(os.getcwd()) self.folders_to_ignore = folders_to_ignore or [] self.explicitly_listed_files = explicitly_listed_files or None self.disable_search = disable_search + self.report_type = report_type - def find_coverage_files(self) -> typing.List[UploadCollectionResultFile]: - regex_patterns_to_exclude = globs_to_regex(coverage_files_excluded_patterns) - coverage_files_paths = [] - user_coverage_files_paths = [] + def find_files(self) -> typing.List[UploadCollectionResultFile]: + if self.report_type == "coverage": + files_excluded_patterns = coverage_files_excluded_patterns + files_patterns = coverage_files_patterns + elif self.report_type == "test_results": + files_excluded_patterns = test_results_files_excluded_patterns + files_patterns = test_results_files_patterns + regex_patterns_to_exclude = globs_to_regex(files_excluded_patterns) + files_paths = [] + user_files_paths = [] if self.explicitly_listed_files: - user_coverage_files_paths = self.get_user_specified_coverage_files( - regex_patterns_to_exclude - ) + user_files_paths = self.get_user_specified_files(regex_patterns_to_exclude) if not self.disable_search: - regex_patterns_to_include = globs_to_regex(coverage_files_patterns) - coverage_files_paths = search_files( + regex_patterns_to_include = globs_to_regex(files_patterns) + files_paths = search_files( self.project_root, default_folders_to_ignore + self.folders_to_ignore, filename_include_regex=regex_patterns_to_include, filename_exclude_regex=regex_patterns_to_exclude, ) result_files = [ - UploadCollectionResultFile(path) - for path in coverage_files_paths - if coverage_files_paths + UploadCollectionResultFile(path) for path in files_paths if files_paths ] user_result_files = [ UploadCollectionResultFile(path) - for path in user_coverage_files_paths - if user_coverage_files_paths + for path in user_files_paths + if user_files_paths ] return list(set(result_files + user_result_files)) - def get_user_specified_coverage_files(self, regex_patterns_to_exclude): + def get_user_specified_files(self, regex_patterns_to_exclude): user_filenames_to_include = [] files_excluded_but_user_includes = [] for file in self.explicitly_listed_files: @@ -230,7 +239,7 @@ def get_user_specified_coverage_files(self, regex_patterns_to_exclude): multipart_include_regex = globs_to_regex( [str(path.resolve()) for path in self.explicitly_listed_files] ) - user_coverage_files_paths = list( + user_files_paths = list( search_files( self.project_root, default_folders_to_ignore + self.folders_to_ignore, @@ -241,7 +250,7 @@ def get_user_specified_coverage_files(self, regex_patterns_to_exclude): ) not_found_files = [] for filepath in self.explicitly_listed_files: - if filepath.resolve() not in user_coverage_files_paths: + if filepath.resolve() not in user_files_paths: not_found_files.append(filepath) if not_found_files: @@ -250,13 +259,13 @@ def get_user_specified_coverage_files(self, regex_patterns_to_exclude): extra=dict(extra_log_attributes=dict(not_found_files=not_found_files)), ) - return user_coverage_files_paths + return user_files_paths -def select_coverage_file_finder( +def select_file_finder( root_folder_to_search, folders_to_ignore, explicitly_listed_files, disable_search ): - return CoverageFileFinder( + return FileFinder( root_folder_to_search, folders_to_ignore, explicitly_listed_files, diff --git a/codecov_cli/services/upload/upload_collector.py b/codecov_cli/services/upload/upload_collector.py index 0668d9d6..10db7ebd 100644 --- a/codecov_cli/services/upload/upload_collector.py +++ b/codecov_cli/services/upload/upload_collector.py @@ -8,7 +8,7 @@ import click -from codecov_cli.services.upload.coverage_file_finder import CoverageFileFinder +from codecov_cli.services.upload.file_finder import FileFinder from codecov_cli.services.upload.network_finder import NetworkFinder from codecov_cli.types import ( PreparationPluginInterface, @@ -28,7 +28,7 @@ def __init__( self, preparation_plugins: typing.List[PreparationPluginInterface], network_finder: NetworkFinder, - coverage_file_finder: CoverageFileFinder, + coverage_file_finder: FileFinder, disable_file_fixes: bool = False, ): self.preparation_plugins = preparation_plugins @@ -150,7 +150,7 @@ def generate_upload_data(self) -> UploadCollectionResult: prep.run_preparation(self) logger.debug("Collecting relevant files") network = self.network_finder.find_files() - coverage_files = self.coverage_file_finder.find_coverage_files() + coverage_files = self.coverage_file_finder.find_files() logger.info(f"Found {len(coverage_files)} coverage files to upload") if not coverage_files: raise click.ClickException( diff --git a/tests/services/upload/test_coverage_file_finder.py b/tests/services/upload/test_coverage_file_finder.py index dd83a8a4..31c92937 100644 --- a/tests/services/upload/test_coverage_file_finder.py +++ b/tests/services/upload/test_coverage_file_finder.py @@ -2,17 +2,17 @@ import unittest from pathlib import Path -from codecov_cli.services.upload.coverage_file_finder import CoverageFileFinder +from codecov_cli.services.upload.file_finder import FileFinder from codecov_cli.types import UploadCollectionResultFile class TestCoverageFileFinder(object): def test_find_coverage_files_mocked_search_files(self, mocker): mocker.patch( - "codecov_cli.services.upload.coverage_file_finder.search_files", + "codecov_cli.services.upload.file_finder.search_files", return_value=[], ) - assert CoverageFileFinder().find_coverage_files() == [] + assert FileFinder().find_files() == [] coverage_files_paths = [ Path("a/b.txt"), @@ -20,7 +20,7 @@ def test_find_coverage_files_mocked_search_files(self, mocker): ] mocker.patch( - "codecov_cli.services.upload.coverage_file_finder.search_files", + "codecov_cli.services.upload.file_finder.search_files", return_value=coverage_files_paths, ) @@ -32,7 +32,7 @@ def test_find_coverage_files_mocked_search_files(self, mocker): expected_paths = sorted([file.get_filename() for file in expected]) actual_paths = sorted( - [file.get_filename() for file in CoverageFileFinder().find_coverage_files()] + [file.get_filename() for file in FileFinder().find_files()] ) assert expected_paths == actual_paths @@ -87,12 +87,12 @@ def test_find_coverage_files(self, tmp_path): expected = { UploadCollectionResultFile((tmp_path / file)) for file in should_find } - actual = set(CoverageFileFinder(tmp_path).find_coverage_files()) + actual = set(FileFinder(tmp_path).find_files()) assert actual == expected extra = tmp_path / "sub" / "nosetests.xml" extra.touch() - actual = set(CoverageFileFinder(tmp_path).find_coverage_files()) + actual = set(FileFinder(tmp_path).find_files()) assert actual - expected == {UploadCollectionResultFile(extra)} @@ -106,7 +106,7 @@ def setUp(self): self.project_root / "subdirectory" / "another_file.abc", ] self.disable_search = False - self.coverage_file_finder = CoverageFileFinder( + self.coverage_file_finder = FileFinder( self.project_root, self.folders_to_ignore, self.explicitly_listed_files, @@ -128,10 +128,7 @@ def test_find_coverage_files_with_existing_files(self): file.touch() result = sorted( - [ - file.get_filename() - for file in self.coverage_file_finder.find_coverage_files() - ] + [file.get_filename() for file in self.coverage_file_finder.find_files()] ) expected = [ UploadCollectionResultFile(Path(f"{self.project_root}/coverage.xml")), @@ -143,7 +140,7 @@ def test_find_coverage_files_with_existing_files(self): self.assertEqual(result, expected_paths) def test_find_coverage_files_with_no_files(self): - result = self.coverage_file_finder.find_coverage_files() + result = self.coverage_file_finder.find_files() self.assertEqual(result, []) def test_find_coverage_files_with_disabled_search(self): @@ -163,10 +160,7 @@ def test_find_coverage_files_with_disabled_search(self): self.coverage_file_finder.disable_search = True result = sorted( - [ - file.get_filename() - for file in self.coverage_file_finder.find_coverage_files() - ] + [file.get_filename() for file in self.coverage_file_finder.find_files()] ) expected = [ @@ -192,10 +186,7 @@ def test_find_coverage_files_with_user_specified_files(self): file.touch() result = sorted( - [ - file.get_filename() - for file in self.coverage_file_finder.find_coverage_files() - ] + [file.get_filename() for file in self.coverage_file_finder.find_files()] ) expected = [ @@ -227,10 +218,7 @@ def test_find_coverage_files_with_user_specified_files_not_found(self): ) result = sorted( - [ - file.get_filename() - for file in self.coverage_file_finder.find_coverage_files() - ] + [file.get_filename() for file in self.coverage_file_finder.find_files()] ) expected = [ diff --git a/tests/services/upload/test_upload_service.py b/tests/services/upload/test_upload_service.py index dfb6c4da..4cb361b9 100644 --- a/tests/services/upload/test_upload_service.py +++ b/tests/services/upload/test_upload_service.py @@ -20,8 +20,8 @@ def test_do_upload_logic_happy_path_legacy_uploader(mocker): mock_select_preparation_plugins = mocker.patch( "codecov_cli.services.upload.select_preparation_plugins" ) - mock_select_coverage_file_finder = mocker.patch( - "codecov_cli.services.upload.select_coverage_file_finder" + mock_select_file_finder = mocker.patch( + "codecov_cli.services.upload.select_file_finder" ) mock_select_network_finder = mocker.patch( "codecov_cli.services.upload.select_network_finder" @@ -79,7 +79,7 @@ def test_do_upload_logic_happy_path_legacy_uploader(mocker): mock_select_preparation_plugins.assert_called_with( cli_config, ["first_plugin", "another", "forth"] ) - mock_select_coverage_file_finder.assert_called_with(None, None, None, False) + mock_select_file_finder.assert_called_with(None, None, None, False) mock_select_network_finder.assert_called_with(versioning_system) mock_generate_upload_data.assert_called_with() mock_send_upload_data.assert_called_with( @@ -106,8 +106,8 @@ def test_do_upload_logic_happy_path(mocker): mock_select_preparation_plugins = mocker.patch( "codecov_cli.services.upload.select_preparation_plugins" ) - mock_select_coverage_file_finder = mocker.patch( - "codecov_cli.services.upload.select_coverage_file_finder" + mock_select_file_finder = mocker.patch( + "codecov_cli.services.upload.select_file_finder" ) mock_select_network_finder = mocker.patch( "codecov_cli.services.upload.select_network_finder" @@ -164,7 +164,7 @@ def test_do_upload_logic_happy_path(mocker): mock_select_preparation_plugins.assert_called_with( cli_config, ["first_plugin", "another", "forth"] ) - mock_select_coverage_file_finder.assert_called_with(None, None, None, False) + mock_select_file_finder.assert_called_with(None, None, None, False) mock_select_network_finder.assert_called_with(versioning_system) mock_generate_upload_data.assert_called_with() mock_send_upload_data.assert_called_with( @@ -191,8 +191,8 @@ def test_do_upload_logic_dry_run(mocker): mock_select_preparation_plugins = mocker.patch( "codecov_cli.services.upload.select_preparation_plugins" ) - mock_select_coverage_file_finder = mocker.patch( - "codecov_cli.services.upload.select_coverage_file_finder" + mock_select_file_finder = mocker.patch( + "codecov_cli.services.upload.select_file_finder" ) mock_select_network_finder = mocker.patch( "codecov_cli.services.upload.select_network_finder" @@ -236,7 +236,7 @@ def test_do_upload_logic_dry_run(mocker): enterprise_url=None, ) out_bytes = parse_outstreams_into_log_lines(outstreams[0].getvalue()) - mock_select_coverage_file_finder.assert_called_with(None, None, None, False) + mock_select_file_finder.assert_called_with(None, None, None, False) mock_select_network_finder.assert_called_with(versioning_system) assert mock_generate_upload_data.call_count == 1 assert mock_send_upload_data.call_count == 0 @@ -257,7 +257,7 @@ def test_do_upload_logic_dry_run(mocker): def test_do_upload_logic_verbose(mocker, use_verbose_option): mocker.patch("codecov_cli.services.upload.select_preparation_plugins") - mocker.patch("codecov_cli.services.upload.select_coverage_file_finder") + mocker.patch("codecov_cli.services.upload.select_file_finder") mocker.patch("codecov_cli.services.upload.select_network_finder") mocker.patch.object(UploadCollector, "generate_upload_data") mocker.patch.object( @@ -321,8 +321,8 @@ def test_do_upload_no_cov_reports_found(mocker): mock_select_preparation_plugins = mocker.patch( "codecov_cli.services.upload.select_preparation_plugins" ) - mock_select_coverage_file_finder = mocker.patch( - "codecov_cli.services.upload.select_coverage_file_finder", + mock_select_file_finder = mocker.patch( + "codecov_cli.services.upload.select_file_finder", ) mock_select_network_finder = mocker.patch( "codecov_cli.services.upload.select_network_finder" @@ -385,7 +385,7 @@ def side_effect(*args, **kwargs): mock_select_preparation_plugins.assert_called_with( cli_config, ["first_plugin", "another", "forth"] ) - mock_select_coverage_file_finder.assert_called_with(None, None, None, False) + mock_select_file_finder.assert_called_with(None, None, None, False) mock_select_network_finder.assert_called_with(versioning_system) mock_generate_upload_data.assert_called_with() mock_upload_completion_call.assert_called_with( @@ -402,8 +402,8 @@ def test_do_upload_rase_no_cov_reports_found_error(mocker): mock_select_preparation_plugins = mocker.patch( "codecov_cli.services.upload.select_preparation_plugins" ) - mock_select_coverage_file_finder = mocker.patch( - "codecov_cli.services.upload.select_coverage_file_finder", + mock_select_file_finder = mocker.patch( + "codecov_cli.services.upload.select_file_finder", ) mock_select_network_finder = mocker.patch( "codecov_cli.services.upload.select_network_finder" @@ -456,6 +456,6 @@ def side_effect(*args, **kwargs): mock_select_preparation_plugins.assert_called_with( cli_config, ["first_plugin", "another", "forth"] ) - mock_select_coverage_file_finder.assert_called_with(None, None, None, False) + mock_select_file_finder.assert_called_with(None, None, None, False) mock_select_network_finder.assert_called_with(versioning_system) mock_generate_upload_data.assert_called_with() From fc18ff408226733587a0a32b65390ae2935ecb15 Mon Sep 17 00:00:00 2001 From: joseph-sentry Date: Fri, 29 Dec 2023 11:37:14 -0500 Subject: [PATCH 02/16] chore: change coverage_files to files in UploadCollectionResult --- codecov_cli/services/upload/legacy_upload_sender.py | 4 +--- codecov_cli/services/upload/upload_collector.py | 2 +- codecov_cli/services/upload/upload_sender.py | 2 +- codecov_cli/types.py | 4 ++-- 4 files changed, 5 insertions(+), 7 deletions(-) diff --git a/codecov_cli/services/upload/legacy_upload_sender.py b/codecov_cli/services/upload/legacy_upload_sender.py index da91ae7c..73dbbf25 100644 --- a/codecov_cli/services/upload/legacy_upload_sender.py +++ b/codecov_cli/services/upload/legacy_upload_sender.py @@ -116,9 +116,7 @@ def _generate_network_section(self, upload_data: UploadCollectionResult) -> byte return network_files_section.encode() + b"<<<<<< network\n" def _generate_coverage_files_section(self, upload_data: UploadCollectionResult): - return b"".join( - self._format_coverage_file(file) for file in upload_data.coverage_files - ) + return b"".join(self._format_coverage_file(file) for file in upload_data.files) def _format_coverage_file(self, file: UploadCollectionResultFile) -> bytes: header = b"# path=" + file.get_filename() + b"\n" diff --git a/codecov_cli/services/upload/upload_collector.py b/codecov_cli/services/upload/upload_collector.py index 10db7ebd..4386e1e2 100644 --- a/codecov_cli/services/upload/upload_collector.py +++ b/codecov_cli/services/upload/upload_collector.py @@ -163,6 +163,6 @@ def generate_upload_data(self) -> UploadCollectionResult: logger.info(f"> {file}") return UploadCollectionResult( network=network, - coverage_files=coverage_files, + files=coverage_files, file_fixes=self._produce_file_fixes_for_network(network), ) diff --git a/codecov_cli/services/upload/upload_sender.py b/codecov_cli/services/upload/upload_sender.py index f500f71b..64085fa0 100644 --- a/codecov_cli/services/upload/upload_sender.py +++ b/codecov_cli/services/upload/upload_sender.py @@ -138,7 +138,7 @@ def _get_file_fixers( return file_fixers def _get_coverage_files(self, upload_data: UploadCollectionResult): - return [self._format_coverage_file(file) for file in upload_data.coverage_files] + return [self._format_coverage_file(file) for file in upload_data.files] def _format_coverage_file(self, file: UploadCollectionResultFile): format, formatted_content = self._get_format_info(file) diff --git a/codecov_cli/types.py b/codecov_cli/types.py index 95f9f759..d9405f2e 100644 --- a/codecov_cli/types.py +++ b/codecov_cli/types.py @@ -38,9 +38,9 @@ class UploadCollectionResultFileFixer(object): @dataclass class UploadCollectionResult(object): - __slots__ = ["network", "coverage_files", "file_fixes"] + __slots__ = ["network", "files", "file_fixes"] network: typing.List[str] - coverage_files: typing.List[UploadCollectionResultFile] + files: typing.List[UploadCollectionResultFile] file_fixes: typing.List[UploadCollectionResultFileFixer] From 957992891dfa5130a7076709c1a0fac547a2ba39 Mon Sep 17 00:00:00 2001 From: joseph-sentry Date: Fri, 29 Dec 2023 11:40:46 -0500 Subject: [PATCH 03/16] feat: update upload collector to handle test result files --- .../services/upload/upload_collector.py | 22 ++++++++++--------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/codecov_cli/services/upload/upload_collector.py b/codecov_cli/services/upload/upload_collector.py index 4386e1e2..282c0e99 100644 --- a/codecov_cli/services/upload/upload_collector.py +++ b/codecov_cli/services/upload/upload_collector.py @@ -28,12 +28,12 @@ def __init__( self, preparation_plugins: typing.List[PreparationPluginInterface], network_finder: NetworkFinder, - coverage_file_finder: FileFinder, + file_finder: FileFinder, disable_file_fixes: bool = False, ): self.preparation_plugins = preparation_plugins self.network_finder = network_finder - self.coverage_file_finder = coverage_file_finder + self.file_finder = file_finder self.disable_file_fixes = disable_file_fixes def _produce_file_fixes_for_network( @@ -144,25 +144,27 @@ def _get_file_fixes( path, fixed_lines_without_reason, fixed_lines_with_reason, eof ) - def generate_upload_data(self) -> UploadCollectionResult: + def generate_upload_data(self, report_type="coverage") -> UploadCollectionResult: for prep in self.preparation_plugins: logger.debug(f"Running preparation plugin: {type(prep)}") prep.run_preparation(self) logger.debug("Collecting relevant files") network = self.network_finder.find_files() - coverage_files = self.coverage_file_finder.find_files() - logger.info(f"Found {len(coverage_files)} coverage files to upload") - if not coverage_files: + files = self.file_finder.find_files() + logger.info(f"Found {len(files)} {report_type} files to upload") + if not files: raise click.ClickException( click.style( - "No coverage reports found. Please make sure you're generating reports successfully.", + f"No {report_type} reports found. Please make sure you're generating reports successfully.", fg="red", ) ) - for file in coverage_files: + for file in files: logger.info(f"> {file}") return UploadCollectionResult( network=network, - files=coverage_files, - file_fixes=self._produce_file_fixes_for_network(network), + files=files, + file_fixes=self._produce_file_fixes_for_network(network) + if report_type == "coverage" + else [], ) From 3f92c81881a525646dfa9cbc17485c8f73ba8c78 Mon Sep 17 00:00:00 2001 From: joseph-sentry Date: Fri, 29 Dec 2023 12:11:45 -0500 Subject: [PATCH 04/16] feat: update upload senders to handle test result files --- .../services/upload/legacy_upload_sender.py | 1 - codecov_cli/services/upload/upload_sender.py | 49 +++++++++++++------ tests/helpers/test_legacy_upload_sender.py | 7 ++- tests/helpers/test_upload_sender.py | 5 +- 4 files changed, 40 insertions(+), 22 deletions(-) diff --git a/codecov_cli/services/upload/legacy_upload_sender.py b/codecov_cli/services/upload/legacy_upload_sender.py index 73dbbf25..6314b110 100644 --- a/codecov_cli/services/upload/legacy_upload_sender.py +++ b/codecov_cli/services/upload/legacy_upload_sender.py @@ -51,7 +51,6 @@ def send_upload_data( git_service: typing.Optional[str] = None, enterprise_url: typing.Optional[str] = None, ) -> UploadSendingResult: - params = { "package": f"codecov-cli/{codecov_cli_version}", "commit": commit_sha, diff --git a/codecov_cli/services/upload/upload_sender.py b/codecov_cli/services/upload/upload_sender.py index 64085fa0..8a2ca60d 100644 --- a/codecov_cli/services/upload/upload_sender.py +++ b/codecov_cli/services/upload/upload_sender.py @@ -1,5 +1,5 @@ -import base64 import json +import base64 import logging import typing import zlib @@ -31,6 +31,7 @@ def send_upload_data( token: str, env_vars: typing.Dict[str, str], report_code: str, + upload_file_type: str = "coverage", name: typing.Optional[str] = None, branch: typing.Optional[str] = None, slug: typing.Optional[str] = None, @@ -66,9 +67,17 @@ def send_upload_data( headers = get_token_header_or_fail(token) encoded_slug = encode_slug(slug) upload_url = enterprise_url or CODECOV_API_URL - url = f"{upload_url}/upload/{git_service}/{encoded_slug}/commits/{commit_sha}/reports/{report_code}/uploads" + if upload_file_type == "coverage": + url = f"{upload_url}/upload/{git_service}/{encoded_slug}/commits/{commit_sha}/reports/{report_code}/uploads" + elif upload_file_type == "test_results": + data["slug"] = encoded_slug + data["commit"] = commit_sha + data["service"] = git_service + url = f"{upload_url}/upload/test_results/v1" # Data that goes to storage - reports_payload = self._generate_payload(upload_data, env_vars) + reports_payload = self._generate_payload( + upload_data, env_vars, upload_file_type + ) logger.debug("Sending upload request to Codecov") resp_from_codecov = send_post_request( @@ -93,18 +102,26 @@ def send_upload_data( return resp_from_storage def _generate_payload( - self, upload_data: UploadCollectionResult, env_vars: typing.Dict[str, str] + self, + upload_data: UploadCollectionResult, + env_vars: typing.Dict[str, str], + upload_file_type="coverage", ) -> bytes: network_files = upload_data.network - payload = { - "report_fixes": { - "format": "legacy", - "value": self._get_file_fixers(upload_data), - }, - "network_files": network_files if network_files is not None else [], - "coverage_files": self._get_coverage_files(upload_data), - "metadata": {}, - } + if upload_file_type == "coverage": + payload = { + "report_fixes": { + "format": "legacy", + "value": self._get_file_fixers(upload_data), + }, + "network_files": network_files if network_files is not None else [], + "coverage_files": self._get_files(upload_data), + "metadata": {}, + } + elif upload_file_type == "test_results": + payload = { + "test_results_files": self._get_files(upload_data), + } json_data = json.dumps(payload) return json_data.encode() @@ -137,10 +154,10 @@ def _get_file_fixers( return file_fixers - def _get_coverage_files(self, upload_data: UploadCollectionResult): - return [self._format_coverage_file(file) for file in upload_data.files] + def _get_files(self, upload_data: UploadCollectionResult): + return [self._format_file(file) for file in upload_data.files] - def _format_coverage_file(self, file: UploadCollectionResultFile): + def _format_file(self, file: UploadCollectionResultFile): format, formatted_content = self._get_format_info(file) return { "filename": file.get_filename().decode(), diff --git a/tests/helpers/test_legacy_upload_sender.py b/tests/helpers/test_legacy_upload_sender.py index fdfb9229..beb4c79c 100644 --- a/tests/helpers/test_legacy_upload_sender.py +++ b/tests/helpers/test_legacy_upload_sender.py @@ -166,7 +166,11 @@ def test_upload_sender_http_error_with_invalid_sha( mocked_legacy_upload_endpoint.status = 400 sender = LegacyUploadSender().send_upload_data( - upload_collection, random_sha, random_token, {}, **named_upload_data + upload_collection, + random_sha, + random_token, + {}, + **named_upload_data, ) assert sender.error is not None @@ -279,7 +283,6 @@ def test_format_coverage_file(self, mocker): ) def test_generate_coverage_files_section(self, mocker): - mocker.patch( "codecov_cli.services.upload.LegacyUploadSender._format_coverage_file", side_effect=lambda file_bytes: file_bytes, diff --git a/tests/helpers/test_upload_sender.py b/tests/helpers/test_upload_sender.py index ec54d3b3..2ea9fe6e 100644 --- a/tests/helpers/test_upload_sender.py +++ b/tests/helpers/test_upload_sender.py @@ -15,6 +15,7 @@ random_token = "f359afb9-8a2a-42ab-a448-c3d267ff495b" random_sha = "845548c6b95223f12e8317a1820705f64beaf69e" named_upload_data = { + "upload_file_type": "coverage", "report_code": "report_code", "env_vars": {}, "name": "name", @@ -369,9 +370,7 @@ def test_coverage_file_format(self, mocker, mocked_coverage_file): "codecov_cli.services.upload.upload_sender.UploadSender._get_format_info", return_value=("base64+compressed", "encoded_file_data"), ) - json_formatted_coverage_file = UploadSender()._format_coverage_file( - mocked_coverage_file - ) + json_formatted_coverage_file = UploadSender()._format_file(mocked_coverage_file) print(json_formatted_coverage_file["data"]) assert json_formatted_coverage_file == { "filename": mocked_coverage_file.get_filename().decode(), From fee768c96316113508af2517d65e5c9ef6f225b7 Mon Sep 17 00:00:00 2001 From: joseph-sentry Date: Fri, 29 Dec 2023 12:35:17 -0500 Subject: [PATCH 05/16] feat: add report type option and rename coverage files options to files --- codecov_cli/commands/upload.py | 40 +++++++++------ codecov_cli/commands/upload_process.py | 39 ++++++++------- codecov_cli/services/upload/__init__.py | 20 ++++---- tests/commands/test_invoke_upload_process.py | 10 ++-- tests/services/upload/test_upload_service.py | 52 +++++++++++--------- 5 files changed, 93 insertions(+), 68 deletions(-) diff --git a/codecov_cli/commands/upload.py b/codecov_cli/commands/upload.py index 9ee04b99..fafb34af 100644 --- a/codecov_cli/commands/upload.py +++ b/codecov_cli/commands/upload.py @@ -33,7 +33,8 @@ def _turn_env_vars_into_dict(ctx, params, value): "-s", "--dir", "--coverage-files-search-root-folder", - "coverage_files_search_root_folder", + "--files-search-root-folder", + "files_search_root_folder", help="Folder where to search for coverage files", type=click.Path(path_type=pathlib.Path), default=pathlib.Path.cwd, @@ -42,7 +43,8 @@ def _turn_env_vars_into_dict(ctx, params, value): click.option( "--exclude", "--coverage-files-search-exclude-folder", - "coverage_files_search_exclude_folders", + "--files-search-exclude-folder", + "files_search_exclude_folders", help="Folders to exclude from search", type=click.Path(path_type=pathlib.Path), multiple=True, @@ -52,7 +54,8 @@ def _turn_env_vars_into_dict(ctx, params, value): "-f", "--file", "--coverage-files-search-direct-file", - "coverage_files_search_explicitly_listed_files", + "--files-search-direct-file", + "files_search_explicitly_listed_files", help="Explicit files to upload. These will be added to the coverage files found for upload. If you wish to only upload the specified files, please consider using --disable-search to disable uploading other files.", type=click.Path(path_type=pathlib.Path), multiple=True, @@ -155,6 +158,12 @@ def _turn_env_vars_into_dict(ctx, params, value): is_flag=True, help="Raise no excpetions when no coverage reports found.", ), + click.option( + "--report-type", + help="The type of the file to upload, coverage by default. Possible values are: testing, coverage.", + default="coverage", + type=click.Choice(["coverage", "test_results"]), + ), ] @@ -179,9 +188,9 @@ def do_upload( flags: typing.List[str], name: typing.Optional[str], network_root_folder: pathlib.Path, - coverage_files_search_root_folder: pathlib.Path, - coverage_files_search_exclude_folders: typing.List[pathlib.Path], - coverage_files_search_explicitly_listed_files: typing.List[pathlib.Path], + files_search_root_folder: pathlib.Path, + files_search_exclude_folders: typing.List[pathlib.Path], + files_search_explicitly_listed_files: typing.List[pathlib.Path], disable_search: bool, disable_file_fixes: bool, token: typing.Optional[str], @@ -194,6 +203,7 @@ def do_upload( dry_run: bool, git_service: typing.Optional[str], handle_no_reports_found: bool, + report_type: str, ): versioning_system = ctx.obj["versioning_system"] codecov_yaml = ctx.obj["codecov_yaml"] or {} @@ -204,6 +214,7 @@ def do_upload( "Starting upload processing", extra=dict( extra_log_attributes=dict( + upload_file_type=report_type, commit_sha=commit_sha, report_code=report_code, build_code=build_code, @@ -213,9 +224,9 @@ def do_upload( flags=flags, name=name, network_root_folder=network_root_folder, - coverage_files_search_root_folder=coverage_files_search_root_folder, - coverage_files_search_exclude_folders=coverage_files_search_exclude_folders, - coverage_files_search_explicitly_listed_files=coverage_files_search_explicitly_listed_files, + files_search_root_folder=files_search_root_folder, + files_search_exclude_folders=files_search_exclude_folders, + files_search_explicitly_listed_files=files_search_explicitly_listed_files, plugin_names=plugin_names, token=token, branch=branch, @@ -233,6 +244,7 @@ def do_upload( cli_config, versioning_system, ci_adapter, + upload_file_type=report_type, commit_sha=commit_sha, report_code=report_code, build_code=build_code, @@ -242,13 +254,9 @@ def do_upload( flags=flags, name=name, network_root_folder=network_root_folder, - coverage_files_search_root_folder=coverage_files_search_root_folder, - coverage_files_search_exclude_folders=list( - coverage_files_search_exclude_folders - ), - coverage_files_search_explicitly_listed_files=list( - coverage_files_search_explicitly_listed_files - ), + files_search_root_folder=files_search_root_folder, + files_search_exclude_folders=list(files_search_exclude_folders), + files_search_explicitly_listed_files=list(files_search_explicitly_listed_files), plugin_names=plugin_names, token=token, branch=branch, diff --git a/codecov_cli/commands/upload_process.py b/codecov_cli/commands/upload_process.py index b8270b79..20b67352 100644 --- a/codecov_cli/commands/upload_process.py +++ b/codecov_cli/commands/upload_process.py @@ -32,9 +32,9 @@ def upload_process( flags: typing.List[str], name: typing.Optional[str], network_root_folder: pathlib.Path, - coverage_files_search_root_folder: pathlib.Path, - coverage_files_search_exclude_folders: typing.List[pathlib.Path], - coverage_files_search_explicitly_listed_files: typing.List[pathlib.Path], + files_search_root_folder: pathlib.Path, + files_search_exclude_folders: typing.List[pathlib.Path], + files_search_explicitly_listed_files: typing.List[pathlib.Path], disable_search: bool, disable_file_fixes: bool, token: typing.Optional[str], @@ -48,6 +48,7 @@ def upload_process( git_service: typing.Optional[str], parent_sha: typing.Optional[str], handle_no_reports_found: bool, + report_type: str, ): logger.debug( "Starting upload process", @@ -62,9 +63,9 @@ def upload_process( flags=flags, name=name, network_root_folder=network_root_folder, - coverage_files_search_root_folder=coverage_files_search_root_folder, - coverage_files_search_exclude_folders=coverage_files_search_exclude_folders, - coverage_files_search_explicitly_listed_files=coverage_files_search_explicitly_listed_files, + files_search_root_folder=files_search_root_folder, + files_search_exclude_folders=files_search_exclude_folders, + files_search_explicitly_listed_files=files_search_explicitly_listed_files, plugin_names=plugin_names, token=token, branch=branch, @@ -90,15 +91,16 @@ def upload_process( git_service=git_service, fail_on_error=True, ) - ctx.invoke( - create_report, - token=token, - code=report_code, - fail_on_error=True, - commit_sha=commit_sha, - slug=slug, - git_service=git_service, - ) + if report_type == "coverage": + ctx.invoke( + create_report, + token=token, + code=report_code, + fail_on_error=True, + commit_sha=commit_sha, + slug=slug, + git_service=git_service, + ) ctx.invoke( do_upload, commit_sha=commit_sha, @@ -110,9 +112,9 @@ def upload_process( flags=flags, name=name, network_root_folder=network_root_folder, - coverage_files_search_root_folder=coverage_files_search_root_folder, - coverage_files_search_exclude_folders=coverage_files_search_exclude_folders, - coverage_files_search_explicitly_listed_files=coverage_files_search_explicitly_listed_files, + files_search_root_folder=files_search_root_folder, + files_search_exclude_folders=files_search_exclude_folders, + files_search_explicitly_listed_files=files_search_explicitly_listed_files, disable_search=disable_search, token=token, plugin_names=plugin_names, @@ -125,4 +127,5 @@ def upload_process( git_service=git_service, handle_no_reports_found=handle_no_reports_found, disable_file_fixes=disable_file_fixes, + report_type=report_type, ) diff --git a/codecov_cli/services/upload/__init__.py b/codecov_cli/services/upload/__init__.py index f62fcac9..c3f5bd34 100644 --- a/codecov_cli/services/upload/__init__.py +++ b/codecov_cli/services/upload/__init__.py @@ -34,14 +34,15 @@ def do_upload_logic( flags: typing.List[str], name: typing.Optional[str], network_root_folder: Path, - coverage_files_search_root_folder: Path, - coverage_files_search_exclude_folders: typing.List[Path], - coverage_files_search_explicitly_listed_files: typing.List[Path], + files_search_root_folder: Path, + files_search_exclude_folders: typing.List[Path], + files_search_explicitly_listed_files: typing.List[Path], plugin_names: typing.List[str], token: str, branch: typing.Optional[str], slug: typing.Optional[str], pull_request_number: typing.Optional[str], + upload_file_type: str = "coverage", use_legacy_uploader: bool = False, fail_on_error: bool = False, dry_run: bool = False, @@ -52,18 +53,18 @@ def do_upload_logic( disable_file_fixes: bool = False, ): preparation_plugins = select_preparation_plugins(cli_config, plugin_names) - coverage_file_selector = select_file_finder( - coverage_files_search_root_folder, - coverage_files_search_exclude_folders, - coverage_files_search_explicitly_listed_files, + file_selector = select_file_finder( + files_search_root_folder, + files_search_exclude_folders, + files_search_explicitly_listed_files, disable_search, ) network_finder = select_network_finder(versioning_system) collector = UploadCollector( - preparation_plugins, network_finder, coverage_file_selector, disable_file_fixes + preparation_plugins, network_finder, file_selector, disable_file_fixes ) try: - upload_data = collector.generate_upload_data() + upload_data = collector.generate_upload_data(upload_file_type) except click.ClickException as exp: if handle_no_reports_found: logger.info( @@ -98,6 +99,7 @@ def do_upload_logic( if not dry_run: sending_result = sender.send_upload_data( + upload_file_type, upload_data, commit_sha, token, diff --git a/tests/commands/test_invoke_upload_process.py b/tests/commands/test_invoke_upload_process.py index 7476588b..67e88607 100644 --- a/tests/commands/test_invoke_upload_process.py +++ b/tests/commands/test_invoke_upload_process.py @@ -78,12 +78,12 @@ def test_upload_process_options(mocker): " --network-root-folder PATH Root folder from which to consider paths on", " the network section [default: (Current", " working directory)]", - " -s, --dir, --coverage-files-search-root-folder PATH", + " -s, --dir, --coverage-files-search-root-folder, --files-search-root-folder PATH", " Folder where to search for coverage files", " [default: (Current Working Directory)]", - " --exclude, --coverage-files-search-exclude-folder PATH", + " --exclude, --coverage-files-search-exclude-folder, --files-search-exclude-folder PATH", " Folders to exclude from search", - " -f, --file, --coverage-files-search-direct-file PATH", + " -f, --file, --coverage-files-search-direct-file, --files-search-direct-file PATH", " Explicit files to upload. These will be added", " to the coverage files found for upload. If you", " wish to only upload the specified files,", @@ -114,6 +114,10 @@ def test_upload_process_options(mocker): " Use the legacy upload endpoint", " --handle-no-reports-found Raise no excpetions when no coverage reports", " found.", + " --report-type [coverage|test_results]", + " The type of the file to upload, coverage by", + " default. Possible values are: testing,", + " coverage.", " --parent-sha TEXT SHA (with 40 chars) of what should be the", " parent of this commit", " -h, --help Show this message and exit.", diff --git a/tests/services/upload/test_upload_service.py b/tests/services/upload/test_upload_service.py index 4cb361b9..bf6db7be 100644 --- a/tests/services/upload/test_upload_service.py +++ b/tests/services/upload/test_upload_service.py @@ -47,6 +47,7 @@ def test_do_upload_logic_happy_path_legacy_uploader(mocker): cli_config, versioning_system, ci_adapter, + upload_file_type="coverage", commit_sha="commit_sha", report_code="report_code", build_code="build_code", @@ -56,9 +57,9 @@ def test_do_upload_logic_happy_path_legacy_uploader(mocker): flags=None, name="name", network_root_folder=None, - coverage_files_search_root_folder=None, - coverage_files_search_exclude_folders=None, - coverage_files_search_explicitly_listed_files=None, + files_search_root_folder=None, + files_search_exclude_folders=None, + files_search_explicitly_listed_files=None, plugin_names=["first_plugin", "another", "forth"], token="token", branch="branch", @@ -81,8 +82,9 @@ def test_do_upload_logic_happy_path_legacy_uploader(mocker): ) mock_select_file_finder.assert_called_with(None, None, None, False) mock_select_network_finder.assert_called_with(versioning_system) - mock_generate_upload_data.assert_called_with() + mock_generate_upload_data.assert_called_with("coverage") mock_send_upload_data.assert_called_with( + "coverage", mock_generate_upload_data.return_value, "commit_sha", "token", @@ -133,6 +135,7 @@ def test_do_upload_logic_happy_path(mocker): cli_config, versioning_system, ci_adapter, + upload_file_type="coverage", commit_sha="commit_sha", report_code="report_code", build_code="build_code", @@ -142,9 +145,9 @@ def test_do_upload_logic_happy_path(mocker): flags=None, name="name", network_root_folder=None, - coverage_files_search_root_folder=None, - coverage_files_search_exclude_folders=None, - coverage_files_search_explicitly_listed_files=None, + files_search_root_folder=None, + files_search_exclude_folders=None, + files_search_explicitly_listed_files=None, plugin_names=["first_plugin", "another", "forth"], token="token", branch="branch", @@ -166,8 +169,9 @@ def test_do_upload_logic_happy_path(mocker): ) mock_select_file_finder.assert_called_with(None, None, None, False) mock_select_network_finder.assert_called_with(versioning_system) - mock_generate_upload_data.assert_called_with() + mock_generate_upload_data.assert_called_with("coverage") mock_send_upload_data.assert_called_with( + "coverage", mock_generate_upload_data.return_value, "commit_sha", "token", @@ -214,6 +218,7 @@ def test_do_upload_logic_dry_run(mocker): cli_config, versioning_system, ci_adapter, + upload_file_type="coverage", commit_sha="commit_sha", report_code="report_code", build_code="build_code", @@ -223,9 +228,9 @@ def test_do_upload_logic_dry_run(mocker): flags=None, name="name", network_root_folder=None, - coverage_files_search_root_folder=None, - coverage_files_search_exclude_folders=None, - coverage_files_search_explicitly_listed_files=None, + files_search_root_folder=None, + files_search_exclude_folders=None, + files_search_explicitly_listed_files=None, plugin_names=["first_plugin", "another", "forth"], token="token", branch="branch", @@ -274,6 +279,7 @@ def test_do_upload_logic_verbose(mocker, use_verbose_option): cli_config, versioning_system, ci_adapter, + upload_file_type="coverage", commit_sha="commit_sha", report_code="report_code", build_code="build_code", @@ -283,9 +289,9 @@ def test_do_upload_logic_verbose(mocker, use_verbose_option): flags=None, name="name", network_root_folder=None, - coverage_files_search_root_folder=None, - coverage_files_search_exclude_folders=None, - coverage_files_search_explicitly_listed_files=None, + files_search_root_folder=None, + files_search_exclude_folders=None, + files_search_explicitly_listed_files=None, plugin_names=["first_plugin", "another", "forth"], token="token", branch="branch", @@ -348,6 +354,7 @@ def side_effect(*args, **kwargs): cli_config, versioning_system, ci_adapter, + upload_file_type="coverage", commit_sha="commit_sha", report_code="report_code", build_code="build_code", @@ -357,9 +364,9 @@ def side_effect(*args, **kwargs): flags=None, name="name", network_root_folder=None, - coverage_files_search_root_folder=None, - coverage_files_search_exclude_folders=None, - coverage_files_search_explicitly_listed_files=None, + files_search_root_folder=None, + files_search_exclude_folders=None, + files_search_explicitly_listed_files=None, plugin_names=["first_plugin", "another", "forth"], token="token", branch="branch", @@ -387,7 +394,7 @@ def side_effect(*args, **kwargs): ) mock_select_file_finder.assert_called_with(None, None, None, False) mock_select_network_finder.assert_called_with(versioning_system) - mock_generate_upload_data.assert_called_with() + mock_generate_upload_data.assert_called_with("coverage") mock_upload_completion_call.assert_called_with( commit_sha="commit_sha", slug="slug", @@ -428,6 +435,7 @@ def side_effect(*args, **kwargs): cli_config, versioning_system, ci_adapter, + upload_file_type="coverage", commit_sha="commit_sha", report_code="report_code", build_code="build_code", @@ -437,9 +445,9 @@ def side_effect(*args, **kwargs): flags=None, name="name", network_root_folder=None, - coverage_files_search_root_folder=None, - coverage_files_search_exclude_folders=None, - coverage_files_search_explicitly_listed_files=None, + files_search_root_folder=None, + files_search_exclude_folders=None, + files_search_explicitly_listed_files=None, plugin_names=["first_plugin", "another", "forth"], token="token", branch="branch", @@ -458,4 +466,4 @@ def side_effect(*args, **kwargs): ) mock_select_file_finder.assert_called_with(None, None, None, False) mock_select_network_finder.assert_called_with(versioning_system) - mock_generate_upload_data.assert_called_with() + mock_generate_upload_data.assert_called_with("coverage") From 06d2abc7d35f5d93f7e4db687c985e608337beaf Mon Sep 17 00:00:00 2001 From: joseph-sentry Date: Wed, 3 Jan 2024 09:32:43 -0500 Subject: [PATCH 06/16] chore: make lint --- codecov_cli/services/upload/upload_sender.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/codecov_cli/services/upload/upload_sender.py b/codecov_cli/services/upload/upload_sender.py index 8a2ca60d..c97fc5a8 100644 --- a/codecov_cli/services/upload/upload_sender.py +++ b/codecov_cli/services/upload/upload_sender.py @@ -1,5 +1,5 @@ -import json import base64 +import json import logging import typing import zlib From 85f00f84cf7fe6447fc8edc3bbdacadea015ba0a Mon Sep 17 00:00:00 2001 From: joseph-sentry Date: Wed, 3 Jan 2024 09:32:57 -0500 Subject: [PATCH 07/16] chore: fix failing tests --- codecov_cli/services/upload/__init__.py | 2 +- codecov_cli/services/upload/legacy_upload_sender.py | 1 + tests/services/upload/test_upload_service.py | 4 ++-- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/codecov_cli/services/upload/__init__.py b/codecov_cli/services/upload/__init__.py index c3f5bd34..b9757342 100644 --- a/codecov_cli/services/upload/__init__.py +++ b/codecov_cli/services/upload/__init__.py @@ -99,12 +99,12 @@ def do_upload_logic( if not dry_run: sending_result = sender.send_upload_data( - upload_file_type, upload_data, commit_sha, token, env_vars, report_code, + upload_file_type, name, branch, slug, diff --git a/codecov_cli/services/upload/legacy_upload_sender.py b/codecov_cli/services/upload/legacy_upload_sender.py index 6314b110..283b204d 100644 --- a/codecov_cli/services/upload/legacy_upload_sender.py +++ b/codecov_cli/services/upload/legacy_upload_sender.py @@ -39,6 +39,7 @@ def send_upload_data( token: str, env_vars: typing.Dict[str, str], report_code: str = None, + upload_file_type: str = None, name: typing.Optional[str] = None, branch: typing.Optional[str] = None, slug: typing.Optional[str] = None, diff --git a/tests/services/upload/test_upload_service.py b/tests/services/upload/test_upload_service.py index bf6db7be..f910a724 100644 --- a/tests/services/upload/test_upload_service.py +++ b/tests/services/upload/test_upload_service.py @@ -84,12 +84,12 @@ def test_do_upload_logic_happy_path_legacy_uploader(mocker): mock_select_network_finder.assert_called_with(versioning_system) mock_generate_upload_data.assert_called_with("coverage") mock_send_upload_data.assert_called_with( - "coverage", mock_generate_upload_data.return_value, "commit_sha", "token", None, "report_code", + "coverage", "name", "branch", "slug", @@ -171,12 +171,12 @@ def test_do_upload_logic_happy_path(mocker): mock_select_network_finder.assert_called_with(versioning_system) mock_generate_upload_data.assert_called_with("coverage") mock_send_upload_data.assert_called_with( - "coverage", mock_generate_upload_data.return_value, "commit_sha", "token", None, "report_code", + "coverage", "name", "branch", "slug", From e8908d2af93747532454337266a7a2d2b2944ff6 Mon Sep 17 00:00:00 2001 From: joseph-sentry Date: Wed, 3 Jan 2024 09:57:34 -0500 Subject: [PATCH 08/16] tests: add tests for test_results Signed-off-by: joseph-sentry --- tests/helpers/test_upload_sender.py | 62 ++++++++++++++ tests/services/upload/test_upload_service.py | 87 ++++++++++++++++++++ 2 files changed, 149 insertions(+) diff --git a/tests/helpers/test_upload_sender.py b/tests/helpers/test_upload_sender.py index 2ea9fe6e..1d46dbfa 100644 --- a/tests/helpers/test_upload_sender.py +++ b/tests/helpers/test_upload_sender.py @@ -29,6 +29,21 @@ "ci_service": "ci_service", "git_service": "github", } +test_results_named_upload_data = { + "upload_file_type": "test_results", + "report_code": "report_code", + "env_vars": {}, + "name": "name", + "branch": "branch", + "slug": "org/repo", + "pull_request_number": "pr", + "build_code": "build_code", + "build_url": "build_url", + "job_code": "job_code", + "flags": "flags", + "ci_service": "ci_service", + "git_service": "github", +} request_data = { "ci_url": "build_url", "env": {}, @@ -61,6 +76,20 @@ def mocked_legacy_upload_endpoint(mocked_responses): yield resp +@pytest.fixture +def mocked_test_results_endpoint(mocked_responses): + resp = responses.Response( + responses.POST, + f"https://api.codecov.io/upload/test_results/v1", + status=200, + json={ + "raw_upload_location": "https://puturl.com", + }, + ) + mocked_responses.add(resp) + yield resp + + @pytest.fixture def mocked_storage_server(mocked_responses): resp = responses.Response(responses.PUT, "https://puturl.com", status=200) @@ -160,6 +189,39 @@ def test_upload_sender_post_called_with_right_parameters( post_req_made.headers.items() >= headers.items() ) # test dict is a subset of the other + def test_upload_sender_post_called_with_right_parameters_test_results( + self, mocked_responses, mocked_test_results_endpoint, mocked_storage_server + ): + headers = {"Authorization": f"token {random_token}"} + + mocked_legacy_upload_endpoint.match = [ + matchers.json_params_matcher(request_data), + matchers.header_matcher(headers), + ] + + sending_result = UploadSender().send_upload_data( + upload_collection, + random_sha, + random_token, + **test_results_named_upload_data, + ) + assert sending_result.error is None + assert sending_result.warnings == [] + + assert len(mocked_responses.calls) == 2 + + post_req_made = mocked_responses.calls[0].request + response = json.loads(mocked_responses.calls[0].response.text) + assert response.get("raw_upload_location") == "https://puturl.com" + assert post_req_made.url == "https://api.codecov.io/upload/test_results/v1" + assert ( + post_req_made.headers.items() >= headers.items() + ) # test dict is a subset of the other + + put_req_made = mocked_responses.calls[1].request + assert put_req_made.url == "https://puturl.com/" + assert "test_results_files" in put_req_made.body.decode("utf-8") + def test_upload_sender_post_called_with_right_parameters_tokenless( self, mocked_responses, diff --git a/tests/services/upload/test_upload_service.py b/tests/services/upload/test_upload_service.py index f910a724..45db650b 100644 --- a/tests/services/upload/test_upload_service.py +++ b/tests/services/upload/test_upload_service.py @@ -467,3 +467,90 @@ def side_effect(*args, **kwargs): mock_select_file_finder.assert_called_with(None, None, None, False) mock_select_network_finder.assert_called_with(versioning_system) mock_generate_upload_data.assert_called_with("coverage") + + +def test_do_upload_logic_happy_path_test_results(mocker): + mock_select_preparation_plugins = mocker.patch( + "codecov_cli.services.upload.select_preparation_plugins" + ) + mock_select_file_finder = mocker.patch( + "codecov_cli.services.upload.select_file_finder" + ) + mock_select_network_finder = mocker.patch( + "codecov_cli.services.upload.select_network_finder" + ) + mock_generate_upload_data = mocker.patch.object( + UploadCollector, "generate_upload_data" + ) + mock_send_upload_data = mocker.patch.object( + UploadSender, + "send_upload_data", + return_value=UploadSendingResult( + error=None, + warnings=[UploadSendingResultWarning(message="somewarningmessage")], + ), + ) + cli_config = {} + versioning_system = mocker.MagicMock() + ci_adapter = mocker.MagicMock() + ci_adapter.get_fallback_value.return_value = "service" + runner = CliRunner() + with runner.isolation() as outstreams: + res = do_upload_logic( + cli_config, + versioning_system, + ci_adapter, + upload_file_type="test_results", + commit_sha="commit_sha", + report_code="report_code", + build_code="build_code", + build_url="build_url", + job_code="job_code", + env_vars=None, + flags=None, + name="name", + network_root_folder=None, + files_search_root_folder=None, + files_search_exclude_folders=None, + files_search_explicitly_listed_files=None, + plugin_names=["first_plugin", "another", "forth"], + token="token", + branch="branch", + slug="slug", + pull_request_number="pr", + git_service="git_service", + enterprise_url=None, + ) + out_bytes = parse_outstreams_into_log_lines(outstreams[0].getvalue()) + assert out_bytes == [ + ("info", "Process Upload complete"), + ("info", "Upload process had 1 warning"), + ("warning", "Warning 1: somewarningmessage"), + ] + + assert res == UploadSender.send_upload_data.return_value + mock_select_preparation_plugins.assert_called_with( + cli_config, ["first_plugin", "another", "forth"] + ) + mock_select_file_finder.assert_called_with(None, None, None, False) + mock_select_network_finder.assert_called_with(versioning_system) + mock_generate_upload_data.assert_called_with("test_results") + mock_send_upload_data.assert_called_with( + mock_generate_upload_data.return_value, + "commit_sha", + "token", + None, + "report_code", + "test_results", + "name", + "branch", + "slug", + "pr", + "build_code", + "build_url", + "job_code", + None, + "service", + "git_service", + None, + ) From d24e5a9b8f8222c9b7167b28a83e74cba3f9ea5e Mon Sep 17 00:00:00 2001 From: joseph-sentry Date: Wed, 3 Jan 2024 10:14:53 -0500 Subject: [PATCH 09/16] fix: fix file finder excluded patterns --- codecov_cli/services/upload/file_finder.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/codecov_cli/services/upload/file_finder.py b/codecov_cli/services/upload/file_finder.py index e8ecf5a3..c0458035 100644 --- a/codecov_cli/services/upload/file_finder.py +++ b/codecov_cli/services/upload/file_finder.py @@ -39,8 +39,6 @@ "*junit*", ] -test_results_files_excluded_patterns = [] - coverage_files_excluded_patterns = [ "*.am", "*.bash", @@ -139,6 +137,10 @@ "*.zip", ] +test_results_files_excluded_patterns = ( + coverage_files_patterns + coverage_files_excluded_patterns +) + default_folders_to_ignore = [ "vendor", From 03dbb10b17765dd36c40324632d56a07a4370f14 Mon Sep 17 00:00:00 2001 From: joseph-sentry Date: Wed, 3 Jan 2024 10:15:02 -0500 Subject: [PATCH 10/16] tests: update file finder tests --- .../upload/test_coverage_file_finder.py | 57 +++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/tests/services/upload/test_coverage_file_finder.py b/tests/services/upload/test_coverage_file_finder.py index 31c92937..953e6873 100644 --- a/tests/services/upload/test_coverage_file_finder.py +++ b/tests/services/upload/test_coverage_file_finder.py @@ -95,6 +95,63 @@ def test_find_coverage_files(self, tmp_path): actual = set(FileFinder(tmp_path).find_files()) assert actual - expected == {UploadCollectionResultFile(extra)} + def test_find_coverage_files_test_results(self, tmp_path): + (tmp_path / "sub").mkdir() + (tmp_path / "sub" / "subsub").mkdir() + (tmp_path / "node_modules").mkdir() + + should_find = ["junit.xml", "abc.junit.xml", "sub/junit.xml"] + + should_ignore = [ + "abc.codecov.exe", + "sub/abc.codecov.exe", + "codecov.exe", + "__pycache__", + "sub/subsub/__pycache__", + ".gitignore", + "a.sql", + "a.csv", + ".abc-coveragerc", + ".coverage-xyz", + "sub/scoverage.measurements.xyz", + "sub/test_abcd_coverage.txt", + "test-result-ff-codecoverage.json", + "node_modules/abc-coverage.cov", + "abc-coverage.cov", + "coverage-abc.abc", + "sub/coverage-abc.abc", + "sub/subsub/coverage-abc.abc", + "coverage.abc", + "jacocoxyz.xml", + "sub/jacocoxyz.xml", + "codecov.abc", + "sub/subsub/codecov.abc", + "xyz.codecov.abc", + "sub/xyz.codecov.abc", + "sub/subsub/xyz.codecov.abc", + "cover.out", + "abc.gcov", + "sub/abc.gcov", + "sub/subsub/abc.gcov", + ] + + for filename in should_find: + (tmp_path / filename).touch() + + for filename in should_ignore: + (tmp_path / filename).touch() + + expected = { + UploadCollectionResultFile((tmp_path / file)) for file in should_find + } + actual = set(FileFinder(tmp_path, report_type="test_results").find_files()) + assert actual == expected + + extra = tmp_path / "sub" / "nosetests.junit.xml" + extra.touch() + actual = set(FileFinder(tmp_path, report_type="test_results").find_files()) + assert actual - expected == {UploadCollectionResultFile(extra)} + class TestCoverageFileFinderUserInput(unittest.TestCase): def setUp(self): From 83bd89fc6b7d6d88b51cc61e319eccc613d3ec91 Mon Sep 17 00:00:00 2001 From: joseph-sentry Date: Wed, 3 Jan 2024 12:21:57 -0500 Subject: [PATCH 11/16] tests: add tests for generate_upload_data --- .../services/upload/test_upload_collector.py | 65 +++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/tests/services/upload/test_upload_collector.py b/tests/services/upload/test_upload_collector.py index 15279275..e4d05993 100644 --- a/tests/services/upload/test_upload_collector.py +++ b/tests/services/upload/test_upload_collector.py @@ -2,6 +2,10 @@ from unittest.mock import patch from codecov_cli.services.upload.upload_collector import UploadCollector +from codecov_cli.services.upload.file_finder import FileFinder +from codecov_cli.services.upload.network_finder import NetworkFinder +from codecov_cli.helpers.versioning_systems import GitVersioningSystem +from codecov_cli.types import UploadCollectionResultFile def test_fix_kt_files(): @@ -109,3 +113,64 @@ def test_fix_when_disabled_fixes(tmp_path): assert len(fixes) == 0 assert fixes == [] + + +def test_generate_upload_data(tmp_path): + (tmp_path / "sub").mkdir() + (tmp_path / "sub" / "subsub").mkdir() + (tmp_path / "node_modules").mkdir() + + should_find = [ + "abc-coverage.cov", + "coverage-abc.abc", + "sub/coverage-abc.abc", + "sub/subsub/coverage-abc.abc", + "coverage.abc", + "jacocoxyz.xml", + "sub/jacocoxyz.xml", + "codecov.abc", + "sub/subsub/codecov.abc", + "xyz.codecov.abc", + "sub/xyz.codecov.abc", + "sub/subsub/xyz.codecov.abc", + "cover.out", + "abc.gcov", + "sub/abc.gcov", + "sub/subsub/abc.gcov", + ] + + should_ignore = [ + "abc.codecov.exe", + "sub/abc.codecov.exe", + "codecov.exe", + "__pycache__", + "sub/subsub/__pycache__", + ".gitignore", + "a.sql", + "a.csv", + ".abc-coveragerc", + ".coverage-xyz", + "sub/scoverage.measurements.xyz", + "sub/test_abcd_coverage.txt", + "test-result-ff-codecoverage.json", + "node_modules/abc-coverage.cov", + ] + + for filename in should_find: + (tmp_path / filename).touch() + + for filename in should_ignore: + (tmp_path / filename).touch() + + file_finder = FileFinder(tmp_path) + + network_finder = NetworkFinder(GitVersioningSystem()) + + collector = UploadCollector([], network_finder, file_finder) + + res = collector.generate_upload_data() + + expected = {UploadCollectionResultFile(tmp_path / file) for file in should_find} + + for file in expected: + assert file in res.files From 9b0b7d6402a4466194de38227f4911bf0f7b3703 Mon Sep 17 00:00:00 2001 From: joseph-sentry Date: Tue, 23 Jan 2024 14:55:34 -0500 Subject: [PATCH 12/16] fix: move url and data choice to separate function in upload sender Signed-off-by: joseph-sentry --- codecov_cli/services/upload/upload_sender.py | 36 ++++++++++++++++---- 1 file changed, 29 insertions(+), 7 deletions(-) diff --git a/codecov_cli/services/upload/upload_sender.py b/codecov_cli/services/upload/upload_sender.py index c97fc5a8..f1399d48 100644 --- a/codecov_cli/services/upload/upload_sender.py +++ b/codecov_cli/services/upload/upload_sender.py @@ -67,13 +67,15 @@ def send_upload_data( headers = get_token_header_or_fail(token) encoded_slug = encode_slug(slug) upload_url = enterprise_url or CODECOV_API_URL - if upload_file_type == "coverage": - url = f"{upload_url}/upload/{git_service}/{encoded_slug}/commits/{commit_sha}/reports/{report_code}/uploads" - elif upload_file_type == "test_results": - data["slug"] = encoded_slug - data["commit"] = commit_sha - data["service"] = git_service - url = f"{upload_url}/upload/test_results/v1" + url, data = self.get_url_and_possibly_update_data( + data, + upload_file_type, + upload_url, + git_service, + encoded_slug, + commit_sha, + report_code, + ) # Data that goes to storage reports_payload = self._generate_payload( upload_data, env_vars, upload_file_type @@ -172,3 +174,23 @@ def _get_format_info(self, file: UploadCollectionResultFile): base64.b64encode(zlib.compress((file.get_content()))) ).decode() return format, formatted_content + + def get_url_and_possibly_update_data( + self, + data, + report_type, + upload_url, + git_service, + encoded_slug, + commit_sha, + report_code, + ): + if report_type == "coverage": + url = f"{upload_url}/upload/{git_service}/{encoded_slug}/commits/{commit_sha}/reports/{report_code}/uploads" + elif report_type == "test_results": + data["slug"] = encoded_slug + data["commit"] = commit_sha + data["service"] = git_service + url = f"{upload_url}/upload/test_results/v1" + + return url, data From 4cbc86bbc07183fcaede04bc070dca224717df0b Mon Sep 17 00:00:00 2001 From: joseph-sentry Date: Wed, 24 Jan 2024 14:15:22 -0500 Subject: [PATCH 13/16] fix: no more prep plugins in test results upload Signed-off-by: joseph-sentry --- codecov_cli/services/upload/__init__.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/codecov_cli/services/upload/__init__.py b/codecov_cli/services/upload/__init__.py index b9757342..30960ae6 100644 --- a/codecov_cli/services/upload/__init__.py +++ b/codecov_cli/services/upload/__init__.py @@ -52,12 +52,16 @@ def do_upload_logic( handle_no_reports_found: bool = False, disable_file_fixes: bool = False, ): - preparation_plugins = select_preparation_plugins(cli_config, plugin_names) + if upload_file_type == "coverage": + preparation_plugins = select_preparation_plugins(cli_config, plugin_names) + elif upload_file_type == "test_results": + preparation_plugins = [] file_selector = select_file_finder( files_search_root_folder, files_search_exclude_folders, files_search_explicitly_listed_files, disable_search, + upload_file_type, ) network_finder = select_network_finder(versioning_system) collector = UploadCollector( From 098683a40ab9fa631f10b8e9b42f9d214789196e Mon Sep 17 00:00:00 2001 From: joseph-sentry Date: Wed, 24 Jan 2024 14:15:42 -0500 Subject: [PATCH 14/16] fix: pass report type to file finder constructor Signed-off-by: joseph-sentry --- codecov_cli/services/upload/file_finder.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/codecov_cli/services/upload/file_finder.py b/codecov_cli/services/upload/file_finder.py index c0458035..e98517de 100644 --- a/codecov_cli/services/upload/file_finder.py +++ b/codecov_cli/services/upload/file_finder.py @@ -265,11 +265,16 @@ def get_user_specified_files(self, regex_patterns_to_exclude): def select_file_finder( - root_folder_to_search, folders_to_ignore, explicitly_listed_files, disable_search + root_folder_to_search, + folders_to_ignore, + explicitly_listed_files, + disable_search, + report_type="coverage", ): return FileFinder( root_folder_to_search, folders_to_ignore, explicitly_listed_files, disable_search, + report_type, ) From 255b211debf633f5417062e3eddfe7c5e09e1914 Mon Sep 17 00:00:00 2001 From: joseph-sentry Date: Wed, 24 Jan 2024 14:22:09 -0500 Subject: [PATCH 15/16] chore: make lint Signed-off-by: joseph-sentry --- tests/services/upload/test_upload_collector.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/services/upload/test_upload_collector.py b/tests/services/upload/test_upload_collector.py index e4d05993..0df1c0bc 100644 --- a/tests/services/upload/test_upload_collector.py +++ b/tests/services/upload/test_upload_collector.py @@ -1,10 +1,10 @@ from pathlib import Path from unittest.mock import patch -from codecov_cli.services.upload.upload_collector import UploadCollector +from codecov_cli.helpers.versioning_systems import GitVersioningSystem from codecov_cli.services.upload.file_finder import FileFinder from codecov_cli.services.upload.network_finder import NetworkFinder -from codecov_cli.helpers.versioning_systems import GitVersioningSystem +from codecov_cli.services.upload.upload_collector import UploadCollector from codecov_cli.types import UploadCollectionResultFile From bc1865892fd298e38779b4f236713d0e57fbf144 Mon Sep 17 00:00:00 2001 From: joseph-sentry Date: Wed, 24 Jan 2024 14:26:00 -0500 Subject: [PATCH 16/16] test: fix tests due to prep plugin and file finder changes Signed-off-by: joseph-sentry --- tests/services/upload/test_upload_service.py | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/tests/services/upload/test_upload_service.py b/tests/services/upload/test_upload_service.py index 45db650b..9f7dbf61 100644 --- a/tests/services/upload/test_upload_service.py +++ b/tests/services/upload/test_upload_service.py @@ -80,7 +80,7 @@ def test_do_upload_logic_happy_path_legacy_uploader(mocker): mock_select_preparation_plugins.assert_called_with( cli_config, ["first_plugin", "another", "forth"] ) - mock_select_file_finder.assert_called_with(None, None, None, False) + mock_select_file_finder.assert_called_with(None, None, None, False, "coverage") mock_select_network_finder.assert_called_with(versioning_system) mock_generate_upload_data.assert_called_with("coverage") mock_send_upload_data.assert_called_with( @@ -167,7 +167,7 @@ def test_do_upload_logic_happy_path(mocker): mock_select_preparation_plugins.assert_called_with( cli_config, ["first_plugin", "another", "forth"] ) - mock_select_file_finder.assert_called_with(None, None, None, False) + mock_select_file_finder.assert_called_with(None, None, None, False, "coverage") mock_select_network_finder.assert_called_with(versioning_system) mock_generate_upload_data.assert_called_with("coverage") mock_send_upload_data.assert_called_with( @@ -241,7 +241,7 @@ def test_do_upload_logic_dry_run(mocker): enterprise_url=None, ) out_bytes = parse_outstreams_into_log_lines(outstreams[0].getvalue()) - mock_select_file_finder.assert_called_with(None, None, None, False) + mock_select_file_finder.assert_called_with(None, None, None, False, "coverage") mock_select_network_finder.assert_called_with(versioning_system) assert mock_generate_upload_data.call_count == 1 assert mock_send_upload_data.call_count == 0 @@ -392,7 +392,7 @@ def side_effect(*args, **kwargs): mock_select_preparation_plugins.assert_called_with( cli_config, ["first_plugin", "another", "forth"] ) - mock_select_file_finder.assert_called_with(None, None, None, False) + mock_select_file_finder.assert_called_with(None, None, None, False, "coverage") mock_select_network_finder.assert_called_with(versioning_system) mock_generate_upload_data.assert_called_with("coverage") mock_upload_completion_call.assert_called_with( @@ -464,7 +464,7 @@ def side_effect(*args, **kwargs): mock_select_preparation_plugins.assert_called_with( cli_config, ["first_plugin", "another", "forth"] ) - mock_select_file_finder.assert_called_with(None, None, None, False) + mock_select_file_finder.assert_called_with(None, None, None, False, "coverage") mock_select_network_finder.assert_called_with(versioning_system) mock_generate_upload_data.assert_called_with("coverage") @@ -529,10 +529,8 @@ def test_do_upload_logic_happy_path_test_results(mocker): ] assert res == UploadSender.send_upload_data.return_value - mock_select_preparation_plugins.assert_called_with( - cli_config, ["first_plugin", "another", "forth"] - ) - mock_select_file_finder.assert_called_with(None, None, None, False) + mock_select_preparation_plugins.assert_not_called + mock_select_file_finder.assert_called_with(None, None, None, False, "test_results") mock_select_network_finder.assert_called_with(versioning_system) mock_generate_upload_data.assert_called_with("test_results") mock_send_upload_data.assert_called_with(