From 13be3c95a5fa25b87db6bdc612e5f415f13c57e5 Mon Sep 17 00:00:00 2001 From: Greg Kaleka Date: Fri, 3 Apr 2026 10:34:30 -0400 Subject: [PATCH 1/3] Support README.adoc as fallback for library descriptions --- libraries/models.py | 2 +- libraries/tests/test_models.py | 36 ++++++++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/libraries/models.py b/libraries/models.py index bfd10139a..5e234393e 100644 --- a/libraries/models.py +++ b/libraries/models.py @@ -341,7 +341,7 @@ def get_description(self, client, tag="develop"): """ content = None # File paths/names where description data might be stored. - files = ["doc/library-detail.adoc", "README.md"] + files = ["doc/library-detail.adoc", "README.md", "README.adoc"] # Try to get the content from the cache first static_content_cache = caches["static_content"] diff --git a/libraries/tests/test_models.py b/libraries/tests/test_models.py index 441e65933..4eb6c0d22 100644 --- a/libraries/tests/test_models.py +++ b/libraries/tests/test_models.py @@ -1,7 +1,12 @@ import datetime +from unittest.mock import MagicMock, patch + +import pytest +from django.core.cache import caches from django.db.models import Sum from model_bakery import baker +from core.models import RenderedContent from libraries.models import CommitAuthor from mailing_list.models import EmailData @@ -140,6 +145,37 @@ def test_library_version_first_boost_version_property(library): assert library.first_boost_version == version_3 +DESCRIPTION_FILES = ["doc/library-detail.adoc", "README.md", "README.adoc"] + + +@pytest.mark.parametrize( + "first_available, expected", + [(0, "

adoc

"), (1, "

md

"), (2, "

adoc

"), (None, None)], + ids=["library-detail.adoc", "README.md-fallback", "README.adoc-fallback", "none"], +) +@patch("libraries.models.process_md", return_value=("", "

md

")) +@patch("libraries.models.write_content_to_tempfile") +@patch("libraries.models.convert_adoc_to_html", return_value="

adoc

") +def test_get_description_file_priority( + mock_adoc, mock_tempfile, mock_md, library, first_available, expected +): + """Files are tried in order; the first available file wins.""" + caches["static_content"].clear() + RenderedContent.objects.all().delete() + mock_tempfile.return_value.name = "/tmp/fake" + + available = { + f: b"content" if first_available is not None and i >= first_available else None + for i, f in enumerate(DESCRIPTION_FILES) + } + client = MagicMock() + client.get_file_content.side_effect = ( + lambda repo_slug, tag, file_path: available.get(file_path) + ) + + assert library.get_description(client) == expected + + def test_merge_author_deletes_author(): author_1_email = baker.make("libraries.CommitAuthorEmail") author_1 = author_1_email.author From 6e40ffef86f2bf58aa2ab9745895b8862f049ca4 Mon Sep 17 00:00:00 2001 From: Greg Kaleka Date: Fri, 3 Apr 2026 11:49:17 -0400 Subject: [PATCH 2/3] Fix README missing message and docstring typos --- libraries/constants.py | 2 +- libraries/models.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/libraries/constants.py b/libraries/constants.py index 51d2fbcbc..3dac7b31b 100644 --- a/libraries/constants.py +++ b/libraries/constants.py @@ -348,7 +348,7 @@ # This constant is for library-versions missing a README README_MISSING = ( - "⚠️ This library has no README.md or library-details.adoc; " + "⚠️ This library has no README file or library-detail.adoc; " "consider contributing one." ) diff --git a/libraries/models.py b/libraries/models.py index 5e234393e..071fa1ad3 100644 --- a/libraries/models.py +++ b/libraries/models.py @@ -335,9 +335,9 @@ def save(self, *args, **kwargs): def get_description(self, client, tag="develop"): """Get description from the appropriate file on GitHub. - For more recent versions, that will be `/doc/library-details.adoc`. + For more recent versions, that will be `/doc/library-detail.adoc`. For older versions, or libraries that have not adopted the adoc file, - that will be `/README.md`. + that will be `/README.md` or `/README.adoc`. """ content = None # File paths/names where description data might be stored. From 9fd566fafae98b8ffdc731639b593a2dc3895100 Mon Sep 17 00:00:00 2001 From: Greg Kaleka Date: Sat, 4 Apr 2026 13:22:29 -0400 Subject: [PATCH 3/3] Extract DESCRIPTION_FILES constant and simplify test --- libraries/constants.py | 3 +++ libraries/models.py | 5 ++--- libraries/tests/test_models.py | 16 +++++++--------- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/libraries/constants.py b/libraries/constants.py index 3dac7b31b..9b4fb744d 100644 --- a/libraries/constants.py +++ b/libraries/constants.py @@ -346,6 +346,9 @@ # List of versions for which we know docs are missing VERSION_DOCS_MISSING = ["boost-1.33.0"] +# File paths where library description content might be stored, in priority order. +DESCRIPTION_FILES = ["doc/library-detail.adoc", "README.md", "README.adoc"] + # This constant is for library-versions missing a README README_MISSING = ( "⚠️ This library has no README file or library-detail.adoc; " diff --git a/libraries/models.py b/libraries/models.py index 071fa1ad3..9f42716c1 100644 --- a/libraries/models.py +++ b/libraries/models.py @@ -25,7 +25,7 @@ from libraries.managers import IssueManager from mailing_list.models import EmailData from versions.models import ReportConfiguration -from .constants import LIBRARY_GITHUB_URL_OVERRIDES +from .constants import DESCRIPTION_FILES, LIBRARY_GITHUB_URL_OVERRIDES from .utils import ( generate_random_string, @@ -340,8 +340,7 @@ def get_description(self, client, tag="develop"): that will be `/README.md` or `/README.adoc`. """ content = None - # File paths/names where description data might be stored. - files = ["doc/library-detail.adoc", "README.md", "README.adoc"] + files = DESCRIPTION_FILES # Try to get the content from the cache first static_content_cache = caches["static_content"] diff --git a/libraries/tests/test_models.py b/libraries/tests/test_models.py index 4eb6c0d22..103b0aaba 100644 --- a/libraries/tests/test_models.py +++ b/libraries/tests/test_models.py @@ -7,6 +7,7 @@ from model_bakery import baker from core.models import RenderedContent +from libraries.constants import DESCRIPTION_FILES from libraries.models import CommitAuthor from mailing_list.models import EmailData @@ -145,9 +146,6 @@ def test_library_version_first_boost_version_property(library): assert library.first_boost_version == version_3 -DESCRIPTION_FILES = ["doc/library-detail.adoc", "README.md", "README.adoc"] - - @pytest.mark.parametrize( "first_available, expected", [(0, "

adoc

"), (1, "

md

"), (2, "

adoc

"), (None, None)], @@ -157,22 +155,22 @@ def test_library_version_first_boost_version_property(library): @patch("libraries.models.write_content_to_tempfile") @patch("libraries.models.convert_adoc_to_html", return_value="

adoc

") def test_get_description_file_priority( - mock_adoc, mock_tempfile, mock_md, library, first_available, expected + _adoc, mock_tempfile, _md, library, first_available, expected ): """Files are tried in order; the first available file wins.""" caches["static_content"].clear() RenderedContent.objects.all().delete() mock_tempfile.return_value.name = "/tmp/fake" - available = { - f: b"content" if first_available is not None and i >= first_available else None - for i, f in enumerate(DESCRIPTION_FILES) - } + available = dict.fromkeys(DESCRIPTION_FILES) + if first_available is not None: + for f in DESCRIPTION_FILES[first_available:]: + available[f] = b"content" + client = MagicMock() client.get_file_content.side_effect = ( lambda repo_slug, tag, file_path: available.get(file_path) ) - assert library.get_description(client) == expected