mirror of
https://github.com/home-assistant/core.git
synced 2026-07-04 05:05:38 +01:00
165 lines
5.0 KiB
Python
165 lines
5.0 KiB
Python
"""Tests for script.check_requirements.__main__ (CLI entry point)."""
|
|
|
|
import json
|
|
from pathlib import Path
|
|
|
|
import pytest
|
|
|
|
from script.check_requirements import __main__ as main_mod
|
|
from script.check_requirements.gate import GateDecision
|
|
from script.check_requirements.pypi import ProvenanceResult, PypiPackageInfo
|
|
|
|
_SHA = "abc1234def5678abc1234def5678abc1234def56"
|
|
|
|
|
|
def _write_bump_diff(path: Path) -> None:
|
|
path.write_text(
|
|
"diff --git a/requirements_all.txt b/requirements_all.txt\n"
|
|
"--- a/requirements_all.txt\n"
|
|
"+++ b/requirements_all.txt\n"
|
|
"@@ -1 +1 @@\n"
|
|
"-pkg==1.0.0\n"
|
|
"+pkg==1.1.0\n",
|
|
encoding="utf-8",
|
|
)
|
|
|
|
|
|
def _mock_pypi(monkeypatch: pytest.MonkeyPatch) -> None:
|
|
monkeypatch.setattr(
|
|
"script.check_requirements.runner.fetch_package_info",
|
|
lambda name, version: PypiPackageInfo(
|
|
project_urls={"Source": "https://github.com/example/pkg"},
|
|
repo_url="https://github.com/example/pkg",
|
|
file_provenance_urls=["whatever"],
|
|
found=True,
|
|
),
|
|
)
|
|
monkeypatch.setattr(
|
|
"script.check_requirements.runner.check_provenance",
|
|
lambda info: ProvenanceResult(
|
|
has_attestation=True,
|
|
publisher_kind="GitHub",
|
|
recognized_publisher=True,
|
|
detail="ok",
|
|
),
|
|
)
|
|
|
|
|
|
def test_main_writes_artifact(
|
|
tmp_path: Path,
|
|
monkeypatch: pytest.MonkeyPatch,
|
|
capsys: pytest.CaptureFixture[str],
|
|
) -> None:
|
|
"""When the gate runs the checks, the CLI writes a non-skipped artifact."""
|
|
diff_file = tmp_path / "diff.patch"
|
|
_write_bump_diff(diff_file)
|
|
output_file = tmp_path / "results.json"
|
|
monkeypatch.setattr(
|
|
main_mod, "_resolve_skip", lambda pr, sha: GateDecision(False, "running checks")
|
|
)
|
|
_mock_pypi(monkeypatch)
|
|
|
|
exit_code = main_mod.main(
|
|
[
|
|
"--pr-number",
|
|
"42",
|
|
"--head-sha",
|
|
_SHA,
|
|
"--diff",
|
|
str(diff_file),
|
|
"--output",
|
|
str(output_file),
|
|
]
|
|
)
|
|
assert exit_code == 0
|
|
|
|
payload = json.loads(output_file.read_text(encoding="utf-8"))
|
|
assert payload["skip_aw"] is False
|
|
assert payload["pr_number"] == 42
|
|
assert payload["head_sha"] == _SHA
|
|
assert payload["packages"][0]["name"] == "pkg"
|
|
assert (
|
|
f"https://github.com/home-assistant/core/commit/{_SHA}"
|
|
in payload["rendered_comment"]
|
|
)
|
|
assert "check_requirements: 1 package change(s)" in capsys.readouterr().err
|
|
|
|
|
|
def test_main_skips_but_still_writes_artifact(
|
|
tmp_path: Path,
|
|
monkeypatch: pytest.MonkeyPatch,
|
|
) -> None:
|
|
"""When the gate skips, no checks run but a skip-flagged artifact is written."""
|
|
diff_file = tmp_path / "diff.patch"
|
|
_write_bump_diff(diff_file)
|
|
output_file = tmp_path / "results.json"
|
|
monkeypatch.setattr(
|
|
main_mod, "_resolve_skip", lambda pr, sha: GateDecision(True, "nothing changed")
|
|
)
|
|
|
|
# The checks must not run when skipping; make them explode if they do.
|
|
def _boom(name: str, version: str) -> None:
|
|
raise AssertionError("checks must not run when the gate skips")
|
|
|
|
monkeypatch.setattr("script.check_requirements.runner.fetch_package_info", _boom)
|
|
|
|
exit_code = main_mod.main(
|
|
[
|
|
"--pr-number",
|
|
"42",
|
|
"--head-sha",
|
|
_SHA,
|
|
"--diff",
|
|
str(diff_file),
|
|
"--output",
|
|
str(output_file),
|
|
]
|
|
)
|
|
assert exit_code == 0
|
|
payload = json.loads(output_file.read_text(encoding="utf-8"))
|
|
assert payload == {
|
|
"version": 1,
|
|
"pr_number": 42,
|
|
"skip_aw": True,
|
|
"head_sha": _SHA,
|
|
"needs_agent": False,
|
|
"packages": [],
|
|
"rendered_comment": "",
|
|
}
|
|
|
|
|
|
def test_resolve_skip_without_credentials_runs(monkeypatch: pytest.MonkeyPatch) -> None:
|
|
"""Missing repo/token falls open (runs) without ever calling the gate."""
|
|
monkeypatch.delenv("GITHUB_REPOSITORY", raising=False)
|
|
monkeypatch.delenv("GITHUB_TOKEN", raising=False)
|
|
|
|
def _boom(*args: object, **kwargs: object) -> None:
|
|
raise AssertionError("decide_skip must not be called without credentials")
|
|
|
|
monkeypatch.setattr(main_mod, "decide_skip", _boom)
|
|
assert main_mod._resolve_skip(42, _SHA).skip is False
|
|
|
|
|
|
def test_main_missing_diff_file_exits(
|
|
tmp_path: Path,
|
|
capsys: pytest.CaptureFixture[str],
|
|
) -> None:
|
|
"""A missing --diff file triggers argparse's error path (SystemExit)."""
|
|
output_file = tmp_path / "results.json"
|
|
missing_diff = tmp_path / "does-not-exist.patch"
|
|
|
|
with pytest.raises(SystemExit) as excinfo:
|
|
main_mod.main(
|
|
[
|
|
"--pr-number",
|
|
"1",
|
|
"--diff",
|
|
str(missing_diff),
|
|
"--output",
|
|
str(output_file),
|
|
]
|
|
)
|
|
assert excinfo.value.code == 2 # argparse error exit
|
|
captured = capsys.readouterr()
|
|
assert "not found" in captured.err
|