Skip to content

Story 2430: Library Subpage Integration#2524

Open
julhoang wants to merge 28 commits into
developfrom
feat/library-subpage-content
Open

Story 2430: Library Subpage Integration#2524
julhoang wants to merge 28 commits into
developfrom
feat/library-subpage-content

Conversation

@julhoang

@julhoang julhoang commented Jul 10, 2026

Copy link
Copy Markdown
Collaborator

Issue: #2430

Summary & Context

Renders the library subpage from two sources: (1) data we already ingest (metadata, dependencies, contributors, long-form docs) and (2) a net-new, optional maintainer-authored meta/website.adoc in each library repo that supplies the marketing/quick-start content we don't otherwise collect. All dynamic sections render with graceful empty states.

Changes

website.adoc ingestion pipeline (net-new)

  • Add GithubAPIClient.get_website_adoc() to fetch a repo's optional meta/website.adoc from raw GitHub, returning None quietly on the common 404
  • Add libraries/website_adoc.py — parser that maps stable AsciiDoc section IDs/attributes ([#about], [#designed-for], [#links], [#playground], [#install], [#benchmarks], [#freeform]) into structured fields
  • Store parsed content on LibraryVersion.website_adoc plus the raw source, with per-section status editing in the Wagtail/Django admin (libraries/admin.py, migration 0043)
  • Add daily Celery task update_library_version_website_adoc (scoped to the most recent version, fetched from master); a missing file or transient fetch failure leaves any existing value untouched. Skips the refresh while a newer release is in betamaster has drifted toward that release, so the current stable keeps its release-tag snapshot until the beta is promoted
  • Add management command import_library_version_website_adoc for manual/backfill ingestion

Page header

  • Add Library.slack_url admin field with fallback to https://cppalliance.org/slack/ (migration 0042); surfaced on the hero and the “Discuss in Slack” redirect

Render website.adoc sections with empty states

  • Render About (blurb + code sample), Install, and This library is designed for (feature highlights) as V3 cards
  • Render Quick Start links from [#links] (:common-use-case-url: / :code-example-url:), each validated as a Boost-owned URL (boost.org / github.com/boostorg) or falling back to the documentation link
  • Render Benchmarks bar-chart card from [#benchmarks] sub-sections
  • Render Freeform maintainer-authored markdown card from [#freeform]
  • Each optional section is hidden when its source content is absent
    ⚠️ An autoflow masonry layout has been implemented in this PR, but the UI layout is a bit out of scope so we might need a follow-up to fine-tune all elements as needed (e.g setting card max height, make the code section scroll on overflow, etc) ⚠️

Compiler Explorer link (net-new)

  • Add libraries/godbolt.py — builds a godbolt.org /clientstate/<base64> “Edit in Compiler Explorer” URL from the [#playground] code, selecting the Boost version matching the active release dropdown (falling back to the newest version Compiler Explorer offers); the Boost version→id map is fetched from the CE libraries API and cached for a day

Contributors & documentation

  • Add version-aware All Contributors list (authors + maintainers from libraries.json + commit contributors up to the selected version) with identity-based dedup by CommitAuthor id (never by display name)
  • Wire up the Documentation card from the resolved long-form docs body

Demo & tooling

  • Add load_website_adoc_demo command, website_adoc_demo.adoc, and website_adoc_template.adoc (maintainer-facing reference)
  • Add “Designed for” and “Benchmarks” demo cards to the V3 component demo page

Tests

  • Add test_godbolt.py, test_website_adoc.py, and extend test_mixins.py / test_views.py / test_tasks.py covering the parser, Compiler Explorer URL building, contributor dedup, view context, and the daily-refresh beta guard

‼️ Risks & Considerations ‼️

  • The Django management command import_library_version_website_adoc is implemented but we cannot really test it until a library ships a meta/website.adoc file. The parser is unit-tested, but the full pipeline is untested until a maintainer adds the file to a library repo.
  • The Compiler Explorer link depends on the external godbolt.org libraries API. It's cached for a day and degrades gracefully (link still opens with code pre-filled, Boost just isn't preselected) if the API is unavailable.
  • master vs release-tag drift: the daily refresh pulls the current stable's website.adoc from master, which drifts toward the next release over the cycle — so the stable page tracks the freshest maintainer content rather than a frozen tag snapshot. This is intended (marketing/quick-start copy), but the worst case (a newer release in beta, where master already reflects that release) is guarded: the daily task skips the refresh while a newer beta is live. Older/archived versions are never refreshed and stay frozen at their release-tag import snapshot.
    • ‼️ Sequential website.adoc fetch in the import loop: import_library_versions (versions/tasks.py) now calls fetch_website_adoc_fields per library, adding a third sequential GitHub round-trip alongside get_libraries_json and get_repo. This runs in a background Celery task (not a user request path) and each call is guarded/non-raising, so it's non-blocking — but on large catalogs it extends total import runtime and GitHub API pressure. Left as-is for now; revisit with batching or bounded concurrency (e.g. a ThreadPoolExecutor prefetch) only if the import starts timing out. ‼️

Peer-Testing Guidelines

Setup

  1. Pull the branch and apply migrations: docker compose exec web python manage.py migrate
  2. Seed demo website.adoc content onto a library (swap beast for any slug):
    docker compose exec web python manage.py load_website_adoc_demo --library beast

Test

  1. Populated subpage — open http://localhost:8000/library/latest/beast/ and confirm the About, Designed-for, Quick Start, Install, Benchmarks, and Freeform cards all render.
  2. Empty state — view a version or library with no seeded content and confirm the page renders cleanly with those cards simply absent (no empty shells): an earlier version, http://localhost:8000/library/1.89.0/beast/, or an unseeded library, http://localhost:8000/library/latest/accumulators/.
  3. Slack link — in the Django admin, set a Library's slack_url (e.g. beast) and reload: the “Discuss in Slack” link should use it. Clear it and confirm it falls back to https://cppalliance.org/slack/.
Screenshot 2026-07-10 at 12 05 43 PM
  1. Compiler Explorer — confirm the “Edit in Compiler Explorer” link in Quick Start opens godbolt.org with the [#playground] code pre-filled and Boost selected. (Godbolt may take a few minutes to compile.)
  2. All Contributors — confirm the card includes the libraries.json authors/maintainers and doesn't duplicate an author who is already linked.

Optional

  1. Try different section combinations — locally edit libraries/website_adoc_demo.adoc (comment out or delete sections), re-run the seed command from step 2, and reload to see how the layout adapts when sections are missing.
  2. To clear the demo data, run: docker compose exec web python manage.py load_website_adoc_demo --library beast --clear

Screenshots

Screenshot Notes
Boost · 12 28pm · 07-10 Example with all new sections filled out
Boost · 12 28pm · 07-10 (1) Example with website_adoc not provided
Screenshot 2026-07-10 at 12 05 43 PM New Slack URL field in Library
Screenshot 2026-07-10 at 12 27 02 PM New website_adoc related fields in LibraryVersion
Screenshot 2026-07-10 at 12 26 13 PM Placeholder UI for when library does not exist in a Version branch

Self-review Checklist

  • Tag at least one team member from each team to review this PR
  • Link this PR to the related GitHub Project ticket

Frontend

  • UI implementation matches Figma design
  • Tested in light and dark mode
  • Responsive / mobile verified
  • Accessibility checked (keyboard navigation, etc.)
  • Ensure design tokens are used for colors, spacing, typography, etc. – No hardcoded values
  • Test without JavaScript (if applicable)
  • No console errors or warnings

Summary by CodeRabbit

Summary by CodeRabbit

  • New Features
    • Library pages now support maintainer-provided website content sections (About, Install, Designed For, Benchmarks, documentation, free-form), including V3 demo cards.
    • Added “Edit in Compiler Explorer” links for supported snippets.
    • Added dedicated Slack channel links, including a “join Slack” URL and automatic fallback.
    • Added admin controls to refresh and review website content status.
  • Bug Fixes
    • Improved category filtering/CTAs, quick-start URL handling, and V3 card layout/scrolling behavior.
  • Documentation
    • Added website-adoc templates and demo content.
  • Tests
    • Expanded coverage for website parsing/rendering, URL building, views, tasks, and contributor logic.

@coderabbitai

coderabbitai Bot commented Jul 10, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 47e025aa-740e-41fe-ae67-9dba45437936

📥 Commits

Reviewing files that changed from the base of the PR and between 7587805 and 78ae29a.

📒 Files selected for processing (5)
  • core/githubhelper.py
  • libraries/management/commands/import_library_version_website_adoc.py
  • libraries/tasks.py
  • libraries/tests/test_tasks.py
  • templates/v3/libraries/library-subpage.html
🚧 Files skipped from review as they are similar to previous changes (5)
  • core/githubhelper.py
  • templates/v3/libraries/library-subpage.html
  • libraries/tests/test_tasks.py
  • libraries/tasks.py
  • libraries/management/commands/import_library_version_website_adoc.py

📝 Walkthrough

Walkthrough

Adds structured meta/website.adoc parsing, storage, refresh commands, admin controls, and V3 library-page rendering. It also adds Slack metadata, contributor handling, Compiler Explorer links, benchmark/demo cards, responsive styling, and related tests.

Changes

Website content pipeline

Layer / File(s) Summary
Website content contract and ingestion
libraries/website_adoc.py, libraries/models.py, libraries/migrations/*, libraries/management/commands/*website_adoc*, libraries/tests/test_website_adoc.py, libraries/website_adoc_*.adoc, versions/tasks.py
Defines the website.adoc format, parses and renders supported sections, stores raw and derived content, imports content from repository versions, provides demo-loading commands, and validates parsing and failure isolation.
Refresh task and admin workflow
config/celery.py, core/githubhelper.py, libraries/tasks.py, libraries/admin.py, templates/admin/*, libraries/tests/test_tasks.py
Adds daily and manual refresh paths, repository fetching, beta-cycle guards, per-section admin statuses, and task coverage.
V3 library rendering and supporting metadata
libraries/views.py, libraries/utils.py, libraries/mixins.py, libraries/models.py, core/views.py, templates/v3/*, static/css/v3/*, core/constants.py, libraries/tests/test_views.py, libraries/tests/test_mixins.py, libraries/tests/test_models.py
Uses parsed website content for library cards, links, contributors, Slack fallback, categories, demos, benchmarks, and page styling.
Compiler Explorer link generation
libraries/godbolt.py, libraries/tests/test_godbolt.py
Fetches and caches Compiler Explorer Boost versions, resolves version IDs, and builds URL-safe clientstate links from playground code.

Estimated code review effort: 4 (Complex) | ~60 minutes

Possibly related issues

  • Webpage Integration: Library Subpage #2430 — Covers the same library subpage work, including website.adoc ingestion/rendering, Slack fallback, contributors, quick-start links, and Compiler Explorer integration.

Possibly related PRs

Suggested reviewers: herzog0, julioest, kattyode, jlchilders11

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 56.82% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title is concise and clearly reflects the main library subpage integration work.
Description check ✅ Passed The description follows the template well, covering issue, context, changes, risks, screenshots, and checklist items.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/library-subpage-content

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@julhoang julhoang linked an issue Jul 10, 2026 that may be closed by this pull request

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 7

🧹 Nitpick comments (2)
libraries/management/commands/load_website_adoc_demo.py (1)

46-49: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Chain the original exception when re-raising in except blocks.

Flagged by Ruff (B904). Minor for a dev-only CLI tool, but preserves the original traceback context for debugging.

🔧 Proposed fix
     try:
         library = Library.objects.get(slug=library_slug)
-    except Library.DoesNotExist:
-        raise click.ClickException(f"No library with slug '{library_slug}'.")
+    except Library.DoesNotExist as err:
+        raise click.ClickException(f"No library with slug '{library_slug}'.") from err
     try:
         library_version = LibraryVersion.objects.get(library=library, version=version)
-    except LibraryVersion.DoesNotExist:
+    except LibraryVersion.DoesNotExist as err:
         raise click.ClickException(
             f"'{library_slug}' has no LibraryVersion for {version.slug}."
-        )
+        ) from err

Also applies to: 59-64

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@libraries/management/commands/load_website_adoc_demo.py` around lines 46 -
49, Chain the original exception when converting lookup failures into click
errors. In the library lookup exception handler and the additional exception
handler around the related lookup (the block also flagged at lines 59–64), add
explicit exception chaining with “from” when raising click.ClickException,
preserving the caught exception context.

Source: Linters/SAST tools

versions/tasks.py (1)

31-31: 🚀 Performance & Scalability | 🔵 Trivial

Adds another sequential network call per library in an already I/O-heavy import loop.

Functionally correct — fetch_website_adoc_fields never raises, so it's safe to inline here. Worth noting for a large catalog import: this stacks a third per-library HTTP round-trip (alongside get_libraries_json and get_repo) onto a fully sequential loop, extending total import runtime and GitHub API pressure. Not blocking, just something to watch if import_library_versions starts timing out on large releases.

Also applies to: 477-477

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@versions/tasks.py` at line 31, The import loop adds a third sequential HTTP
request per library through fetch_website_adoc_fields, increasing runtime and
API pressure. Update import_library_versions to avoid serializing this call for
every library, preferably by batching or bounded concurrency while preserving
the function’s non-raising behavior and existing data handling.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@core/githubhelper.py`:
- Around line 334-353: Add a finite timeout to the requests.get call in
get_website_adoc, and catch requests.exceptions.RequestException instead of only
HTTPError so connection and timeout failures return None consistently. Preserve
the existing informational logging for all request failures.

In `@libraries/godbolt.py`:
- Around line 39-64: Move the response-shape parsing loop in
_fetch_boost_version_map inside the existing try block so malformed JSON
structures are handled defensively. Broaden the exception handling to catch
parsing-related TypeError and AttributeError (or an appropriate safe exception
boundary), log the failure with logger.exception, and return {} for any
unexpected API payload without allowing page rendering to fail.

In `@libraries/migrations/0042_library_slack_url.py`:
- Around line 16-20: The `slack_url` URLField in migration
`0042_library_slack_url` is non-nullable without a database default, which can
fail on existing rows. Add `default=""` to the field definition alongside
`blank=True` so the migration populates existing records safely.

In `@libraries/mixins.py`:
- Around line 343-379: Update build_all_contributors so its library_versions
queryset always includes the selected library_version explicitly, in addition to
the applicable versions returned by Version.objects.minor_versions(). Ensure
patch, beta, and branch builds retain the selected release and avoid duplicate
LibraryVersion rows when combining the querysets.

In `@libraries/tasks.py`:
- Around line 93-106: In store_library_version_website_adoc, guard the
client.get_website_adoc call with exception handling so connection failures and
redirect errors are logged and processing continues to the next library. Update
get_website_adoc in core/githubhelper.py to pass an appropriate timeout to
requests.get, while preserving its existing HTTPError handling.

In `@libraries/website_adoc_template.adoc`:
- Line 127: Update the freeform section instruction in
website_adoc_template.adoc by changing “Markdown formatting is supported” to
“AsciiDoc formatting is supported,” ensuring the guidance matches the
convert_adoc_to_html rendering pipeline.

In `@libraries/website_adoc.py`:
- Around line 169-186: Update _freeform to track whether iteration is inside a
---- source/listing fence, and only skip //-prefixed lines while outside that
fenced block; preserve all lines verbatim, including // comments, while the
fence is active. Follow the fence-state handling used by _segment(), while
retaining the existing heading detection, placeholder validation, and content
assembly.

---

Nitpick comments:
In `@libraries/management/commands/load_website_adoc_demo.py`:
- Around line 46-49: Chain the original exception when converting lookup
failures into click errors. In the library lookup exception handler and the
additional exception handler around the related lookup (the block also flagged
at lines 59–64), add explicit exception chaining with “from” when raising
click.ClickException, preserving the caught exception context.

In `@versions/tasks.py`:
- Line 31: The import loop adds a third sequential HTTP request per library
through fetch_website_adoc_fields, increasing runtime and API pressure. Update
import_library_versions to avoid serializing this call for every library,
preferably by batching or bounded concurrency while preserving the function’s
non-raising behavior and existing data handling.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 47f1f402-fe53-4d5e-a632-a2846aff2ef9

📥 Commits

Reviewing files that changed from the base of the PR and between c7720d2 and 9fe0746.

📒 Files selected for processing (31)
  • config/celery.py
  • core/constants.py
  • core/githubhelper.py
  • core/views.py
  • libraries/admin.py
  • libraries/godbolt.py
  • libraries/management/commands/import_library_version_website_adoc.py
  • libraries/management/commands/load_website_adoc_demo.py
  • libraries/migrations/0042_library_slack_url.py
  • libraries/migrations/0043_libraryversion_website_adoc_and_more.py
  • libraries/mixins.py
  • libraries/models.py
  • libraries/tasks.py
  • libraries/tests/test_godbolt.py
  • libraries/tests/test_mixins.py
  • libraries/tests/test_models.py
  • libraries/tests/test_tasks.py
  • libraries/tests/test_views.py
  • libraries/tests/test_website_adoc.py
  • libraries/utils.py
  • libraries/views.py
  • libraries/website_adoc.py
  • libraries/website_adoc_demo.adoc
  • libraries/website_adoc_template.adoc
  • static/css/v3/library-subpage.css
  • static/css/v3/stats.css
  • templates/admin/libraryversion_change_list.html
  • templates/v3/examples/_v3_example_section.html
  • templates/v3/includes/_stats_benchmarks.html
  • templates/v3/libraries/library-subpage.html
  • versions/tasks.py
💤 Files with no reviewable changes (1)
  • templates/v3/includes/_stats_benchmarks.html

Comment thread core/githubhelper.py Outdated
Comment thread libraries/godbolt.py
Comment thread libraries/migrations/0042_library_slack_url.py
Comment thread libraries/mixins.py
Comment thread libraries/tasks.py
Comment thread libraries/website_adoc_template.adoc Outdated
Comment thread libraries/website_adoc.py

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
templates/v3/includes/_hero_library.html (1)

11-11: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Update the added_text docs and remaining example callers. templates/v3/includes/_hero_library.html:11 still documents the full "Added in 1.66.0" text even though the template prepends Added in itself, and templates/v3/examples/_v3_example_section.html:92-95 still passes the full phrase, which will render as Added in Added in 1.66.0.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@templates/v3/includes/_hero_library.html` at line 11, Update the `added_text`
documentation in `_hero_library.html` to show only the version value, such as
`1.66.0`, because the template adds the `Added in ` prefix. Update the remaining
example invocation in `_v3_example_section.html` to pass only the version value
so it does not render a duplicated prefix.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@templates/v3/includes/_hero_library.html`:
- Line 11: Update the `added_text` documentation in `_hero_library.html` to show
only the version value, such as `1.66.0`, because the template adds the `Added
in ` prefix. Update the remaining example invocation in
`_v3_example_section.html` to pass only the version value so it does not render
a duplicated prefix.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 5348ae1a-438e-4b13-b55f-cf67e50d4dad

📥 Commits

Reviewing files that changed from the base of the PR and between 9fe0746 and c255e1d.

📒 Files selected for processing (11)
  • core/githubhelper.py
  • libraries/godbolt.py
  • libraries/management/commands/load_website_adoc_demo.py
  • libraries/migrations/0042_library_slack_url.py
  • libraries/mixins.py
  • libraries/models.py
  • libraries/tasks.py
  • libraries/tests/test_website_adoc.py
  • libraries/website_adoc.py
  • libraries/website_adoc_template.adoc
  • templates/v3/includes/_hero_library.html
🚧 Files skipped from review as they are similar to previous changes (10)
  • libraries/migrations/0042_library_slack_url.py
  • libraries/mixins.py
  • core/githubhelper.py
  • libraries/management/commands/load_website_adoc_demo.py
  • libraries/tasks.py
  • libraries/website_adoc_template.adoc
  • libraries/models.py
  • libraries/tests/test_website_adoc.py
  • libraries/website_adoc.py
  • libraries/godbolt.py

@julhoang julhoang marked this pull request as ready for review July 10, 2026 19:25

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@templates/v3/libraries/library-subpage.html`:
- Line 17: Guard the empty-state message in the library subpage template against
a missing object.first_boost_version before accessing display_name. Render the
first-release sentence only when first_boost_version exists, while preserving
the no-version message for libraries without any LibraryVersion records.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: ff518074-8b1a-4ba6-b273-faa0182fd1de

📥 Commits

Reviewing files that changed from the base of the PR and between c255e1d and 7587805.

📒 Files selected for processing (6)
  • libraries/views.py
  • libraries/website_adoc_demo.adoc
  • static/css/v3/library-subpage.css
  • templates/v3/examples/_v3_example_section.html
  • templates/v3/includes/_hero_library.html
  • templates/v3/libraries/library-subpage.html
✅ Files skipped from review due to trivial changes (1)
  • libraries/website_adoc_demo.adoc
🚧 Files skipped from review as they are similar to previous changes (1)
  • libraries/views.py

Comment thread templates/v3/libraries/library-subpage.html
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Webpage Integration: Library Subpage

1 participant