codecov-cli 0.2.2__tar.gz → 0.3.1__tar.gz

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 (97) hide show
  1. {codecov-cli-0.2.2/codecov_cli.egg-info → codecov-cli-0.3.1}/PKG-INFO +1 -1
  2. codecov-cli-0.3.1/codecov_cli/__init__.py +1 -0
  3. {codecov-cli-0.2.2 → codecov-cli-0.3.1}/codecov_cli/commands/labelanalysis.py +59 -30
  4. {codecov-cli-0.2.2 → codecov-cli-0.3.1}/codecov_cli/helpers/config.py +1 -1
  5. {codecov-cli-0.2.2 → codecov-cli-0.3.1}/codecov_cli/main.py +5 -4
  6. {codecov-cli-0.2.2 → codecov-cli-0.3.1}/codecov_cli/runners/python_standard_runner.py +37 -24
  7. {codecov-cli-0.2.2 → codecov-cli-0.3.1}/codecov_cli/runners/types.py +3 -2
  8. {codecov-cli-0.2.2 → codecov-cli-0.3.1}/codecov_cli/services/staticanalysis/analyzers/general.py +21 -4
  9. {codecov-cli-0.2.2 → codecov-cli-0.3.1/codecov_cli.egg-info}/PKG-INFO +1 -1
  10. {codecov-cli-0.2.2 → codecov-cli-0.3.1}/codecov_cli.egg-info/requires.txt +1 -1
  11. {codecov-cli-0.2.2 → codecov-cli-0.3.1}/setup.py +1 -1
  12. codecov-cli-0.2.2/codecov_cli/__init__.py +0 -1
  13. {codecov-cli-0.2.2 → codecov-cli-0.3.1}/LICENSE +0 -0
  14. {codecov-cli-0.2.2 → codecov-cli-0.3.1}/MANIFEST.in +0 -0
  15. {codecov-cli-0.2.2 → codecov-cli-0.3.1}/README.md +0 -0
  16. {codecov-cli-0.2.2 → codecov-cli-0.3.1}/codecov_cli/commands/__init__.py +0 -0
  17. {codecov-cli-0.2.2 → codecov-cli-0.3.1}/codecov_cli/commands/base_picking.py +0 -0
  18. {codecov-cli-0.2.2 → codecov-cli-0.3.1}/codecov_cli/commands/commit.py +0 -0
  19. {codecov-cli-0.2.2 → codecov-cli-0.3.1}/codecov_cli/commands/create_report_result.py +0 -0
  20. {codecov-cli-0.2.2 → codecov-cli-0.3.1}/codecov_cli/commands/empty_upload.py +0 -0
  21. {codecov-cli-0.2.2 → codecov-cli-0.3.1}/codecov_cli/commands/get_report_results.py +0 -0
  22. {codecov-cli-0.2.2 → codecov-cli-0.3.1}/codecov_cli/commands/report.py +0 -0
  23. {codecov-cli-0.2.2 → codecov-cli-0.3.1}/codecov_cli/commands/send_notifications.py +0 -0
  24. {codecov-cli-0.2.2 → codecov-cli-0.3.1}/codecov_cli/commands/staticanalysis.py +0 -0
  25. {codecov-cli-0.2.2 → codecov-cli-0.3.1}/codecov_cli/commands/upload.py +0 -0
  26. {codecov-cli-0.2.2 → codecov-cli-0.3.1}/codecov_cli/commands/upload_process.py +0 -0
  27. {codecov-cli-0.2.2 → codecov-cli-0.3.1}/codecov_cli/fallbacks.py +0 -0
  28. {codecov-cli-0.2.2 → codecov-cli-0.3.1}/codecov_cli/helpers/__init__.py +0 -0
  29. {codecov-cli-0.2.2 → codecov-cli-0.3.1}/codecov_cli/helpers/ci_adapters/__init__.py +0 -0
  30. {codecov-cli-0.2.2 → codecov-cli-0.3.1}/codecov_cli/helpers/ci_adapters/appveyor_ci.py +0 -0
  31. {codecov-cli-0.2.2 → codecov-cli-0.3.1}/codecov_cli/helpers/ci_adapters/azure_pipelines.py +0 -0
  32. {codecov-cli-0.2.2 → codecov-cli-0.3.1}/codecov_cli/helpers/ci_adapters/base.py +0 -0
  33. {codecov-cli-0.2.2 → codecov-cli-0.3.1}/codecov_cli/helpers/ci_adapters/bitbucket_ci.py +0 -0
  34. {codecov-cli-0.2.2 → codecov-cli-0.3.1}/codecov_cli/helpers/ci_adapters/bitrise_ci.py +0 -0
  35. {codecov-cli-0.2.2 → codecov-cli-0.3.1}/codecov_cli/helpers/ci_adapters/buildkite.py +0 -0
  36. {codecov-cli-0.2.2 → codecov-cli-0.3.1}/codecov_cli/helpers/ci_adapters/circleci.py +0 -0
  37. {codecov-cli-0.2.2 → codecov-cli-0.3.1}/codecov_cli/helpers/ci_adapters/cirrus_ci.py +0 -0
  38. {codecov-cli-0.2.2 → codecov-cli-0.3.1}/codecov_cli/helpers/ci_adapters/codebuild.py +0 -0
  39. {codecov-cli-0.2.2 → codecov-cli-0.3.1}/codecov_cli/helpers/ci_adapters/droneci.py +0 -0
  40. {codecov-cli-0.2.2 → codecov-cli-0.3.1}/codecov_cli/helpers/ci_adapters/github_actions.py +0 -0
  41. {codecov-cli-0.2.2 → codecov-cli-0.3.1}/codecov_cli/helpers/ci_adapters/gitlab_ci.py +0 -0
  42. {codecov-cli-0.2.2 → codecov-cli-0.3.1}/codecov_cli/helpers/ci_adapters/heroku.py +0 -0
  43. {codecov-cli-0.2.2 → codecov-cli-0.3.1}/codecov_cli/helpers/ci_adapters/jenkins.py +0 -0
  44. {codecov-cli-0.2.2 → codecov-cli-0.3.1}/codecov_cli/helpers/ci_adapters/local.py +0 -0
  45. {codecov-cli-0.2.2 → codecov-cli-0.3.1}/codecov_cli/helpers/ci_adapters/teamcity.py +0 -0
  46. {codecov-cli-0.2.2 → codecov-cli-0.3.1}/codecov_cli/helpers/ci_adapters/travis_ci.py +0 -0
  47. {codecov-cli-0.2.2 → codecov-cli-0.3.1}/codecov_cli/helpers/ci_adapters/woodpeckerci.py +0 -0
  48. {codecov-cli-0.2.2 → codecov-cli-0.3.1}/codecov_cli/helpers/encoder.py +0 -0
  49. {codecov-cli-0.2.2 → codecov-cli-0.3.1}/codecov_cli/helpers/folder_searcher.py +0 -0
  50. {codecov-cli-0.2.2 → codecov-cli-0.3.1}/codecov_cli/helpers/git.py +0 -0
  51. {codecov-cli-0.2.2 → codecov-cli-0.3.1}/codecov_cli/helpers/logging_utils.py +0 -0
  52. {codecov-cli-0.2.2 → codecov-cli-0.3.1}/codecov_cli/helpers/options.py +0 -0
  53. {codecov-cli-0.2.2 → codecov-cli-0.3.1}/codecov_cli/helpers/request.py +0 -0
  54. {codecov-cli-0.2.2 → codecov-cli-0.3.1}/codecov_cli/helpers/validators.py +0 -0
  55. {codecov-cli-0.2.2 → codecov-cli-0.3.1}/codecov_cli/helpers/versioning_systems.py +0 -0
  56. {codecov-cli-0.2.2 → codecov-cli-0.3.1}/codecov_cli/plugins/__init__.py +0 -0
  57. {codecov-cli-0.2.2 → codecov-cli-0.3.1}/codecov_cli/plugins/compress_pycoverage_contexts.py +0 -0
  58. {codecov-cli-0.2.2 → codecov-cli-0.3.1}/codecov_cli/plugins/gcov.py +0 -0
  59. {codecov-cli-0.2.2 → codecov-cli-0.3.1}/codecov_cli/plugins/pycoverage.py +0 -0
  60. {codecov-cli-0.2.2 → codecov-cli-0.3.1}/codecov_cli/plugins/types.py +0 -0
  61. {codecov-cli-0.2.2 → codecov-cli-0.3.1}/codecov_cli/plugins/xcode.py +0 -0
  62. {codecov-cli-0.2.2 → codecov-cli-0.3.1}/codecov_cli/runners/__init__.py +0 -0
  63. {codecov-cli-0.2.2 → codecov-cli-0.3.1}/codecov_cli/runners/dan_runner.py +0 -0
  64. {codecov-cli-0.2.2 → codecov-cli-0.3.1}/codecov_cli/services/__init__.py +0 -0
  65. {codecov-cli-0.2.2 → codecov-cli-0.3.1}/codecov_cli/services/commit/__init__.py +0 -0
  66. {codecov-cli-0.2.2 → codecov-cli-0.3.1}/codecov_cli/services/commit/base_picking.py +0 -0
  67. {codecov-cli-0.2.2 → codecov-cli-0.3.1}/codecov_cli/services/empty_upload/__init__.py +0 -0
  68. {codecov-cli-0.2.2 → codecov-cli-0.3.1}/codecov_cli/services/report/__init__.py +0 -0
  69. {codecov-cli-0.2.2 → codecov-cli-0.3.1}/codecov_cli/services/staticanalysis/__init__.py +0 -0
  70. {codecov-cli-0.2.2 → codecov-cli-0.3.1}/codecov_cli/services/staticanalysis/analyzers/__init__.py +0 -0
  71. {codecov-cli-0.2.2 → codecov-cli-0.3.1}/codecov_cli/services/staticanalysis/analyzers/javascript_es6/__init__.py +0 -0
  72. {codecov-cli-0.2.2 → codecov-cli-0.3.1}/codecov_cli/services/staticanalysis/analyzers/javascript_es6/node_wrappers.py +0 -0
  73. {codecov-cli-0.2.2 → codecov-cli-0.3.1}/codecov_cli/services/staticanalysis/analyzers/python/__init__.py +0 -0
  74. {codecov-cli-0.2.2 → codecov-cli-0.3.1}/codecov_cli/services/staticanalysis/analyzers/python/node_wrappers.py +0 -0
  75. {codecov-cli-0.2.2 → codecov-cli-0.3.1}/codecov_cli/services/staticanalysis/exceptions.py +0 -0
  76. {codecov-cli-0.2.2 → codecov-cli-0.3.1}/codecov_cli/services/staticanalysis/finders.py +0 -0
  77. {codecov-cli-0.2.2 → codecov-cli-0.3.1}/codecov_cli/services/staticanalysis/types.py +0 -0
  78. {codecov-cli-0.2.2 → codecov-cli-0.3.1}/codecov_cli/services/upload/__init__.py +0 -0
  79. {codecov-cli-0.2.2 → codecov-cli-0.3.1}/codecov_cli/services/upload/coverage_file_finder.py +0 -0
  80. {codecov-cli-0.2.2 → codecov-cli-0.3.1}/codecov_cli/services/upload/legacy_upload_sender.py +0 -0
  81. {codecov-cli-0.2.2 → codecov-cli-0.3.1}/codecov_cli/services/upload/network_finder.py +0 -0
  82. {codecov-cli-0.2.2 → codecov-cli-0.3.1}/codecov_cli/services/upload/upload_collector.py +0 -0
  83. {codecov-cli-0.2.2 → codecov-cli-0.3.1}/codecov_cli/services/upload/upload_sender.py +0 -0
  84. {codecov-cli-0.2.2 → codecov-cli-0.3.1}/codecov_cli/services/upload_completion/__init__.py +0 -0
  85. {codecov-cli-0.2.2 → codecov-cli-0.3.1}/codecov_cli/types.py +0 -0
  86. {codecov-cli-0.2.2 → codecov-cli-0.3.1}/codecov_cli.egg-info/SOURCES.txt +0 -0
  87. {codecov-cli-0.2.2 → codecov-cli-0.3.1}/codecov_cli.egg-info/dependency_links.txt +0 -0
  88. {codecov-cli-0.2.2 → codecov-cli-0.3.1}/codecov_cli.egg-info/entry_points.txt +0 -0
  89. {codecov-cli-0.2.2 → codecov-cli-0.3.1}/codecov_cli.egg-info/top_level.txt +0 -0
  90. {codecov-cli-0.2.2 → codecov-cli-0.3.1}/languages/languages.c +0 -0
  91. {codecov-cli-0.2.2 → codecov-cli-0.3.1}/languages/treesitterjavascript/src/parser.c +0 -0
  92. {codecov-cli-0.2.2 → codecov-cli-0.3.1}/languages/treesitterjavascript/src/scanner.c +0 -0
  93. {codecov-cli-0.2.2 → codecov-cli-0.3.1}/languages/treesitterjavascript/src/tree_sitter/parser.h +0 -0
  94. {codecov-cli-0.2.2 → codecov-cli-0.3.1}/languages/treesitterpython/src/parser.c +0 -0
  95. {codecov-cli-0.2.2 → codecov-cli-0.3.1}/languages/treesitterpython/src/scanner.cc +0 -0
  96. {codecov-cli-0.2.2 → codecov-cli-0.3.1}/languages/treesitterpython/src/tree_sitter/parser.h +0 -0
  97. {codecov-cli-0.2.2 → codecov-cli-0.3.1}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: codecov-cli
3
- Version: 0.2.2
3
+ Version: 0.3.1
4
4
  Summary: Codecov Command Line Interface
5
5
  Author: Codecov
6
6
  Author-email: support@codecov.io
@@ -0,0 +1 @@
1
+ __version__ = "0.3.1"
@@ -1,7 +1,7 @@
1
- import json
2
1
  import logging
2
+ import pathlib
3
3
  import time
4
- from typing import List
4
+ from typing import List, Optional
5
5
 
6
6
  import click
7
7
  import requests
@@ -55,9 +55,16 @@ logger = logging.getLogger("codecovcli")
55
55
  @click.option(
56
56
  "--dry-run",
57
57
  "dry_run",
58
- help="Userful during setup. This will run the label analysis, but will print the result to stdout and terminate instead of calling the runner.process_labelanalysis_result",
58
+ help='Print list of tests to run and options that need to be added to the test runner as a space-separated list to stdout. Format is ATS_TESTS_TO_RUN="<options> <test_1> <test_2> ... <test_n>"',
59
59
  is_flag=True,
60
60
  )
61
+ @click.option(
62
+ "--dry-run-output-path",
63
+ "dry_run_output_path",
64
+ help="Prints the dry-run list into dry_run_output_path (in addition to stdout)",
65
+ type=pathlib.Path,
66
+ default=None,
67
+ )
61
68
  @click.pass_context
62
69
  def label_analysis(
63
70
  ctx: click.Context,
@@ -67,6 +74,7 @@ def label_analysis(
67
74
  runner_name: str,
68
75
  max_wait_time: str,
69
76
  dry_run: bool,
77
+ dry_run_output_path: Optional[pathlib.Path],
70
78
  ):
71
79
  enterprise_url = ctx.obj.get("enterprise_url")
72
80
  logger.debug(
@@ -137,7 +145,12 @@ def label_analysis(
137
145
  # Retry it
138
146
  eid = _send_labelanalysis_request(payload, url, token_header)
139
147
  if eid is None:
140
- _fallback_to_collected_labels(requested_labels, runner, dry_run=dry_run)
148
+ _fallback_to_collected_labels(
149
+ requested_labels,
150
+ runner,
151
+ dry_run=dry_run,
152
+ dry_run_output_path=dry_run_output_path,
153
+ )
141
154
  return
142
155
 
143
156
  has_result = False
@@ -151,13 +164,25 @@ def label_analysis(
151
164
  )
152
165
  resp_json = resp_data.json()
153
166
  if resp_json["state"] == "finished":
167
+ logger.info(
168
+ "Received list of tests from Codecov",
169
+ extra=dict(
170
+ extra_log_attributes=dict(
171
+ processing_errors=resp_json.get("errors", [])
172
+ )
173
+ ),
174
+ )
154
175
  request_result = _potentially_calculate_absent_labels(
155
- resp_data.json()["result"], requested_labels
176
+ resp_json["result"], requested_labels
156
177
  )
157
178
  if not dry_run:
158
179
  runner.process_labelanalysis_result(request_result)
159
180
  else:
160
- _dry_run_output(LabelAnalysisRequestResult(request_result))
181
+ _dry_run_output(
182
+ LabelAnalysisRequestResult(request_result),
183
+ runner,
184
+ dry_run_output_path,
185
+ )
161
186
  return
162
187
  if resp_json["state"] == "error":
163
188
  logger.error(
@@ -165,7 +190,10 @@ def label_analysis(
165
190
  extra=dict(extra_log_attributes=dict(resp_json=resp_json)),
166
191
  )
167
192
  _fallback_to_collected_labels(
168
- collected_labels=requested_labels, runner=runner, dry_run=dry_run
193
+ collected_labels=requested_labels,
194
+ runner=runner,
195
+ dry_run=dry_run,
196
+ dry_run_output_path=dry_run_output_path,
169
197
  )
170
198
  return
171
199
  if max_wait_time and (time.monotonic() - start_wait) > max_wait_time:
@@ -173,7 +201,10 @@ def label_analysis(
173
201
  f"Exceeded max waiting time of {max_wait_time} seconds. Running all tests.",
174
202
  )
175
203
  _fallback_to_collected_labels(
176
- collected_labels=requested_labels, runner=runner, dry_run=dry_run
204
+ collected_labels=requested_labels,
205
+ runner=runner,
206
+ dry_run=dry_run,
207
+ dry_run_output_path=dry_run_output_path,
177
208
  )
178
209
  return
179
210
  logger.info("Waiting more time for result...")
@@ -183,14 +214,6 @@ def label_analysis(
183
214
  def _potentially_calculate_absent_labels(
184
215
  request_result, requested_labels
185
216
  ) -> LabelAnalysisRequestResult:
186
- logger.info(
187
- "Received list of tests from Codecov",
188
- extra=dict(
189
- extra_log_attributes=dict(
190
- processing_errors=request_result.get("errors", [])
191
- )
192
- ),
193
- )
194
217
  if request_result["absent_labels"]:
195
218
  # This means that Codecov already calculated everything for us
196
219
  final_result = LabelAnalysisRequestResult(request_result)
@@ -285,20 +308,23 @@ def _send_labelanalysis_request(payload, url, token_header):
285
308
  return eid
286
309
 
287
310
 
288
- def _dry_run_output(result: LabelAnalysisRequestResult):
289
- logger.info(
290
- "Not executing tests because '--dry-run' is on. List of labels selected for running below."
291
- )
292
- logger.info("")
293
- logger.info("Label groups:")
294
- logger.info(
295
- "- absent_labels: Set of new labels found in HEAD that are not present in BASE"
311
+ def _dry_run_output(
312
+ result: LabelAnalysisRequestResult,
313
+ runner: LabelAnalysisRunnerInterface,
314
+ dry_run_output_path: Optional[pathlib.Path],
315
+ ):
316
+ labels_to_run = list(
317
+ set(
318
+ result.absent_labels
319
+ + result.global_level_labels
320
+ + result.present_diff_labels
321
+ )
296
322
  )
297
- logger.info("- present_diff_labels: Set of labels affected by the git diff")
298
- logger.info("- global_level_labels: Set of labels that possibly touch global code")
299
- logger.info("- present_report_labels: Set of labels previously uploaded")
300
- logger.info("")
301
- logger.info(json.dumps(result))
323
+ output = runner.dry_run_runner_options + sorted(labels_to_run)
324
+ if dry_run_output_path is not None:
325
+ with open(dry_run_output_path, "w") as fd:
326
+ fd.write(" ".join(output) + "\n")
327
+ click.echo(f"ATS_TESTS_TO_RUN=\"{' '.join(output)}\"")
302
328
 
303
329
 
304
330
  def _fallback_to_collected_labels(
@@ -306,6 +332,7 @@ def _fallback_to_collected_labels(
306
332
  runner: LabelAnalysisRunnerInterface,
307
333
  *,
308
334
  dry_run: bool = False,
335
+ dry_run_output_path: Optional[pathlib.Path] = None,
309
336
  ) -> dict:
310
337
  logger.info("Trying to fallback on collected labels")
311
338
  if collected_labels:
@@ -321,6 +348,8 @@ def _fallback_to_collected_labels(
321
348
  if not dry_run:
322
349
  return runner.process_labelanalysis_result(fake_response)
323
350
  else:
324
- return _dry_run_output(LabelAnalysisRequestResult(fake_response))
351
+ return _dry_run_output(
352
+ LabelAnalysisRequestResult(fake_response), runner, dry_run_output_path
353
+ )
325
354
  logger.error("Cannot fallback to collected labels because no labels were collected")
326
355
  raise click.ClickException("Failed to get list of labels to run")
@@ -15,6 +15,6 @@ def load_cli_config(codecov_yml_path: pathlib.Path):
15
15
  with open(codecov_yml_path, "r") as file_stream:
16
16
  return yaml.safe_load(file_stream.read())
17
17
  logger.warning(
18
- f"File {codecov_yml_path} not found, or is not a file. Ignoring config."
18
+ f"Config file {codecov_yml_path} not found, or is not a file. Ignoring config."
19
19
  )
20
20
  return None
@@ -20,6 +20,8 @@ from codecov_cli.helpers.config import load_cli_config
20
20
  from codecov_cli.helpers.logging_utils import configure_logger
21
21
  from codecov_cli.helpers.versioning_systems import get_versioning_system
22
22
 
23
+ from . import __version__
24
+
23
25
  logger = logging.getLogger("codecovcli")
24
26
 
25
27
 
@@ -34,13 +36,14 @@ logger = logging.getLogger("codecovcli")
34
36
  @click.option(
35
37
  "--codecov-yml-path",
36
38
  type=click.Path(path_type=pathlib.Path),
39
+ default=pathlib.Path("codecov.yml"),
37
40
  )
38
41
  @click.option(
39
42
  "--enterprise-url", "--url", "-u", help="Change the upload host (Enterprise use)"
40
43
  )
41
44
  @click.option("-v", "--verbose", "verbose", help="Use verbose logging", is_flag=True)
42
45
  @click.pass_context
43
- @click.version_option()
46
+ @click.version_option(__version__, prog_name="codecovcli")
44
47
  def cli(
45
48
  ctx: click.Context,
46
49
  auto_load_params_from: typing.Optional[str],
@@ -52,9 +55,7 @@ def cli(
52
55
  ctx.help_option_names = ["-h", "--help"]
53
56
  ctx.obj["ci_adapter"] = get_ci_adapter(auto_load_params_from)
54
57
  ctx.obj["versioning_system"] = get_versioning_system()
55
- ctx.obj["codecov_yaml"] = (
56
- load_cli_config(codecov_yml_path) if codecov_yml_path else None
57
- )
58
+ ctx.obj["codecov_yaml"] = load_cli_config(codecov_yml_path)
58
59
  if ctx.obj["codecov_yaml"] is None:
59
60
  logger.debug("No codecov_yaml found")
60
61
  ctx.obj["enterprise_url"] = enterprise_url
@@ -53,30 +53,21 @@ class PythonStandardRunnerConfigParams(dict):
53
53
  """
54
54
  return self.get("strict_mode", False)
55
55
 
56
- @property
57
- def include_curr_dir(self) -> bool:
58
- """
59
- Only valid for 'strict mode'
60
- Account for the difference 'pytest' vs 'python -m pytest'
61
- https://docs.pytest.org/en/7.1.x/how-to/usage.html#calling-pytest-through-python-m-pytest
62
- """
63
- return self.get("include_curr_dir", True)
64
-
65
56
 
66
57
  def _include_curr_dir(method):
67
58
  """
68
59
  Account for the difference 'pytest' vs 'python -m pytest'
69
60
  https://docs.pytest.org/en/7.1.x/how-to/usage.html#calling-pytest-through-python-m-pytest
61
+ Used only in strict_mode
70
62
  """
71
63
 
72
64
  def call_method(self, *args, **kwargs):
73
- include_curr_dir = self.params.include_curr_dir
74
65
  curr_dir = getcwd()
75
- if include_curr_dir:
76
- path.append(curr_dir)
66
+ path.append(curr_dir)
67
+
77
68
  result = method(self, *args, **kwargs)
78
- if include_curr_dir:
79
- path.remove(curr_dir)
69
+
70
+ path.remove(curr_dir)
80
71
  return result
81
72
 
82
73
  return call_method
@@ -106,6 +97,9 @@ def _execute_pytest_subprocess(
106
97
 
107
98
 
108
99
  class PythonStandardRunner(LabelAnalysisRunnerInterface):
100
+
101
+ dry_run_runner_options = ["--cov-context=test"]
102
+
109
103
  def __init__(self, config_params: Optional[dict] = None) -> None:
110
104
  super().__init__()
111
105
  if config_params is None:
@@ -150,10 +144,25 @@ class PythonStandardRunner(LabelAnalysisRunnerInterface):
150
144
  if p.exitcode != 0 or (result != pytest.ExitCode.OK and result != 0):
151
145
  message = f"Pytest exited with non-zero code {result}."
152
146
  message += "\nThis is likely not a problem with label-analysis. Check pytest's output and options."
153
- message += "\n(you can check pytest options on the logs before the test session start)"
147
+ if capture_output:
148
+ # If pytest failed but we captured its output the user won't know what's wrong
149
+ # So we need to include that in the error message
150
+ message += "\nPYTEST OUTPUT:"
151
+ message += "\n" + output
152
+ else:
153
+ message += "\n(you can check pytest options on the logs before the test session start)"
154
154
  raise click.ClickException(message)
155
155
  return output
156
156
 
157
+ def parse_captured_output_error(self, exp: CalledProcessError) -> str:
158
+ result = ""
159
+ for out_stream in [exp.stdout, exp.stderr]:
160
+ if out_stream:
161
+ if type(out_stream) is bytes:
162
+ out_stream = out_stream.decode()
163
+ result += "\n" + out_stream
164
+ return result
165
+
157
166
  def _execute_pytest(self, pytest_args: List[str], capture_output: bool = True):
158
167
  """Handles calling pytest using subprocess.run.
159
168
  Raises Exception if pytest fails
@@ -170,7 +179,14 @@ class PythonStandardRunner(LabelAnalysisRunnerInterface):
170
179
  except CalledProcessError as exp:
171
180
  message = f"Pytest exited with non-zero code {exp.returncode}."
172
181
  message += "\nThis is likely not a problem with label-analysis. Check pytest's output and options."
173
- message += "\n(you can check pytest options on the logs before the test session start)"
182
+
183
+ if capture_output:
184
+ # If pytest failed but we captured its output the user won't know what's wrong
185
+ # So we need to include that in the error message
186
+ message += "\nPYTEST OUTPUT:"
187
+ message += self.parse_captured_output_error(exp)
188
+ else:
189
+ message += "\n(you can check pytest options on the logs before the test session start)"
174
190
  raise click.ClickException(message)
175
191
  if capture_output:
176
192
  return result.stdout.decode()
@@ -230,14 +246,10 @@ class PythonStandardRunner(LabelAnalysisRunnerInterface):
230
246
  ]
231
247
  command_array = default_options + tests_to_run
232
248
  logger.info(
233
- "Running tests. (run in verbose mode to get list of tests executed)",
234
- extra=dict(
235
- extra_log_attributes=dict(
236
- pytest_options=default_options,
237
- executed_tests_count=len(tests_to_run),
238
- )
239
- ),
249
+ "Running tests. (run in verbose mode to get list of tests executed)"
240
250
  )
251
+ logger.info(f" pytest options: \"{' '.join(default_options)}\"")
252
+ logger.info(f" executed tests: {len(tests_to_run)}")
241
253
  logger.debug(
242
254
  "List of tests executed",
243
255
  extra=dict(extra_log_attributes=dict(executed_tests=tests_to_run)),
@@ -246,5 +258,6 @@ class PythonStandardRunner(LabelAnalysisRunnerInterface):
246
258
  output = self._execute_pytest_strict(command_array, capture_output=False)
247
259
  else:
248
260
  output = self._execute_pytest(command_array, capture_output=False)
249
- logger.info("Finished running tests successfully")
261
+ logger.info(f"Finished running {len(tests_to_run)} tests successfully")
262
+ logger.info(f" pytest options: \"{' '.join(default_options)}\"")
250
263
  logger.debug(output)
@@ -1,4 +1,4 @@
1
- from typing import List
1
+ from typing import Dict, List
2
2
 
3
3
 
4
4
  # This is supposed to be a TypedDict,
@@ -23,7 +23,8 @@ class LabelAnalysisRequestResult(dict):
23
23
 
24
24
 
25
25
  class LabelAnalysisRunnerInterface(object):
26
- params = None
26
+ params: Dict = None
27
+ dry_run_runner_options: List[str] = []
27
28
 
28
29
  def collect_tests(self) -> List[str]:
29
30
  raise NotImplementedError()
@@ -1,4 +1,5 @@
1
1
  import hashlib
2
+ from collections import deque
2
3
 
3
4
 
4
5
  class BaseAnalyzer(object):
@@ -16,10 +17,26 @@ class BaseAnalyzer(object):
16
17
  count += 1
17
18
  return count
18
19
 
19
- def _get_max_nested_conditional(self, node):
20
- return (1 if node.type in self.condition_statements else 0) + max(
21
- (self._get_max_nested_conditional(x) for x in node.children), default=0
22
- )
20
+ def _get_max_nested_conditional(self, head):
21
+ """Iterates over all nodes in a function body and returns the max nested conditional depth.
22
+ Uses BFS to avoid recursion calls (so we don't throw RecursionError)
23
+ """
24
+ nodes_to_visit = deque()
25
+ nodes_to_visit.append([head, int(head.type in self.condition_statements)])
26
+ max_nested_depth = 0
27
+
28
+ while nodes_to_visit:
29
+ curr_node, curr_depth = nodes_to_visit.popleft()
30
+ max_nested_depth = max(max_nested_depth, curr_depth)
31
+ # Here is where the depth might change
32
+ # If the current node is a conditional
33
+ is_curr_conditional = curr_node.type in self.condition_statements
34
+
35
+ # Enqueue all child nodes of the curr_node
36
+ for child in curr_node.children:
37
+ nodes_to_visit.append([child, curr_depth + is_curr_conditional])
38
+
39
+ return max_nested_depth
23
40
 
24
41
  def _get_complexity_metrics(self, body_node):
25
42
  number_conditions = self._count_elements(
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: codecov-cli
3
- Version: 0.2.2
3
+ Version: 0.3.1
4
4
  Summary: Codecov Command Line Interface
5
5
  Author: Codecov
6
6
  Author-email: support@codecov.io
@@ -2,7 +2,7 @@ click==8.*
2
2
  httpx==0.23.*
3
3
  ijson==3.*
4
4
  pytest==7.*
5
- pytest-cov==3.*
5
+ pytest-cov>=3
6
6
  pyyaml==6.*
7
7
  responses==0.21.*
8
8
  smart-open==6.*
@@ -25,7 +25,7 @@ setup(
25
25
  "httpx==0.23.*",
26
26
  "ijson==3.*",
27
27
  "pytest==7.*",
28
- "pytest-cov==3.*",
28
+ "pytest-cov>=3",
29
29
  "pyyaml==6.*",
30
30
  "responses==0.21.*",
31
31
  "smart-open==6.*",
@@ -1 +0,0 @@
1
- __version__ = "0.2.2"
File without changes
File without changes
File without changes
File without changes