Skip to content

Commit

Permalink
Add support for test result ingestion in the CLI (#347)
Browse files Browse the repository at this point in the history
* feat: add test result file finding in FileFinder

* feat: update upload collector to handle test result files

* feat: update upload senders to handle test result files

* feat: add report type option and rename coverage files  options to files

* tests: add tests for test_results

* fix: fix file finder excluded patterns

* tests: update file finder tests

* tests: add tests for generate_upload_data

* fix: move url and data choice to separate function in upload sender

* fix: no more prep plugins in test results upload

* fix: pass report type to file finder constructor

* test: fix tests due to prep plugin and file finder changes

Signed-off-by: joseph-sentry <joseph.sawaya@sentry.io>
  • Loading branch information
joseph-sentry authored Jan 25, 2024
1 parent f3827b3 commit be85cc8
Show file tree
Hide file tree
Showing 14 changed files with 513 additions and 170 deletions.
40 changes: 24 additions & 16 deletions codecov_cli/commands/upload.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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,
Expand All @@ -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,
Expand Down Expand Up @@ -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"]),
),
]


Expand All @@ -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],
Expand All @@ -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 {}
Expand All @@ -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,
Expand All @@ -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,
Expand All @@ -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,
Expand All @@ -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,
Expand Down
39 changes: 21 additions & 18 deletions codecov_cli/commands/upload_process.py
Original file line number Diff line number Diff line change
Expand Up @@ -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],
Expand All @@ -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",
Expand All @@ -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,
Expand All @@ -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,
Expand All @@ -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,
Expand All @@ -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,
)
28 changes: 17 additions & 11 deletions codecov_cli/services/upload/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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,
Expand All @@ -51,19 +52,23 @@ def do_upload_logic(
handle_no_reports_found: bool = False,
disable_file_fixes: bool = False,
):
preparation_plugins = select_preparation_plugins(cli_config, plugin_names)
coverage_file_selector = select_coverage_file_finder(
coverage_files_search_root_folder,
coverage_files_search_exclude_folders,
coverage_files_search_explicitly_listed_files,
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(
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(
Expand Down Expand Up @@ -103,6 +108,7 @@ def do_upload_logic(
token,
env_vars,
report_code,
upload_file_type,
name,
branch,
slug,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@
"test_cov.xml",
]

test_results_files_patterns = [
"*junit*",
]

coverage_files_excluded_patterns = [
"*.am",
Expand Down Expand Up @@ -134,6 +137,10 @@
"*.zip",
]

test_results_files_excluded_patterns = (
coverage_files_patterns + coverage_files_excluded_patterns
)


default_folders_to_ignore = [
"vendor",
Expand Down Expand Up @@ -170,49 +177,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:
Expand All @@ -230,7 +241,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,
Expand All @@ -241,7 +252,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:
Expand All @@ -250,15 +261,20 @@ 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(
root_folder_to_search, folders_to_ignore, explicitly_listed_files, disable_search
def select_file_finder(
root_folder_to_search,
folders_to_ignore,
explicitly_listed_files,
disable_search,
report_type="coverage",
):
return CoverageFileFinder(
return FileFinder(
root_folder_to_search,
folders_to_ignore,
explicitly_listed_files,
disable_search,
report_type,
)
Loading

0 comments on commit be85cc8

Please sign in to comment.