Skip to content

Commit 2e7e27b

Browse files
authored
feat: add GITHUB_REF fallback for --tests-target-branch (#721)
- Add GITHUB_REF as fallback environment variable for --tests-target-branch - Strip refs/heads/ prefix from --tests-target-branch values automatically - Maintain precedence: GITHUB_BASE_REF > MERGIFY_TESTS_TARGET_BRANCH > GITHUB_REF
1 parent 7dda895 commit 2e7e27b

File tree

3 files changed

+183
-3
lines changed

3 files changed

+183
-3
lines changed

mergify_cli/ci/cli.py

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,15 @@
1111
from mergify_cli.ci import upload
1212

1313

14+
def _process_tests_target_branch(
15+
_ctx: click.Context,
16+
_param: click.Parameter,
17+
value: str | None,
18+
) -> str | None:
19+
"""Process the tests_target_branch parameter to strip refs/heads/ prefix from GITHUB_REF."""
20+
return value.removeprefix("refs/heads/") if value else value
21+
22+
1423
ci = click.Group(
1524
"ci",
1625
help="Mergify's CI related commands",
@@ -54,7 +63,8 @@
5463
"-ttb",
5564
help="The branch used to check if failing tests can be ignored with Mergify's Quarantine.",
5665
required=True,
57-
envvar=["GITHUB_BASE_REF", "MERGIFY_TESTS_TARGET_BRANCH"],
66+
envvar=["GITHUB_BASE_REF", "MERGIFY_TESTS_TARGET_BRANCH", "GITHUB_REF"],
67+
callback=_process_tests_target_branch,
5868
)
5969
@click.argument(
6070
"files",
@@ -124,7 +134,8 @@ async def junit_upload( # noqa: PLR0913
124134
"-ttb",
125135
help="The branch used to check if failing tests can be ignored with Mergify's Quarantine.",
126136
required=True,
127-
envvar=["GITHUB_BASE_REF", "MERGIFY_TESTS_TARGET_BRANCH"],
137+
envvar=["GITHUB_BASE_REF", "MERGIFY_TESTS_TARGET_BRANCH", "GITHUB_REF"],
138+
callback=_process_tests_target_branch,
128139
)
129140
@click.argument(
130141
"files",

mergify_cli/tests/ci/test_cli.py

Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
from unittest import mock
33

44
import anys
5+
import click
56
from click import testing
67
import pytest
78

@@ -76,6 +77,115 @@ def test_cli(env: dict[str, str], monkeypatch: pytest.MonkeyPatch) -> None:
7677
}
7778

7879

80+
@pytest.mark.parametrize(
81+
("env", "expected_branch"),
82+
[
83+
pytest.param(
84+
{
85+
"GITHUB_EVENT_NAME": "push",
86+
"GITHUB_ACTIONS": "true",
87+
"MERGIFY_API_URL": "https://api.mergify.com",
88+
"MERGIFY_TOKEN": "abc",
89+
"GITHUB_REPOSITORY": "user/repo",
90+
"GITHUB_SHA": "3af96aa24f1d32fcfbb7067793cacc6dc0c6b199",
91+
"GITHUB_WORKFLOW": "JOB",
92+
"GITHUB_REF": "refs/heads/feature-branch",
93+
},
94+
"feature-branch",
95+
id="GITHUB_REF with refs/heads/ prefix",
96+
),
97+
pytest.param(
98+
{
99+
"GITHUB_EVENT_NAME": "push",
100+
"GITHUB_ACTIONS": "true",
101+
"MERGIFY_API_URL": "https://api.mergify.com",
102+
"MERGIFY_TOKEN": "abc",
103+
"GITHUB_REPOSITORY": "user/repo",
104+
"GITHUB_SHA": "3af96aa24f1d32fcfbb7067793cacc6dc0c6b199",
105+
"GITHUB_WORKFLOW": "JOB",
106+
"GITHUB_REF": "main",
107+
},
108+
"main",
109+
id="GITHUB_REF without refs/heads/ prefix",
110+
),
111+
pytest.param(
112+
{
113+
"GITHUB_EVENT_NAME": "push",
114+
"GITHUB_ACTIONS": "true",
115+
"MERGIFY_API_URL": "https://api.mergify.com",
116+
"MERGIFY_TOKEN": "abc",
117+
"GITHUB_REPOSITORY": "user/repo",
118+
"GITHUB_SHA": "3af96aa24f1d32fcfbb7067793cacc6dc0c6b199",
119+
"GITHUB_WORKFLOW": "JOB",
120+
"GITHUB_BASE_REF": "main",
121+
"GITHUB_REF": "refs/heads/feature-branch",
122+
},
123+
"main",
124+
id="GITHUB_BASE_REF takes precedence over GITHUB_REF",
125+
),
126+
pytest.param(
127+
{
128+
"GITHUB_EVENT_NAME": "push",
129+
"GITHUB_ACTIONS": "true",
130+
"MERGIFY_API_URL": "https://api.mergify.com",
131+
"MERGIFY_TOKEN": "abc",
132+
"GITHUB_REPOSITORY": "user/repo",
133+
"GITHUB_SHA": "3af96aa24f1d32fcfbb7067793cacc6dc0c6b199",
134+
"GITHUB_WORKFLOW": "JOB",
135+
"MERGIFY_TESTS_TARGET_BRANCH": "develop",
136+
"GITHUB_REF": "refs/heads/feature-branch",
137+
},
138+
"develop",
139+
id="MERGIFY_TESTS_TARGET_BRANCH takes precedence over GITHUB_REF",
140+
),
141+
pytest.param(
142+
{
143+
"GITHUB_EVENT_NAME": "push",
144+
"GITHUB_ACTIONS": "true",
145+
"MERGIFY_API_URL": "https://api.mergify.com",
146+
"MERGIFY_TOKEN": "abc",
147+
"GITHUB_REPOSITORY": "user/repo",
148+
"GITHUB_SHA": "3af96aa24f1d32fcfbb7067793cacc6dc0c6b199",
149+
"GITHUB_WORKFLOW": "JOB",
150+
"GITHUB_REF": "refs/tags/v1.0.0",
151+
},
152+
"refs/tags/v1.0.0",
153+
id="GITHUB_REF with refs/tags/ prefix (should not be stripped)",
154+
),
155+
],
156+
)
157+
def test_tests_target_branch_environment_variable_processing(
158+
env: dict[str, str],
159+
expected_branch: str,
160+
monkeypatch: pytest.MonkeyPatch,
161+
) -> None:
162+
"""Test that tests_target_branch environment variable processing works correctly."""
163+
for key in ["GITHUB_REF", "GITHUB_BASE_REF"]: # Override value from CI runner
164+
monkeypatch.delenv(key, raising=False)
165+
166+
for key, value in env.items():
167+
monkeypatch.setenv(key, value)
168+
169+
runner = testing.CliRunner()
170+
171+
with mock.patch.object(
172+
cli_junit_upload,
173+
"_process_junit_files",
174+
mock.AsyncMock(),
175+
) as mocked_process_junit_files:
176+
result = runner.invoke(
177+
cli_junit_upload.junit_process,
178+
[str(REPORT_XML)],
179+
)
180+
181+
assert result.exit_code == 0, result.stdout
182+
183+
# Check that _process_junit_files was called with the expected branch
184+
assert mocked_process_junit_files.call_count == 1
185+
call_kwargs = mocked_process_junit_files.call_args.kwargs
186+
assert call_kwargs["tests_target_branch"] == expected_branch
187+
188+
79189
def test_upload_error(monkeypatch: pytest.MonkeyPatch) -> None:
80190
for key, value in {
81191
"GITHUB_EVENT_NAME": "push",
@@ -114,3 +224,62 @@ def test_upload_error(monkeypatch: pytest.MonkeyPatch) -> None:
114224
"repository": "user/repo",
115225
"spans": anys.ANY_LIST,
116226
}
227+
228+
229+
def test_process_tests_target_branch_callback() -> None:
230+
"""Test the _process_tests_target_branch callback function directly."""
231+
context_mock = mock.MagicMock(spec=click.Context)
232+
param_mock = mock.MagicMock(spec=click.Parameter)
233+
234+
# Test stripping refs/heads/ prefix
235+
assert (
236+
cli_junit_upload._process_tests_target_branch(
237+
context_mock,
238+
param_mock,
239+
"refs/heads/main",
240+
)
241+
== "main"
242+
)
243+
assert (
244+
cli_junit_upload._process_tests_target_branch(
245+
context_mock,
246+
param_mock,
247+
"refs/heads/feature-branch",
248+
)
249+
== "feature-branch"
250+
)
251+
252+
# Test not stripping other prefixes
253+
assert (
254+
cli_junit_upload._process_tests_target_branch(
255+
context_mock,
256+
param_mock,
257+
"refs/tags/v1.0.0",
258+
)
259+
== "refs/tags/v1.0.0"
260+
)
261+
assert (
262+
cli_junit_upload._process_tests_target_branch(
263+
context_mock,
264+
param_mock,
265+
"main",
266+
)
267+
== "main"
268+
)
269+
270+
# Test None value
271+
assert (
272+
cli_junit_upload._process_tests_target_branch(
273+
context_mock,
274+
param_mock,
275+
None,
276+
)
277+
is None
278+
)
279+
280+
# Test empty string
281+
assert not cli_junit_upload._process_tests_target_branch(
282+
context_mock,
283+
param_mock,
284+
"",
285+
)

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,7 @@ ignore = [
148148
]
149149

150150
[tool.ruff.lint.per-file-ignores]
151-
"mergify_cli/tests/**/*.py" = ["S101"]
151+
"mergify_cli/tests/**/*.py" = ["S101", "SLF001"]
152152

153153
[tool.ruff.lint.isort]
154154
force-single-line = true

0 commit comments

Comments
 (0)