Skip to content
This repository was archived by the owner on Jul 16, 2025. It is now read-only.

Commit be7a0b3

Browse files
committed
implement base picking command
1 parent fa566bf commit be7a0b3

File tree

6 files changed

+257
-3
lines changed

6 files changed

+257
-3
lines changed
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
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_is_invalid
9+
from codecov_cli.helpers.request import send_put_request
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+
logger.debug(
58+
"Starting base picking process",
59+
extra=dict(
60+
extra_log_attributes=dict(
61+
pr=pr,
62+
slug=slug,
63+
token=token,
64+
service=service,
65+
)
66+
),
67+
)
68+
69+
if slug_is_invalid(slug):
70+
logger.error(
71+
"Slug is invalid. Slug should be in the form of owner_username/repo_name"
72+
)
73+
return
74+
75+
data = {
76+
"user_provided_base_sha": base_sha,
77+
}
78+
headers = {"Authorization": f"token {token.hex}"}
79+
url = f"https://api.codecov.io/api/v1/{service}/{slug}/pulls/{pr}"
80+
sending_result = send_put_request(url=url, data=data, headers=headers)
81+
82+
if sending_result.warnings:
83+
number_warnings = len(sending_result.warnings)
84+
pluralization = "s" if number_warnings > 1 else ""
85+
logger.info(
86+
f"Base picking process had {number_warnings} warning{pluralization}",
87+
)
88+
for ind, w in enumerate(sending_result.warnings):
89+
logger.warning(f"Warning {ind + 1}: {w}")
90+
if sending_result.error is not None:
91+
logger.error(f"Base picking failed: {sending_result.error.description}")
92+
return
93+
94+
logger.info("Base picking finished successfully")
95+
logger.info(sending_result.text)

codecov_cli/helpers/encoder.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,9 @@ def encode_slug(slug: str):
55
encoded_owner = ":::".join(owner.split("/"))
66
encoded_slug = "::::".join([encoded_owner, repo])
77
return encoded_slug
8+
9+
10+
def slug_is_invalid(slug: str):
11+
if "/" not in slug or slug.count("/") > 1:
12+
return True
13+
return False

codecov_cli/main.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import click
66
import yaml
77

8+
from codecov_cli.commands.base_picking import pr_base_picking
89
from codecov_cli.commands.commit import create_commit
910
from codecov_cli.commands.report import create_report
1011
from codecov_cli.commands.report_result import get_report_results
@@ -47,6 +48,7 @@ def cli(
4748
cli.add_command(create_commit)
4849
cli.add_command(create_report)
4950
cli.add_command(get_report_results)
51+
cli.add_command(pr_base_picking)
5052

5153

5254
def run():

tests/helpers/test_encoder.py

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import pytest
22

3-
from codecov_cli.helpers.encoder import encode_slug
3+
from codecov_cli.helpers.encoder import encode_slug, slug_is_invalid
44

55

66
def test_invalid_slug():
@@ -9,13 +9,23 @@ def test_invalid_slug():
99
encode_slug(slug)
1010

1111

12-
def test_owner_repo_slug():
12+
def test_encode_slug():
1313
slug = "owner/repo"
1414
encoded_slug = encode_slug(slug)
1515
assert encoded_slug == "owner::::repo"
1616

1717

18-
def test_owner_with_subgroups_slug():
18+
def test_encode_owner_with_subgroups_slug():
1919
slug = "owner/subgroup/repo"
2020
encoded_slug = encode_slug(slug)
2121
assert encoded_slug == "owner:::subgroup::::repo"
22+
23+
24+
def test_invalid_slug2():
25+
slug = "invalid_slug"
26+
assert slug_is_invalid(slug)
27+
28+
29+
def test_valid_slug():
30+
slug = "owner/repo"
31+
assert not slug_is_invalid(slug)

tests/test_base_picking.py

Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
import uuid
2+
3+
from click.testing import CliRunner
4+
5+
from codecov_cli.commands.base_picking import pr_base_picking
6+
from codecov_cli.main import cli
7+
from codecov_cli.types import RequestError, RequestResult
8+
9+
10+
def test_base_picking_command(mocker):
11+
mocked_response = mocker.patch(
12+
"codecov_cli.commands.base_picking.send_put_request",
13+
return_value=RequestResult(status_code=200, error=None, warnings=[], text=""),
14+
)
15+
token = uuid.uuid4()
16+
runner = CliRunner()
17+
result = runner.invoke(
18+
pr_base_picking,
19+
[
20+
"-t",
21+
token,
22+
"--pr",
23+
"11",
24+
"--base-sha",
25+
"9a6902ee94c18e8e27561ce316b16d75a02c7bc1",
26+
"--service",
27+
"github",
28+
"--slug",
29+
"owner/repo",
30+
],
31+
)
32+
assert result.exit_code == 0
33+
assert (
34+
f'debug: Starting base picking process --- {{"pr": "11", "slug": "owner/repo", "token": "{token}", "service": "github"}}'
35+
in result.output
36+
)
37+
assert "info: Base picking finished successfully" in result.output
38+
mocked_response.assert_called_once()
39+
40+
41+
def test_base_picking_command_slug_invalid(mocker):
42+
token = uuid.uuid4()
43+
runner = CliRunner()
44+
result = runner.invoke(
45+
pr_base_picking,
46+
[
47+
"-t",
48+
token,
49+
"--pr",
50+
"11",
51+
"--base-sha",
52+
"9a6902ee94c18e8e27561ce316b16d75a02c7bc1",
53+
"--service",
54+
"github",
55+
"--slug",
56+
"owner-repo",
57+
],
58+
)
59+
assert result.exit_code == 0
60+
assert (
61+
"error: Slug is invalid. Slug should be in the form of owner_username/repo_name"
62+
in result.output
63+
)
64+
65+
66+
def test_base_picking_command_warnings(mocker):
67+
mocked_response = mocker.patch(
68+
"codecov_cli.commands.base_picking.send_put_request",
69+
return_value=RequestResult(
70+
status_code=200, error=None, warnings=["some random warning"], text=""
71+
),
72+
)
73+
token = uuid.uuid4()
74+
runner = CliRunner()
75+
result = runner.invoke(
76+
pr_base_picking,
77+
[
78+
"-t",
79+
token,
80+
"--pr",
81+
"11",
82+
"--base-sha",
83+
"9a6902ee94c18e8e27561ce316b16d75a02c7bc1",
84+
"--service",
85+
"github",
86+
"--slug",
87+
"owner/repo",
88+
],
89+
)
90+
assert result.exit_code == 0
91+
assert (
92+
f'debug: Starting base picking process --- {{"pr": "11", "slug": "owner/repo", "token": "{token}", "service": "github"}}'
93+
in result.output
94+
)
95+
assert "info: Base picking process had 1 warning" in result.output
96+
assert "Warning 1: some random warning" in result.output
97+
assert "info: Base picking finished successfully" in result.output
98+
mocked_response.assert_called_once()
99+
100+
101+
def test_base_picking_command_error(mocker):
102+
mocked_response = mocker.patch(
103+
"codecov_cli.commands.base_picking.send_put_request",
104+
return_value=RequestResult(
105+
status_code=401,
106+
error=RequestError(
107+
code="HTTP Error 401",
108+
description="Unauthorized",
109+
params={},
110+
),
111+
warnings=[],
112+
text="",
113+
),
114+
)
115+
token = uuid.uuid4()
116+
runner = CliRunner()
117+
result = runner.invoke(
118+
pr_base_picking,
119+
[
120+
"-t",
121+
token,
122+
"--pr",
123+
"11",
124+
"--base-sha",
125+
"9a6902ee94c18e8e27561ce316b16d75a02c7bc1",
126+
"--service",
127+
"github",
128+
"--slug",
129+
"owner/repo",
130+
],
131+
)
132+
mocked_response.assert_called_once()
133+
print(result.output)
134+
assert result.exit_code == 0
135+
assert (
136+
f'debug: Starting base picking process --- {{"pr": "11", "slug": "owner/repo", "token": "{token}", "service": "github"}}'
137+
in result.output
138+
)
139+
assert "error: Base picking failed: Unauthorized" in result.output
140+
assert "info: Base picking finished successfully" not in result.output

tests/test_codecov_cli.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,5 @@ def test_existing_commands():
1111
"create-report",
1212
"do-upload",
1313
"get-report-results",
14+
"pr-base-picking",
1415
]

0 commit comments

Comments
 (0)