codecov-cli 11.0.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (83) hide show
  1. codecov_cli/__init__.py +3 -0
  2. codecov_cli/commands/__init__.py +0 -0
  3. codecov_cli/commands/base_picking.py +75 -0
  4. codecov_cli/commands/commit.py +72 -0
  5. codecov_cli/commands/create_report_result.py +41 -0
  6. codecov_cli/commands/empty_upload.py +80 -0
  7. codecov_cli/commands/get_report_results.py +50 -0
  8. codecov_cli/commands/labelanalysis.py +269 -0
  9. codecov_cli/commands/process_test_results.py +273 -0
  10. codecov_cli/commands/report.py +65 -0
  11. codecov_cli/commands/send_notifications.py +46 -0
  12. codecov_cli/commands/staticanalysis.py +62 -0
  13. codecov_cli/commands/upload.py +316 -0
  14. codecov_cli/commands/upload_coverage.py +186 -0
  15. codecov_cli/commands/upload_process.py +133 -0
  16. codecov_cli/fallbacks.py +41 -0
  17. codecov_cli/helpers/__init__.py +0 -0
  18. codecov_cli/helpers/args.py +31 -0
  19. codecov_cli/helpers/ci_adapters/__init__.py +63 -0
  20. codecov_cli/helpers/ci_adapters/appveyor_ci.py +54 -0
  21. codecov_cli/helpers/ci_adapters/azure_pipelines.py +44 -0
  22. codecov_cli/helpers/ci_adapters/base.py +102 -0
  23. codecov_cli/helpers/ci_adapters/bitbucket_ci.py +42 -0
  24. codecov_cli/helpers/ci_adapters/bitrise_ci.py +37 -0
  25. codecov_cli/helpers/ci_adapters/buildkite.py +45 -0
  26. codecov_cli/helpers/ci_adapters/circleci.py +47 -0
  27. codecov_cli/helpers/ci_adapters/cirrus_ci.py +36 -0
  28. codecov_cli/helpers/ci_adapters/cloudbuild.py +70 -0
  29. codecov_cli/helpers/ci_adapters/codebuild.py +49 -0
  30. codecov_cli/helpers/ci_adapters/droneci.py +36 -0
  31. codecov_cli/helpers/ci_adapters/github_actions.py +90 -0
  32. codecov_cli/helpers/ci_adapters/gitlab_ci.py +56 -0
  33. codecov_cli/helpers/ci_adapters/heroku.py +36 -0
  34. codecov_cli/helpers/ci_adapters/jenkins.py +38 -0
  35. codecov_cli/helpers/ci_adapters/local.py +39 -0
  36. codecov_cli/helpers/ci_adapters/teamcity.py +37 -0
  37. codecov_cli/helpers/ci_adapters/travis_ci.py +44 -0
  38. codecov_cli/helpers/ci_adapters/woodpeckerci.py +36 -0
  39. codecov_cli/helpers/config.py +66 -0
  40. codecov_cli/helpers/encoder.py +49 -0
  41. codecov_cli/helpers/folder_searcher.py +114 -0
  42. codecov_cli/helpers/git.py +97 -0
  43. codecov_cli/helpers/git_services/__init__.py +14 -0
  44. codecov_cli/helpers/git_services/github.py +40 -0
  45. codecov_cli/helpers/glob.py +146 -0
  46. codecov_cli/helpers/logging_utils.py +77 -0
  47. codecov_cli/helpers/options.py +51 -0
  48. codecov_cli/helpers/request.py +198 -0
  49. codecov_cli/helpers/upload_type.py +15 -0
  50. codecov_cli/helpers/validators.py +13 -0
  51. codecov_cli/helpers/versioning_systems.py +201 -0
  52. codecov_cli/main.py +99 -0
  53. codecov_cli/opentelemetry.py +26 -0
  54. codecov_cli/plugins/__init__.py +92 -0
  55. codecov_cli/plugins/compress_pycoverage_contexts.py +141 -0
  56. codecov_cli/plugins/gcov.py +69 -0
  57. codecov_cli/plugins/pycoverage.py +134 -0
  58. codecov_cli/plugins/types.py +8 -0
  59. codecov_cli/plugins/xcode.py +117 -0
  60. codecov_cli/runners/__init__.py +80 -0
  61. codecov_cli/runners/dan_runner.py +64 -0
  62. codecov_cli/runners/pytest_standard_runner.py +184 -0
  63. codecov_cli/runners/types.py +33 -0
  64. codecov_cli/services/__init__.py +0 -0
  65. codecov_cli/services/commit/__init__.py +86 -0
  66. codecov_cli/services/commit/base_picking.py +24 -0
  67. codecov_cli/services/empty_upload/__init__.py +42 -0
  68. codecov_cli/services/report/__init__.py +169 -0
  69. codecov_cli/services/upload/__init__.py +169 -0
  70. codecov_cli/services/upload/file_finder.py +320 -0
  71. codecov_cli/services/upload/legacy_upload_sender.py +132 -0
  72. codecov_cli/services/upload/network_finder.py +49 -0
  73. codecov_cli/services/upload/upload_collector.py +198 -0
  74. codecov_cli/services/upload/upload_sender.py +232 -0
  75. codecov_cli/services/upload_completion/__init__.py +38 -0
  76. codecov_cli/services/upload_coverage/__init__.py +93 -0
  77. codecov_cli/types.py +88 -0
  78. codecov_cli-11.0.0.dist-info/METADATA +298 -0
  79. codecov_cli-11.0.0.dist-info/RECORD +83 -0
  80. codecov_cli-11.0.0.dist-info/WHEEL +5 -0
  81. codecov_cli-11.0.0.dist-info/entry_points.txt +3 -0
  82. codecov_cli-11.0.0.dist-info/licenses/LICENSE +201 -0
  83. codecov_cli-11.0.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,232 @@
1
+ import base64
2
+ import json
3
+ import logging
4
+ import typing
5
+ import zlib
6
+ from typing import Any, Dict
7
+
8
+ import sentry_sdk
9
+
10
+ from codecov_cli import __version__ as codecov_cli_version
11
+ from codecov_cli.helpers.config import CODECOV_INGEST_URL
12
+ from codecov_cli.helpers.encoder import encode_slug
13
+ from codecov_cli.helpers.upload_type import ReportType
14
+ from codecov_cli.helpers.request import (
15
+ get_token_header,
16
+ send_post_request,
17
+ send_put_request,
18
+ )
19
+ from codecov_cli.types import (
20
+ RequestResult,
21
+ UploadCollectionResult,
22
+ UploadCollectionResultFile,
23
+ )
24
+
25
+ logger = logging.getLogger("codecovcli")
26
+
27
+
28
+ class UploadSender(object):
29
+ def send_upload_data(
30
+ self,
31
+ upload_data: UploadCollectionResult,
32
+ commit_sha: str,
33
+ token: typing.Optional[str],
34
+ env_vars: typing.Dict[str, str],
35
+ report_code: str,
36
+ report_type: ReportType = ReportType.COVERAGE,
37
+ name: typing.Optional[str] = None,
38
+ branch: typing.Optional[str] = None,
39
+ slug: typing.Optional[str] = None,
40
+ pull_request_number: typing.Optional[str] = None,
41
+ build_code: typing.Optional[str] = None,
42
+ build_url: typing.Optional[str] = None,
43
+ job_code: typing.Optional[str] = None,
44
+ flags: typing.List[str] = None,
45
+ ci_service: typing.Optional[str] = None,
46
+ git_service: typing.Optional[str] = None,
47
+ enterprise_url: typing.Optional[str] = None,
48
+ parent_sha: typing.Optional[str] = None,
49
+ upload_coverage: bool = False,
50
+ args: dict = None,
51
+ ) -> RequestResult:
52
+ current_transaction = sentry_sdk.get_current_scope().transaction
53
+ if current_transaction:
54
+ current_transaction.set_data("commit_sha", commit_sha)
55
+ current_transaction.set_data("slug", slug)
56
+
57
+ with sentry_sdk.start_span(name="upload_sender"):
58
+ with sentry_sdk.start_span(name="upload_sender_preparation"):
59
+ file_not_found = False
60
+ if report_type == ReportType.TEST_RESULTS and not upload_data.files:
61
+ file_not_found = True
62
+
63
+ data = {
64
+ "ci_service": ci_service,
65
+ "ci_url": build_url,
66
+ "cli_args": args,
67
+ "env": env_vars,
68
+ "flags": flags,
69
+ "job_code": job_code,
70
+ "name": name,
71
+ "version": codecov_cli_version,
72
+ "file_not_found": file_not_found,
73
+ }
74
+
75
+ if upload_coverage:
76
+ data["branch"] = branch
77
+ data["code"] = report_code
78
+ data["commitid"] = commit_sha
79
+ data["parent_commit_id"] = parent_sha
80
+ data["pullid"] = pull_request_number
81
+ headers = get_token_header(token)
82
+ encoded_slug = encode_slug(slug)
83
+ upload_url = enterprise_url or CODECOV_INGEST_URL
84
+ url, data = self.get_url_and_possibly_update_data(
85
+ data,
86
+ report_type,
87
+ upload_url,
88
+ git_service,
89
+ branch,
90
+ encoded_slug,
91
+ commit_sha,
92
+ report_code,
93
+ upload_coverage,
94
+ )
95
+ # Data that goes to storage
96
+ reports_payload = self._generate_payload(
97
+ upload_data, env_vars, report_type
98
+ )
99
+
100
+ with sentry_sdk.start_span(name="upload_sender_storage_request"):
101
+ logger.debug("Sending upload request to Codecov")
102
+ resp_from_codecov = send_post_request(
103
+ url=url,
104
+ data=data,
105
+ headers=headers,
106
+ )
107
+
108
+ if file_not_found:
109
+ logger.info(
110
+ "No test results reports found. Triggering notifications without uploading."
111
+ )
112
+ return resp_from_codecov
113
+
114
+ if resp_from_codecov.status_code >= 400:
115
+ return resp_from_codecov
116
+ resp_json_obj = json.loads(resp_from_codecov.text)
117
+ if resp_json_obj.get("url"):
118
+ logger.info(
119
+ f"Your upload is now processing. When finished, results will be available at: {resp_json_obj.get('url')}"
120
+ )
121
+ logger.debug(
122
+ "Upload request to Codecov complete.",
123
+ extra=dict(extra_log_attributes=dict(response=resp_json_obj)),
124
+ )
125
+ put_url = resp_json_obj["raw_upload_location"]
126
+
127
+ with sentry_sdk.start_span(name="upload_sender_storage"):
128
+ logger.debug("Sending upload to storage")
129
+ resp_from_storage = send_put_request(put_url, data=reports_payload)
130
+
131
+ return resp_from_storage
132
+
133
+ def _generate_payload(
134
+ self,
135
+ upload_data: UploadCollectionResult,
136
+ env_vars: typing.Dict[str, str],
137
+ report_type: ReportType = ReportType.COVERAGE,
138
+ ) -> bytes:
139
+ network_files = upload_data.network
140
+ if report_type == ReportType.COVERAGE:
141
+ payload = {
142
+ "report_fixes": {
143
+ "format": "legacy",
144
+ "value": self._get_file_fixers(upload_data),
145
+ },
146
+ "network_files": network_files if network_files is not None else [],
147
+ "coverage_files": self._get_files(upload_data),
148
+ "metadata": {},
149
+ }
150
+ elif report_type == ReportType.TEST_RESULTS:
151
+ payload = {
152
+ "test_results_files": self._get_files(upload_data),
153
+ }
154
+
155
+ json_data = json.dumps(payload)
156
+ return json_data.encode()
157
+
158
+ def _get_file_fixers(
159
+ self, upload_data: UploadCollectionResult
160
+ ) -> Dict[str, Dict[str, Any]]:
161
+ """
162
+ Returns file/path fixes in the following format:
163
+
164
+ {
165
+ {path}: {
166
+ "eof": int(eof_line),
167
+ "lines": {set_of_lines},
168
+ },
169
+ }
170
+ """
171
+ file_fixers = {}
172
+ for file_fixer in upload_data.file_fixes:
173
+ fixed_lines_with_reason = set(
174
+ [fixer[0] for fixer in file_fixer.fixed_lines_with_reason]
175
+ )
176
+ total_fixed_lines = list(
177
+ file_fixer.fixed_lines_without_reason.union(fixed_lines_with_reason)
178
+ )
179
+ file_fixers[file_fixer.path.as_posix()] = {
180
+ "eof": file_fixer.eof,
181
+ "lines": total_fixed_lines,
182
+ }
183
+
184
+ return file_fixers
185
+
186
+ def _get_files(self, upload_data: UploadCollectionResult):
187
+ return [self._format_file(file) for file in upload_data.files]
188
+
189
+ def _format_file(self, file: UploadCollectionResultFile):
190
+ format, formatted_content = self._get_format_info(file)
191
+ return {
192
+ "filename": file.get_filename(),
193
+ "format": format,
194
+ "data": formatted_content,
195
+ "labels": "",
196
+ }
197
+
198
+ def _get_format_info(self, file: UploadCollectionResultFile):
199
+ format = "base64+compressed"
200
+ formatted_content = (
201
+ base64.b64encode(zlib.compress((file.get_content())))
202
+ ).decode()
203
+ return format, formatted_content
204
+
205
+ def get_url_and_possibly_update_data(
206
+ self,
207
+ data,
208
+ report_type: ReportType,
209
+ upload_url,
210
+ git_service,
211
+ branch,
212
+ encoded_slug,
213
+ commit_sha,
214
+ report_code,
215
+ upload_coverage=False,
216
+ file_not_found=False,
217
+ ):
218
+ if report_type == ReportType.COVERAGE:
219
+ base_url = f"{upload_url}/upload/{git_service}/{encoded_slug}"
220
+ if upload_coverage:
221
+ url = f"{base_url}/upload-coverage"
222
+ else:
223
+ url = f"{base_url}/commits/{commit_sha}/reports/{report_code}/uploads"
224
+ elif report_type == ReportType.TEST_RESULTS:
225
+ data["slug"] = encoded_slug
226
+ data["branch"] = branch
227
+ data["commit"] = commit_sha
228
+ data["service"] = git_service
229
+ data["file_not_found"] = file_not_found
230
+ url = f"{upload_url}/upload/test_results/v1"
231
+
232
+ return url, data
@@ -0,0 +1,38 @@
1
+ import json
2
+ import logging
3
+
4
+ from codecov_cli.helpers.config import CODECOV_API_URL
5
+ from codecov_cli.helpers.encoder import encode_slug
6
+ from codecov_cli.helpers.request import (
7
+ get_token_header,
8
+ log_warnings_and_errors_if_any,
9
+ send_post_request,
10
+ )
11
+
12
+ logger = logging.getLogger("codecovcli")
13
+
14
+
15
+ def upload_completion_logic(
16
+ commit_sha,
17
+ slug,
18
+ token,
19
+ git_service,
20
+ enterprise_url,
21
+ fail_on_error=False,
22
+ args=None,
23
+ ):
24
+ encoded_slug = encode_slug(slug)
25
+ headers = get_token_header(token)
26
+ upload_url = enterprise_url or CODECOV_API_URL
27
+ url = f"{upload_url}/upload/{git_service}/{encoded_slug}/commits/{commit_sha}/upload-complete"
28
+ data = {
29
+ "cli_args": args,
30
+ }
31
+ sending_result = send_post_request(url=url, data=data, headers=headers)
32
+ log_warnings_and_errors_if_any(
33
+ sending_result, "Upload Completion", fail_on_error=fail_on_error
34
+ )
35
+ if sending_result.status_code == 200:
36
+ response_json = json.loads(sending_result.text)
37
+ logger.info(response_json)
38
+ return sending_result
@@ -0,0 +1,93 @@
1
+ import pathlib
2
+ import typing
3
+
4
+ from codecov_cli.helpers.ci_adapters.base import CIAdapterBase
5
+ from codecov_cli.helpers.versioning_systems import VersioningSystemInterface
6
+ from codecov_cli.services.upload import do_upload_logic
7
+ from codecov_cli.helpers.upload_type import ReportType
8
+
9
+
10
+ def upload_coverage_logic(
11
+ cli_config: typing.Dict,
12
+ versioning_system: VersioningSystemInterface,
13
+ ci_adapter: CIAdapterBase,
14
+ *,
15
+ branch: typing.Optional[str],
16
+ build_code: typing.Optional[str],
17
+ build_url: typing.Optional[str],
18
+ commit_sha: str,
19
+ recurse_submodules: bool,
20
+ disable_file_fixes: bool,
21
+ disable_search: bool,
22
+ dry_run: bool,
23
+ enterprise_url: typing.Optional[str],
24
+ env_vars: typing.Dict[str, str],
25
+ fail_on_error: bool,
26
+ files_search_exclude_folders: typing.List[pathlib.Path],
27
+ files_search_explicitly_listed_files: typing.List[pathlib.Path],
28
+ files_search_root_folder: pathlib.Path,
29
+ flags: typing.List[str],
30
+ gcov_args: typing.Optional[str],
31
+ gcov_executable: typing.Optional[str],
32
+ gcov_ignore: typing.Optional[str],
33
+ gcov_include: typing.Optional[str],
34
+ git_service: typing.Optional[str],
35
+ handle_no_reports_found: bool,
36
+ job_code: typing.Optional[str],
37
+ name: typing.Optional[str],
38
+ network_filter: typing.Optional[str],
39
+ network_prefix: typing.Optional[str],
40
+ network_root_folder: pathlib.Path,
41
+ parent_sha: typing.Optional[str],
42
+ plugin_names: typing.List[str],
43
+ pull_request_number: typing.Optional[str],
44
+ report_code: str,
45
+ slug: typing.Optional[str],
46
+ swift_project: typing.Optional[str],
47
+ token: typing.Optional[str],
48
+ use_legacy_uploader: bool,
49
+ report_type: ReportType = ReportType.COVERAGE,
50
+ args: dict = None,
51
+ ):
52
+ return do_upload_logic(
53
+ cli_config=cli_config,
54
+ versioning_system=versioning_system,
55
+ ci_adapter=ci_adapter,
56
+ upload_coverage=True,
57
+ args=args,
58
+ branch=branch,
59
+ build_code=build_code,
60
+ build_url=build_url,
61
+ commit_sha=commit_sha,
62
+ recurse_submodules=recurse_submodules,
63
+ disable_file_fixes=disable_file_fixes,
64
+ disable_search=disable_search,
65
+ dry_run=dry_run,
66
+ enterprise_url=enterprise_url,
67
+ env_vars=env_vars,
68
+ fail_on_error=fail_on_error,
69
+ files_search_exclude_folders=files_search_exclude_folders,
70
+ files_search_explicitly_listed_files=files_search_explicitly_listed_files,
71
+ files_search_root_folder=files_search_root_folder,
72
+ flags=flags,
73
+ gcov_args=gcov_args,
74
+ gcov_executable=gcov_executable,
75
+ gcov_ignore=gcov_ignore,
76
+ gcov_include=gcov_include,
77
+ git_service=git_service,
78
+ handle_no_reports_found=handle_no_reports_found,
79
+ job_code=job_code,
80
+ name=name,
81
+ network_filter=network_filter,
82
+ network_prefix=network_prefix,
83
+ network_root_folder=network_root_folder,
84
+ parent_sha=parent_sha,
85
+ plugin_names=plugin_names,
86
+ pull_request_number=pull_request_number,
87
+ report_code=report_code,
88
+ slug=slug,
89
+ swift_project=swift_project,
90
+ token=token,
91
+ use_legacy_uploader=use_legacy_uploader,
92
+ report_type=report_type,
93
+ )
codecov_cli/types.py ADDED
@@ -0,0 +1,88 @@
1
+ import pathlib
2
+ import typing as t
3
+ from dataclasses import dataclass
4
+
5
+ import click
6
+
7
+ from codecov_cli.helpers.ci_adapters.base import CIAdapterBase
8
+ from codecov_cli.helpers.versioning_systems import VersioningSystemInterface
9
+
10
+
11
+ class ContextObject(t.TypedDict):
12
+ ci_adapter: t.Optional[CIAdapterBase]
13
+ versioning_system: t.Optional[VersioningSystemInterface]
14
+ codecov_yaml: t.Optional[dict]
15
+ enterprise_url: t.Optional[str]
16
+
17
+
18
+ class CommandContext(click.Context):
19
+ obj: ContextObject
20
+
21
+
22
+ class UploadCollectionResultFile(object):
23
+ def __init__(self, path: pathlib.Path):
24
+ self.path = path
25
+
26
+ def get_filename(self) -> str:
27
+ return self.path.as_posix()
28
+
29
+ def get_content(self) -> bytes:
30
+ with open(self.path, "rb") as f:
31
+ return f.read()
32
+
33
+ def __repr__(self) -> str:
34
+ return str(self.path)
35
+
36
+ def __eq__(self, other):
37
+ if not isinstance(other, UploadCollectionResultFile):
38
+ return False
39
+
40
+ return self.path == other.path
41
+
42
+ def __hash__(self) -> int:
43
+ return hash(str(self.path))
44
+
45
+
46
+ @dataclass
47
+ class UploadCollectionResultFileFixer(object):
48
+ __slots__ = ["path", "fixed_lines_without_reason", "fixed_lines_with_reason", "eof"]
49
+ path: pathlib.Path
50
+ fixed_lines_without_reason: t.Set[int]
51
+ fixed_lines_with_reason: t.Optional[t.Set[t.Tuple[int, str]]]
52
+ eof: t.Optional[int]
53
+
54
+
55
+ @dataclass
56
+ class UploadCollectionResult(object):
57
+ __slots__ = ["network", "files", "file_fixes"]
58
+ network: t.List[str]
59
+ files: t.List[UploadCollectionResultFile]
60
+ file_fixes: t.List[UploadCollectionResultFileFixer]
61
+
62
+
63
+ class PreparationPluginInterface(object):
64
+ def run_preparation(self) -> None:
65
+ pass
66
+
67
+
68
+ @dataclass
69
+ class RequestResultWarning(object):
70
+ __slots__ = ("message",)
71
+ message: str
72
+
73
+
74
+ @dataclass
75
+ class RequestError(object):
76
+ __slots__ = ("code", "params", "description")
77
+ code: str
78
+ params: t.Dict
79
+ description: str
80
+
81
+
82
+ @dataclass
83
+ class RequestResult(object):
84
+ __slots__ = ("error", "warnings", "status_code", "text")
85
+ error: t.Optional[RequestError]
86
+ warnings: t.List[RequestResultWarning]
87
+ status_code: int
88
+ text: str