1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2025-12-28 16:01:18 +01:00

Merge pull request #21741 from LasseRosenow/guides-add-riot-changelog

doc/starlight: add RIOT changelog
This commit is contained in:
crasbe 2025-10-02 12:59:16 +00:00 committed by GitHub
commit 0b436d8898
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 1514 additions and 1493 deletions

View File

@ -18,4 +18,8 @@
"editor.tabSize": 2,
"editor.insertSpaces": true,
},
"[javascript][typescript]": {
"editor.tabSize": 2,
"editor.insertSpaces": true
}
}

View File

@ -892,7 +892,7 @@ INPUT = ../../doc.txt \
src/emulators.md \
src/release-cycle.md \
src/io-mapping-and-shields.md \
src/changelog.md \
src/changelog-deprecated.md \
src/LOSTANDFOUND.md \
../../makefiles/pseudomodules.inc.mk \
../../makefiles/blob.inc.mk \

View File

@ -0,0 +1,6 @@
# Changelog (Deprecated) {#changelog}
@deprecated This page is deprecated.
See [Changelog](https://guide.riot-os.org/changelog)
on the RIOT Guide Site for the latest information.
This page will be removed after release 2026.04.

View File

@ -1,13 +1,28 @@
// @ts-check
import { defineConfig } from "astro/config";
import starlight from "@astrojs/starlight";
import rehypeGithubEmoji from "rehype-github-emoji";
// https://astro.build/config
export default defineConfig({
site: "https://guide.riot-os.org",
markdown: {
rehypePlugins: [rehypeGithubEmoji],
},
integrations: [
starlight({
title: "RIOT Documentation",
head: [
{
tag: "link",
attrs: {
rel: "alternate",
type: "application/rss+xml",
title: "RIOT Changelog",
href: "/changelog/rss.xml",
},
},
],
social: [
{
icon: "github",
@ -150,6 +165,10 @@ export default defineConfig({
"misc/how_to_doc",
],
},
{
label: "Changelog",
link: "changelog",
},
],
customCss: ["./src/styles/custom.css", "./src/fonts/font-face.css"],
logo: {
@ -165,7 +184,7 @@ export default defineConfig({
vite: {
server: {
fs: {
allow: ["./", "../doxygen"],
allow: ["./", "../doxygen", "../../release-notes.txt"],
},
},
},

File diff suppressed because it is too large Load Diff

View File

@ -10,8 +10,10 @@
"astro": "astro"
},
"dependencies": {
"@astrojs/starlight": "^0.33.1",
"astro": "^5.5.3",
"sharp": "^0.32.5"
"@astrojs/rss": "^4.0.12",
"@astrojs/starlight": "^0.36.0",
"astro": "^5.14.0",
"rehype-github-emoji": "^1.0.0",
"sharp": "^0.34.0"
}
}

View File

@ -1,10 +1,125 @@
import { defineCollection } from "astro:content";
import { glob } from "astro/loaders";
import { defineCollection, z } from "astro:content";
import { glob, type Loader } from "astro/loaders";
import { docsSchema } from "@astrojs/starlight/schema";
import { promises as fs } from "node:fs";
export const collections = {
docs: defineCollection({
loader: glob({ pattern: "**/*.(md|mdx)", base: "../guides" }),
schema: docsSchema(),
}),
changelog: defineCollection({
loader: changelogLoader(),
schema: z.object({
title: z.string(),
release: z.string(),
codeName: z.string(),
slug: z.string(),
date: z.date(),
markdown: z.string(),
}),
}),
};
/**
* Generate a content collection containing the release notes of each release as an entry.
* This function parses the release-notes.txt file from the root of the RIOT repository.
* The release-notes syntax is converted to correct markdown and then parsed.
*/
export function changelogLoader(): Loader {
return {
name: "changelog-loader",
load: async (context): Promise<void> => {
// Read release-notes.txt file
const buffer = await fs.readFile("../../release-notes.txt");
// Convert the buffer to text
const content = buffer.toString("utf8");
// convert the text to an array of lines
const lines = content.split("\n");
let currentReleaseHeading: string | null = null;
let currentReleaseHeadingIndex: number | null = null;
for (const [index, line] of lines.entries()) {
const nextLine = lines[index + 1];
// Convert "Setext Style" headings to "ATX Style" headings
// This is necessary to support heading nesting higher than h1 and h2
// Check if next line contains only "=" characters
if (/^=+$/.test(nextLine)) {
// If yes add a "##" to the current lines beginning
lines[index] = `# ${line}`;
// Remove the next lines content
lines[index + 1] = "";
}
// Check if next line contains only "-" characters
if (/^-+$/.test(nextLine)) {
// If yes add a "###" to the current lines beginning
lines[index] = `## ${line}`;
// Remove the next lines content
lines[index + 1] = "";
}
// Convert all headings to be one level lower
// h1 => h2, h2 => h3, h3 => h4 etc.
// This is necessary, because the heading levels of this file are wrong (for markdown)
// We cannot have more than one h1 per document etc.
if (lines[index].startsWith("#")) {
lines[index] = `#${lines[index]}`;
}
// Check if the current line is a RIOT release heading
// or if we have reached the last line of the file.
if (
/(RIOT-.*? - Release Notes)|(Release 2013\.08)/.test(line) ||
index == lines.length - 1
) {
// If we already found a release heading before, we now
// reached the end of its changelog
if (
currentReleaseHeading != null &&
currentReleaseHeadingIndex != null
) {
// Extract the release (YYYY.MM.*) from the release heading
const release =
currentReleaseHeading.match(/(\d{4}\.\d{2}(\.\d+)?)/)?.[1] || "";
// Create a slug based on the date
const slug = release.replaceAll(".", "-");
// Generate a date object from the slug (since it is a date)
const date = new Date(release);
// Extract the release code name from the heading if it exists
const codeName =
currentReleaseHeading.match(/"([^"]+)"/)?.[1] || null;
// Extract current release content
const currentReleaseContent = lines
.slice(currentReleaseHeadingIndex + 1, index)
.join("\n");
// Add entry to content collection
context.store.set({
id: slug,
data: {
title: `RIOT-${release}${
codeName ? ` "${codeName}"` : ""
} - Release Notes`,
release: release,
codeName: codeName,
slug: slug,
date: date,
markdown: currentReleaseContent,
},
rendered: await context.renderMarkdown(currentReleaseContent),
});
}
currentReleaseHeading = line;
currentReleaseHeadingIndex = index;
}
}
},
};
}

View File

@ -0,0 +1,33 @@
---
import StarlightPage from "@astrojs/starlight/components/StarlightPage.astro";
import { LinkButton, LinkCard } from "@astrojs/starlight/components";
import { getCollection } from "astro:content";
const changelog = await getCollection("changelog");
---
<StarlightPage
frontmatter={{
title: "Changelog",
description: "Complete version history and release notes for RIOT",
}}
>
<LinkButton
href="/changelog/rss.xml"
variant="secondary"
icon="rss"
iconPlacement="start"
>
Subscribe to RSS Feed
</LinkButton>
<!-- Add a gap between the rss-feed button and the link-cards -->
<div style={{ height: "0.5rem" }}></div>
{
changelog.map((entry) => (
<LinkCard
title={`${entry.data.release}${entry.data.codeName ? ` "${entry.data.codeName}"` : ""}`}
href={`/changelog/${entry.data.slug}`}
/>
))
}
</StarlightPage>

View File

@ -0,0 +1,30 @@
---
import StarlightPage from "@astrojs/starlight/components/StarlightPage.astro";
import { getCollection, render } from "astro:content";
export async function getStaticPaths() {
const changelog = await getCollection("changelog");
return changelog.map((entry) => ({
params: {
version: entry.data.slug,
},
props: {
entry: entry,
},
}));
}
const { entry } = Astro.props;
const { Content, headings } = await render(entry);
---
<StarlightPage
frontmatter={{
title: entry.data.title,
description: "List of all changes in this release",
pagefind: false, // We don't want to pollute our search with release-notes entries
}}
headings={headings}
><Content />
</StarlightPage>

View File

@ -0,0 +1,23 @@
import rss from "@astrojs/rss";
import { getCollection } from "astro:content";
export async function GET(context) {
const changelog = await getCollection("changelog");
return rss({
// `<title>` field in output xml
title: "RIOT Changelog",
// `<description>` field in output xml
description: "Changelog of RIOT releases",
// Pull in your project "site" from the endpoint context
// https://docs.astro.build/en/reference/api-reference/#site
site: context.site,
// Array of `<item>`s in output xml
// See "Generating items" section for examples using content collections and glob imports
items: changelog.map((entry) => ({
title: entry.data.title,
link: `/changelog/${entry.data.slug}`,
pubDate: entry.data.date,
})),
});
}

View File

@ -5,7 +5,7 @@
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@components/*": ["src/components/*"],
"@components/*": ["src/components/*"]
},
"types": ["astro/client", "astro/astro-jsx"]
}