Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changes/2864.bugfix.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Briefcase now warns when an app's `description` is longer than 80 characters, as overly long descriptions can be truncated by some packaging formats (such as Windows MSI shortcut icons).
20 changes: 20 additions & 0 deletions src/briefcase/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,12 @@
"and cannot end with '-' or '_')."
)

# The `description` is a short, single-line summary of the app. Longer values
# belong in `long_description`. Some packaging formats embed the description in
# length-limited fields (e.g. Windows MSI shortcuts truncate at 256 characters,
# corrupting the icon path), so Briefcase warns when it exceeds this length.
MAX_DESCRIPTION_LENGTH = 80
Comment on lines +44 to +48
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doesn't need to be factored out like this. It's used in exactly one place.



def is_valid_pep508_name(app_name):
"""Determine if the name is valid by PEP508 rules."""
Expand Down Expand Up @@ -1463,6 +1469,20 @@ def parse_config(config_file: Path, platform, output_format, console):
# Normalize license fields to PEP 639 representation.
normalize_license_config(config, app_name, base_path, console)

# The description should be a short, single-line summary. Warn (but don't
# fail) if it's too long, as some packaging formats embed it in
# length-limited fields; for example, an over-long description corrupts
# the shortcut icon path in Windows MSI installers.
Comment on lines +1472 to +1475
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't need excessively long comments explaining code, especially when the warning message explains the underlying problem.

Suggested change
# The description should be a short, single-line summary. Warn (but don't
# fail) if it's too long, as some packaging formats embed it in
# length-limited fields; for example, an over-long description corrupts
# the shortcut icon path in Windows MSI installers.

description = config.get("description")
if isinstance(description, str) and len(description) > MAX_DESCRIPTION_LENGTH:
console.warning(
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When a warning is long, we can now use the console.warning_banner() helper. That helper automatically wraps the the content, as well as standardising the presentation of config issues.

f"The description for {app_name!r} is {len(description)} characters "
f"long. Briefcase recommends a description of no more than "
f"{MAX_DESCRIPTION_LENGTH} characters; longer descriptions may be "
f"truncated when packaging for some platforms. Move any detailed "
f"text into the `long_description` field."
)

# Construct a configuration object, and add it to the list
# of configurations that are being handled.
app_configs[app_name] = config
Expand Down
62 changes: 62 additions & 0 deletions tests/config/test_parse_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -754,6 +754,68 @@ def test_pep_621_merge(tmp_path):
}


def test_long_description_warning(tmp_path):
"""A description longer than the recommended length raises a warning."""
long_description = "This is a needlessly long app description " + ("x" * 50)
assert len(long_description) > 80

config_file = create_file(
tmp_path / "pyproject.toml",
f"""
[tool.briefcase]
license = "MIT"

[tool.briefcase.app.my_app]
description = "{long_description}"
""",
)

console = Mock()
_, apps = parse_config(
config_file,
platform="macOS",
output_format="Xcode",
console=console,
)

# The description is preserved as-is...
assert apps["my_app"]["description"] == long_description
# ...but the user is warned that it's too long.
console.warning.assert_called_once()
warning_text = console.warning.call_args[0][0]
assert "my_app" in warning_text
assert str(len(long_description)) in warning_text
assert "long_description" in warning_text


def test_short_description_no_warning(tmp_path):
"""A description at the recommended length doesn't raise a warning."""
# A description that is exactly at the limit is acceptable.
description = "x" * 80
assert len(description) == 80

config_file = create_file(
tmp_path / "pyproject.toml",
f"""
[tool.briefcase]
license = "MIT"

[tool.briefcase.app.my_app]
description = "{description}"
""",
)

console = Mock()
parse_config(
config_file,
platform="macOS",
output_format="Xcode",
console=console,
)

console.warning.assert_not_called()


def test_license_pep621_table_with_files_is_error(tmp_path):
"""PEP 621 table format mixed with license-files raises an error."""
config_file = create_file(
Expand Down
Loading