Skip to content

Commit

Permalink
provide background and solutions for the most typical linted issues
Browse files Browse the repository at this point in the history
Based on errors in the report, print helpful background and possible solutions
for the user as recommended next steps.
  • Loading branch information
mxmehl authored and carmenbianca committed Oct 24, 2023
1 parent ecd09f3 commit 243d347
Show file tree
Hide file tree
Showing 3 changed files with 123 additions and 1 deletion.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ and licensing information to your code!
(#645).
- `--add-license-concluded`, `--creator-person`, and `--creator-organization`
added to `reuse spdx`. (#623)
- Display recommendations for steps to fix found issues during a lint. (#698)
- Additional license metadata for the Python package has been added. The actual
SPDX license expression remains the same:
`Apache-2.0 AND CC0-1.0 AND CC-BY-SA-4.0 AND GPL-3.0-or-later`. (#733)
Expand Down
19 changes: 19 additions & 0 deletions src/reuse/lint.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# SPDX-FileCopyrightText: 2017 Free Software Foundation Europe e.V. <https://fsfe.org>
# SPDX-FileCopyrightText: 2022 Florian Snow <florian@familysnow.net>
# SPDX-FileCopyrightText: 2023 DB Systel GmbH
#
# SPDX-License-Identifier: GPL-3.0-or-later

Expand All @@ -14,6 +15,7 @@
from io import StringIO
from pathlib import Path
from typing import IO, Any
from textwrap import TextWrapper

from . import __REUSE_version__
from .project import Project
Expand Down Expand Up @@ -201,6 +203,23 @@ def format_plain(report: ProjectReport) -> str:
"{} of the REUSE Specification :-("
).format(__REUSE_version__)
)

# Write recommendations in a nicely wrapped format
output.write("\n\n\n# ")
output.write(_("RECOMMENDATIONS"))
output.write("\n\n")

wrapper = TextWrapper(
width=80,
drop_whitespace=True,
break_long_words=False,
initial_indent="* ",
subsequent_indent=" ",
)
for help_text in data["recommendations"]:
output.write("\n".join(wrapper.wrap(help_text)))
output.write("\n")

output.write("\n")

return output.getvalue()
Expand Down
104 changes: 103 additions & 1 deletion src/reuse/report.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# SPDX-FileCopyrightText: 2017 Free Software Foundation Europe e.V. <https://fsfe.org>
# SPDX-FileCopyrightText: 2022 Florian Snow <florian@familysnow.net>
# SPDX-FileCopyrightText: 2022 Pietro Albini <pietro.albini@ferrous-systems.com>
# SPDX-FileCopyrightText: 2023 DB Systel GmbH
# SPDX-FileCopyrightText: 2023 Carmen Bianca BAKKER <carmenbianca@fsfe.org>
#
# SPDX-License-Identifier: GPL-3.0-or-later
Expand Down Expand Up @@ -113,6 +114,7 @@ def to_dict_lint(self) -> Dict[str, Any]:
"summary": {
"used_licenses": [],
},
"recommendations": [self.recommendations],
}

# Populate 'files'
Expand All @@ -131,6 +133,9 @@ def to_dict_lint(self) -> Dict[str, Any]:
"compliant": self.is_compliant,
}

# Populate 'recommendations'
data["recommendations"] = self.recommendations

# Add the top three keys
unsorted_data = {
"lint_version": LINT_VERSION,
Expand All @@ -140,15 +145,17 @@ def to_dict_lint(self) -> Dict[str, Any]:
}

# Sort dictionary keys while keeping the top three keys at the beginning
# and the recommendations on the bottom
sorted_keys = sorted(list(unsorted_data.keys()))
sorted_keys.remove("lint_version")
sorted_keys.remove("reuse_spec_version")
sorted_keys.remove("reuse_tool_version")
sorted_keys.remove("recommendations")
sorted_keys = [
"lint_version",
"reuse_spec_version",
"reuse_tool_version",
] + sorted_keys
] + sorted_keys + ["recommendations"]

sorted_data = {key: unsorted_data[key] for key in sorted_keys}

Expand Down Expand Up @@ -380,6 +387,101 @@ def is_compliant(self) -> bool:

return self._is_compliant

@property
def recommendations(self) -> Set[str]:
"""Generate help for next steps based on found REUSE issues"""
recommendations = set()

# Bad licenses
if self.bad_licenses:
recommendations.add(
_(
"Fix bad licenses: At least one license in the LICENSES"
" directory and/or provided by 'SPDX-License-Identifier'"
" tags is invalid. They are either not valid SPDX license"
" identifiers or do not start with 'LicenseRef-'. FAQ about"
" custom licenses:"
" https://reuse.software/faq/#custom-license"
)
)

# Deprecated licenses
if self.deprecated_licenses:
recommendations.add(
_(
"Fix deprecated licenses: At least one of the licenses in"
" the LICENSES directory and/or provided by an"
" 'SPDX-License-Identifier' tag or in '.reuse/dep5' has"
" been deprecated by SPDX. The current list and their"
" respective recommended new identifiers can be found"
" here: https://spdx.org/licenses/#deprecated"
)
)

# Licenses without file extension
if self.licenses_without_extension:
recommendations.add(
_(
"Fix licenses without file extension: At least one license"
" text file in the 'LICENSES' directory does not have a"
" '.txt' file extension. Please rename the file(s)"
" accordingly."
)
)

# Missing licenses
if self.missing_licenses:
recommendations.add(
_(
"Fix missing licenses: For at least one of the license"
" identifiers provided by the 'SPDX-LicenseIdentifier'"
" tags, there is no corresponding license text file in the"
" 'LICENSES' directory. For SPDX license identifiers, you"
" can simply run 'reuse download --all' to get any missing"
" ones. For custom licenses (starting with 'LicenseRef-'),"
" you need to add these files yourself."
)
)

# Unused licenses
if self.unused_licenses:
recommendations.add(
_(
"Fix unused licenses: At least one of the license text"
" files in 'LICENSES' is not referenced for any file, e.g."
" by an 'SPDX-License-Identifier' tag. Please make sure"
" that you either tag the accordingly licensed files"
" properly, or delete the unused license text if you are"
" sure that no file or code snippet is licensed as such."
)
)

# Read errors
if self.read_errors:
recommendations.add(
_(
"Fix read errors: At least one of the files in your"
" directory cannot be read by the tool. Please check the"
" file permissions. You will find the affected files at the"
" top of the output as part of the logged error messages."
)
)

# Files without copyright and/or licensing information
if self.files_without_copyright or self.files_without_licenses:
recommendations.add(
_(
"Fix missing copyright/license information: For one or more"
" files, the tool cannot find copyright and/or license"
" information. Please add it as a comment in the file"
" header, ideally using the 'SPDX-FileCopyrightText' tag."
" If that's not possible, you can use adjacent '.license'"
" files or the '.reuse/dep5' file."
)
)

return recommendations


class FileReport: # pylint: disable=too-many-instance-attributes
"""Object that holds a linting report about a single file."""
Expand Down

0 comments on commit 243d347

Please sign in to comment.