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
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,9 @@

def _iter_files(pattern: str) -> typ.Iterable[Path]:
root = Path()
for path in root.glob(pattern):
for path in sorted(
root.glob(pattern), key=lambda candidate: tuple(candidate.parts)
):
if not path.is_file():
continue
parts = set(path.parts)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,4 @@ def test_install_step_uses_python_version_input() -> None:
data = _load_action()
steps = data["runs"]["steps"]
install_step = next(step for step in steps if step["name"] == "Install Python")
assert install_step["run"] == 'uv python install "${{ inputs.python-version }}"'
assert 'uv python install "${{ inputs.python-version }}"' in install_step["run"]
Original file line number Diff line number Diff line change
Expand Up @@ -189,3 +189,25 @@ def fake_urlopen(request: typ.Any, timeout: float = 30) -> DummyResponse: # noq
assert len(attempts) == 3
captured = capsys.readouterr()
assert "GitHub Release 'ok' is published." in captured.out


def test_retries_then_fail(
monkeypatch: pytest.MonkeyPatch,
module: ModuleType,
capsys: pytest.CaptureFixture[str],
fake_token: str,
) -> None:
"""Abort after exhausting retries when transient errors persist."""

def failing_urlopen(request: typ.Any, timeout: float = 30) -> typ.Any: # noqa: ANN401
_ = request, timeout
raise module.urllib.error.URLError("temporary")

monkeypatch.setattr(module.urllib.request, "urlopen", failing_urlopen)
monkeypatch.setattr(module.time, "sleep", lambda _: None)

with pytest.raises(module.typer.Exit):
module.main(tag="v1.0.0", token=fake_token, repo="owner/repo")

captured = capsys.readouterr()
assert "temporary" in captured.err or "fetch" in captured.err
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,47 @@ def test_multiple_toml_files_mixed_validity(
assert "!= tag version" in captured.err


def test_iter_files_discovers_paths_in_deterministic_order(
project_root: Path,
module: ModuleType,
monkeypatch: pytest.MonkeyPatch,
) -> None:
"""Ensure TOML discovery yields paths in a stable, sorted order."""
_write_pyproject(
project_root / "pkg_b",
"""
[project]
name = "pkg-b"
version = "1.0.0"
""",
)
_write_pyproject(
project_root / "pkg_a",
"""
[project]
name = "pkg-a"
version = "1.0.0"
""",
)

first = project_root / "pkg_a" / "pyproject.toml"
second = project_root / "pkg_b" / "pyproject.toml"

def fake_glob(
self: Path,
pattern: str,
) -> typ.Iterator[Path]:
_ = self
assert pattern == "**/pyproject.toml"
return iter((second, first))

monkeypatch.setattr(module.Path, "glob", fake_glob, raising=False)

discovered = list(module._iter_files("**/pyproject.toml"))

assert discovered == [first, second]


@pytest.mark.parametrize("value", ["true", "TRUE", "Yes", "1", "on"])
def test_parse_bool_truthy_values(module: ModuleType, value: str) -> None:
"""Treat recognised truthy values as ``True`` for configuration flags."""
Expand Down
43 changes: 43 additions & 0 deletions .github/actions/rust-build-release/tests/test_target_install.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
CMD_MOX_UNSUPPORTED,
_register_cross_version_stub,
_register_docker_info_stub,
_register_podman_info_stub,
_register_rustup_toolchain_stub,
)

Expand Down Expand Up @@ -144,6 +145,48 @@ def fake_which(name: str) -> str | None:
assert build_cmd[1] == f"+{default_toolchain}-x86_64-unknown-linux-gnu"


@CMD_MOX_UNSUPPORTED
def test_falls_back_to_cargo_when_podman_unusable(
main_module: ModuleType,
cross_module: ModuleType,
runtime_module: ModuleType,
module_harness: HarnessFactory,
cmd_mox: CmdMox,
) -> None:
"""Fallback to cargo when podman runtime detection fails quickly (issue #97)."""

cross_env = module_harness(cross_module)
runtime_env = module_harness(runtime_module)
app_env = module_harness(main_module)

default_toolchain = main_module.DEFAULT_TOOLCHAIN
rustup_stdout = f"{default_toolchain}-x86_64-unknown-linux-gnu\n"
cross_path = _register_cross_version_stub(cmd_mox)
rustup_path = _register_rustup_toolchain_stub(cmd_mox, rustup_stdout)
podman_path = _register_podman_info_stub(cmd_mox, exit_code=1)

def fake_which(name: str) -> str | None:
if name == "podman":
return podman_path
if name == "cross":
return cross_path
return rustup_path if name == "rustup" else None

cross_env.patch_shutil_which(fake_which)
runtime_env.patch_shutil_which(fake_which)
app_env.patch_shutil_which(fake_which)

app_env.patch_attr("ensure_cross", lambda required: (cross_path, required))
app_env.patch_attr("runtime_available", runtime_module.runtime_available)

cmd_mox.replay()
main_module.main("x86_64-unknown-linux-gnu", default_toolchain)
cmd_mox.verify()

assert any(cmd[0] == "cargo" for cmd in app_env.calls)
assert all(cmd[0] != "cross" for cmd in app_env.calls)


@pytest.mark.parametrize(
"target",
[
Expand Down
7 changes: 5 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,12 @@ jobs:
if: matrix.os == 'ubuntu-latest'
# v2.0.2
uses: oven-sh/setup-bun@735343b667d3e6f658f44d0eca948eb6282f2b76
- name: Install action-validator
- name: Validate GitHub Actions metadata
if: matrix.os == 'ubuntu-latest'
run: bun install -g @action-validator/core @action-validator/cli
run: |
set -euxo pipefail
find . -type f \( -name 'action.yml' -o -name 'action.yaml' \) -print0 \
| xargs -0 -n1 bunx -y @action-validator/cli validate
shell: bash
- name: Check formatting
if: matrix.os == 'ubuntu-latest'
Expand Down
10 changes: 10 additions & 0 deletions conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,16 @@ def _register_docker_info_stub(
return _shim_path(cmd_mox, "docker")


def _register_podman_info_stub(
cmd_mox: CmdMox,
*,
exit_code: int = 0,
) -> str: # pragma: no cover - helper
"""Register a stub for ``podman info`` and return the shim path."""
cmd_mox.stub("podman").with_args("info").returns(exit_code=exit_code)
return _shim_path(cmd_mox, "podman")


if sys.platform != "win32": # pragma: win32 no cover - windows lacks cmd-mox
pytest_plugins = ("cmd_mox.pytest_plugin",)
else:
Expand Down
Loading