Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions mergify_cli/ci/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

from mergify_cli import utils
from mergify_cli.ci import detector
from mergify_cli.ci.git_refs import detector as git_refs_detector
from mergify_cli.ci.junit_processing import cli as junit_processing_cli
from mergify_cli.ci.scopes import cli as scopes_cli
from mergify_cli.ci.scopes import exceptions as scopes_exc
Expand Down Expand Up @@ -193,6 +194,17 @@ async def junit_process(
)


@ci.command(
help="""Give the base/head git references of the pull request""",
short_help="""Give the base/head git references of the pull request""",
)
def git_refs() -> None:
ref = git_refs_detector.detect()
click.echo(f"Base: {ref.base}")
click.echo(f"Head: {ref.head}")
ref.maybe_write_to_github_outputs()


@ci.command(
help="""Give the list scope impacted by changed files""",
short_help="""Give the list scope impacted by changed files""",
Expand Down
Empty file.
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
from __future__ import annotations

import dataclasses
import os
import pathlib
import typing

import yaml
Expand All @@ -9,6 +11,10 @@
from mergify_cli.ci.scopes import exceptions


GITHUB_ACTIONS_BASE_OUTPUT_NAME = "base"
GITHUB_ACTIONS_HEAD_OUTPUT_NAME = "head"


class BaseNotFoundError(exceptions.ScopesError):
pass

Expand Down Expand Up @@ -107,6 +113,14 @@ class References:
head: str
is_merge_queue: bool

def maybe_write_to_github_outputs(self) -> None:
gha = os.environ.get("GITHUB_OUTPUT")
if not gha:
return
with pathlib.Path(gha).open("a", encoding="utf-8") as fh:
fh.write(f"{GITHUB_ACTIONS_BASE_OUTPUT_NAME}={self.base}\n")
fh.write(f"{GITHUB_ACTIONS_HEAD_OUTPUT_NAME}={self.head}\n")


PULL_REQUEST_EVENTS = {
"pull_request",
Expand Down
11 changes: 3 additions & 8 deletions mergify_cli/ci/scopes/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,16 @@
import pydantic

from mergify_cli import utils
from mergify_cli.ci.git_refs import detector as git_refs_detector
from mergify_cli.ci.scopes import changed_files
from mergify_cli.ci.scopes import config
from mergify_cli.ci.scopes import exceptions
from mergify_cli.ci.scopes import git_refs_detector


if typing.TYPE_CHECKING:
from collections import abc

GITHUB_ACTIONS_SCOPES_OUTPUT_NAME = "scopes"
GITHUB_ACTIONS_BASE_OUTPUT_NAME = "base"
GITHUB_ACTIONS_HEAD_OUTPUT_NAME = "head"


def match_scopes(
Expand Down Expand Up @@ -56,8 +54,6 @@ def match_scopes(


def maybe_write_github_outputs(
base: str,
head: str,
all_scopes: abc.Iterable[str],
scopes_hit: set[str],
) -> None:
Expand All @@ -74,8 +70,6 @@ def maybe_write_github_outputs(
data = {
key: "true" if key in scopes_hit else "false" for key in sorted(all_scopes)
}
fh.write(f"{GITHUB_ACTIONS_BASE_OUTPUT_NAME}={base}\n")
fh.write(f"{GITHUB_ACTIONS_HEAD_OUTPUT_NAME}={head}\n")
fh.write(
f"{GITHUB_ACTIONS_SCOPES_OUTPUT_NAME}<<{delimiter}\n{json.dumps(data)}\n{delimiter}\n",
)
Expand Down Expand Up @@ -164,7 +158,8 @@ def detect(config_path: str) -> DetectedScope:
else:
click.echo("No scopes matched.")

maybe_write_github_outputs(git_refs.base, git_refs.head, all_scopes, scopes_hit)
git_refs.maybe_write_to_github_outputs()
maybe_write_github_outputs(all_scopes, scopes_hit)
maybe_write_github_step_summary(
git_refs.base,
git_refs.head,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

import pytest

from mergify_cli.ci.scopes import git_refs_detector
from mergify_cli.ci.git_refs import detector


if TYPE_CHECKING:
Expand All @@ -25,9 +25,34 @@ def test_detect_base_from_repository_default_branch(
monkeypatch.setenv("GITHUB_EVENT_NAME", event_name)
monkeypatch.setenv("GITHUB_EVENT_PATH", str(event_file))

result = git_refs_detector.detect()
result = detector.detect()

assert result == git_refs_detector.References("main", "HEAD", is_merge_queue=False)
assert result == detector.References("main", "HEAD", is_merge_queue=False)


def test_maybe_write_github_outputs(
tmp_path: pathlib.Path,
monkeypatch: pytest.MonkeyPatch,
) -> None:
event_data = {"before": "abc123", "after": "xyz987"}
event_file = tmp_path / "event.json"
event_file.write_text(json.dumps(event_data))

output_file = tmp_path / "github_output"

monkeypatch.setenv("GITHUB_OUTPUT", str(output_file))
monkeypatch.setenv("GITHUB_EVENT_NAME", "push")
monkeypatch.setenv("GITHUB_EVENT_PATH", str(event_file))

result = detector.detect()

result.maybe_write_to_github_outputs()

content = output_file.read_text()
expected = """base=abc123
head=xyz987
"""
assert content == expected


def test_detect_base_from_push_event(
Expand All @@ -41,9 +66,9 @@ def test_detect_base_from_push_event(
monkeypatch.setenv("GITHUB_EVENT_NAME", "push")
monkeypatch.setenv("GITHUB_EVENT_PATH", str(event_file))

result = git_refs_detector.detect()
result = detector.detect()

assert result == git_refs_detector.References(
assert result == detector.References(
"abc123",
"xyz987",
is_merge_queue=False,
Expand All @@ -66,9 +91,9 @@ def test_detect_base_from_pull_request_event_path(
monkeypatch.setenv("GITHUB_EVENT_NAME", "pull_request")
monkeypatch.setenv("GITHUB_EVENT_PATH", str(event_file))

result = git_refs_detector.detect()
result = detector.detect()

assert result == git_refs_detector.References(
assert result == detector.References(
"abc123",
"xyz987",
is_merge_queue=False,
Expand All @@ -92,9 +117,9 @@ def test_detect_base_merge_queue_override(
monkeypatch.setenv("GITHUB_EVENT_NAME", "pull_request")
monkeypatch.setenv("GITHUB_EVENT_PATH", str(event_file))

result = git_refs_detector.detect()
result = detector.detect()

assert result == git_refs_detector.References("xyz789", "HEAD", is_merge_queue=True)
assert result == detector.References("xyz789", "HEAD", is_merge_queue=True)


def test_detect_base_no_info(
Expand All @@ -109,10 +134,10 @@ def test_detect_base_no_info(
monkeypatch.setenv("GITHUB_EVENT_PATH", str(event_file))

with pytest.raises(
git_refs_detector.BaseNotFoundError,
detector.BaseNotFoundError,
match="Could not detect base SHA",
):
git_refs_detector.detect()
detector.detect()


def test_yaml_docs_from_fenced_blocks_valid() -> None:
Expand All @@ -126,9 +151,9 @@ def test_yaml_docs_from_fenced_blocks_valid() -> None:
```
More text"""

result = git_refs_detector._yaml_docs_from_fenced_blocks(body)
result = detector._yaml_docs_from_fenced_blocks(body)

assert result == git_refs_detector.MergeQueueMetadata(
assert result == detector.MergeQueueMetadata(
{
"checking_base_sha": "xyz789",
"pull_requests": [{"number": 1}],
Expand All @@ -140,7 +165,7 @@ def test_yaml_docs_from_fenced_blocks_valid() -> None:
def test_yaml_docs_from_fenced_blocks_no_yaml() -> None:
body = "No yaml here"

result = git_refs_detector._yaml_docs_from_fenced_blocks(body)
result = detector._yaml_docs_from_fenced_blocks(body)

assert result is None

Expand All @@ -151,6 +176,6 @@ def test_yaml_docs_from_fenced_blocks_empty_yaml() -> None:
```
More text"""

result = git_refs_detector._yaml_docs_from_fenced_blocks(body)
result = detector._yaml_docs_from_fenced_blocks(body)

assert result is None
26 changes: 12 additions & 14 deletions mergify_cli/tests/ci/scopes/test_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@
import respx
import yaml

from mergify_cli.ci.git_refs import detector
from mergify_cli.ci.scopes import cli
from mergify_cli.ci.scopes import config
from mergify_cli.ci.scopes import git_refs_detector


if TYPE_CHECKING:
Expand Down Expand Up @@ -293,12 +293,10 @@ def test_maybe_write_github_outputs(
scopes_hit = {"backend", "docs"}

with mock.patch("uuid.uuid4", return_value="fixed-uuid"):
cli.maybe_write_github_outputs("base-sha", "head-sha", all_scopes, scopes_hit)
cli.maybe_write_github_outputs(all_scopes, scopes_hit)

content = output_file.read_text()
expected = """base=base-sha
head=head-sha
scopes<<ghadelimiter_fixed-uuid
expected = """scopes<<ghadelimiter_fixed-uuid
{"backend": "true", "docs": "true", "frontend": "false"}
ghadelimiter_fixed-uuid
"""
Expand Down Expand Up @@ -335,10 +333,10 @@ def test_maybe_write_github_outputs_no_env(
monkeypatch.delenv("GITHUB_OUTPUT", raising=False)

# Should not raise any exception
cli.maybe_write_github_outputs("old", "new", ["backend"], {"backend"})
cli.maybe_write_github_outputs(["backend"], {"backend"})


@mock.patch("mergify_cli.ci.scopes.cli.git_refs_detector.detect")
@mock.patch("mergify_cli.ci.git_refs.detector.detect")
@mock.patch("mergify_cli.ci.scopes.changed_files.git_changed_files")
@mock.patch("mergify_cli.ci.scopes.cli.maybe_write_github_outputs")
def test_detect_with_matches(
Expand All @@ -362,7 +360,7 @@ def test_detect_with_matches(
config_file.write_text(yaml.dump(config_data))

# Setup mocks
mock_detect_base.return_value = git_refs_detector.References(
mock_detect_base.return_value = detector.References(
"old",
"new",
is_merge_queue=True,
Expand Down Expand Up @@ -391,7 +389,7 @@ def test_detect_with_matches(
assert result.scopes == {"backend", "merge-queue"}


@mock.patch("mergify_cli.ci.scopes.cli.git_refs_detector.detect")
@mock.patch("mergify_cli.ci.git_refs.detector.detect")
@mock.patch("mergify_cli.ci.scopes.cli.maybe_write_github_outputs")
def test_detect_manual(
_: mock.Mock,
Expand All @@ -406,7 +404,7 @@ def test_detect_manual(
config_file.write_text(yaml.dump(config_data))

# Setup mocks
mock_detect_base.return_value = git_refs_detector.References(
mock_detect_base.return_value = detector.References(
"old",
"new",
is_merge_queue=False,
Expand All @@ -426,7 +424,7 @@ def test_detect_manual(
assert result.head_ref == "new"


@mock.patch("mergify_cli.ci.scopes.cli.git_refs_detector.detect")
@mock.patch("mergify_cli.ci.git_refs.detector.detect")
@mock.patch("mergify_cli.ci.scopes.changed_files.git_changed_files")
@mock.patch("mergify_cli.ci.scopes.cli.maybe_write_github_outputs")
def test_detect_no_matches(
Expand All @@ -443,7 +441,7 @@ def test_detect_no_matches(
config_file.write_text(yaml.dump(config_data))

# Setup mocks
mock_detect_base.return_value = git_refs_detector.References(
mock_detect_base.return_value = detector.References(
"old",
"new",
is_merge_queue=False,
Expand All @@ -464,7 +462,7 @@ def test_detect_no_matches(
assert result.head_ref == "new"


@mock.patch("mergify_cli.ci.scopes.cli.git_refs_detector.detect")
@mock.patch("mergify_cli.ci.git_refs.detector.detect")
@mock.patch("mergify_cli.ci.scopes.changed_files.git_changed_files")
def test_detect_debug_output(
mock_git_changed: mock.Mock,
Expand All @@ -483,7 +481,7 @@ def test_detect_debug_output(
config_file.write_text(yaml.dump(config_data))

# Setup mocks
mock_detect_base.return_value = git_refs_detector.References(
mock_detect_base.return_value = detector.References(
"main",
"HEAD",
is_merge_queue=False,
Expand Down
25 changes: 25 additions & 0 deletions mergify_cli/tests/ci/test_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -458,3 +458,28 @@ def test_scopes_send(
assert result.exit_code == 0, result.output
payload = json.loads(post_mock.calls[0].request.content)
assert sorted(payload["scopes"]) == ["backend", "foobar", "frontend"]


def test_git_refs(
tmp_path: pathlib.Path,
monkeypatch: pytest.MonkeyPatch,
) -> None:
event_data = {"before": "abc123", "after": "xyz987"}
event_file = tmp_path / "event.json"
event_file.write_text(json.dumps(event_data))

output_file = tmp_path / "github_output"

monkeypatch.setenv("GITHUB_OUTPUT", str(output_file))
monkeypatch.setenv("GITHUB_EVENT_NAME", "push")
monkeypatch.setenv("GITHUB_EVENT_PATH", str(event_file))

runner = testing.CliRunner()
result = runner.invoke(ci_cli.git_refs, [])
assert result.exit_code == 0, result.output

content = output_file.read_text()
expected = """base=abc123
head=xyz987
"""
assert content == expected