Public Access
DEVX-57: feat: add FORCE_DEPLOY env var, --git flag, --from-tag flag
Post-merge / detect-type (push) Successful in 13s
Post-merge / configure-repo (push) Successful in 12s
Post-merge / validate-commit-msg (push) Successful in 13s
Post-merge / release (push) Successful in 58s
Post-merge / vikunja (push) Successful in 19s
Post-merge / badges (push) Successful in 55s
Post-merge / sync-wiki (push) Successful in 1m18s
Post-merge / detect-type (push) Successful in 13s
Post-merge / configure-repo (push) Successful in 12s
Post-merge / validate-commit-msg (push) Successful in 13s
Post-merge / release (push) Successful in 58s
Post-merge / vikunja (push) Successful in 19s
Post-merge / badges (push) Successful in 55s
Post-merge / sync-wiki (push) Successful in 1m18s
This commit was merged in pull request #94.
This commit is contained in:
@@ -788,3 +788,49 @@ class TestGithubOutput:
|
||||
content = gh_file.read_text()
|
||||
assert "user-facing-changed=true" in content
|
||||
assert "ansible-changed" not in content
|
||||
|
||||
@patch("devx.ci.classify_changes._get_classifier")
|
||||
def test_force_deploy_env_var(self, mock_clf: MagicMock, tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
|
||||
"""FORCE_DEPLOY=true env var activates force mode without --force flag."""
|
||||
mock_clf.return_value = self._make_classifier_with_ansible()
|
||||
gh_file = tmp_path / "output.txt"
|
||||
monkeypatch.setenv("GITHUB_OUTPUT", str(gh_file))
|
||||
monkeypatch.setenv("FORCE_DEPLOY", "true")
|
||||
runner = CliRunner()
|
||||
result = runner.invoke(main, ["--github-output"])
|
||||
assert result.exit_code == 0
|
||||
content = gh_file.read_text()
|
||||
assert "user-facing-changed=true" in content
|
||||
assert "ansible-changed=true" in content
|
||||
|
||||
@patch("devx.ci.classify_changes._get_classifier")
|
||||
def test_force_deploy_env_var_false(
|
||||
self, mock_clf: MagicMock, tmp_path: Path, monkeypatch: pytest.MonkeyPatch
|
||||
) -> None:
|
||||
"""FORCE_DEPLOY=false does not activate force mode."""
|
||||
mock_clf.return_value = self._make_classifier_with_ansible()
|
||||
gh_file = tmp_path / "output.txt"
|
||||
monkeypatch.setenv("GITHUB_OUTPUT", str(gh_file))
|
||||
monkeypatch.setenv("FORCE_DEPLOY", "false")
|
||||
with patch.object(classify_changes_mod, "get_latest_tag", return_value="v1.0"):
|
||||
with patch.object(classify_changes_mod, "get_changed_files", return_value=[]):
|
||||
runner = CliRunner()
|
||||
result = runner.invoke(main, ["--github-output"])
|
||||
assert result.exit_code == 0
|
||||
content = gh_file.read_text()
|
||||
assert "user-facing-changed=false" in content
|
||||
|
||||
@patch("devx.ci.classify_changes._get_classifier")
|
||||
def test_force_flag_overrides_env_var(
|
||||
self, mock_clf: MagicMock, tmp_path: Path, monkeypatch: pytest.MonkeyPatch
|
||||
) -> None:
|
||||
"""--force flag works even when FORCE_DEPLOY=false."""
|
||||
mock_clf.return_value = self._make_classifier_with_ansible()
|
||||
gh_file = tmp_path / "output.txt"
|
||||
monkeypatch.setenv("GITHUB_OUTPUT", str(gh_file))
|
||||
monkeypatch.setenv("FORCE_DEPLOY", "false")
|
||||
runner = CliRunner()
|
||||
result = runner.invoke(main, ["--github-output", "--force"])
|
||||
assert result.exit_code == 0
|
||||
content = gh_file.read_text()
|
||||
assert "user-facing-changed=true" in content
|
||||
|
||||
@@ -11,6 +11,8 @@ from devx.ci.publish import (
|
||||
_default_gitea_registry_url,
|
||||
build_package,
|
||||
generate_release_notes,
|
||||
get_latest_tag,
|
||||
is_release_commit,
|
||||
main,
|
||||
publish_to_gitea_registry,
|
||||
publish_to_pypi,
|
||||
@@ -385,5 +387,82 @@ class TestMain:
|
||||
runner = CliRunner()
|
||||
result = runner.invoke(main, ["v1.0.0", "owner/repo"])
|
||||
assert result.exit_code == 0
|
||||
assert "Gitea release v1.0.0 created" in result.output
|
||||
mock_tea.create_release.assert_called_once()
|
||||
|
||||
|
||||
class TestFromTag:
|
||||
def test_get_latest_tag_success(self) -> None:
|
||||
import subprocess
|
||||
|
||||
with patch("devx.ci.publish.subprocess.run") as mock_run:
|
||||
mock_run.return_value = subprocess.CompletedProcess(args=[], returncode=0, stdout="v1.2.3\n")
|
||||
result = get_latest_tag()
|
||||
assert result == "v1.2.3"
|
||||
|
||||
def test_get_latest_tag_no_tags(self) -> None:
|
||||
import subprocess
|
||||
|
||||
with patch("devx.ci.publish.subprocess.run") as mock_run:
|
||||
mock_run.side_effect = subprocess.CalledProcessError(1, [])
|
||||
result = get_latest_tag()
|
||||
assert result is None
|
||||
|
||||
def test_is_release_commit_match(self) -> None:
|
||||
import subprocess
|
||||
|
||||
with patch("devx.ci.publish.subprocess.run") as mock_run:
|
||||
mock_run.return_value = subprocess.CompletedProcess(
|
||||
args=[], returncode=0, stdout="release: v1.2.3 [skip ci]\n"
|
||||
)
|
||||
result = is_release_commit("v1.2.3")
|
||||
assert result is True
|
||||
|
||||
def test_is_release_commit_no_match(self) -> None:
|
||||
import subprocess
|
||||
|
||||
with patch("devx.ci.publish.subprocess.run") as mock_run:
|
||||
mock_run.return_value = subprocess.CompletedProcess(args=[], returncode=0, stdout="feat: add feature\n")
|
||||
result = is_release_commit("v1.2.3")
|
||||
assert result is False
|
||||
|
||||
def test_is_release_commit_git_error(self) -> None:
|
||||
import subprocess
|
||||
|
||||
with patch("devx.ci.publish.subprocess.run") as mock_run:
|
||||
mock_run.side_effect = subprocess.CalledProcessError(1, [])
|
||||
result = is_release_commit("v1.2.3")
|
||||
assert result is False
|
||||
|
||||
@patch("devx.ci.publish.get_latest_tag", return_value=None)
|
||||
def test_from_tag_no_tag_skips(self, _mock: MagicMock) -> None:
|
||||
runner = CliRunner()
|
||||
result = runner.invoke(main, ["--from-tag", "--skip-build", "", "owner/repo"])
|
||||
assert result.exit_code == 0
|
||||
assert "No tag found" in result.output
|
||||
|
||||
@patch("devx.ci.publish.is_release_commit", return_value=False)
|
||||
@patch("devx.ci.publish.get_latest_tag", return_value="v1.0.0")
|
||||
def test_from_tag_not_release_commit_skips(self, _mock_tag: MagicMock, _mock_rel: MagicMock) -> None:
|
||||
runner = CliRunner()
|
||||
result = runner.invoke(main, ["--from-tag", "--skip-build", "", "owner/repo"])
|
||||
assert result.exit_code == 0
|
||||
assert "not a release commit" in result.output
|
||||
|
||||
@patch("devx.ci.publish.is_release_commit", return_value=True)
|
||||
@patch("devx.ci.publish.get_latest_tag", return_value="v1.0.0")
|
||||
def test_from_tag_publishes(self, _mock_tag: MagicMock, _mock_rel: MagicMock) -> None:
|
||||
with patch.dict("os.environ", {"REPO_TOKEN": "fake"}):
|
||||
with patch("devx.ci.publish.TeaCLI") as mock_tea_cls:
|
||||
mock_tea = MagicMock()
|
||||
mock_tea.list_releases.return_value = []
|
||||
mock_tea_cls.return_value = mock_tea
|
||||
with patch("devx.ci.publish.generate_release_notes", return_value="notes"):
|
||||
runner = CliRunner()
|
||||
result = runner.invoke(main, ["--from-tag", "--skip-build", "", "owner/repo"])
|
||||
assert result.exit_code == 0
|
||||
assert "Publishing release v1.0.0" in result.output
|
||||
|
||||
def test_no_tag_no_from_tag_raises(self) -> None:
|
||||
runner = CliRunner()
|
||||
result = runner.invoke(main, ["", "owner/repo", "--skip-build"])
|
||||
assert result.exit_code != 0
|
||||
assert "Tag is required" in result.output
|
||||
|
||||
@@ -7,7 +7,7 @@ from unittest.mock import patch
|
||||
|
||||
from click.testing import CliRunner
|
||||
|
||||
from devx.ci.validate_commit_msg import first_line, get_branch, main
|
||||
from devx.ci.validate_commit_msg import first_line, get_branch, get_latest_commit_msg, main
|
||||
from devx.config import CONVENTIONAL_RE, TASK_ID_RE
|
||||
|
||||
|
||||
@@ -126,7 +126,7 @@ class TestMain:
|
||||
def test_usage_message_without_args(self) -> None:
|
||||
runner = CliRunner()
|
||||
result = runner.invoke(main, [])
|
||||
assert result.exit_code == 2
|
||||
assert result.exit_code != 0
|
||||
|
||||
def test_branch_override_accepts_master_commit(self) -> None:
|
||||
"""--branch master overrides branch detection (for CI use)."""
|
||||
@@ -257,3 +257,45 @@ def test_main_module_block() -> None:
|
||||
namespace["main"]([msg_path], standalone_mode=False)
|
||||
|
||||
os.unlink(msg_path)
|
||||
|
||||
|
||||
class TestGitMode:
|
||||
def test_git_flag_reads_from_git(self, tmp_path) -> None:
|
||||
with patch("devx.ci.validate_commit_msg.get_latest_commit_msg", return_value="feat: add feature"):
|
||||
with patch("devx.ci.validate_commit_msg.get_branch", return_value="feature-branch"):
|
||||
runner = CliRunner()
|
||||
result = runner.invoke(main, ["--git"])
|
||||
assert result.exit_code == 0
|
||||
|
||||
def test_git_flag_master_valid(self) -> None:
|
||||
msg = "DEVX-24: fix: resolve timeout"
|
||||
with patch("devx.ci.validate_commit_msg.get_latest_commit_msg", return_value=msg):
|
||||
with patch("devx.ci.validate_commit_msg.get_branch", return_value="master"):
|
||||
runner = CliRunner()
|
||||
result = runner.invoke(main, ["--git", "--branch", "master"])
|
||||
assert result.exit_code == 0
|
||||
|
||||
def test_git_flag_master_invalid(self) -> None:
|
||||
msg = "fix: resolve timeout"
|
||||
with patch("devx.ci.validate_commit_msg.get_latest_commit_msg", return_value=msg):
|
||||
with patch("devx.ci.validate_commit_msg.get_branch", return_value="master"):
|
||||
runner = CliRunner()
|
||||
result = runner.invoke(main, ["--git", "--branch", "master"])
|
||||
assert result.exit_code != 0
|
||||
|
||||
def test_no_file_no_git_raises(self) -> None:
|
||||
runner = CliRunner()
|
||||
result = runner.invoke(main, ["--branch", "master"])
|
||||
assert result.exit_code != 0
|
||||
|
||||
def test_get_latest_commit_msg_success(self) -> None:
|
||||
with patch("subprocess.run") as mock_run:
|
||||
mock_run.return_value = subprocess.CompletedProcess(args=[], returncode=0, stdout="feat: test\n\nBody")
|
||||
result = get_latest_commit_msg()
|
||||
assert result == "feat: test\n\nBody"
|
||||
|
||||
def test_stdin_input(self) -> None:
|
||||
with patch("devx.ci.validate_commit_msg.get_branch", return_value="feature-branch"):
|
||||
runner = CliRunner()
|
||||
result = runner.invoke(main, input="feat: add feature\n", args=["-", "--branch", "feature-branch"])
|
||||
assert result.exit_code == 0
|
||||
|
||||
Reference in New Issue
Block a user