Skip to content
Draft
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
11 changes: 11 additions & 0 deletions src/reuse/comment.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
# SPDX-FileCopyrightText: 2024 Anthony Loiseau <[email protected]>
# SPDX-FileCopyrightText: 2025 Raphael Schlarb <[email protected]>
# SPDX-FileCopyrightText: 2025 Kiko Fernandez-Reyes <[email protected]>
# SPDX-FileCopyrightText: 2025 Matthias Schoettle <[email protected]>
#
# SPDX-License-Identifier: GPL-3.0-or-later

Expand Down Expand Up @@ -386,6 +387,16 @@ class FortranCommentStyle(CommentStyle):
INDENT_AFTER_SINGLE = " "


class FrontmatterCommentStyle(CommentStyle):
"""Frontmatter comment style."""

SHORTHAND = "frontmatter"

SINGLE_LINE = "#"
INDENT_AFTER_SINGLE = " "
SHEBANGS = ["---"]


class ModernFortranCommentStyle(CommentStyle):
"""Fortran (free form) comment style."""

Expand Down
16 changes: 15 additions & 1 deletion src/reuse/header.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
# SPDX-FileCopyrightText: 2022 Yaman Qalieh
# SPDX-FileCopyrightText: 2022 Carmen Bianca Bakker <[email protected]>
# SPDX-FileCopyrightText: 2025 Rivos Inc.
# SPDX-FileCopyrightText: 2025 Matthias Schoettle <[email protected]>
#
# SPDX-License-Identifier: GPL-3.0-or-later

Expand All @@ -24,7 +25,13 @@
from license_expression import ExpressionError

from . import ReuseInfo
from .comment import CommentStyle, EmptyCommentStyle, PythonCommentStyle
from .comment import (
CommentStyle,
EmptyCommentStyle,
FrontmatterCommentStyle,
HtmlCommentStyle,
PythonCommentStyle,
)
from .copyright import merge_copyright_lines
from .exceptions import (
CommentCreateError,
Expand Down Expand Up @@ -270,6 +277,12 @@ def find_and_replace_header(
if style is None:
style = PythonCommentStyle

# Workaround: Treat Markdown files with frontmatter with the Frontmatter style instead
if style is HtmlCommentStyle and text.startswith(
FrontmatterCommentStyle.SHEBANGS[0]
):
style = FrontmatterCommentStyle

try:
before, header, after = _find_first_spdx_comment(text, style=style)
except MissingReuseInfoError:
Expand All @@ -279,6 +292,7 @@ def find_and_replace_header(
if style is EmptyCommentStyle:
after = ""


_LOGGER.debug(f"before = {repr(before)}")
_LOGGER.debug(f"header = {repr(header)}")
_LOGGER.debug(f"after = {repr(after)}")
Expand Down
185 changes: 185 additions & 0 deletions tests/test_cli_annotate.py
Original file line number Diff line number Diff line change
Expand Up @@ -393,6 +393,191 @@ def test_shebang_wrong_comment_style(self, fake_repository):
assert result.exit_code == 0
assert simple_file.read_text() == expected

def test_xml(self, fake_repository):
"""Keep the XML header when annotating."""
simple_file = fake_repository / "foo.xml"
simple_file.write_text(
cleandoc(
"""
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<root>
</root>
"""
)
)
expected = cleandoc(
"""
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>

<!--
SPDX-License-Identifier: MIT
-->

<root>
</root>
"""
)

result = CliRunner().invoke(
main,
[
"annotate",
"--license",
"MIT",
"foo.xml",
],
)

assert result.exit_code == 0
assert simple_file.read_text() == expected

def test_xml_wrong_comment_style(self, fake_repository):
"""If a comment style does not support the XML header at the top, don't
treat the shebang as special.
"""
simple_file = fake_repository / "foo.sh"
simple_file.write_text(
cleandoc(
"""
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<root>
</root>
"""
)
)
expected = cleandoc(
"""
# SPDX-License-Identifier: MIT

<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<root>
</root>
"""
)

result = CliRunner().invoke(
main,
[
"annotate",
"--license",
"MIT",
"foo.sh",
],
)

assert result.exit_code == 0
assert simple_file.read_text() == expected

def test_markdown(self, fake_repository):
"""Markdown uses the HTML comment style."""
simple_file = fake_repository / "foo.md"
simple_file.write_text(
cleandoc(
"""
# Heading
"""
)
)
expected = cleandoc(
"""
<!--
SPDX-License-Identifier: MIT
-->

# Heading
"""
)

result = CliRunner().invoke(
main,
[
"annotate",
"--license",
"MIT",
"foo.md",
],
)

assert result.exit_code == 0
assert simple_file.read_text() == expected

def test_frontmatter(self, fake_repository):
"""Keep the frontmatter when annotating."""
simple_file = fake_repository / "foo.md"
simple_file.write_text(
cleandoc(
"""
---
description: test
---
# Heading
"""
)
)
expected = cleandoc(
"""
---

# SPDX-License-Identifier: MIT

description: test
---
# Heading
"""
)

result = CliRunner().invoke(
main,
[
"annotate",
"--license",
"MIT",
"foo.md",
],
)

assert result.exit_code == 0
assert simple_file.read_text() == expected

def test_frontmatter_wrong_comment_style(self, fake_repository):
"""If a comment style does not support the frontmatter header at the top, don't
treat the shebang as special.
"""
simple_file = fake_repository / "foo.sh"
simple_file.write_text(
cleandoc(
"""
---
description: test
---
# Heading
"""
)
)
expected = cleandoc(
"""
# SPDX-License-Identifier: MIT

---
description: test
---
# Heading
"""
)

result = CliRunner().invoke(
main,
[
"annotate",
"--license",
"MIT",
"foo.sh",
],
)

assert result.exit_code == 0
assert simple_file.read_text() == expected

def test_contributors_only(
self, fake_repository, mock_date_today, contributors
):
Expand Down
Loading