diff --git a/changes/2873.feature.md b/changes/2873.feature.md new file mode 100644 index 000000000..71853ad86 --- /dev/null +++ b/changes/2873.feature.md @@ -0,0 +1 @@ +Added a warning when `description` exceeds 80 characters, prompting users to use `long_description` for longer text. Long descriptions can cause icon corruption in MSI installers. \ No newline at end of file diff --git a/src/briefcase/commands/base.py b/src/briefcase/commands/base.py index 893b32a43..e498b2f37 100644 --- a/src/briefcase/commands/base.py +++ b/src/briefcase/commands/base.py @@ -1122,6 +1122,22 @@ def parse_config(self, filename, overrides): msg=f"Configuration for '{app_name}'", ) + # Warn if the app description is longer than 80 characters. + # Long descriptions can cause MSI shortcut icon corruption + # (the description field is limited to 256 chars in Windows + # shortcuts, and the description length overflows into the + # icon path prefix). Users should use the long_description + # field for longer text. + if len(self.apps[app_name].description) > 80: + self.console.warning( + f"The description for '{app_name}' is " + f"{len(self.apps[app_name].description)} characters. " + "Briefcase descriptions should be no more than 80 " + "characters. Long descriptions may cause icon display " + "issues on some platforms (e.g., MSI installers). " + "Use the `long_description` field for longer text." + ) + except OSError as e: raise BriefcaseConfigError( f"""\ diff --git a/tests/commands/base/test_parse_config.py b/tests/commands/base/test_parse_config.py index c11f5fe38..1b32f7356 100644 --- a/tests/commands/base/test_parse_config.py +++ b/tests/commands/base/test_parse_config.py @@ -3,6 +3,13 @@ from briefcase.exceptions import BriefcaseConfigError +from unittest.mock import MagicMock + +import pytest +from packaging.version import Version + +from briefcase.exceptions import BriefcaseConfigError + from ...utils import create_file @@ -223,3 +230,56 @@ def test_parse_config_with_invalid_override(base_command): "version": "not-a-version-number", }, ) + + +def test_short_description_no_warning(base_command): + """A config with a short description (<=80 chars) does not trigger a warning.""" + filename = base_command.base_path / "pyproject.toml" + create_file( + filename, + """ + [tool.briefcase] + project_name = "Sample project" + version = "1.2.3" + description = "A sample app" + bundle = "org.beeware" + license = "MIT" + + [tool.briefcase.app.my-app] + sources = ['src/my_app'] + """, + ) + + base_command.console.warning = MagicMock() + base_command.parse_config(filename, {}) + + base_command.console.warning.assert_not_called() + + +def test_long_description_warning(base_command): + """A config with a long description (>80 chars) triggers a warning.""" + long_desc = "x" * 81 + filename = base_command.base_path / "pyproject.toml" + create_file( + filename, + f""" + [tool.briefcase] + project_name = "Sample project" + version = "1.2.3" + bundle = "org.beeware" + license = "MIT" + + [tool.briefcase.app.my-app] + description = "{long_desc}" + sources = ['src/my_app'] + """, + ) + + base_command.console.warning = MagicMock() + base_command.parse_config(filename, {}) + + base_command.console.warning.assert_called_once() + warning_msg = base_command.console.warning.call_args[0][0] + assert "my-app" in warning_msg + assert "81 characters" in warning_msg + assert "long_description" in warning_msg