| @@ -262,7 +262,24 @@ pub async fn build_site(config: AbbayeConfig) -> Result<()> { |
| .into_diagnostic()?; |
| |
| // ── 10. Atom feed ───────────────────────────────────────────────────────── |
| - let atom_xml = generate_atom_feed(&config.site.name, &all_versions, base_url); |
| + // Load all changelog sections once so we can embed release notes in feed entries. |
| + let changelog_sections = match ChangelogExtractor |
| + .all_sections(config.changelog.clone()) |
| + .await |
| + { |
| + Ok(map) => map, |
| + Err(_) => { |
| + warn!("Could not load changelog for Atom feed; entries will have no content"); |
| + std::collections::HashMap::new() |
| + } |
| + }; |
| + |
| + let atom_xml = generate_atom_feed( |
| + &config.site.name, |
| + &all_versions, |
| + base_url, |
| + &changelog_sections, |
| + ); |
| tokio::fs::write(output_dir.join(ATOM_FEED_FILENAME), atom_xml) |
| .await |
| .into_diagnostic()?; |
| @@ -432,10 +449,14 @@ fn xml_escape(s: &str) -> String { |
| /// - `base_url`: when provided (already stripped of trailing `/`), used to |
| /// build `<link>` and `<id>` elements with absolute URLs. When absent, |
| /// a `urn:` based ID is used and no `<link>` elements are emitted. |
| +/// - `changelog_sections`: map from version string to Markdown release-note |
| +/// body. When a matching entry is found it is rendered to HTML and included |
| +/// as a `<content type="html">` element in the Atom entry. |
| fn generate_atom_feed( |
| project_name: &str, |
| versions: &[VersionInfo], |
| base_url: Option<&str>, |
| + changelog_sections: &std::collections::HashMap<String, String>, |
| ) -> String { |
| let now: DateTime<Utc> = Utc::now(); |
| |
| @@ -482,12 +503,26 @@ fn generate_atom_feed( |
| None => String::new(), |
| }; |
| |
| + // Render the changelog section (if any) to HTML, then XML-escape |
| + // it for embedding inside <content type="html">. |
| + let content_element = match changelog_sections.get(&vi.version) { |
| + Some(md) if !md.is_empty() => { |
| + let html = render_markdown(md); |
| + format!( |
| + " <content type=\"html\">{}</content>\n", |
| + xml_escape(&html) |
| + ) |
| + } |
| + _ => String::new(), |
| + }; |
| + |
| format!( |
| " <entry>\n\ |
| \x20 <title>{v_escaped}</title>\n\ |
| \x20 <id>{entry_id}</id>\n\ |
| \x20 <updated>{entry_date_str}</updated>\n\ |
| {entry_link}\ |
| + {content_element}\ |
| \x20 </entry>" |
| ) |
| }) |