Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
/static/feeds/*.json
/static/data/*.json
!/static/data/sbom-attestations.json
!/static/data/firehose-apps.json

# Misc
.DS_Store
Expand Down
10 changes: 10 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@
"fetch-board-data": "node scripts/fetch-board-data.js",
"generate-report": "node scripts/generate-report.mjs",
"fetch-sbom": "node scripts/fetch-github-sbom.js",
"fetch-data": "npm run fetch-feeds && npm run fetch-playlists && npm run fetch-github-profiles && npm run fetch-github-repos && npm run fetch-github-driver-versions && npm run fetch-github-images && npm run fetch-contributors && npm run fetch-board-data"
"fetch-firehose": "node scripts/fetch-firehose.js",
"fetch-data": "npm run fetch-feeds && npm run fetch-playlists && npm run fetch-github-profiles && npm run fetch-github-repos && npm run fetch-github-driver-versions && npm run fetch-github-images && npm run fetch-contributors && npm run fetch-board-data && npm run fetch-firehose"
},
"dependencies": {
"@1password/docusaurus-plugin-stored-data": "^1.0.0",
Expand All @@ -45,6 +46,7 @@
"prism-react-renderer": "^2.3.0",
"react": "^19.0.0",
"react-dom": "^19.0.0",
"react-icons": "^5.6.0",
"xml2js": "^0.6.2"
},
"devDependencies": {
Expand Down
92 changes: 92 additions & 0 deletions scripts/fetch-firehose.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
const fs = require("fs");
const path = require("path");

const OUTPUT_DIR = path.join(__dirname, "..", "static", "data");
const OUTPUT_FILE = path.join(OUTPUT_DIR, "firehose-apps.json");
const SOURCE_URL =
"https://castrojo.github.io/bluefin-releases/apps.json";

// Cache configuration — match the 6h pipeline schedule of bluefin-releases
const CACHE_MAX_AGE_HOURS = 6;

async function fetchFirehoseData() {
// Check if existing cache is fresh enough
if (fs.existsSync(OUTPUT_FILE)) {
const stats = fs.statSync(OUTPUT_FILE);
const ageHours = (Date.now() - stats.mtimeMs) / (1000 * 60 * 60);

if (ageHours < CACHE_MAX_AGE_HOURS && !process.argv.includes("--force")) {
console.log(
`✓ Firehose cache is ${ageHours.toFixed(1)}h old (max ${CACHE_MAX_AGE_HOURS}h). Skipping fetch.`,
);
console.log(` Use --force flag to bypass cache and force fresh fetch.`);
return;
} else if (ageHours >= CACHE_MAX_AGE_HOURS) {
console.log(
`⏱️ Firehose cache is ${ageHours.toFixed(1)}h old (max ${CACHE_MAX_AGE_HOURS}h). Fetching fresh data...`,
);
} else {
console.log("🔄 --force flag detected. Fetching fresh firehose data...");
}
} else {
console.log("Fetching firehose data for the first time...");
}

try {
console.log(`Fetching ${SOURCE_URL}...`);
const response = await fetch(SOURCE_URL);

if (!response.ok) {
throw new Error(
`HTTP ${response.status} ${response.statusText} from ${SOURCE_URL}`,
);
}

const data = await response.json();

// Basic shape validation
if (!data || !Array.isArray(data.apps)) {
throw new Error(
`Unexpected response shape — expected {apps: [...], metadata: {...}}`,
);
}

// Ensure output directory exists
if (!fs.existsSync(OUTPUT_DIR)) {
fs.mkdirSync(OUTPUT_DIR, { recursive: true });
}

fs.writeFileSync(OUTPUT_FILE, JSON.stringify(data, null, 2), "utf-8");

console.log(
`✓ Firehose data saved: ${data.apps.length} apps to ${OUTPUT_FILE}`,
);
} catch (error) {
console.warn(`\n⚠️ Failed to fetch firehose data: ${error.message}`);
console.warn(
" The changelogs page will use the committed seed file (empty app list).",
);
console.warn(
" This is expected on first run before the bluefin-releases pipeline has deployed.\n",
);

// Graceful degradation — keep the existing file (seed or last successful fetch).
// Do NOT write an empty file here; the committed seed is the fallback.
if (!fs.existsSync(OUTPUT_FILE)) {
// Safety net: write a valid empty structure if the seed is somehow missing
if (!fs.existsSync(OUTPUT_DIR)) {
fs.mkdirSync(OUTPUT_DIR, { recursive: true });
}
fs.writeFileSync(
OUTPUT_FILE,
JSON.stringify({ apps: [], metadata: {} }, null, 2),
"utf-8",
);
}
}
}

fetchFirehoseData().catch((error) => {
console.error("Fatal error in fetch-firehose:", error);
// Never fail the build — keep existing file
});
61 changes: 2 additions & 59 deletions src/components/CommunityFeeds.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import React from "react";
import Layout from "@theme/Layout";
import { CombinedFeedItems } from "../components/FeedItems";
import PackageSummary from "../components/PackageSummary";
import FirehoseFeed from "../components/FirehoseFeed";
import styles from "./CommunityFeeds.module.css";

const CommunityFeeds: React.FC = () => {
Expand All @@ -13,71 +12,15 @@
<div className="container margin-vert--lg">
<div className={styles.overviewPanel}>
<div className={styles.header}>
<h1>Changelogs and Feeds</h1>

Check warning on line 15 in src/components/CommunityFeeds.tsx

View workflow job for this annotation

GitHub Actions / Build Docusaurus

Do not use any of the `<hn>` tags for headings. Use the `<Heading />` component from `@theme/Heading` instead
<p className={styles.overviewLinks}>
Need project-wide status? See <a href="/reports">Monthly Reports</a>{" "}
for delivery summaries from <a href="https://todo.projectbluefin.io">todo.projectbluefin.io</a>.
</p>
</div>

<div className={styles.packageSummaryGrid}>
<PackageSummary feedKey="bluefinLtsReleases" title="Bluefin LTS" />
<PackageSummary
feedKey="bluefinReleases"
title="Bluefin"
filter={(item) => item.title.startsWith("stable-")}
/>
</div>
</div>

<div className={styles.feedGrid}>
<CombinedFeedItems
title="Release Changelogs"
feeds={[
{ feedId: "bluefinLtsReleases", label: "Bluefin LTS" },
{
feedId: "bluefinReleases",
label: "Bluefin",
filter: (item) => item.title.startsWith("stable-"),
},
]}
maxItems={20}
/>
</div>

<div className={styles.additionalLinks}>
<h2>Additional Feeds</h2>
<div className={styles.linkGrid}>
<a
href="https://docs.projectbluefin.io/blog/rss.xml"
className={styles.resourceLink}
>
<strong>Blog RSS Feed</strong>
<span>Subscribe to official blog posts and announcements</span>
</a>
<a
href="https://github.com/ublue-os/bluefin/releases.atom"
className={styles.resourceLink}
>
<strong>Releases Feed</strong>
<span>Direct feed for Bluefin releases</span>
</a>
<a
href="https://github.com/ublue-os/bluefin-lts/releases.atom"
className={styles.resourceLink}
>
<strong>LTS Releases Feed</strong>
<span>Direct feed for Bluefin LTS releases</span>
</a>
<a
href="https://github.com/ublue-os/bluefin/discussions.atom"
className={styles.resourceLink}
>
<strong>Discussions Feed</strong>
<span>Community discussions and support topics</span>
</a>
</div>
</div>
<FirehoseFeed />
</div>
</Layout>
);
Expand Down
Loading
Loading