From 3f174b5fc925a4b6bf8661f0ef9b83d488145fd2 Mon Sep 17 00:00:00 2001 From: cooronx <2197083441@qq.com> Date: Sat, 18 Apr 2026 10:17:44 +0800 Subject: [PATCH] feat: remove homepage GitHub API request --- .github/workflows/master.yml | 3 ++ .github/workflows/pr_ci.yml | 3 ++ package.json | 1 + scripts/generate-footer-stars.js | 46 +++++++------------------ scripts/generate-homepage-release.js | 51 ++++++++++++++++++++++++++++ scripts/github-data-utils.js | 45 ++++++++++++++++++++++++ src/data/latest-release.json | 5 +++ src/pages/index.js | 16 ++++----- 8 files changed, 126 insertions(+), 44 deletions(-) create mode 100644 scripts/generate-homepage-release.js create mode 100644 scripts/github-data-utils.js create mode 100644 src/data/latest-release.json diff --git a/.github/workflows/master.yml b/.github/workflows/master.yml index 6c0091a4a..ad7bbf4bb 100644 --- a/.github/workflows/master.yml +++ b/.github/workflows/master.yml @@ -51,6 +51,9 @@ jobs: - name: Generate footer stars run: yarn generate:footer-stars + - name: Generate homepage release + run: yarn generate:homepage-release + - name: Build run: yarn build diff --git a/.github/workflows/pr_ci.yml b/.github/workflows/pr_ci.yml index 3024e6cec..9a99b4611 100644 --- a/.github/workflows/pr_ci.yml +++ b/.github/workflows/pr_ci.yml @@ -25,5 +25,8 @@ jobs: - name: Generate footer stars run: yarn generate:footer-stars + - name: Generate homepage release + run: yarn generate:homepage-release + - name: Build website run: yarn build --locale en diff --git a/package.json b/package.json index d63b6281e..4fc98b49f 100644 --- a/package.json +++ b/package.json @@ -6,6 +6,7 @@ "scripts": { "docusaurus": "docusaurus", "generate:footer-stars": "node scripts/generate-footer-stars.js", + "generate:homepage-release": "node scripts/generate-homepage-release.js", "start": "node scripts/start.js", "build": "docusaurus build", "swizzle": "docusaurus swizzle", diff --git a/scripts/generate-footer-stars.js b/scripts/generate-footer-stars.js index 0ab1a51a0..83beca7f2 100644 --- a/scripts/generate-footer-stars.js +++ b/scripts/generate-footer-stars.js @@ -1,5 +1,9 @@ -const fs = require("fs"); const path = require("path"); +const { + fetchGitHubJson, + readExistingJson, + writeJson, +} = require("./github-data-utils"); const badges = require("../src/components/FooterMoreBadges/badges.json"); @@ -16,40 +20,14 @@ function getRepoKey(owner, repo) { return `${owner}/${repo}`; } -function readExistingStars() { - if (!fs.existsSync(outputPath)) { - return null; - } - - try { - return JSON.parse(fs.readFileSync(outputPath, "utf8")); - } catch { - return null; - } -} - async function fetchStars() { - const headers = { - Accept: "application/vnd.github+json", - "User-Agent": "casbin-website-footer-stars", - }; - - if (process.env.GITHUB_TOKEN) { - headers.Authorization = `Bearer ${process.env.GITHUB_TOKEN}`; - } - const results = await Promise.all( badges.map(async({owner, repo}) => { - const response = await fetch(`https://api.github.com/repos/${owner}/${repo}`, { - headers, - }); - - if (!response.ok) { - const body = await response.text(); - throw new Error(`Failed to fetch stars for ${owner}/${repo}: ${response.status} ${body}`); - } - - const data = await response.json(); + const data = await fetchGitHubJson( + `https://api.github.com/repos/${owner}/${repo}`, + "casbin-website-footer-stars", + `stars for ${owner}/${repo}` + ); if (typeof data.stargazers_count !== "number") { throw new Error(`Missing stargazers_count for ${owner}/${repo}`); @@ -63,7 +41,7 @@ async function fetchStars() { } async function main() { - const existingStars = readExistingStars(); + const existingStars = readExistingJson(outputPath); try { const stars = await fetchStars(); @@ -72,7 +50,7 @@ async function main() { stars, }; - fs.writeFileSync(outputPath, `${JSON.stringify(payload, null, 2)}\n`); + writeJson(outputPath, payload); process.stdout.write(`Updated footer stars at ${outputPath}\n`); } catch (error) { if (existingStars?.stars) { diff --git a/scripts/generate-homepage-release.js b/scripts/generate-homepage-release.js new file mode 100644 index 000000000..17eef6abb --- /dev/null +++ b/scripts/generate-homepage-release.js @@ -0,0 +1,51 @@ +const path = require("path"); +const { + fetchGitHubJson, + readExistingJson, + writeJson, +} = require("./github-data-utils"); + +const outputPath = path.join(__dirname, "..", "src", "data", "latest-release.json"); +const fallbackTag = "v3.4.1"; +const fallbackUrl = `https://github.com/apache/casbin/releases/tag/${fallbackTag}`; + +async function fetchLatestRelease() { + const data = await fetchGitHubJson( + "https://api.github.com/repos/casbin/casbin/releases/latest", + "casbin-website-homepage-release", + "latest homepage release" + ); + + return { + generatedAt: new Date().toISOString(), + tagName: data.tag_name || fallbackTag, + url: data.html_url || fallbackUrl, + }; +} + +async function main() { + const existingRelease = readExistingJson(outputPath); + + try { + const payload = await fetchLatestRelease(); + writeJson(outputPath, payload); + process.stdout.write(`Updated homepage release at ${outputPath}\n`); + } catch (error) { + if (existingRelease?.tagName && existingRelease?.url) { + process.stderr.write(`${error.message}\nUsing existing homepage release JSON.\n`); + return; + } + + writeJson(outputPath, { + generatedAt: new Date().toISOString(), + tagName: fallbackTag, + url: fallbackUrl, + }); + process.stderr.write(`${error.message}\nUsing fallback homepage release JSON.\n`); + } +} + +main().catch((error) => { + process.stderr.write(`${error.stack || error}\n`); + process.exit(1); +}); diff --git a/scripts/github-data-utils.js b/scripts/github-data-utils.js new file mode 100644 index 000000000..081b275ac --- /dev/null +++ b/scripts/github-data-utils.js @@ -0,0 +1,45 @@ +const fs = require("fs"); +const path = require("path"); + +function readExistingJson(filePath) { + if (!fs.existsSync(filePath)) { + return null; + } + + try { + return JSON.parse(fs.readFileSync(filePath, "utf8")); + } catch { + return null; + } +} + +function writeJson(filePath, payload) { + fs.mkdirSync(path.dirname(filePath), {recursive: true}); + fs.writeFileSync(filePath, `${JSON.stringify(payload, null, 2)}\n`); +} + +function getGitHubHeaders(userAgent) { + return { + Accept: "application/vnd.github+json", + "User-Agent": userAgent, + }; +} + +async function fetchGitHubJson(url, userAgent, errorLabel) { + const response = await fetch(url, { + headers: getGitHubHeaders(userAgent), + }); + + if (!response.ok) { + const body = await response.text(); + throw new Error(`Failed to fetch ${errorLabel}: ${response.status} ${body}`); + } + + return response.json(); +} + +module.exports = { + fetchGitHubJson, + readExistingJson, + writeJson, +}; diff --git a/src/data/latest-release.json b/src/data/latest-release.json new file mode 100644 index 000000000..f419b3723 --- /dev/null +++ b/src/data/latest-release.json @@ -0,0 +1,5 @@ +{ + "generatedAt": "2026-04-18T02:02:59.172Z", + "tagName": "v3.10.0", + "url": "https://github.com/apache/casbin/releases/tag/v3.10.0" +} diff --git a/src/pages/index.js b/src/pages/index.js index 5c66b31e4..b95671ad0 100644 --- a/src/pages/index.js +++ b/src/pages/index.js @@ -1,4 +1,4 @@ -import React, {useEffect, useRef, useState} from "react"; +import React, {useEffect, useRef} from "react"; import clsx from "clsx"; import Layout from "@theme/Layout"; import Link from "@docusaurus/Link"; @@ -12,26 +12,22 @@ import useDocusaurusContext from "@docusaurus/useDocusaurusContext"; import AnimatedText from "../components/AnimatedText"; import {Code, Zap} from "lucide-react"; import LogoCarousel from "@site/src/components/LogoCarousel"; +import latestReleaseData from "@site/src/data/latest-release.json"; function HomepageHeader() { - const [latestVersion, setLatestVersion] = useState("v3.4.1"); const headerRef = useRef(null); const haloRef = useRef(null); const {siteConfig} = useDocusaurusContext(); const {customFields} = siteConfig; + const latestVersion = latestReleaseData.tagName || "v3.4.1"; + const latestReleaseLink = + latestReleaseData.url || `https://github.com/apache/casbin/releases/tag/${latestVersion}`; // Activate halo behavior for this header useHeroCursorHalo(headerRef, haloRef); - useEffect(() => { - fetch("https://api.github.com/repos/casbin/casbin/releases/latest") - .then(res => res.json()) - .then(data => setLatestVersion(data.tag_name || "v3.4.1")) - .catch(() => setLatestVersion("v3.4.1")); - }, []); - const pillText = customFields?.customMessage || `${latestVersion} Released`; - const link = customFields?.customLink || `https://github.com/casbin/casbin/releases/tag/${latestVersion}`; + const link = customFields?.customLink || latestReleaseLink; return (