from __future__ import annotations import subprocess from pathlib import Path from unittest.mock import patch import pytest from click import ClickException from click.testing import CliRunner import devx.ci.detect_release_commit as detect_release_commit class TestGetCommitMessage: def test_success(self) -> None: mock_result = subprocess.CompletedProcess(args=[], returncode=0, stdout="feat: add feature\n", stderr="") with patch("subprocess.run", return_value=mock_result): assert detect_release_commit.get_commit_message() == "feat: add feature" def test_failure(self) -> None: mock_result = subprocess.CompletedProcess(args=[], returncode=1, stdout="", stderr="git error") with patch("subprocess.run", return_value=mock_result): with pytest.raises(ClickException, match="git log failed"): detect_release_commit.get_commit_message() class TestIsReleaseCommit: def test_release_commit(self) -> None: assert detect_release_commit.is_release_commit("release: v1.0.0 [skip ci]") is True def test_release_commit_no_skip(self) -> None: assert detect_release_commit.is_release_commit("release: v0.1.0") is True def test_regular_commit(self) -> None: assert detect_release_commit.is_release_commit("feat: add feature") is False def test_empty(self) -> None: assert detect_release_commit.is_release_commit("") is False class TestIsBadgeCommit: def test_badge_commit(self) -> None: assert detect_release_commit.is_badge_commit("chore: update badge URLs to commit abc123 [skip ci]") is True def test_regular_chore(self) -> None: assert detect_release_commit.is_badge_commit("chore: cleanup deps") is False def test_empty(self) -> None: assert detect_release_commit.is_badge_commit("") is False class TestIsAutomatedCommit: def test_release_is_automated(self) -> None: assert detect_release_commit.is_automated_commit("release: v1.0.0 [skip ci]") is True def test_badge_is_automated(self) -> None: assert detect_release_commit.is_automated_commit("chore: update badge URLs to commit abc123 [skip ci]") is True def test_regular_is_not_automated(self) -> None: assert detect_release_commit.is_automated_commit("OBL-INFRA-363: fix: something") is False def test_empty(self) -> None: assert detect_release_commit.is_automated_commit("") is False class TestWriteGithubOutput: def test_write(self, tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None: gh_file = tmp_path / "output.txt" monkeypatch.setenv("GITHUB_OUTPUT", str(gh_file)) detect_release_commit.write_github_output("is-release", "true") with open(gh_file) as f: assert f.read() == "is-release=true\n" def test_no_env(self, monkeypatch: pytest.MonkeyPatch) -> None: monkeypatch.delenv("GITHUB_OUTPUT", raising=False) with pytest.raises(ClickException, match="GITHUB_OUTPUT"): detect_release_commit.write_github_output("is-release", "true") class TestMain: def test_release_commit(self, tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None: gh_file = tmp_path / "output.txt" monkeypatch.setenv("GITHUB_OUTPUT", str(gh_file)) with patch.object(detect_release_commit, "get_commit_message", return_value="release: v1.0.0 [skip ci]"): runner = CliRunner() result = runner.invoke(detect_release_commit.main, []) assert result.exit_code == 0 assert "Release commit" in result.output with open(gh_file) as f: content = f.read() assert "is-release=true" in content assert "is-automated=true" in content def test_badge_commit(self, tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None: gh_file = tmp_path / "output.txt" monkeypatch.setenv("GITHUB_OUTPUT", str(gh_file)) with patch.object( detect_release_commit, "get_commit_message", return_value="chore: update badge URLs to commit abc123 [skip ci]", ): runner = CliRunner() result = runner.invoke(detect_release_commit.main, []) assert result.exit_code == 0 assert "Automated CI commit" in result.output with open(gh_file) as f: content = f.read() assert "is-release=false" in content assert "is-automated=true" in content def test_regular_commit(self, tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None: gh_file = tmp_path / "output.txt" monkeypatch.setenv("GITHUB_OUTPUT", str(gh_file)) with patch.object(detect_release_commit, "get_commit_message", return_value="feat: add feature"): runner = CliRunner() result = runner.invoke(detect_release_commit.main, []) assert result.exit_code == 0 assert "Regular merge commit" in result.output with open(gh_file) as f: content = f.read() assert "is-release=false" in content assert "is-automated=false" in content