From e1e8f6f4e846329ffdd9841916edcc3d5476db30 Mon Sep 17 00:00:00 2001 From: Sorin Sbarnea Date: Mon, 18 Nov 2024 22:06:36 +0000 Subject: [PATCH] Make git dirty an error only under CI/CD pipelines (#120) --- src/tox_extra/hooks.py | 21 +++++++++++++++------ tests/test_plugin.py | 5 +++-- 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/src/tox_extra/hooks.py b/src/tox_extra/hooks.py index d37feba..70c7cb0 100644 --- a/src/tox_extra/hooks.py +++ b/src/tox_extra/hooks.py @@ -2,6 +2,7 @@ from __future__ import annotations +import logging import os import pathlib import shutil @@ -22,10 +23,14 @@ from tox.tox_env.api import ToxEnv -MSG_GIT_DIRTY = ( - "exit code 1 due to 'git status -s' reporting dirty. " - "That should not happen regardless if status is passed, failed or aborted. " - "Modify .gitignore file to avoid this." +logger = logging.getLogger(__name__) +WARNING_MSG_GIT_DIRTY = ( + "'git status -s' reported dirty. " + "Modify .gitignore file as this will cause an error under CI/CD pipelines." +) + +ERROR_MSG_GIT_DIRTY = ( + "::error title=tox-extra detected git dirty status:: " + WARNING_MSG_GIT_DIRTY ) @@ -37,7 +42,9 @@ def is_git_dirty(path: str) -> bool: try: repo = git.Repo(pathlib.Path.cwd()) if repo.is_dirty(untracked_files=True): - os.system(f"{git_path} status -s") # noqa: S605 + # stderr is hidden to avoid noise like occasional: + # warning: untracked cache is disabled on this system or location + os.system(f"{git_path} status -s 2>/dev/null") # noqa: S605 # We want to display long diff only on non-interactive shells, # like CI/CD pipelines because on local shell, the user can # decide to run it himself if the status line was not enogh. @@ -95,4 +102,6 @@ def tox_after_run_commands( """Hook that runs after test commands.""" allow_dirty = getattr(tox_env.options, "allow_dirty", False) if not allow_dirty and is_git_dirty("."): - raise Fail(MSG_GIT_DIRTY) + if os.environ.get("CI") == "true": + raise Fail(ERROR_MSG_GIT_DIRTY) + logger.error(WARNING_MSG_GIT_DIRTY) diff --git a/tests/test_plugin.py b/tests/test_plugin.py index f749653..49bf14e 100644 --- a/tests/test_plugin.py +++ b/tests/test_plugin.py @@ -4,6 +4,7 @@ from pathlib import Path from runpy import run_module from subprocess import PIPE, check_output, run +from unittest.mock import patch import pytest @@ -75,7 +76,7 @@ def test_fail_if_dirty(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None: # check tox is failing while dirty # We use runpy to call tox in order to assure that coverage happens, as # running a subprocess would prevent it from working. - with pytest.raises(SystemExit) as exc: + with patch.dict("os.environ", {"CI": "true"}), pytest.raises(SystemExit) as exc: run_module("tox", run_name="__main__", alter_sys=True) assert exc.type is SystemExit assert exc.value.code == 1 @@ -85,7 +86,7 @@ def test_fail_if_dirty(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None: run("git commit -m 'Add untracked files'", shell=True, check=True) # check that tox is now passing - with pytest.raises(SystemExit) as exc: + with patch.dict("os.environ", {"CI": "true"}), pytest.raises(SystemExit) as exc: run_module("tox", run_name="__main__", alter_sys=True) assert exc.type is SystemExit assert exc.value.code == 0