codecov-cli 0.5.2__tar.gz → 0.7.0__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 (100) hide show
  1. {codecov-cli-0.5.2/codecov_cli.egg-info → codecov-cli-0.7.0}/PKG-INFO +1 -1
  2. codecov-cli-0.7.0/codecov_cli/commands/process_test_results.py +175 -0
  3. {codecov-cli-0.5.2 → codecov-cli-0.7.0}/codecov_cli/helpers/ci_adapters/__init__.py +2 -0
  4. codecov-cli-0.7.0/codecov_cli/helpers/ci_adapters/cloudbuild.py +70 -0
  5. {codecov-cli-0.5.2 → codecov-cli-0.7.0}/codecov_cli/helpers/ci_adapters/codebuild.py +6 -6
  6. {codecov-cli-0.5.2 → codecov-cli-0.7.0}/codecov_cli/helpers/folder_searcher.py +1 -1
  7. {codecov-cli-0.5.2 → codecov-cli-0.7.0}/codecov_cli/helpers/git.py +4 -20
  8. {codecov-cli-0.5.2 → codecov-cli-0.7.0}/codecov_cli/helpers/git_services/github.py +5 -3
  9. {codecov-cli-0.5.2 → codecov-cli-0.7.0}/codecov_cli/helpers/request.py +18 -5
  10. {codecov-cli-0.5.2 → codecov-cli-0.7.0}/codecov_cli/helpers/versioning_systems.py +5 -3
  11. {codecov-cli-0.5.2 → codecov-cli-0.7.0}/codecov_cli/main.py +2 -0
  12. {codecov-cli-0.5.2 → codecov-cli-0.7.0}/codecov_cli/services/commit/__init__.py +7 -6
  13. {codecov-cli-0.5.2 → codecov-cli-0.7.0}/codecov_cli/services/report/__init__.py +1 -12
  14. {codecov-cli-0.5.2 → codecov-cli-0.7.0}/codecov_cli/services/staticanalysis/analyzers/general.py +2 -2
  15. {codecov-cli-0.5.2 → codecov-cli-0.7.0}/codecov_cli/services/upload/file_finder.py +5 -1
  16. {codecov-cli-0.5.2 → codecov-cli-0.7.0}/codecov_cli/services/upload/upload_collector.py +4 -2
  17. {codecov-cli-0.5.2 → codecov-cli-0.7.0}/codecov_cli/services/upload/upload_sender.py +2 -15
  18. {codecov-cli-0.5.2 → codecov-cli-0.7.0}/codecov_cli/services/upload_completion/__init__.py +2 -2
  19. {codecov-cli-0.5.2 → codecov-cli-0.7.0/codecov_cli.egg-info}/PKG-INFO +1 -1
  20. {codecov-cli-0.5.2 → codecov-cli-0.7.0}/codecov_cli.egg-info/SOURCES.txt +2 -0
  21. {codecov-cli-0.5.2 → codecov-cli-0.7.0}/codecov_cli.egg-info/requires.txt +2 -0
  22. {codecov-cli-0.5.2 → codecov-cli-0.7.0}/setup.py +3 -1
  23. {codecov-cli-0.5.2 → codecov-cli-0.7.0}/LICENSE +0 -0
  24. {codecov-cli-0.5.2 → codecov-cli-0.7.0}/MANIFEST.in +0 -0
  25. {codecov-cli-0.5.2 → codecov-cli-0.7.0}/README.md +0 -0
  26. {codecov-cli-0.5.2 → codecov-cli-0.7.0}/codecov_cli/__init__.py +0 -0
  27. {codecov-cli-0.5.2 → codecov-cli-0.7.0}/codecov_cli/commands/__init__.py +0 -0
  28. {codecov-cli-0.5.2 → codecov-cli-0.7.0}/codecov_cli/commands/base_picking.py +0 -0
  29. {codecov-cli-0.5.2 → codecov-cli-0.7.0}/codecov_cli/commands/commit.py +0 -0
  30. {codecov-cli-0.5.2 → codecov-cli-0.7.0}/codecov_cli/commands/create_report_result.py +0 -0
  31. {codecov-cli-0.5.2 → codecov-cli-0.7.0}/codecov_cli/commands/empty_upload.py +0 -0
  32. {codecov-cli-0.5.2 → codecov-cli-0.7.0}/codecov_cli/commands/get_report_results.py +0 -0
  33. {codecov-cli-0.5.2 → codecov-cli-0.7.0}/codecov_cli/commands/labelanalysis.py +0 -0
  34. {codecov-cli-0.5.2 → codecov-cli-0.7.0}/codecov_cli/commands/report.py +0 -0
  35. {codecov-cli-0.5.2 → codecov-cli-0.7.0}/codecov_cli/commands/send_notifications.py +0 -0
  36. {codecov-cli-0.5.2 → codecov-cli-0.7.0}/codecov_cli/commands/staticanalysis.py +0 -0
  37. {codecov-cli-0.5.2 → codecov-cli-0.7.0}/codecov_cli/commands/upload.py +0 -0
  38. {codecov-cli-0.5.2 → codecov-cli-0.7.0}/codecov_cli/commands/upload_process.py +0 -0
  39. {codecov-cli-0.5.2 → codecov-cli-0.7.0}/codecov_cli/fallbacks.py +0 -0
  40. {codecov-cli-0.5.2 → codecov-cli-0.7.0}/codecov_cli/helpers/__init__.py +0 -0
  41. {codecov-cli-0.5.2 → codecov-cli-0.7.0}/codecov_cli/helpers/ci_adapters/appveyor_ci.py +0 -0
  42. {codecov-cli-0.5.2 → codecov-cli-0.7.0}/codecov_cli/helpers/ci_adapters/azure_pipelines.py +0 -0
  43. {codecov-cli-0.5.2 → codecov-cli-0.7.0}/codecov_cli/helpers/ci_adapters/base.py +0 -0
  44. {codecov-cli-0.5.2 → codecov-cli-0.7.0}/codecov_cli/helpers/ci_adapters/bitbucket_ci.py +0 -0
  45. {codecov-cli-0.5.2 → codecov-cli-0.7.0}/codecov_cli/helpers/ci_adapters/bitrise_ci.py +0 -0
  46. {codecov-cli-0.5.2 → codecov-cli-0.7.0}/codecov_cli/helpers/ci_adapters/buildkite.py +0 -0
  47. {codecov-cli-0.5.2 → codecov-cli-0.7.0}/codecov_cli/helpers/ci_adapters/circleci.py +0 -0
  48. {codecov-cli-0.5.2 → codecov-cli-0.7.0}/codecov_cli/helpers/ci_adapters/cirrus_ci.py +0 -0
  49. {codecov-cli-0.5.2 → codecov-cli-0.7.0}/codecov_cli/helpers/ci_adapters/droneci.py +0 -0
  50. {codecov-cli-0.5.2 → codecov-cli-0.7.0}/codecov_cli/helpers/ci_adapters/github_actions.py +0 -0
  51. {codecov-cli-0.5.2 → codecov-cli-0.7.0}/codecov_cli/helpers/ci_adapters/gitlab_ci.py +0 -0
  52. {codecov-cli-0.5.2 → codecov-cli-0.7.0}/codecov_cli/helpers/ci_adapters/heroku.py +0 -0
  53. {codecov-cli-0.5.2 → codecov-cli-0.7.0}/codecov_cli/helpers/ci_adapters/jenkins.py +0 -0
  54. {codecov-cli-0.5.2 → codecov-cli-0.7.0}/codecov_cli/helpers/ci_adapters/local.py +0 -0
  55. {codecov-cli-0.5.2 → codecov-cli-0.7.0}/codecov_cli/helpers/ci_adapters/teamcity.py +0 -0
  56. {codecov-cli-0.5.2 → codecov-cli-0.7.0}/codecov_cli/helpers/ci_adapters/travis_ci.py +0 -0
  57. {codecov-cli-0.5.2 → codecov-cli-0.7.0}/codecov_cli/helpers/ci_adapters/woodpeckerci.py +0 -0
  58. {codecov-cli-0.5.2 → codecov-cli-0.7.0}/codecov_cli/helpers/config.py +0 -0
  59. {codecov-cli-0.5.2 → codecov-cli-0.7.0}/codecov_cli/helpers/encoder.py +0 -0
  60. {codecov-cli-0.5.2 → codecov-cli-0.7.0}/codecov_cli/helpers/git_services/__init__.py +0 -0
  61. {codecov-cli-0.5.2 → codecov-cli-0.7.0}/codecov_cli/helpers/logging_utils.py +0 -0
  62. {codecov-cli-0.5.2 → codecov-cli-0.7.0}/codecov_cli/helpers/options.py +0 -0
  63. {codecov-cli-0.5.2 → codecov-cli-0.7.0}/codecov_cli/helpers/validators.py +0 -0
  64. {codecov-cli-0.5.2 → codecov-cli-0.7.0}/codecov_cli/plugins/__init__.py +0 -0
  65. {codecov-cli-0.5.2 → codecov-cli-0.7.0}/codecov_cli/plugins/compress_pycoverage_contexts.py +0 -0
  66. {codecov-cli-0.5.2 → codecov-cli-0.7.0}/codecov_cli/plugins/gcov.py +0 -0
  67. {codecov-cli-0.5.2 → codecov-cli-0.7.0}/codecov_cli/plugins/pycoverage.py +0 -0
  68. {codecov-cli-0.5.2 → codecov-cli-0.7.0}/codecov_cli/plugins/types.py +0 -0
  69. {codecov-cli-0.5.2 → codecov-cli-0.7.0}/codecov_cli/plugins/xcode.py +0 -0
  70. {codecov-cli-0.5.2 → codecov-cli-0.7.0}/codecov_cli/runners/__init__.py +0 -0
  71. {codecov-cli-0.5.2 → codecov-cli-0.7.0}/codecov_cli/runners/dan_runner.py +0 -0
  72. {codecov-cli-0.5.2 → codecov-cli-0.7.0}/codecov_cli/runners/pytest_standard_runner.py +0 -0
  73. {codecov-cli-0.5.2 → codecov-cli-0.7.0}/codecov_cli/runners/types.py +0 -0
  74. {codecov-cli-0.5.2 → codecov-cli-0.7.0}/codecov_cli/services/__init__.py +0 -0
  75. {codecov-cli-0.5.2 → codecov-cli-0.7.0}/codecov_cli/services/commit/base_picking.py +0 -0
  76. {codecov-cli-0.5.2 → codecov-cli-0.7.0}/codecov_cli/services/empty_upload/__init__.py +0 -0
  77. {codecov-cli-0.5.2 → codecov-cli-0.7.0}/codecov_cli/services/staticanalysis/__init__.py +0 -0
  78. {codecov-cli-0.5.2 → codecov-cli-0.7.0}/codecov_cli/services/staticanalysis/analyzers/__init__.py +0 -0
  79. {codecov-cli-0.5.2 → codecov-cli-0.7.0}/codecov_cli/services/staticanalysis/analyzers/javascript_es6/__init__.py +0 -0
  80. {codecov-cli-0.5.2 → codecov-cli-0.7.0}/codecov_cli/services/staticanalysis/analyzers/javascript_es6/node_wrappers.py +0 -0
  81. {codecov-cli-0.5.2 → codecov-cli-0.7.0}/codecov_cli/services/staticanalysis/analyzers/python/__init__.py +0 -0
  82. {codecov-cli-0.5.2 → codecov-cli-0.7.0}/codecov_cli/services/staticanalysis/analyzers/python/node_wrappers.py +0 -0
  83. {codecov-cli-0.5.2 → codecov-cli-0.7.0}/codecov_cli/services/staticanalysis/exceptions.py +0 -0
  84. {codecov-cli-0.5.2 → codecov-cli-0.7.0}/codecov_cli/services/staticanalysis/finders.py +0 -0
  85. {codecov-cli-0.5.2 → codecov-cli-0.7.0}/codecov_cli/services/staticanalysis/types.py +0 -0
  86. {codecov-cli-0.5.2 → codecov-cli-0.7.0}/codecov_cli/services/upload/__init__.py +0 -0
  87. {codecov-cli-0.5.2 → codecov-cli-0.7.0}/codecov_cli/services/upload/legacy_upload_sender.py +0 -0
  88. {codecov-cli-0.5.2 → codecov-cli-0.7.0}/codecov_cli/services/upload/network_finder.py +0 -0
  89. {codecov-cli-0.5.2 → codecov-cli-0.7.0}/codecov_cli/types.py +0 -0
  90. {codecov-cli-0.5.2 → codecov-cli-0.7.0}/codecov_cli.egg-info/dependency_links.txt +0 -0
  91. {codecov-cli-0.5.2 → codecov-cli-0.7.0}/codecov_cli.egg-info/entry_points.txt +0 -0
  92. {codecov-cli-0.5.2 → codecov-cli-0.7.0}/codecov_cli.egg-info/top_level.txt +0 -0
  93. {codecov-cli-0.5.2 → codecov-cli-0.7.0}/languages/languages.c +0 -0
  94. {codecov-cli-0.5.2 → codecov-cli-0.7.0}/languages/treesitterjavascript/src/parser.c +0 -0
  95. {codecov-cli-0.5.2 → codecov-cli-0.7.0}/languages/treesitterjavascript/src/scanner.c +0 -0
  96. {codecov-cli-0.5.2 → codecov-cli-0.7.0}/languages/treesitterjavascript/src/tree_sitter/parser.h +0 -0
  97. {codecov-cli-0.5.2 → codecov-cli-0.7.0}/languages/treesitterpython/src/parser.c +0 -0
  98. {codecov-cli-0.5.2 → codecov-cli-0.7.0}/languages/treesitterpython/src/scanner.cc +0 -0
  99. {codecov-cli-0.5.2 → codecov-cli-0.7.0}/languages/treesitterpython/src/tree_sitter/parser.h +0 -0
  100. {codecov-cli-0.5.2 → codecov-cli-0.7.0}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: codecov-cli
3
- Version: 0.5.2
3
+ Version: 0.7.0
4
4
  Summary: Codecov Command Line Interface
5
5
  Author: Codecov
6
6
  Author-email: support@codecov.io
@@ -0,0 +1,175 @@
1
+ import logging
2
+ import os
3
+ import pathlib
4
+ from dataclasses import dataclass
5
+ from typing import List
6
+
7
+ import click
8
+ from test_results_parser import (
9
+ Outcome,
10
+ ParserError,
11
+ Testrun,
12
+ build_message,
13
+ parse_junit_xml,
14
+ )
15
+
16
+ from codecov_cli.helpers.request import (
17
+ log_warnings_and_errors_if_any,
18
+ send_post_request,
19
+ )
20
+ from codecov_cli.services.upload.file_finder import select_file_finder
21
+
22
+ logger = logging.getLogger("codecovcli")
23
+
24
+
25
+ _process_test_results_options = [
26
+ click.option(
27
+ "-s",
28
+ "--dir",
29
+ "--files-search-root-folder",
30
+ "dir",
31
+ help="Folder where to search for test results files",
32
+ type=click.Path(path_type=pathlib.Path),
33
+ default=pathlib.Path.cwd,
34
+ show_default="Current Working Directory",
35
+ ),
36
+ click.option(
37
+ "-f",
38
+ "--file",
39
+ "--files-search-direct-file",
40
+ "files",
41
+ help="Explicit files to upload. These will be added to the test results files to be processed. If you wish to only process the specified files, please consider using --disable-search to disable processing other files.",
42
+ type=click.Path(path_type=pathlib.Path),
43
+ multiple=True,
44
+ default=[],
45
+ ),
46
+ click.option(
47
+ "--exclude",
48
+ "--files-search-exclude-folder",
49
+ "exclude_folders",
50
+ help="Folders to exclude from search",
51
+ type=click.Path(path_type=pathlib.Path),
52
+ multiple=True,
53
+ default=[],
54
+ ),
55
+ click.option(
56
+ "--disable-search",
57
+ help="Disable search for coverage files. This is helpful when specifying what files you want to upload with the --file option.",
58
+ is_flag=True,
59
+ default=False,
60
+ ),
61
+ click.option(
62
+ "--provider-token",
63
+ help="Token used to make calls to Repo provider API",
64
+ type=str,
65
+ default=None,
66
+ ),
67
+ ]
68
+
69
+
70
+ def process_test_results_options(func):
71
+ for option in reversed(_process_test_results_options):
72
+ func = option(func)
73
+ return func
74
+
75
+
76
+ @dataclass
77
+ class TestResultsNotificationPayload:
78
+ failures: List[Testrun]
79
+ failed: int = 0
80
+ passed: int = 0
81
+ skipped: int = 0
82
+
83
+
84
+ @click.command()
85
+ @process_test_results_options
86
+ def process_test_results(
87
+ dir=None, files=None, exclude_folders=None, disable_search=None, provider_token=None
88
+ ):
89
+ if provider_token is None:
90
+ raise click.ClickException(
91
+ "Provider token was not provided. Make sure to pass --provider-token option with the contents of the GITHUB_TOKEN secret, so we can make a comment."
92
+ )
93
+
94
+ summary_file_path = os.getenv("GITHUB_STEP_SUMMARY")
95
+ if summary_file_path is None:
96
+ raise click.ClickException(
97
+ "Error getting step summary file path from environment. Can't find GITHUB_STEP_SUMMARY environment variable."
98
+ )
99
+
100
+ slug = os.getenv("GITHUB_REPOSITORY")
101
+ if slug is None:
102
+ raise click.ClickException(
103
+ "Error getting repo slug from environment. Can't find GITHUB_REPOSITORY environment variable."
104
+ )
105
+
106
+ ref = os.getenv("GITHUB_REF")
107
+ if ref is None or "pull" not in ref:
108
+ raise click.ClickException(
109
+ "Error getting PR number from environment. Can't find GITHUB_REF environment variable."
110
+ )
111
+
112
+ file_finder = select_file_finder(
113
+ dir, exclude_folders, files, disable_search, report_type="test_results"
114
+ )
115
+
116
+ upload_collection_results = file_finder.find_files()
117
+ if len(upload_collection_results) == 0:
118
+ raise click.ClickException(
119
+ "No JUnit XML files were found. Make sure to specify them using the --file option."
120
+ )
121
+
122
+ payload = generate_message_payload(upload_collection_results)
123
+
124
+ message = build_message(payload)
125
+
126
+ # write to step summary file
127
+ with open(summary_file_path, "w") as f:
128
+ f.write(message)
129
+
130
+ # GITHUB_REF is documented here: https://docs.github.com/en/actions/learn-github-actions/variables#default-environment-variables
131
+ pr_number = ref.split("/")[2]
132
+
133
+ create_github_comment(provider_token, slug, pr_number, message)
134
+
135
+
136
+ def create_github_comment(token, repo_slug, pr_number, message):
137
+ url = f"https://api.github.com/repos/{repo_slug}/issues/{pr_number}/comments"
138
+
139
+ headers = {
140
+ "Accept": "application/vnd.github+json",
141
+ "Authorization": f"Bearer {token}",
142
+ "X-GitHub-Api-Version": "2022-11-28",
143
+ }
144
+ logger.info("Posting github comment")
145
+
146
+ log_warnings_and_errors_if_any(
147
+ send_post_request(url=url, data={"body": message}, headers=headers),
148
+ "Posting test results comment",
149
+ )
150
+
151
+
152
+ def generate_message_payload(upload_collection_results):
153
+ payload = TestResultsNotificationPayload(failures=[])
154
+
155
+ for result in upload_collection_results:
156
+ testruns = []
157
+ try:
158
+ logger.info(f"Parsing {result.get_filename()}")
159
+ testruns = parse_junit_xml(result.get_content())
160
+ for testrun in testruns:
161
+ if (
162
+ testrun.outcome == Outcome.Failure
163
+ or testrun.outcome == Outcome.Error
164
+ ):
165
+ payload.failed += 1
166
+ payload.failures.append(testrun)
167
+ elif testrun.outcome == Outcome.Skip:
168
+ payload.skipped += 1
169
+ else:
170
+ payload.passed += 1
171
+ except ParserError as err:
172
+ raise click.ClickException(
173
+ f"Error parsing {str(result.get_filename(), 'utf8')} with error: {err}"
174
+ )
175
+ return payload
@@ -7,6 +7,7 @@ from codecov_cli.helpers.ci_adapters.bitrise_ci import BitriseCIAdapter
7
7
  from codecov_cli.helpers.ci_adapters.buildkite import BuildkiteAdapter
8
8
  from codecov_cli.helpers.ci_adapters.circleci import CircleCICIAdapter
9
9
  from codecov_cli.helpers.ci_adapters.cirrus_ci import CirrusCIAdapter
10
+ from codecov_cli.helpers.ci_adapters.cloudbuild import GoogleCloudBuildAdapter
10
11
  from codecov_cli.helpers.ci_adapters.codebuild import AWSCodeBuildCIAdapter
11
12
  from codecov_cli.helpers.ci_adapters.droneci import DroneCIAdapter
12
13
  from codecov_cli.helpers.ci_adapters.github_actions import GithubActionsCIAdapter
@@ -54,6 +55,7 @@ def get_ci_providers_list():
54
55
  TeamcityAdapter(),
55
56
  TravisCIAdapter(),
56
57
  AWSCodeBuildCIAdapter(),
58
+ GoogleCloudBuildAdapter(),
57
59
  # local adapter should always be the last one
58
60
  LocalAdapter(),
59
61
  ]
@@ -0,0 +1,70 @@
1
+ import os
2
+
3
+ from codecov_cli.helpers.ci_adapters.base import CIAdapterBase
4
+
5
+
6
+ class GoogleCloudBuildAdapter(CIAdapterBase):
7
+ """
8
+ Google Cloud Build uses variable substitutions in the builds
9
+ https://cloud.google.com/build/docs/configuring-builds/substitute-variable-values
10
+ For these to be available as environment variables, so this adapter
11
+ can read the values, you have to manually map the substitution variables to
12
+ environment variables on the build step, like this
13
+ env:
14
+ - '_PR_NUMBER=$_PR_NUMBER'
15
+ - 'BRANCH_NAME=$BRANCH_NAME'
16
+ - 'BUILD_ID=$BUILD_ID'
17
+ - 'COMMIT_SHA=$COMMIT_SHA'
18
+ - 'LOCATION=$LOCATION'
19
+ - 'PROJECT_ID=$PROJECT_ID'
20
+ - 'PROJECT_NUMBER=$PROJECT_NUMBER'
21
+ - 'REF_NAME=$REF_NAME'
22
+ - 'REPO_FULL_NAME=$REPO_FULL_NAME'
23
+ - 'TRIGGER_NAME=$TRIGGER_NAME'
24
+ Read more about manual substitution mapping here:
25
+ https://cloud.google.com/build/docs/configuring-builds/substitute-variable-values#map_substitutions_manually
26
+ """
27
+
28
+ def detect(self) -> bool:
29
+ return all(
30
+ list(
31
+ map(os.getenv, ["LOCATION", "PROJECT_NUMBER", "PROJECT_ID", "BUILD_ID"])
32
+ )
33
+ )
34
+
35
+ def _get_branch(self):
36
+ return os.getenv("BRANCH_NAME")
37
+
38
+ def _get_build_code(self):
39
+ return os.getenv("BUILD_ID")
40
+
41
+ def _get_commit_sha(self):
42
+ return os.getenv("COMMIT_SHA")
43
+
44
+ def _get_slug(self):
45
+ return os.getenv("REPO_FULL_NAME")
46
+
47
+ def _get_build_url(self):
48
+ # to build the url, the environment variables LOCATION, PROJECT_ID and BUILD_ID are needed
49
+ if not all(list(map(os.getenv, ["LOCATION", "PROJECT_ID", "BUILD_ID"]))):
50
+ return None
51
+
52
+ location = os.getenv("LOCATION")
53
+ project_id = os.getenv("PROJECT_ID")
54
+ build_id = os.getenv("BUILD_ID")
55
+
56
+ return f"https://console.cloud.google.com/cloud-build/builds;region={location}/{build_id}?project={project_id}"
57
+
58
+ def _get_pull_request_number(self):
59
+ pr_num = os.getenv("_PR_NUMBER")
60
+ return pr_num if pr_num != "" else None
61
+
62
+ def _get_job_code(self):
63
+ job_code = os.getenv("TRIGGER_NAME")
64
+ return job_code if job_code != "" else None
65
+
66
+ def _get_service(self):
67
+ return "google_cloud_build"
68
+
69
+ def get_service_name(self):
70
+ return "GoogleCloudBuild"
@@ -12,7 +12,7 @@ class AWSCodeBuildCIAdapter(CIAdapterBase):
12
12
  def _get_branch(self):
13
13
  branch = os.getenv("CODEBUILD_WEBHOOK_HEAD_REF")
14
14
  if branch:
15
- return re.sub("^refs\/heads\/", "", branch)
15
+ return re.sub(r"^refs\/heads\/", "", branch)
16
16
  return None
17
17
 
18
18
  def _get_build_code(self):
@@ -27,10 +27,10 @@ class AWSCodeBuildCIAdapter(CIAdapterBase):
27
27
  def _get_slug(self):
28
28
  slug = os.getenv("CODEBUILD_SOURCE_REPO_URL")
29
29
  if slug:
30
- slug = re.sub("^.*github.com\/", "", slug)
31
- slug = re.sub("^.*gitlab.com\/", "", slug)
32
- slug = re.sub("^.*bitbucket.com\/", "", slug)
33
- return re.sub("\.git$", "", slug)
30
+ slug = re.sub(r"^.*github.com\/", "", slug)
31
+ slug = re.sub(r"^.*gitlab.com\/", "", slug)
32
+ slug = re.sub(r"^.*bitbucket.com\/", "", slug)
33
+ return re.sub(r"\.git$", "", slug)
34
34
  return None
35
35
 
36
36
  def _get_service(self):
@@ -39,7 +39,7 @@ class AWSCodeBuildCIAdapter(CIAdapterBase):
39
39
  def _get_pull_request_number(self):
40
40
  pr = os.getenv("CODEBUILD_SOURCE_VERSION")
41
41
  if pr and pr.startswith("pr/"):
42
- return re.sub("^pr\/", "", pr)
42
+ return re.sub(r"^pr\/", "", pr)
43
43
  return None
44
44
 
45
45
  def _get_job_code(self):
@@ -58,7 +58,7 @@ def search_files(
58
58
  this_is_excluded = functools.partial(
59
59
  _is_excluded, filename_exclude_regex, multipart_exclude_regex
60
60
  )
61
- for (dirpath, dirnames, filenames) in os.walk(folder_to_search):
61
+ for dirpath, dirnames, filenames in os.walk(folder_to_search):
62
62
  dirs_to_remove = set(d for d in dirnames if d in folders_to_ignore)
63
63
 
64
64
  if multipart_exclude_regex is not None:
@@ -61,13 +61,16 @@ def parse_git_service(remote_repo_url: str):
61
61
  Possible cases we're considering:
62
62
  - https://github.com/codecov/codecov-cli.git returns github
63
63
  - git@github.com:codecov/codecov-cli.git returns github
64
+ - ssh://git@github.com/gitcodecov/codecov-cli returns github
65
+ - ssh://git@github.com:gitcodecov/codecov-cli returns github
64
66
  - https://user-name@bitbucket.org/namespace-codecov/first_repo.git returns bitbucket
65
67
  """
66
68
  services = [service.value for service in GitService]
67
69
  parsed_url = urlparse(remote_repo_url)
68
70
  service = None
69
71
 
70
- if remote_repo_url.startswith("https://"):
72
+ scheme = parsed_url.scheme
73
+ if scheme in ("https", "ssh"):
71
74
  netloc = parsed_url.netloc
72
75
  if "@" in netloc:
73
76
  netloc = netloc.split("@", 1)[1]
@@ -92,22 +95,3 @@ def parse_git_service(remote_repo_url: str):
92
95
  extra=dict(remote_repo_url=remote_repo_url),
93
96
  )
94
97
  return None
95
-
96
-
97
- def is_fork_pr(pull_dict: PullDict) -> bool:
98
- """
99
- takes in dict: pull_dict
100
- returns true if PR is made in a fork context, false if not.
101
- """
102
- return pull_dict and pull_dict["head"]["slug"] != pull_dict["base"]["slug"]
103
-
104
-
105
- def get_pull(service, slug, pr_num) -> Optional[PullDict]:
106
- """
107
- takes in str git service e.g. github, gitlab etc., slug in the owner/repo format, and the pull request number
108
- returns the pull request info gotten from the git service provider if successful, None if not
109
- """
110
- git_service = get_git_service(service)
111
- if git_service:
112
- pull_dict = git_service.get_pull_request(slug, pr_num)
113
- return pull_dict
@@ -24,9 +24,11 @@ class Github:
24
24
  "ref": res["head"]["ref"],
25
25
  # Through empiric test data it seems that the "repo" key in "head" is set to None
26
26
  # If the PR is from the same repo (e.g. not from a fork)
27
- "slug": res["head"]["repo"]["full_name"]
28
- if res["head"]["repo"]
29
- else res["base"]["repo"]["full_name"],
27
+ "slug": (
28
+ res["head"]["repo"]["full_name"]
29
+ if res["head"]["repo"]
30
+ else res["base"]["repo"]["full_name"]
31
+ ),
30
32
  },
31
33
  "base": {
32
34
  "sha": res["base"]["sha"],
@@ -1,6 +1,7 @@
1
1
  import logging
2
2
  from sys import exit
3
3
  from time import sleep
4
+ from typing import Optional
4
5
 
5
6
  import click
6
7
  import requests
@@ -15,7 +16,7 @@ MAX_RETRIES = 3
15
16
  USER_AGENT = f"codecov-cli/{__version__}"
16
17
 
17
18
 
18
- def _set_user_agent(headers: dict = None) -> dict:
19
+ def _set_user_agent(headers: Optional[dict] = None) -> dict:
19
20
  headers = headers or {}
20
21
  headers.setdefault("User-Agent", USER_AGENT)
21
22
  return headers
@@ -37,7 +38,10 @@ def put(url: str, data: dict = None, headers: dict = None) -> requests.Response:
37
38
 
38
39
 
39
40
  def post(
40
- url: str, data: dict = None, headers: dict = None, params: dict = None
41
+ url: str,
42
+ data: Optional[dict] = None,
43
+ headers: Optional[dict] = None,
44
+ params: Optional[dict] = None,
41
45
  ) -> requests.Response:
42
46
  headers = _set_user_agent(headers)
43
47
  return requests.post(url, json=data, headers=headers, params=params)
@@ -57,9 +61,9 @@ def retry_request(func):
57
61
  while retry < MAX_RETRIES:
58
62
  try:
59
63
  response = func(*args, **kwargs)
60
- if response.status_code == 502:
64
+ if response.status_code >= 500:
61
65
  logger.warning(
62
- "Response status code was 502.",
66
+ f"Response status code was {response.status_code}.",
63
67
  extra=dict(extra_log_attributes=dict(retry=retry)),
64
68
  )
65
69
  raise RetryException
@@ -82,7 +86,10 @@ def retry_request(func):
82
86
 
83
87
  @retry_request
84
88
  def send_post_request(
85
- url: str, data: dict = None, headers: dict = None, params: dict = None
89
+ url: str,
90
+ data: Optional[dict] = None,
91
+ headers: Optional[dict] = None,
92
+ params: Optional[dict] = None,
86
93
  ):
87
94
  return request_result(post(url=url, data=data, headers=headers, params=params))
88
95
 
@@ -95,6 +102,12 @@ def get_token_header_or_fail(token: str) -> dict:
95
102
  return {"Authorization": f"token {token}"}
96
103
 
97
104
 
105
+ def get_token_header(token: str) -> Optional[dict]:
106
+ if token is None:
107
+ return None
108
+ return {"Authorization": f"token {token}"}
109
+
110
+
98
111
  @retry_request
99
112
  def send_put_request(
100
113
  url: str,
@@ -135,9 +135,11 @@ class GitVersioningSystem(VersioningSystemInterface):
135
135
  )
136
136
 
137
137
  return [
138
- filename[1:-1]
139
- if filename.startswith('"') and filename.endswith('"')
140
- else filename
138
+ (
139
+ filename[1:-1]
140
+ if filename.startswith('"') and filename.endswith('"')
141
+ else filename
142
+ )
141
143
  for filename in res.stdout.decode("unicode_escape").strip().split("\n")
142
144
  ]
143
145
 
@@ -11,6 +11,7 @@ from codecov_cli.commands.create_report_result import create_report_results
11
11
  from codecov_cli.commands.empty_upload import empty_upload
12
12
  from codecov_cli.commands.get_report_results import get_report_results
13
13
  from codecov_cli.commands.labelanalysis import label_analysis
14
+ from codecov_cli.commands.process_test_results import process_test_results
14
15
  from codecov_cli.commands.report import create_report
15
16
  from codecov_cli.commands.send_notifications import send_notifications
16
17
  from codecov_cli.commands.staticanalysis import static_analysis
@@ -71,6 +72,7 @@ cli.add_command(static_analysis)
71
72
  cli.add_command(empty_upload)
72
73
  cli.add_command(upload_process)
73
74
  cli.add_command(send_notifications)
75
+ cli.add_command(process_test_results)
74
76
 
75
77
 
76
78
  def run():
@@ -1,9 +1,9 @@
1
1
  import logging
2
+ import os
2
3
  import typing
3
4
 
4
5
  from codecov_cli.helpers.config import CODECOV_API_URL
5
6
  from codecov_cli.helpers.encoder import decode_slug, encode_slug
6
- from codecov_cli.helpers.git import get_pull, is_fork_pr
7
7
  from codecov_cli.helpers.request import (
8
8
  get_token_header_or_fail,
9
9
  log_warnings_and_errors_if_any,
@@ -43,11 +43,12 @@ def create_commit_logic(
43
43
  def send_commit_data(
44
44
  commit_sha, parent_sha, pr, branch, slug, token, service, enterprise_url
45
45
  ):
46
- decoded_slug = decode_slug(slug)
47
- pull_dict = get_pull(service, decoded_slug, pr) if not token else None
48
- if is_fork_pr(pull_dict):
49
- headers = {"X-Tokenless": pull_dict["head"]["slug"], "X-Tokenless-PR": pr}
50
- branch = pull_dict["head"]["slug"] + ":" + branch
46
+ # this is how the CLI receives the username of the user to whom the fork belongs
47
+ # to and the branch name from the action
48
+ tokenless = os.environ.get("TOKENLESS")
49
+ if tokenless:
50
+ headers = None # type: ignore
51
+ branch = tokenless # type: ignore
51
52
  logger.info("The PR is happening in a forked repo. Using tokenless upload.")
52
53
  else:
53
54
  headers = get_token_header_or_fail(token)
@@ -7,7 +7,6 @@ import requests
7
7
  from codecov_cli.helpers import request
8
8
  from codecov_cli.helpers.config import CODECOV_API_URL
9
9
  from codecov_cli.helpers.encoder import decode_slug, encode_slug
10
- from codecov_cli.helpers.git import get_pull, is_fork_pr
11
10
  from codecov_cli.helpers.request import (
12
11
  get_token_header_or_fail,
13
12
  log_warnings_and_errors_if_any,
@@ -47,17 +46,7 @@ def send_create_report_request(
47
46
  commit_sha, code, service, token, encoded_slug, enterprise_url, pull_request_number
48
47
  ):
49
48
  data = {"code": code}
50
- decoded_slug = decode_slug(encoded_slug)
51
- pull_dict = (
52
- get_pull(service, decoded_slug, pull_request_number) if not token else None
53
- )
54
- if is_fork_pr(pull_dict):
55
- headers = {
56
- "X-Tokenless": pull_dict["head"]["slug"],
57
- "X-Tokenless-PR": pull_request_number,
58
- }
59
- else:
60
- headers = get_token_header_or_fail(token)
49
+ headers = get_token_header_or_fail(token)
61
50
  upload_url = enterprise_url or CODECOV_API_URL
62
51
  url = f"{upload_url}/upload/{service}/{encoded_slug}/commits/{commit_sha}/reports"
63
52
  return send_post_request(url=url, headers=headers, data=data)
@@ -85,13 +85,13 @@ class BaseAnalyzer(object):
85
85
 
86
86
  def get_import_lines(self, root_node, imports_query):
87
87
  import_lines = set()
88
- for (a, _) in imports_query.captures(root_node):
88
+ for a, _ in imports_query.captures(root_node):
89
89
  import_lines.add((a.start_point[0] + 1, a.end_point[0] - a.start_point[0]))
90
90
  return import_lines
91
91
 
92
92
  def get_definition_lines(self, root_node, definitions_query):
93
93
  definition_lines = set()
94
- for (a, _) in definitions_query.captures(root_node):
94
+ for a, _ in definitions_query.captures(root_node):
95
95
  definition_lines.add(
96
96
  (a.start_point[0] + 1, a.end_point[0] - a.start_point[0])
97
97
  )
@@ -253,7 +253,11 @@ class FileFinder(object):
253
253
  user_files_paths_resolved = [path.resolve() for path in user_files_paths]
254
254
  for filepath in self.explicitly_listed_files:
255
255
  if filepath.resolve() not in user_files_paths_resolved:
256
- not_found_files.append(filepath)
256
+ ## The file given might be linked or in a parent dir, check to see if it exists
257
+ if filepath.exists():
258
+ user_files_paths.append(filepath)
259
+ else:
260
+ not_found_files.append(filepath)
257
261
 
258
262
  if not_found_files:
259
263
  logger.warning(
@@ -46,6 +46,7 @@ class UploadCollector(object):
46
46
  comment_regex = re.compile(r"^\s*\/\/.*$")
47
47
  bracket_regex = re.compile(r"^\s*[\{\}]\s*(\/\/.*)?$")
48
48
  list_regex = re.compile(r"^\s*[\]\[]\s*(\/\/.*)?$")
49
+ parenthesis_regex = re.compile(r"^\s*[\(\)]\s*(\/\/.*)?$")
49
50
  go_function_regex = re.compile(r"^\s*func\s*[\{]\s*(\/\/.*)?$")
50
51
  php_end_bracket_regex = re.compile(r"^\s*\);\s*(\/\/.*)?$")
51
52
 
@@ -54,7 +55,7 @@ class UploadCollector(object):
54
55
  lcov_excel_regex = re.compile(r"\/\/ LCOV_EXCL")
55
56
 
56
57
  kt_patterns_to_apply = fix_patterns_to_apply(
57
- [bracket_regex], [comment_block_regex], True
58
+ [bracket_regex, parenthesis_regex], [comment_block_regex], True
58
59
  )
59
60
  go_patterns_to_apply = fix_patterns_to_apply(
60
61
  [empty_line_regex, comment_regex, bracket_regex, go_function_regex],
@@ -71,7 +72,6 @@ class UploadCollector(object):
71
72
  [],
72
73
  False,
73
74
  )
74
-
75
75
  cpp_swift_vala_patterns_to_apply = fix_patterns_to_apply(
76
76
  [empty_line_regex, bracket_regex],
77
77
  [lcov_excel_regex],
@@ -139,6 +139,8 @@ class UploadCollector(object):
139
139
  reason=err.reason,
140
140
  ),
141
141
  )
142
+ except IsADirectoryError as err:
143
+ logger.info(f"Skipping {filename}, found a directory not a file")
142
144
 
143
145
  return UploadCollectionResultFileFixer(
144
146
  path, fixed_lines_without_reason, fixed_lines_with_reason, eof
@@ -8,9 +8,8 @@ from typing import Any, Dict
8
8
  from codecov_cli import __version__ as codecov_cli_version
9
9
  from codecov_cli.helpers.config import CODECOV_API_URL
10
10
  from codecov_cli.helpers.encoder import encode_slug
11
- from codecov_cli.helpers.git import get_pull, is_fork_pr
12
11
  from codecov_cli.helpers.request import (
13
- get_token_header_or_fail,
12
+ get_token_header,
14
13
  send_post_request,
15
14
  send_put_request,
16
15
  )
@@ -53,19 +52,7 @@ class UploadSender(object):
53
52
  "version": codecov_cli_version,
54
53
  "ci_service": ci_service,
55
54
  }
56
-
57
- # Data to upload to Codecov
58
- pull_dict = (
59
- get_pull(git_service, slug, pull_request_number) if not token else None
60
- )
61
-
62
- if is_fork_pr(pull_dict):
63
- headers = {
64
- "X-Tokenless": pull_dict["head"]["slug"],
65
- "X-Tokenless-PR": pull_request_number,
66
- }
67
- else:
68
- headers = get_token_header_or_fail(token)
55
+ headers = get_token_header(token)
69
56
  encoded_slug = encode_slug(slug)
70
57
  upload_url = enterprise_url or CODECOV_API_URL
71
58
  url, data = self.get_url_and_possibly_update_data(
@@ -4,7 +4,7 @@ import logging
4
4
  from codecov_cli.helpers.config import CODECOV_API_URL
5
5
  from codecov_cli.helpers.encoder import encode_slug
6
6
  from codecov_cli.helpers.request import (
7
- get_token_header_or_fail,
7
+ get_token_header,
8
8
  log_warnings_and_errors_if_any,
9
9
  send_post_request,
10
10
  )
@@ -16,7 +16,7 @@ def upload_completion_logic(
16
16
  commit_sha, slug, token, git_service, enterprise_url, fail_on_error=False
17
17
  ):
18
18
  encoded_slug = encode_slug(slug)
19
- headers = get_token_header_or_fail(token)
19
+ headers = get_token_header(token)
20
20
  upload_url = enterprise_url or CODECOV_API_URL
21
21
  url = f"{upload_url}/upload/{git_service}/{encoded_slug}/commits/{commit_sha}/upload-complete"
22
22
  sending_result = send_post_request(url=url, headers=headers)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: codecov-cli
3
- Version: 0.5.2
3
+ Version: 0.7.0
4
4
  Summary: Codecov Command Line Interface
5
5
  Author: Codecov
6
6
  Author-email: support@codecov.io
@@ -19,6 +19,7 @@ codecov_cli/commands/create_report_result.py
19
19
  codecov_cli/commands/empty_upload.py
20
20
  codecov_cli/commands/get_report_results.py
21
21
  codecov_cli/commands/labelanalysis.py
22
+ codecov_cli/commands/process_test_results.py
22
23
  codecov_cli/commands/report.py
23
24
  codecov_cli/commands/send_notifications.py
24
25
  codecov_cli/commands/staticanalysis.py
@@ -43,6 +44,7 @@ codecov_cli/helpers/ci_adapters/bitrise_ci.py
43
44
  codecov_cli/helpers/ci_adapters/buildkite.py
44
45
  codecov_cli/helpers/ci_adapters/circleci.py
45
46
  codecov_cli/helpers/ci_adapters/cirrus_ci.py
47
+ codecov_cli/helpers/ci_adapters/cloudbuild.py
46
48
  codecov_cli/helpers/ci_adapters/codebuild.py
47
49
  codecov_cli/helpers/ci_adapters/droneci.py
48
50
  codecov_cli/helpers/ci_adapters/github_actions.py
@@ -4,3 +4,5 @@ ijson==3.*
4
4
  pyyaml==6.*
5
5
  responses==0.21.*
6
6
  tree-sitter==0.20.*
7
+ test-results-parser==0.1.*
8
+ regex
@@ -10,7 +10,7 @@ with open(path.join(here, "README.md"), encoding="utf-8") as f:
10
10
 
11
11
  setup(
12
12
  name="codecov-cli",
13
- version="0.5.2",
13
+ version="0.7.0",
14
14
  packages=find_packages(exclude=["contrib", "docs", "tests*"]),
15
15
  description="Codecov Command Line Interface",
16
16
  long_description=long_description,
@@ -24,6 +24,8 @@ setup(
24
24
  "pyyaml==6.*",
25
25
  "responses==0.21.*",
26
26
  "tree-sitter==0.20.*",
27
+ "test-results-parser==0.1.*",
28
+ "regex",
27
29
  ],
28
30
  entry_points={
29
31
  "console_scripts": [
File without changes
File without changes
File without changes
File without changes