diff --git a/changes/1915.feature.rst b/changes/1915.feature.rst new file mode 100644 index 000000000..4c245ee11 --- /dev/null +++ b/changes/1915.feature.rst @@ -0,0 +1 @@ +When the available version if Git is older than v2.17.0, an error message now prompts the user to upgrade their install of Git to proceed. diff --git a/src/briefcase/integrations/git.py b/src/briefcase/integrations/git.py index 55b83c59f..976f5af02 100644 --- a/src/briefcase/integrations/git.py +++ b/src/briefcase/integrations/git.py @@ -10,6 +10,9 @@ class Git(Tool): name = "git" full_name = "Git" + MIN_VERSION = (2, 17, 0) + GIT_URL = "https://git-scm.com/" + @classmethod def verify_install(cls, tools: ToolCache, **kwargs) -> ModuleType: """Verify if git is installed. @@ -42,14 +45,14 @@ def verify_install(cls, tools: ToolCache, **kwargs) -> ModuleType: # for this. if tools.host_os == "Darwin": raise BriefcaseCommandError( - """\ + f"""\ Briefcase requires git, but it is not installed. Xcode provides git; you should be shown a dialog prompting you to install Xcode and the Command Line Developer Tools. Select "Install" to install the Command Line Developer Tools. Alternatively, you can visit: - https://git-scm.com/ + {cls.GIT_URL} to download and install git manually. @@ -60,10 +63,10 @@ def verify_install(cls, tools: ToolCache, **kwargs) -> ModuleType: else: raise BriefcaseCommandError( - """\ + f"""\ Briefcase requires git, but it is not installed (or is not on your PATH). Visit: - https://git-scm.com/ + {cls.GIT_URL} to download and install git manually. @@ -72,6 +75,16 @@ def verify_install(cls, tools: ToolCache, **kwargs) -> ModuleType: """ ) from e + installed_version = git.cmd.Git().version_info + if installed_version < cls.MIN_VERSION: + raise BriefcaseCommandError( + f"At least Git v{'.'.join(map(str, cls.MIN_VERSION))} is required; " + f"however, v{'.'.join(map(str, installed_version))} is installed.\n" + "\n" + f"Please update Git; downloads are available at {cls.GIT_URL}.", + skip_logfile=True, + ) + tools.logger.configure_stdlib_logging("git") tools.git = git diff --git a/tests/integrations/git/test_Git__verify.py b/tests/integrations/git/test_Git__verify.py index 0a8e6ae08..dceab6bfe 100644 --- a/tests/integrations/git/test_Git__verify.py +++ b/tests/integrations/git/test_Git__verify.py @@ -1,9 +1,11 @@ import logging +from unittest.mock import PropertyMock +import git import pytest from briefcase.console import LogLevel, RichLoggingHandler -from briefcase.exceptions import UnsupportedHostError +from briefcase.exceptions import BriefcaseCommandError, UnsupportedHostError from briefcase.integrations.git import Git @@ -49,3 +51,31 @@ def test_git_stdlib_logging(mock_tools, logging_level, handler_expected): # reset handlers since they are persistent logging.getLogger("git").handlers.clear() + + +@pytest.mark.parametrize("version", [(2, 17, 0), (2, 45, 2), (3, 0, 0)]) +def test_git_version_valid(mock_tools, version, monkeypatch): + """A valid Git version is accepted.""" + monkeypatch.setattr( + git.cmd.Git, + "version_info", + PropertyMock(return_value=version), + ) + + Git.verify(mock_tools) + + +@pytest.mark.parametrize("version", [(2, 16, 6), (2, 13, 2), (1, 0, 0)]) +def test_git_version_invalid(mock_tools, version, monkeypatch): + """An invalid Git version is rejected.""" + monkeypatch.setattr( + git.cmd.Git, + "version_info", + PropertyMock(return_value=version), + ) + + with pytest.raises( + BriefcaseCommandError, + match=f"At least Git v2.17.0 is required; however, v{'.'.join(map(str, version))} is installed.", + ): + Git.verify(mock_tools)