You are viewing a plain text version of this content. The canonical link for it is here.
Posted to site-notify@rai.apache.org by ak...@apache.org on 2026/10/21 04:55:03 UTC

(rai-site) branch preview/akm-blog updated: Fixing site build issues

This is an automated email from the ASF dual-hosted git repository.

andrewmusselman pushed a commit to branch preview/akm-blog
in repository https://gitbox.apache.org/repos/asf/rai-site.git


The following commit(s) were added to refs/heads/preview/akm-blog by this push:
     new 2d4d4fe  Fixing site build issues
2d4d4fe is described below

commit 2d4d4fe5f278a262ee39ad2f15920db299b795b7
Author: Andrew Musselman <an...@gmail.com>
AuthorDate: Tue Oct 20 21:54:50 2026 -0700

    Fixing site build issues
---
 AGENTS.md                                | 55 +++++++++++++++++++++++---------
 README.md                                | 10 ++++--
 content/pages/blog.md                    |  9 ++++++
 content/theme/templates/author.html      |  4 +++
 content/theme/templates/blog.html        |  2 ++
 content/theme/templates/blogindex.html   | 24 +-------------
 content/theme/templates/breadcrumbs.html |  4 +--
 content/theme/templates/category.html    |  4 +++
 content/theme/templates/postlist.html    | 24 ++++++++++++++
 content/theme/templates/tag.html         |  4 +++
 content/theme/templates/taxonomy.html    | 51 +++++++++++++++++++++++++++++
 pelicanconf.py                           | 14 +-------
 12 files changed, 150 insertions(+), 55 deletions(-)

diff --git a/AGENTS.md b/AGENTS.md
index 389f2f8..6dd1d1d 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -14,17 +14,32 @@ There is **no simple local build**. The authoritative build runs on **ASF
 infrastructure**, driven by `.asf.yaml`: the `pelican`/`publish` configuration builds
 the `main` branch and publishes the generated HTML to the `asf-site` branch, which is
 served at `rai.apache.org` (see [`apache/infrastructure-asfyaml`](https://github.com/apache/infrastructure-asfyaml#deploy)
-for how that mechanism works). In CI this is mirrored by
-`apache/infrastructure-actions/pelican` (`.github/workflows/build-pelican.yml`).
-
-That action — not `pyproject.toml` — supplies the ASF Pelican plugins the config
-requires (`asfgenid`, `asfrun`, plus `toc`, `spu`, `gfm`). `pyproject.toml` lists only
-`pelican` + helpers, so `pelican` alone will **not** reproduce the real build. To build
-outside the ASF action you need the plugins from
-[`apache/infrastructure-pelican`](https://github.com/apache/infrastructure-pelican).
-
-`pagefind.sh` (referenced as `ASF_POSTRUN` in `pelicanconf.py`) downloads the `pagefind`
-binary at build time and generates the search index into `_pagefind/`.
+for how that mechanism works). The build runs on **ASF BuildBot**
+([ci2.apache.org](https://ci2.apache.org)) — commits on `asf-site` are labelled
+"Automatic Site Publish by Buildbot". There is **no GitHub Actions build**: the only
+workflow in this repo is `pre-commit.yml`, so the Actions tab will never show a site
+build, and build results arrive by email instead (`notifications.jobs` in `.asf.yaml`,
+plus the pushing committer's `@apache.org` address).
+
+> **`pelicanconf.py` is not what the build reads.** `buildsite.py` in
+> [`apache/infrastructure-pelican`](https://github.com/apache/infrastructure-pelican)
+> checks for `pelicanconf.yaml` first, and when it exists — it does here — it
+> *generates* `pelican.auto.py` from that YAML via `bin/pelican.auto.ezt` and passes
+> that to Pelican. `pelicanconf.py` is only a fallback for repositories with no YAML,
+> and the copy in this repository is a stale snapshot of the generated file, kept for
+> local builds. **Editing `pelicanconf.py` has no effect on the published site**, and
+> the YAML schema is fixed: it accepts the keys in
+> [`pelicanconf.md`](https://github.com/apache/infrastructure-pelican/blob/master/pelicanconf.md)
+> and offers no way to set arbitrary Pelican settings. Anything the generated settings
+> don't give you has to be solved in the theme or in content metadata.
+
+The ASF plugins the config requires (`asfgenid`, `asfrun`, plus `toc`, `spu`, `gfm`) come
+from `infrastructure-pelican`, not `pyproject.toml`, which lists only `pelican` + helpers.
+So `pelican` alone will **not** reproduce the real build.
+
+`pagefind.sh` (`postrun` in `pelicanconf.yaml`, `ASF_POSTRUN` in the generated settings)
+downloads the `pagefind` binary at build time and generates the search index into
+`_pagefind/`.
 
 ## Build and test commands
 
@@ -45,10 +60,20 @@ before opening or updating a PR.
   Pelican metadata block — at least `Title:` and `license:`; the home page also sets
   `Template: index`. Mermaid code blocks render as diagrams.
 - Blog posts live in `content/blog/*.md` and need `Date:` as well (plus optional
-  `Author:`, `Tags:`, `Summary:`). They publish to `/blog/<slug>.html` with an index at
-  `/blog/index.html`, rendered by `blog.html` as a Pelican `DIRECT_TEMPLATES` entry. Tag,
-  category and author pages are deliberately not generated (`TAG_SAVE_AS` and friends are
-  `""`); tags are labels only. See README.md for the post front matter.
+  `Author:`, `Tags:`, `Summary:`). They publish to `/blog/<slug>.html`. See README.md for
+  the front matter.
+- **The blog index is a page, not a direct template.** `content/pages/blog.md` carries
+  `Template: blog`, `Save_as: blog/index.html` and `URL: blog/`, and holds no content of
+  its own. It is done this way because `DIRECT_TEMPLATES` can only be set in Pelican
+  settings, and the generated settings aren't ours to change (see above).
+- **`tag.html`, `category.html` and `author.html` must exist.** The generated settings set
+  only the plural switches (`TAGS_SAVE_AS` and friends) and leave the singular ones at
+  their defaults, so Pelican writes one page per tag, category and author for every post
+  whether we want them or not. With no template of our own it falls back to Pelican's
+  built-in simple theme, which extends `index.html`, which expects a `page` — and the
+  whole build dies with something unhelpful like `'str' object has no attribute 'slug'`.
+  The three thin templates and the shared `taxonomy.html` exist to catch that. **Removing
+  them breaks every build that has a post in it**, not just the taxonomy pages.
 - Adding a page does **not** add it to the navigation. Update the nav by hand in
   `content/theme/templates/menu.html`.
 - **Links are deliberately relative** (`about.html`, `css/…`, not `/about.html`,
diff --git a/README.md b/README.md
index 1498bf3..35d2dec 100644
--- a/README.md
+++ b/README.md
@@ -15,8 +15,8 @@ content/
   blog/         Markdown blog posts (one file per post, published under /blog/)
   theme/        Pelican theme (templates)
   css/ js/ fonts/ highlight/ images/   static assets
-pelicanconf.py  Pelican configuration (Python)
-pelicanconf.yaml
+pelicanconf.yaml  Pelican configuration — the one the ASF build reads
+pelicanconf.py    Stale copy of the generated settings, for local builds only
 .asf.yaml       ASF infrastructure configuration (build + notifications)
 pyproject.toml  Python dependencies (managed with uv)
 ```
@@ -57,6 +57,12 @@ Two things to watch:
   `../get-involved.html`, not `get-involved.html`. Links between posts are plain
   (`other-post.html`), and so are external links.
 
+The index at `/blog/` is `content/pages/blog.md`, which only tells Pelican where to put
+the page; the heading and the post list come from the theme. Posts also generate
+`/tag/*.html`, `/category/*.html` and `/author/*.html` listings — those are a requirement
+of the ASF build rather than a feature, and they're marked `noindex`. See AGENTS.md
+before touching any of it.
+
 ## Local build (optional)
 
 The authoritative build runs on ASF infrastructure. To preview locally you need the ASF
diff --git a/content/pages/blog.md b/content/pages/blog.md
new file mode 100644
index 0000000..6eaf8da
--- /dev/null
+++ b/content/pages/blog.md
@@ -0,0 +1,9 @@
+Title: Blog
+Template: blog
+Save_as: blog/index.html
+URL: blog/
+license: https://www.apache.org/licenses/LICENSE-2.0
+
+The blog index is built from the posts in `content/blog/`; this page only tells
+Pelican where to put it. The heading and the list of posts come from the
+`blog.html` template.
diff --git a/content/theme/templates/author.html b/content/theme/templates/author.html
new file mode 100644
index 0000000..945ae21
--- /dev/null
+++ b/content/theme/templates/author.html
@@ -0,0 +1,4 @@
+{% set root = '../' %}
+{% set taxonomy_label = 'Author' %}
+{% set taxonomy_name = author %}
+{% include "taxonomy.html" %}
diff --git a/content/theme/templates/blog.html b/content/theme/templates/blog.html
index 6f6a7c9..12069a9 100644
--- a/content/theme/templates/blog.html
+++ b/content/theme/templates/blog.html
@@ -1,4 +1,6 @@
 {% set root = '../' %}
+{# the Blog crumb is already the last one here, so don't repeat the page #}
+{% set hide_page_crumb = true %}
 {% block head %}
 <!doctype html>
 <html class="no-js" lang="en" dir="ltr">
diff --git a/content/theme/templates/blogindex.html b/content/theme/templates/blogindex.html
index 1707b9b..1c031ee 100644
--- a/content/theme/templates/blogindex.html
+++ b/content/theme/templates/blogindex.html
@@ -5,29 +5,7 @@
     <div class="mx-auto">
       <h1>Blog</h1>
       <p class="rai-lede">News and updates from the Responsible AI initiative at The Apache Software Foundation.</p>
-
-      {% if articles %}
-      <ul class="rai-postlist">
-        {% for article in articles %}
-        <li class="rai-postlist-item">
-          <h2><a href="{{ root }}blog/{{ article.slug }}.html">{{ article.title }}</a></h2>
-          <p class="rai-meta">
-            <time datetime="{{ article.date.isoformat() }}">{{ article.date.strftime('%d %B %Y') }}</time>
-            {%- if article.author %} · {{ article.author }}{% endif %}
-          </p>
-          {% if article.summary %}<div class="rai-summary">{{ article.summary }}</div>{% endif %}
-          {% if article.tags %}
-          <p class="rai-tags">
-            {% for tag in article.tags %}<span class="rai-tag">{{ tag.name }}</span>{% endfor %}
-          </p>
-          {% endif %}
-          <p><a class="rai-more" href="{{ root }}blog/{{ article.slug }}.html">Continue reading &rarr;</a></p>
-        </li>
-        {% endfor %}
-      </ul>
-      {% else %}
-      <p>No posts yet.</p>
-      {% endif %}
+      {% include "postlist.html" %}
     </div>
   </div>
 </div>
diff --git a/content/theme/templates/breadcrumbs.html b/content/theme/templates/breadcrumbs.html
index 2226975..40a39eb 100644
--- a/content/theme/templates/breadcrumbs.html
+++ b/content/theme/templates/breadcrumbs.html
@@ -10,8 +10,8 @@
       {% if article %}
       <li class="breadcrumb-item active"><a href="{{ root }}blog/{{ article.slug }}.html">{{ article.title }}</a></li>
       <li class="breadcrumb-item active">(<a href="https://github.com/apache/rai-site/tree/main/content/blog/{{ article.slug }}.md">edit</a>)</li>
-      {% elif page %}
-      <li class="breadcrumb-item active"><a href="{{ root }}{{ page.slug }}.html">{{ page.title }}</a></li>
+      {% elif page and not hide_page_crumb %}
+      <li class="breadcrumb-item active"><a href="{{ root }}{{ page.url }}">{{ page.title }}</a></li>
       <li class="breadcrumb-item active">(<a href="https://github.com/apache/rai-site/tree/main/content/pages/{{ page.slug }}.md">edit</a>)</li>
       {% endif %}
     </ol>
diff --git a/content/theme/templates/category.html b/content/theme/templates/category.html
new file mode 100644
index 0000000..30d817c
--- /dev/null
+++ b/content/theme/templates/category.html
@@ -0,0 +1,4 @@
+{% set root = '../' %}
+{% set taxonomy_label = 'Category' %}
+{% set taxonomy_name = category %}
+{% include "taxonomy.html" %}
diff --git a/content/theme/templates/postlist.html b/content/theme/templates/postlist.html
new file mode 100644
index 0000000..fb2a4e0
--- /dev/null
+++ b/content/theme/templates/postlist.html
@@ -0,0 +1,24 @@
+{% set root = root|default('') %}
+<!-- shared list of posts, used by the blog index and the taxonomy pages -->
+{% if articles %}
+<ul class="rai-postlist">
+  {% for article in articles %}
+  <li class="rai-postlist-item">
+    <h2><a href="{{ root }}blog/{{ article.slug }}.html">{{ article.title }}</a></h2>
+    <p class="rai-meta">
+      <time datetime="{{ article.date.isoformat() }}">{{ article.date.strftime('%d %B %Y') }}</time>
+      {%- if article.author %} · {{ article.author }}{% endif %}
+    </p>
+    {% if article.summary %}<div class="rai-summary">{{ article.summary }}</div>{% endif %}
+    {% if article.tags %}
+    <p class="rai-tags">
+      {% for tag in article.tags %}<span class="rai-tag">{{ tag.name }}</span>{% endfor %}
+    </p>
+    {% endif %}
+    <p><a class="rai-more" href="{{ root }}blog/{{ article.slug }}.html">Continue reading &rarr;</a></p>
+  </li>
+  {% endfor %}
+</ul>
+{% else %}
+<p>No posts yet.</p>
+{% endif %}
diff --git a/content/theme/templates/tag.html b/content/theme/templates/tag.html
new file mode 100644
index 0000000..2bf6af0
--- /dev/null
+++ b/content/theme/templates/tag.html
@@ -0,0 +1,4 @@
+{% set root = '../' %}
+{% set taxonomy_label = 'Tag' %}
+{% set taxonomy_name = tag %}
+{% include "taxonomy.html" %}
diff --git a/content/theme/templates/taxonomy.html b/content/theme/templates/taxonomy.html
new file mode 100644
index 0000000..3e5fe65
--- /dev/null
+++ b/content/theme/templates/taxonomy.html
@@ -0,0 +1,51 @@
+{% set root = root|default('../') %}
+{#
+  Shared page for Pelican's per-tag, per-category and per-author listings.
+
+  These pages exist because the ASF build generates its settings from
+  pelicanconf.yaml, and that template sets only the plural switches
+  (TAGS_SAVE_AS and friends). The singular ones default to tag/{slug}.html,
+  category/{slug}.html and author/{slug}.html, so Pelican writes one page per
+  tag, category and author whether or not we want them. Without a template of
+  our own it falls back to Pelican's simple theme, which extends index.html and
+  takes the whole build down. Giving it somewhere to land is the fix.
+#}
+{% block head %}
+<!doctype html>
+<html class="no-js" lang="en" dir="ltr">
+  <head>
+    <meta charset="utf-8">
+    <meta http-equiv="x-ua-compatible" content="ie=edge">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+    <title>{{ taxonomy_label }}: {{ taxonomy_name }} - {{SITENAME}}</title>
+    <meta name="robots" content="noindex, follow">
+    {% include "styles.html" %}
+  </head>
+  <body class="d-flex flex-column h-100">
+    {% include "menu.html" %}
+    <main class="flex-shrink-0">
+      <div class="card" style="height: 34px;">
+        <nav aria-label="breadcrumb" style="padding-left: 12px; padding-top: 4px;">
+          <ol class="breadcrumb">
+            <li class="breadcrumb-item"><a href="{{ root }}index.html">Home</a></li>
+            <li class="breadcrumb-item"><a href="{{ root }}blog/">Blog</a></li>
+            <li class="breadcrumb-item active">{{ taxonomy_label }}: {{ taxonomy_name }}</li>
+          </ol>
+        </nav>
+      </div>
+      <div id="contents">
+        <div class="bg-white rounded">
+          <div class="mx-auto">
+            <h1>{{ taxonomy_name }}</h1>
+            <p class="rai-lede">Posts filed under this {{ taxonomy_label|lower }}.</p>
+            {% include "postlist.html" %}
+            <p class="rai-backlink"><a href="{{ root }}blog/">&larr; All posts</a></p>
+          </div>
+        </div>
+      </div>
+      {% include "footer.html" %}
+    </main>
+    {% include "post.html" %}
+  </body>
+</html>
+{% endblock %}
diff --git a/pelicanconf.py b/pelicanconf.py
index a492315..8854cef 100644
--- a/pelicanconf.py
+++ b/pelicanconf.py
@@ -45,23 +45,11 @@ TAGS_SAVE_AS = ""
 CATEGORIES_SAVE_AS = ""
 AUTHORS_SAVE_AS = ""
 ARCHIVES_SAVE_AS = ""
-# Per-tag / per-category / per-author pages too: the theme has no template for
-# them, and posts carry tags only as labels on the post and the blog index.
-TAG_SAVE_AS = ""
-CATEGORY_SAVE_AS = ""
-AUTHOR_SAVE_AS = ""
 # Blog posts live in content/blog/ and are published under /blog/
 ARTICLE_PATHS = ["blog"]
+# needed to create blogs page
 ARTICLE_URL = "blog/{slug}.html"
 ARTICLE_SAVE_AS = "blog/{slug}.html"
-ARTICLE_ORDER_BY = "reversed-date"
-# The blog index: content/theme/templates/blog.html rendered to /blog/index.html
-DIRECT_TEMPLATES = ["blog"]
-BLOG_URL = "blog/"
-BLOG_SAVE_AS = "blog/index.html"
-# Posts carry a Date; drafts are excluded until their status says published
-DEFAULT_DATE_FORMAT = "%d %B %Y"
-WITH_FUTURE_DATES = False
 # Disable all processing of .html files
 READERS = {
     "html": None,