codecov-cli 0.3.4__cp311-cp311-win_amd64.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.
- codecov_cli/__init__.py +4 -0
- codecov_cli/commands/__init__.py +0 -0
- codecov_cli/commands/base_picking.py +77 -0
- codecov_cli/commands/commit.py +75 -0
- codecov_cli/commands/create_report_result.py +45 -0
- codecov_cli/commands/empty_upload.py +42 -0
- codecov_cli/commands/get_report_results.py +53 -0
- codecov_cli/commands/labelanalysis.py +398 -0
- codecov_cli/commands/report.py +50 -0
- codecov_cli/commands/send_notifications.py +46 -0
- codecov_cli/commands/staticanalysis.py +88 -0
- codecov_cli/commands/upload.py +266 -0
- codecov_cli/commands/upload_process.py +129 -0
- codecov_cli/fallbacks.py +41 -0
- codecov_cli/helpers/__init__.py +0 -0
- codecov_cli/helpers/ci_adapters/__init__.py +59 -0
- codecov_cli/helpers/ci_adapters/appveyor_ci.py +54 -0
- codecov_cli/helpers/ci_adapters/azure_pipelines.py +42 -0
- codecov_cli/helpers/ci_adapters/base.py +102 -0
- codecov_cli/helpers/ci_adapters/bitbucket_ci.py +42 -0
- codecov_cli/helpers/ci_adapters/bitrise_ci.py +37 -0
- codecov_cli/helpers/ci_adapters/buildkite.py +45 -0
- codecov_cli/helpers/ci_adapters/circleci.py +47 -0
- codecov_cli/helpers/ci_adapters/cirrus_ci.py +36 -0
- codecov_cli/helpers/ci_adapters/codebuild.py +49 -0
- codecov_cli/helpers/ci_adapters/droneci.py +36 -0
- codecov_cli/helpers/ci_adapters/github_actions.py +90 -0
- codecov_cli/helpers/ci_adapters/gitlab_ci.py +56 -0
- codecov_cli/helpers/ci_adapters/heroku.py +36 -0
- codecov_cli/helpers/ci_adapters/jenkins.py +38 -0
- codecov_cli/helpers/ci_adapters/local.py +39 -0
- codecov_cli/helpers/ci_adapters/teamcity.py +37 -0
- codecov_cli/helpers/ci_adapters/travis_ci.py +44 -0
- codecov_cli/helpers/ci_adapters/woodpeckerci.py +36 -0
- codecov_cli/helpers/config.py +20 -0
- codecov_cli/helpers/encoder.py +29 -0
- codecov_cli/helpers/folder_searcher.py +103 -0
- codecov_cli/helpers/git.py +84 -0
- codecov_cli/helpers/logging_utils.py +77 -0
- codecov_cli/helpers/options.py +52 -0
- codecov_cli/helpers/request.py +107 -0
- codecov_cli/helpers/validators.py +13 -0
- codecov_cli/helpers/versioning_systems.py +131 -0
- codecov_cli/main.py +81 -0
- codecov_cli/plugins/__init__.py +76 -0
- codecov_cli/plugins/compress_pycoverage_contexts.py +140 -0
- codecov_cli/plugins/gcov.py +64 -0
- codecov_cli/plugins/pycoverage.py +131 -0
- codecov_cli/plugins/types.py +8 -0
- codecov_cli/plugins/xcode.py +109 -0
- codecov_cli/runners/__init__.py +61 -0
- codecov_cli/runners/dan_runner.py +64 -0
- codecov_cli/runners/python_standard_runner.py +151 -0
- codecov_cli/runners/types.py +33 -0
- codecov_cli/services/__init__.py +0 -0
- codecov_cli/services/commit/__init__.py +55 -0
- codecov_cli/services/commit/base_picking.py +23 -0
- codecov_cli/services/empty_upload/__init__.py +28 -0
- codecov_cli/services/report/__init__.py +139 -0
- codecov_cli/services/staticanalysis/__init__.py +280 -0
- codecov_cli/services/staticanalysis/analyzers/__init__.py +14 -0
- codecov_cli/services/staticanalysis/analyzers/general.py +124 -0
- codecov_cli/services/staticanalysis/analyzers/javascript_es6/__init__.py +122 -0
- codecov_cli/services/staticanalysis/analyzers/javascript_es6/node_wrappers.py +71 -0
- codecov_cli/services/staticanalysis/analyzers/python/__init__.py +111 -0
- codecov_cli/services/staticanalysis/analyzers/python/node_wrappers.py +117 -0
- codecov_cli/services/staticanalysis/exceptions.py +2 -0
- codecov_cli/services/staticanalysis/finders.py +47 -0
- codecov_cli/services/staticanalysis/types.py +19 -0
- codecov_cli/services/upload/__init__.py +128 -0
- codecov_cli/services/upload/coverage_file_finder.py +264 -0
- codecov_cli/services/upload/legacy_upload_sender.py +131 -0
- codecov_cli/services/upload/network_finder.py +21 -0
- codecov_cli/services/upload/upload_collector.py +163 -0
- codecov_cli/services/upload/upload_sender.py +147 -0
- codecov_cli/services/upload_completion/__init__.py +29 -0
- codecov_cli/types.py +72 -0
- codecov_cli-0.3.4.dist-info/LICENSE +201 -0
- codecov_cli-0.3.4.dist-info/METADATA +321 -0
- codecov_cli-0.3.4.dist-info/RECORD +84 -0
- codecov_cli-0.3.4.dist-info/WHEEL +5 -0
- codecov_cli-0.3.4.dist-info/entry_points.txt +2 -0
- codecov_cli-0.3.4.dist-info/top_level.txt +2 -0
- staticcodecov_languages.cpython-311-x86_64-linux-gnu.so +0 -0
codecov_cli/__init__.py
ADDED
|
File without changes
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
import typing
|
|
3
|
+
import uuid
|
|
4
|
+
|
|
5
|
+
import click
|
|
6
|
+
|
|
7
|
+
from codecov_cli.fallbacks import CodecovOption, FallbackFieldEnum
|
|
8
|
+
from codecov_cli.helpers.encoder import slug_without_subgroups_is_invalid
|
|
9
|
+
from codecov_cli.services.commit.base_picking import base_picking_logic
|
|
10
|
+
|
|
11
|
+
logger = logging.getLogger("codecovcli")
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@click.command()
|
|
15
|
+
@click.option(
|
|
16
|
+
"--base-sha",
|
|
17
|
+
help="Base commit SHA (with 40 chars)",
|
|
18
|
+
cls=CodecovOption,
|
|
19
|
+
fallback_field=FallbackFieldEnum.commit_sha,
|
|
20
|
+
required=True,
|
|
21
|
+
)
|
|
22
|
+
@click.option(
|
|
23
|
+
"--pr",
|
|
24
|
+
help="Pull Request id to associate commit with",
|
|
25
|
+
cls=CodecovOption,
|
|
26
|
+
fallback_field=FallbackFieldEnum.pull_request_number,
|
|
27
|
+
)
|
|
28
|
+
@click.option(
|
|
29
|
+
"--slug",
|
|
30
|
+
cls=CodecovOption,
|
|
31
|
+
fallback_field=FallbackFieldEnum.slug,
|
|
32
|
+
help="owner/repo slug",
|
|
33
|
+
envvar="CODECOV_SLUG",
|
|
34
|
+
)
|
|
35
|
+
@click.option(
|
|
36
|
+
"-t",
|
|
37
|
+
"--token",
|
|
38
|
+
help="Codecov upload token",
|
|
39
|
+
type=click.UUID,
|
|
40
|
+
envvar="CODECOV_TOKEN",
|
|
41
|
+
)
|
|
42
|
+
@click.option(
|
|
43
|
+
"--service",
|
|
44
|
+
cls=CodecovOption,
|
|
45
|
+
fallback_field=FallbackFieldEnum.service,
|
|
46
|
+
help="Specify the service provider of the repo e.g. github",
|
|
47
|
+
)
|
|
48
|
+
@click.pass_context
|
|
49
|
+
def pr_base_picking(
|
|
50
|
+
ctx,
|
|
51
|
+
base_sha: str,
|
|
52
|
+
pr: typing.Optional[int],
|
|
53
|
+
slug: typing.Optional[str],
|
|
54
|
+
token: typing.Optional[uuid.UUID],
|
|
55
|
+
service: typing.Optional[str],
|
|
56
|
+
):
|
|
57
|
+
enterprise_url = ctx.obj.get("enterprise_url")
|
|
58
|
+
logger.debug(
|
|
59
|
+
"Starting base picking process",
|
|
60
|
+
extra=dict(
|
|
61
|
+
extra_log_attributes=dict(
|
|
62
|
+
pr=pr,
|
|
63
|
+
slug=slug,
|
|
64
|
+
token=token,
|
|
65
|
+
service=service,
|
|
66
|
+
enterprise_url=enterprise_url,
|
|
67
|
+
)
|
|
68
|
+
),
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
if slug_without_subgroups_is_invalid(slug):
|
|
72
|
+
logger.error(
|
|
73
|
+
"Slug is invalid. Slug should be in the form of owner_username/repo_name"
|
|
74
|
+
)
|
|
75
|
+
return
|
|
76
|
+
|
|
77
|
+
base_picking_logic(base_sha, pr, slug, token, service, enterprise_url)
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
import typing
|
|
3
|
+
import uuid
|
|
4
|
+
|
|
5
|
+
import click
|
|
6
|
+
|
|
7
|
+
from codecov_cli.fallbacks import CodecovOption, FallbackFieldEnum
|
|
8
|
+
from codecov_cli.helpers.git import GitService
|
|
9
|
+
from codecov_cli.helpers.options import global_options
|
|
10
|
+
from codecov_cli.services.commit import create_commit_logic
|
|
11
|
+
|
|
12
|
+
logger = logging.getLogger("codecovcli")
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
@click.command()
|
|
16
|
+
@click.option(
|
|
17
|
+
"--parent-sha",
|
|
18
|
+
help="SHA (with 40 chars) of what should be the parent of this commit",
|
|
19
|
+
)
|
|
20
|
+
@click.option(
|
|
21
|
+
"-P",
|
|
22
|
+
"--pr",
|
|
23
|
+
"--pull-request-number",
|
|
24
|
+
"pull_request_number",
|
|
25
|
+
help="Specify the pull request number mannually. Used to override pre-existing CI environment variables",
|
|
26
|
+
cls=CodecovOption,
|
|
27
|
+
fallback_field=FallbackFieldEnum.pull_request_number,
|
|
28
|
+
)
|
|
29
|
+
@click.option(
|
|
30
|
+
"-B",
|
|
31
|
+
"--branch",
|
|
32
|
+
help="Branch to which this commit belongs to",
|
|
33
|
+
cls=CodecovOption,
|
|
34
|
+
fallback_field=FallbackFieldEnum.branch,
|
|
35
|
+
)
|
|
36
|
+
@global_options
|
|
37
|
+
@click.pass_context
|
|
38
|
+
def create_commit(
|
|
39
|
+
ctx,
|
|
40
|
+
commit_sha: str,
|
|
41
|
+
parent_sha: typing.Optional[str],
|
|
42
|
+
pull_request_number: typing.Optional[int],
|
|
43
|
+
branch: typing.Optional[str],
|
|
44
|
+
slug: typing.Optional[str],
|
|
45
|
+
token: typing.Optional[uuid.UUID],
|
|
46
|
+
git_service: typing.Optional[str],
|
|
47
|
+
fail_on_error: bool,
|
|
48
|
+
):
|
|
49
|
+
enterprise_url = ctx.obj.get("enterprise_url")
|
|
50
|
+
logger.debug(
|
|
51
|
+
"Starting create commit process",
|
|
52
|
+
extra=dict(
|
|
53
|
+
extra_log_attributes=dict(
|
|
54
|
+
commit_sha=commit_sha,
|
|
55
|
+
parent_sha=parent_sha,
|
|
56
|
+
pr=pull_request_number,
|
|
57
|
+
branch=branch,
|
|
58
|
+
slug=slug,
|
|
59
|
+
token=token,
|
|
60
|
+
service=git_service,
|
|
61
|
+
enterprise_url=enterprise_url,
|
|
62
|
+
)
|
|
63
|
+
),
|
|
64
|
+
)
|
|
65
|
+
create_commit_logic(
|
|
66
|
+
commit_sha,
|
|
67
|
+
parent_sha,
|
|
68
|
+
pull_request_number,
|
|
69
|
+
branch,
|
|
70
|
+
slug,
|
|
71
|
+
token,
|
|
72
|
+
git_service,
|
|
73
|
+
enterprise_url,
|
|
74
|
+
fail_on_error,
|
|
75
|
+
)
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
import uuid
|
|
3
|
+
|
|
4
|
+
import click
|
|
5
|
+
|
|
6
|
+
from codecov_cli.fallbacks import CodecovOption, FallbackFieldEnum
|
|
7
|
+
from codecov_cli.helpers.git import GitService
|
|
8
|
+
from codecov_cli.helpers.options import global_options
|
|
9
|
+
from codecov_cli.services.report import create_report_results_logic
|
|
10
|
+
|
|
11
|
+
logger = logging.getLogger("codecovcli")
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@click.command()
|
|
15
|
+
@click.option(
|
|
16
|
+
"--code", help="The code of the report. If unsure, leave default", default="default"
|
|
17
|
+
)
|
|
18
|
+
@global_options
|
|
19
|
+
@click.pass_context
|
|
20
|
+
def create_report_results(
|
|
21
|
+
ctx,
|
|
22
|
+
commit_sha: str,
|
|
23
|
+
code: str,
|
|
24
|
+
slug: str,
|
|
25
|
+
git_service: str,
|
|
26
|
+
token: uuid.UUID,
|
|
27
|
+
fail_on_error: bool,
|
|
28
|
+
):
|
|
29
|
+
enterprise_url = ctx.obj.get("enterprise_url")
|
|
30
|
+
logger.debug(
|
|
31
|
+
"Creating report results",
|
|
32
|
+
extra=dict(
|
|
33
|
+
extra_log_attributes=dict(
|
|
34
|
+
commit_sha=commit_sha,
|
|
35
|
+
code=code,
|
|
36
|
+
slug=slug,
|
|
37
|
+
service=git_service,
|
|
38
|
+
enterprise_url=enterprise_url,
|
|
39
|
+
token=token,
|
|
40
|
+
)
|
|
41
|
+
),
|
|
42
|
+
)
|
|
43
|
+
create_report_results_logic(
|
|
44
|
+
commit_sha, code, slug, git_service, token, enterprise_url, fail_on_error
|
|
45
|
+
)
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
import typing
|
|
3
|
+
import uuid
|
|
4
|
+
|
|
5
|
+
import click
|
|
6
|
+
|
|
7
|
+
from codecov_cli.fallbacks import CodecovOption, FallbackFieldEnum
|
|
8
|
+
from codecov_cli.helpers.git import GitService
|
|
9
|
+
from codecov_cli.helpers.options import global_options
|
|
10
|
+
from codecov_cli.services.empty_upload import empty_upload_logic
|
|
11
|
+
|
|
12
|
+
logger = logging.getLogger("codecovcli")
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
@click.command()
|
|
16
|
+
@global_options
|
|
17
|
+
@click.pass_context
|
|
18
|
+
def empty_upload(
|
|
19
|
+
ctx,
|
|
20
|
+
commit_sha: str,
|
|
21
|
+
slug: typing.Optional[str],
|
|
22
|
+
token: typing.Optional[uuid.UUID],
|
|
23
|
+
git_service: typing.Optional[str],
|
|
24
|
+
fail_on_error: typing.Optional[bool],
|
|
25
|
+
):
|
|
26
|
+
enterprise_url = ctx.obj.get("enterprise_url")
|
|
27
|
+
logger.debug(
|
|
28
|
+
"Starting empty upload process",
|
|
29
|
+
extra=dict(
|
|
30
|
+
extra_log_attributes=dict(
|
|
31
|
+
commit_sha=commit_sha,
|
|
32
|
+
slug=slug,
|
|
33
|
+
token=token,
|
|
34
|
+
service=git_service,
|
|
35
|
+
enterprise_url=enterprise_url,
|
|
36
|
+
fail_on_error=fail_on_error,
|
|
37
|
+
)
|
|
38
|
+
),
|
|
39
|
+
)
|
|
40
|
+
return empty_upload_logic(
|
|
41
|
+
commit_sha, slug, token, git_service, enterprise_url, fail_on_error
|
|
42
|
+
)
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
import uuid
|
|
3
|
+
|
|
4
|
+
import click
|
|
5
|
+
|
|
6
|
+
from codecov_cli.fallbacks import CodecovOption, FallbackFieldEnum
|
|
7
|
+
from codecov_cli.helpers.encoder import encode_slug
|
|
8
|
+
from codecov_cli.helpers.git import GitService
|
|
9
|
+
from codecov_cli.helpers.options import global_options
|
|
10
|
+
from codecov_cli.services.report import send_reports_result_get_request
|
|
11
|
+
|
|
12
|
+
logger = logging.getLogger("codecovcli")
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
@click.command()
|
|
16
|
+
@click.option(
|
|
17
|
+
"--code", help="The code of the report. If unsure, leave default", default="default"
|
|
18
|
+
)
|
|
19
|
+
@global_options
|
|
20
|
+
@click.pass_context
|
|
21
|
+
def get_report_results(
|
|
22
|
+
ctx,
|
|
23
|
+
commit_sha: str,
|
|
24
|
+
code: str,
|
|
25
|
+
slug: str,
|
|
26
|
+
git_service: str,
|
|
27
|
+
token: uuid.UUID,
|
|
28
|
+
fail_on_error: bool,
|
|
29
|
+
):
|
|
30
|
+
enterprise_url = ctx.obj.get("enterprise_url")
|
|
31
|
+
logger.debug(
|
|
32
|
+
"Getting report results",
|
|
33
|
+
extra=dict(
|
|
34
|
+
extra_log_attributes=dict(
|
|
35
|
+
commit_sha=commit_sha,
|
|
36
|
+
code=code,
|
|
37
|
+
slug=slug,
|
|
38
|
+
service=git_service,
|
|
39
|
+
enterprise_url=enterprise_url,
|
|
40
|
+
token=token,
|
|
41
|
+
)
|
|
42
|
+
),
|
|
43
|
+
)
|
|
44
|
+
encoded_slug = encode_slug(slug)
|
|
45
|
+
send_reports_result_get_request(
|
|
46
|
+
commit_sha=commit_sha,
|
|
47
|
+
report_code=code,
|
|
48
|
+
encoded_slug=encoded_slug,
|
|
49
|
+
service=git_service,
|
|
50
|
+
token=token,
|
|
51
|
+
enterprise_url=enterprise_url,
|
|
52
|
+
fail_on_error=fail_on_error,
|
|
53
|
+
)
|
|
@@ -0,0 +1,398 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import logging
|
|
3
|
+
import pathlib
|
|
4
|
+
import time
|
|
5
|
+
from typing import List, Optional
|
|
6
|
+
|
|
7
|
+
import click
|
|
8
|
+
import requests
|
|
9
|
+
|
|
10
|
+
from codecov_cli.fallbacks import CodecovOption, FallbackFieldEnum
|
|
11
|
+
from codecov_cli.helpers.config import CODECOV_API_URL
|
|
12
|
+
from codecov_cli.helpers.validators import validate_commit_sha
|
|
13
|
+
from codecov_cli.runners import get_runner
|
|
14
|
+
from codecov_cli.runners.types import (
|
|
15
|
+
LabelAnalysisRequestResult,
|
|
16
|
+
LabelAnalysisRunnerInterface,
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
logger = logging.getLogger("codecovcli")
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
@click.command()
|
|
23
|
+
@click.option(
|
|
24
|
+
"--token",
|
|
25
|
+
required=True,
|
|
26
|
+
envvar="CODECOV_STATIC_TOKEN",
|
|
27
|
+
help="The static analysis token (NOT the same token as upload)",
|
|
28
|
+
)
|
|
29
|
+
@click.option(
|
|
30
|
+
"--head-sha",
|
|
31
|
+
"head_commit_sha",
|
|
32
|
+
help="Commit SHA (with 40 chars)",
|
|
33
|
+
cls=CodecovOption,
|
|
34
|
+
fallback_field=FallbackFieldEnum.commit_sha,
|
|
35
|
+
callback=validate_commit_sha,
|
|
36
|
+
required=True,
|
|
37
|
+
)
|
|
38
|
+
@click.option(
|
|
39
|
+
"--base-sha",
|
|
40
|
+
"base_commit_sha",
|
|
41
|
+
help="Commit SHA (with 40 chars)",
|
|
42
|
+
cls=CodecovOption,
|
|
43
|
+
callback=validate_commit_sha,
|
|
44
|
+
required=True,
|
|
45
|
+
)
|
|
46
|
+
@click.option(
|
|
47
|
+
"--runner-name", "--runner", "runner_name", help="Runner to use", default="python"
|
|
48
|
+
)
|
|
49
|
+
@click.option(
|
|
50
|
+
"--max-wait-time",
|
|
51
|
+
"max_wait_time",
|
|
52
|
+
help="Max time (in seconds) to wait for the label analysis result before falling back to running all tests. Default is to wait forever.",
|
|
53
|
+
default=None,
|
|
54
|
+
type=int,
|
|
55
|
+
)
|
|
56
|
+
@click.option(
|
|
57
|
+
"--dry-run",
|
|
58
|
+
"dry_run",
|
|
59
|
+
help=(
|
|
60
|
+
"Print list of tests to run AND tests skipped (and options that need to be added to the test runner) to stdout. "
|
|
61
|
+
+ "Also prints the same information in JSON format. "
|
|
62
|
+
+ "JSON will have keys 'ats_tests_to_run', 'ats_tests_to_skip' and 'runner_options'. "
|
|
63
|
+
+ "List of tests to run is prefixed with ATS_TESTS_TO_RUN= "
|
|
64
|
+
+ "List of tests to skip is prefixed with ATS_TESTS_TO_SKIP="
|
|
65
|
+
),
|
|
66
|
+
is_flag=True,
|
|
67
|
+
)
|
|
68
|
+
@click.option(
|
|
69
|
+
"--dry-run-output-path",
|
|
70
|
+
"dry_run_output_path",
|
|
71
|
+
help=(
|
|
72
|
+
"Prints the dry-run list (ATS_TESTS_TO_RUN) into dry_run_output_path (in addition to stdout)\n"
|
|
73
|
+
+ "AND prints ATS_TESTS_TO_SKIP into dry_run_output_path_skipped\n"
|
|
74
|
+
+ "AND prints dry-run JSON output into dry_run_output_path.json"
|
|
75
|
+
),
|
|
76
|
+
type=pathlib.Path,
|
|
77
|
+
default=None,
|
|
78
|
+
)
|
|
79
|
+
@click.pass_context
|
|
80
|
+
def label_analysis(
|
|
81
|
+
ctx: click.Context,
|
|
82
|
+
token: str,
|
|
83
|
+
head_commit_sha: str,
|
|
84
|
+
base_commit_sha: str,
|
|
85
|
+
runner_name: str,
|
|
86
|
+
max_wait_time: str,
|
|
87
|
+
dry_run: bool,
|
|
88
|
+
dry_run_output_path: Optional[pathlib.Path],
|
|
89
|
+
):
|
|
90
|
+
enterprise_url = ctx.obj.get("enterprise_url")
|
|
91
|
+
logger.debug(
|
|
92
|
+
"Starting label analysis",
|
|
93
|
+
extra=dict(
|
|
94
|
+
extra_log_attributes=dict(
|
|
95
|
+
head_commit_sha=head_commit_sha,
|
|
96
|
+
base_commit_sha=base_commit_sha,
|
|
97
|
+
token=token,
|
|
98
|
+
runner_name=runner_name,
|
|
99
|
+
enterprise_url=enterprise_url,
|
|
100
|
+
max_wait_time=max_wait_time,
|
|
101
|
+
dry_run=dry_run,
|
|
102
|
+
)
|
|
103
|
+
),
|
|
104
|
+
)
|
|
105
|
+
if head_commit_sha == base_commit_sha:
|
|
106
|
+
logger.error(
|
|
107
|
+
"Base and head sha can't be the same",
|
|
108
|
+
extra=dict(
|
|
109
|
+
extra_log_attributes=dict(
|
|
110
|
+
head_commit_sha=head_commit_sha,
|
|
111
|
+
base_commit_sha=base_commit_sha,
|
|
112
|
+
)
|
|
113
|
+
),
|
|
114
|
+
)
|
|
115
|
+
raise click.ClickException(
|
|
116
|
+
click.style("Unable to run label analysis", fg="red")
|
|
117
|
+
)
|
|
118
|
+
|
|
119
|
+
codecov_yaml = ctx.obj["codecov_yaml"] or {}
|
|
120
|
+
cli_config = codecov_yaml.get("cli", {})
|
|
121
|
+
# Raises error if no runner is found
|
|
122
|
+
runner = get_runner(cli_config, runner_name)
|
|
123
|
+
logger.debug(
|
|
124
|
+
f"Selected runner: {runner}",
|
|
125
|
+
extra=dict(extra_log_attributes=dict(config=runner.params)),
|
|
126
|
+
)
|
|
127
|
+
|
|
128
|
+
upload_url = enterprise_url or CODECOV_API_URL
|
|
129
|
+
url = f"{upload_url}/labels/labels-analysis"
|
|
130
|
+
token_header = f"Repotoken {token}"
|
|
131
|
+
payload = {
|
|
132
|
+
"base_commit": base_commit_sha,
|
|
133
|
+
"head_commit": head_commit_sha,
|
|
134
|
+
"requested_labels": None,
|
|
135
|
+
}
|
|
136
|
+
# Send the initial label analysis request without labels
|
|
137
|
+
# Because labels might take a long time to collect
|
|
138
|
+
eid = _send_labelanalysis_request(payload, url, token_header)
|
|
139
|
+
|
|
140
|
+
logger.info("Collecting labels...")
|
|
141
|
+
requested_labels = runner.collect_tests()
|
|
142
|
+
logger.info(f"Collected {len(requested_labels)} test labels")
|
|
143
|
+
logger.debug(
|
|
144
|
+
"Labels collected",
|
|
145
|
+
extra=dict(extra_log_attributes=dict(labels_collected=requested_labels)),
|
|
146
|
+
)
|
|
147
|
+
payload["requested_labels"] = requested_labels
|
|
148
|
+
|
|
149
|
+
if eid:
|
|
150
|
+
# Initial request with no labels was successful
|
|
151
|
+
# Now we PATCH the labels in
|
|
152
|
+
patch_url = f"{upload_url}/labels/labels-analysis/{eid}"
|
|
153
|
+
_patch_labels(payload, patch_url, token_header)
|
|
154
|
+
else:
|
|
155
|
+
# Initial request with no labels failed
|
|
156
|
+
# Retry it
|
|
157
|
+
eid = _send_labelanalysis_request(payload, url, token_header)
|
|
158
|
+
if eid is None:
|
|
159
|
+
_fallback_to_collected_labels(
|
|
160
|
+
requested_labels,
|
|
161
|
+
runner,
|
|
162
|
+
dry_run=dry_run,
|
|
163
|
+
dry_run_output_path=dry_run_output_path,
|
|
164
|
+
)
|
|
165
|
+
return
|
|
166
|
+
|
|
167
|
+
has_result = False
|
|
168
|
+
logger.info("Waiting for list of tests to run...")
|
|
169
|
+
start_wait = time.monotonic()
|
|
170
|
+
time.sleep(1)
|
|
171
|
+
while not has_result:
|
|
172
|
+
resp_data = requests.get(
|
|
173
|
+
f"{upload_url}/labels/labels-analysis/{eid}",
|
|
174
|
+
headers={"Authorization": token_header},
|
|
175
|
+
)
|
|
176
|
+
resp_json = resp_data.json()
|
|
177
|
+
if resp_json["state"] == "finished":
|
|
178
|
+
logger.info(
|
|
179
|
+
"Received list of tests from Codecov",
|
|
180
|
+
extra=dict(
|
|
181
|
+
extra_log_attributes=dict(
|
|
182
|
+
processing_errors=resp_json.get("errors", [])
|
|
183
|
+
)
|
|
184
|
+
),
|
|
185
|
+
)
|
|
186
|
+
request_result = _potentially_calculate_absent_labels(
|
|
187
|
+
resp_json["result"], requested_labels
|
|
188
|
+
)
|
|
189
|
+
if not dry_run:
|
|
190
|
+
runner.process_labelanalysis_result(request_result)
|
|
191
|
+
else:
|
|
192
|
+
_dry_run_output(
|
|
193
|
+
LabelAnalysisRequestResult(request_result),
|
|
194
|
+
runner,
|
|
195
|
+
dry_run_output_path,
|
|
196
|
+
)
|
|
197
|
+
return
|
|
198
|
+
if resp_json["state"] == "error":
|
|
199
|
+
logger.error(
|
|
200
|
+
"Request had problems calculating",
|
|
201
|
+
extra=dict(extra_log_attributes=dict(resp_json=resp_json)),
|
|
202
|
+
)
|
|
203
|
+
_fallback_to_collected_labels(
|
|
204
|
+
collected_labels=requested_labels,
|
|
205
|
+
runner=runner,
|
|
206
|
+
dry_run=dry_run,
|
|
207
|
+
dry_run_output_path=dry_run_output_path,
|
|
208
|
+
)
|
|
209
|
+
return
|
|
210
|
+
if max_wait_time and (time.monotonic() - start_wait) > max_wait_time:
|
|
211
|
+
logger.error(
|
|
212
|
+
f"Exceeded max waiting time of {max_wait_time} seconds. Running all tests.",
|
|
213
|
+
)
|
|
214
|
+
_fallback_to_collected_labels(
|
|
215
|
+
collected_labels=requested_labels,
|
|
216
|
+
runner=runner,
|
|
217
|
+
dry_run=dry_run,
|
|
218
|
+
dry_run_output_path=dry_run_output_path,
|
|
219
|
+
)
|
|
220
|
+
return
|
|
221
|
+
logger.info("Waiting more time for result...")
|
|
222
|
+
time.sleep(5)
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
def _potentially_calculate_absent_labels(
|
|
226
|
+
request_result, requested_labels
|
|
227
|
+
) -> LabelAnalysisRequestResult:
|
|
228
|
+
if request_result["absent_labels"]:
|
|
229
|
+
# This means that Codecov already calculated everything for us
|
|
230
|
+
final_result = LabelAnalysisRequestResult(request_result)
|
|
231
|
+
else:
|
|
232
|
+
# Here we have to calculate the absent labels
|
|
233
|
+
# And also remove labels that maybe don't exist anymore from the set of labels to test
|
|
234
|
+
# Because codecov didn't have this info previously
|
|
235
|
+
requested_labels_set = set(requested_labels)
|
|
236
|
+
present_diff_labels_set = set(request_result.get("present_diff_labels", []))
|
|
237
|
+
present_report_labels_set = set(request_result.get("present_report_labels", []))
|
|
238
|
+
global_level_labels_set = set(request_result.get("global_level_labels", []))
|
|
239
|
+
final_result = LabelAnalysisRequestResult(
|
|
240
|
+
{
|
|
241
|
+
"present_report_labels": sorted(
|
|
242
|
+
present_report_labels_set & requested_labels_set
|
|
243
|
+
),
|
|
244
|
+
"present_diff_labels": sorted(
|
|
245
|
+
present_diff_labels_set & requested_labels_set
|
|
246
|
+
),
|
|
247
|
+
"absent_labels": sorted(
|
|
248
|
+
requested_labels_set - present_report_labels_set
|
|
249
|
+
),
|
|
250
|
+
"global_level_labels": sorted(
|
|
251
|
+
global_level_labels_set & requested_labels_set
|
|
252
|
+
),
|
|
253
|
+
}
|
|
254
|
+
)
|
|
255
|
+
logger.info(
|
|
256
|
+
"Received information about tests to run",
|
|
257
|
+
extra=dict(
|
|
258
|
+
extra_log_attributes=dict(
|
|
259
|
+
absent_labels=len(final_result.absent_labels),
|
|
260
|
+
present_diff_labels=len(final_result.present_diff_labels),
|
|
261
|
+
global_level_labels=len(final_result.global_level_labels),
|
|
262
|
+
present_report_labels=len(final_result.present_report_labels),
|
|
263
|
+
)
|
|
264
|
+
),
|
|
265
|
+
)
|
|
266
|
+
return final_result
|
|
267
|
+
|
|
268
|
+
|
|
269
|
+
def _patch_labels(payload, url, token_header):
|
|
270
|
+
logger.info("Sending collected labels to Codecov...")
|
|
271
|
+
try:
|
|
272
|
+
response = requests.patch(
|
|
273
|
+
url, json=payload, headers={"Authorization": token_header}
|
|
274
|
+
)
|
|
275
|
+
if response.status_code < 300:
|
|
276
|
+
logger.info("Labels successfully sent to Codecov")
|
|
277
|
+
except requests.RequestException:
|
|
278
|
+
raise click.ClickException(click.style("Unable to reach Codecov", fg="red"))
|
|
279
|
+
|
|
280
|
+
|
|
281
|
+
def _send_labelanalysis_request(payload, url, token_header):
|
|
282
|
+
logger.info(
|
|
283
|
+
"Requesting set of labels to run...",
|
|
284
|
+
extra=dict(
|
|
285
|
+
extra_log_attributes=dict(
|
|
286
|
+
with_labels=(payload["requested_labels"] is not None)
|
|
287
|
+
)
|
|
288
|
+
),
|
|
289
|
+
)
|
|
290
|
+
try:
|
|
291
|
+
response = requests.post(
|
|
292
|
+
url, json=payload, headers={"Authorization": token_header}
|
|
293
|
+
)
|
|
294
|
+
if response.status_code >= 500:
|
|
295
|
+
logger.warning(
|
|
296
|
+
"Sorry. Codecov is having problems",
|
|
297
|
+
extra=dict(extra_log_attributes=dict(status_code=response.status_code)),
|
|
298
|
+
)
|
|
299
|
+
return None
|
|
300
|
+
if response.status_code >= 400:
|
|
301
|
+
logger.warning(
|
|
302
|
+
"Got a 4XX status code back from Codecov",
|
|
303
|
+
extra=dict(
|
|
304
|
+
extra_log_attributes=dict(
|
|
305
|
+
status_code=response.status_code, response_json=response.json()
|
|
306
|
+
)
|
|
307
|
+
),
|
|
308
|
+
)
|
|
309
|
+
raise click.ClickException(
|
|
310
|
+
"There is some problem with the submitted information"
|
|
311
|
+
)
|
|
312
|
+
except requests.RequestException:
|
|
313
|
+
raise click.ClickException(click.style("Unable to reach Codecov", fg="red"))
|
|
314
|
+
eid = response.json()["external_id"]
|
|
315
|
+
logger.info(
|
|
316
|
+
"Label Analysis request successful",
|
|
317
|
+
extra=dict(extra_log_attributes=dict(request_id=eid)),
|
|
318
|
+
)
|
|
319
|
+
return eid
|
|
320
|
+
|
|
321
|
+
|
|
322
|
+
def _dry_run_output(
|
|
323
|
+
result: LabelAnalysisRequestResult,
|
|
324
|
+
runner: LabelAnalysisRunnerInterface,
|
|
325
|
+
dry_run_output_path: Optional[pathlib.Path],
|
|
326
|
+
):
|
|
327
|
+
labels_to_run = set(
|
|
328
|
+
result.absent_labels + result.global_level_labels + result.present_diff_labels
|
|
329
|
+
)
|
|
330
|
+
labels_skipped = set(result.present_report_labels) - labels_to_run
|
|
331
|
+
# If the test label can contain spaces and dashes the test runner might
|
|
332
|
+
# interpret it as an option and not a label
|
|
333
|
+
# So we wrap it in doublequotes just to be extra sure
|
|
334
|
+
labels_run_wrapped_double_quotes = sorted(
|
|
335
|
+
map(lambda l: '"' + l + '"', labels_to_run)
|
|
336
|
+
)
|
|
337
|
+
labels_skip_wrapped_double_quotes = sorted(
|
|
338
|
+
map(lambda l: '"' + l + '"', labels_skipped)
|
|
339
|
+
)
|
|
340
|
+
|
|
341
|
+
output_as_dict = dict(
|
|
342
|
+
runner_options=runner.dry_run_runner_options,
|
|
343
|
+
ats_tests_to_run=labels_run_wrapped_double_quotes,
|
|
344
|
+
ats_tests_to_skip=labels_skip_wrapped_double_quotes,
|
|
345
|
+
)
|
|
346
|
+
if dry_run_output_path is not None:
|
|
347
|
+
with open(dry_run_output_path, "w") as fd:
|
|
348
|
+
fd.write(
|
|
349
|
+
" ".join(
|
|
350
|
+
runner.dry_run_runner_options + labels_run_wrapped_double_quotes
|
|
351
|
+
)
|
|
352
|
+
+ "\n"
|
|
353
|
+
)
|
|
354
|
+
with open(str(dry_run_output_path) + "_skipped", "w") as fd:
|
|
355
|
+
fd.write(
|
|
356
|
+
" ".join(
|
|
357
|
+
runner.dry_run_runner_options + labels_skip_wrapped_double_quotes
|
|
358
|
+
)
|
|
359
|
+
+ "\n"
|
|
360
|
+
)
|
|
361
|
+
with open(str(dry_run_output_path) + ".json", "w") as fd:
|
|
362
|
+
fd.write(json.dumps(output_as_dict) + "\n")
|
|
363
|
+
|
|
364
|
+
click.echo(json.dumps(output_as_dict))
|
|
365
|
+
click.echo(
|
|
366
|
+
f"ATS_TESTS_TO_RUN={' '.join(runner.dry_run_runner_options + labels_run_wrapped_double_quotes)}"
|
|
367
|
+
)
|
|
368
|
+
click.echo(
|
|
369
|
+
f"ATS_TESTS_TO_SKIP={' '.join(runner.dry_run_runner_options + labels_skip_wrapped_double_quotes)}"
|
|
370
|
+
)
|
|
371
|
+
|
|
372
|
+
|
|
373
|
+
def _fallback_to_collected_labels(
|
|
374
|
+
collected_labels: List[str],
|
|
375
|
+
runner: LabelAnalysisRunnerInterface,
|
|
376
|
+
*,
|
|
377
|
+
dry_run: bool = False,
|
|
378
|
+
dry_run_output_path: Optional[pathlib.Path] = None,
|
|
379
|
+
) -> dict:
|
|
380
|
+
logger.info("Trying to fallback on collected labels")
|
|
381
|
+
if collected_labels:
|
|
382
|
+
logger.info("Using collected labels as tests to run")
|
|
383
|
+
fake_response = LabelAnalysisRequestResult(
|
|
384
|
+
{
|
|
385
|
+
"present_report_labels": [],
|
|
386
|
+
"absent_labels": collected_labels,
|
|
387
|
+
"present_diff_labels": [],
|
|
388
|
+
"global_level_labels": [],
|
|
389
|
+
}
|
|
390
|
+
)
|
|
391
|
+
if not dry_run:
|
|
392
|
+
return runner.process_labelanalysis_result(fake_response)
|
|
393
|
+
else:
|
|
394
|
+
return _dry_run_output(
|
|
395
|
+
LabelAnalysisRequestResult(fake_response), runner, dry_run_output_path
|
|
396
|
+
)
|
|
397
|
+
logger.error("Cannot fallback to collected labels because no labels were collected")
|
|
398
|
+
raise click.ClickException("Failed to get list of labels to run")
|