You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@casbin.apache.org by hs...@apache.org on 2026/08/20 17:02:24 UTC
(casbin-website) branch master updated: feat: auto-generate download page release info
This is an automated email from the ASF dual-hosted git repository.
hsluoyz pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/casbin-website.git
The following commit(s) were added to refs/heads/master by this push:
new 45040fa25 feat: auto-generate download page release info
45040fa25 is described below
commit 45040fa2504de5521e0e4b90926ee76565c3219d
Author: Yang Luo <hs...@gmail.com>
AuthorDate: Fri Aug 21 01:02:13 2026 +0800
feat: auto-generate download page release info
---
.github/workflows/master.yml | 3 +
.github/workflows/pr_ci.yml | 3 +
docs/Download.mdx | 26 ++++++++
docusaurus.config.js | 9 +++
package.json | 1 +
scripts/generate-asf-release.js | 103 +++++++++++++++++++++++++++++
sidebars.js | 2 +-
src/components/AsfReleaseDownload/index.js | 33 +++++++++
src/data/asf-release.json | 8 +++
9 files changed, 187 insertions(+), 1 deletion(-)
diff --git a/.github/workflows/master.yml b/.github/workflows/master.yml
index ad7bbf4bb..6bf4c63c6 100644
--- a/.github/workflows/master.yml
+++ b/.github/workflows/master.yml
@@ -54,6 +54,9 @@ jobs:
- name: Generate homepage release
run: yarn generate:homepage-release
+ - name: Generate ASF release
+ run: yarn generate:asf-release
+
- name: Build
run: yarn build
diff --git a/.github/workflows/pr_ci.yml b/.github/workflows/pr_ci.yml
index 9a99b4611..7fc0cd3da 100644
--- a/.github/workflows/pr_ci.yml
+++ b/.github/workflows/pr_ci.yml
@@ -28,5 +28,8 @@ jobs:
- name: Generate homepage release
run: yarn generate:homepage-release
+ - name: Generate ASF release
+ run: yarn generate:asf-release
+
- name: Build website
run: yarn build --locale en
diff --git a/docs/Download.mdx b/docs/Download.mdx
new file mode 100644
index 000000000..bc8f89db4
--- /dev/null
+++ b/docs/Download.mdx
@@ -0,0 +1,26 @@
+---
+id: download
+title: Download
+description: Download and verify Apache Casbin releases
+keywords: [Casbin, download, release, source release, PGP signature, SHA-512, verification]
+---
+
+```mdx-code-block
+import AsfReleaseDownload from "@site/src/components/AsfReleaseDownload";
+```
+
+The official Apache Casbin release is the source archive published by The Apache Software Foundation. For package-manager installation and first use, see [Get Started](/docs/get-started).
+
+## Latest release
+
+```mdx-code-block
+<AsfReleaseDownload />
+```
+
+## Verify your download
+
+Always verify the source archive with its SHA-512 checksum and PGP signature before use. The signing keys are in the KEYS file above, and [the ASF verification guide](https://www.apache.org/info/verification.html) explains how to check both.
+
+## Older releases
+
+Every Apache Casbin release stays available in [the ASF distribution archive](https://archive.apache.org/dist/incubator/casbin/). Only the latest release is supported.
diff --git a/docusaurus.config.js b/docusaurus.config.js
index bf35edb36..6184b6ccc 100644
--- a/docusaurus.config.js
+++ b/docusaurus.config.js
@@ -84,6 +84,11 @@ module.exports = {
},
],
},
+ {
+ to: "/docs/download",
+ label: "Download",
+ position: "left",
+ },
{
to: "/ecosystem",
label: "Plugins",
@@ -183,6 +188,10 @@ module.exports = {
{
title: "Docs",
items: [
+ {
+ label: "Download",
+ to: "/docs/download",
+ },
{
label: "Getting Started",
to: "/docs/get-started",
diff --git a/package.json b/package.json
index 476481e5e..a53d84d13 100644
--- a/package.json
+++ b/package.json
@@ -7,6 +7,7 @@
"docusaurus": "docusaurus",
"generate:footer-stars": "node scripts/generate-footer-stars.js",
"generate:homepage-release": "node scripts/generate-homepage-release.js",
+ "generate:asf-release": "node scripts/generate-asf-release.js",
"start": "node scripts/start.js",
"build": "docusaurus build",
"swizzle": "docusaurus swizzle",
diff --git a/scripts/generate-asf-release.js b/scripts/generate-asf-release.js
new file mode 100644
index 000000000..2531e21c1
--- /dev/null
+++ b/scripts/generate-asf-release.js
@@ -0,0 +1,103 @@
+const path = require("path");
+const {readExistingJson, writeJson} = require("./github-data-utils");
+
+// Podling releases live under /incubator/; drop that segment once Casbin graduates.
+const distPath = "incubator/casbin";
+// Checksums, signatures and KEYS must come from the ASF distribution directory,
+// while the source archive itself must go through the closer.lua mirror script.
+// See https://infra.apache.org/release-download-pages.html
+const downloadsBase = `https://downloads.apache.org/${distPath}`;
+const mirrorBase = `https://www.apache.org/dyn/closer.lua/${distPath}`;
+
+const outputPath = path.join(__dirname, "..", "src", "data", "asf-release.json");
+const fallbackVersion = "3.11.0-incubating";
+
+function buildRelease(version, sourceFile) {
+ return {
+ generatedAt: new Date().toISOString(),
+ version,
+ sourceUrl: `${mirrorBase}/${version}/${sourceFile}`,
+ signatureUrl: `${downloadsBase}/${version}/${sourceFile}.asc`,
+ checksumUrl: `${downloadsBase}/${version}/${sourceFile}.sha512`,
+ keysUrl: `${downloadsBase}/KEYS`,
+ };
+}
+
+async function fetchListing(url) {
+ const response = await fetch(url, {
+ headers: {"User-Agent": "casbin-website-asf-release"},
+ });
+
+ if (!response.ok) {
+ const body = await response.text();
+ throw new Error(`Failed to fetch ASF release listing ${url}: ${response.status} ${body}`);
+ }
+
+ return response.text();
+}
+
+function parseHrefs(html) {
+ return [...html.matchAll(/href="([^"]+)"/gu)].map((match) => match[1]);
+}
+
+function compareVersions(left, right) {
+ const toParts = (version) => version.split("-")[0].split(".").map(Number);
+ const leftParts = toParts(left);
+ const rightParts = toParts(right);
+
+ for (let i = 0; i < Math.max(leftParts.length, rightParts.length); i += 1) {
+ const diff = (leftParts[i] ?? 0) - (rightParts[i] ?? 0);
+ if (diff !== 0) {
+ return diff;
+ }
+ }
+
+ return 0;
+}
+
+async function fetchLatestRelease() {
+ const versions = parseHrefs(await fetchListing(`${downloadsBase}/`))
+ .filter((href) => /^\d+\.\d+[^/]*\/$/u.test(href))
+ .map((href) => href.replace(/\/$/u, ""))
+ .sort(compareVersions);
+
+ const version = versions[versions.length - 1];
+ if (!version) {
+ throw new Error(`Found no release directory under ${downloadsBase}/`);
+ }
+
+ const sourceFile = parseHrefs(await fetchListing(`${downloadsBase}/${version}/`))
+ .map((href) => href.split("/").pop())
+ .find((file) => file.endsWith("-src.tar.gz"));
+
+ if (!sourceFile) {
+ throw new Error(`Found no source archive under ${downloadsBase}/${version}/`);
+ }
+
+ return buildRelease(version, sourceFile);
+}
+
+async function main() {
+ const existingRelease = readExistingJson(outputPath);
+
+ try {
+ writeJson(outputPath, await fetchLatestRelease());
+ process.stdout.write(`Updated ASF release at ${outputPath}\n`);
+ } catch (error) {
+ if (existingRelease?.version && existingRelease?.sourceUrl) {
+ process.stderr.write(`${error.message}\nUsing existing ASF release JSON.\n`);
+ return;
+ }
+
+ writeJson(
+ outputPath,
+ buildRelease(fallbackVersion, `apache-casbin-${fallbackVersion}-src.tar.gz`)
+ );
+ process.stderr.write(`${error.message}\nUsing fallback ASF release JSON.\n`);
+ }
+}
+
+main().catch((error) => {
+ process.stderr.write(`${error.stack || error}\n`);
+ process.exit(1);
+});
diff --git a/sidebars.js b/sidebars.js
index ed40816d1..7278a1668 100644
--- a/sidebars.js
+++ b/sidebars.js
@@ -16,7 +16,7 @@ module.exports = {
// But you can create a sidebar manually
docs: [
- "downloads",
+ "download",
{
type: "category",
label: "Basics",
diff --git a/src/components/AsfReleaseDownload/index.js b/src/components/AsfReleaseDownload/index.js
new file mode 100644
index 000000000..83b387ad3
--- /dev/null
+++ b/src/components/AsfReleaseDownload/index.js
@@ -0,0 +1,33 @@
+import React from "react";
+import Translate from "@docusaurus/Translate";
+import release from "@site/src/data/asf-release.json";
+
+// The release metadata is refreshed at build time by scripts/generate-asf-release.js,
+// so a new ASF release shows up here without editing the download page.
+export default function AsfReleaseDownload() {
+ return (
+ <ul>
+ <li>
+ <a href={release.sourceUrl}>
+ <Translate
+ values={{version: release.version}}
+ >
+ {"Apache Casbin {version} source release"}
+ </Translate>
+ </a>
+ {" ("}
+ <a href={release.signatureUrl}>
+ <Translate>PGP signature</Translate>
+ </a>
+ {", "}
+ <a href={release.checksumUrl}>SHA-512</a>
+ {")"}
+ </li>
+ <li>
+ <a href={release.keysUrl}>
+ <Translate>Release signing keys (KEYS)</Translate>
+ </a>
+ </li>
+ </ul>
+ );
+}
diff --git a/src/data/asf-release.json b/src/data/asf-release.json
new file mode 100644
index 000000000..ce521c198
--- /dev/null
+++ b/src/data/asf-release.json
@@ -0,0 +1,8 @@
+{
+ "generatedAt": "2026-08-20T16:55:02.560Z",
+ "version": "3.11.0-incubating",
+ "sourceUrl": "https://www.apache.org/dyn/closer.lua/incubator/casbin/3.11.0-incubating/apache-casbin-3.11.0-incubating-src.tar.gz",
+ "signatureUrl": "https://downloads.apache.org/incubator/casbin/3.11.0-incubating/apache-casbin-3.11.0-incubating-src.tar.gz.asc",
+ "checksumUrl": "https://downloads.apache.org/incubator/casbin/3.11.0-incubating/apache-casbin-3.11.0-incubating-src.tar.gz.sha512",
+ "keysUrl": "https://downloads.apache.org/incubator/casbin/KEYS"
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@casbin.apache.org
For additional commands, e-mail: commits-help@casbin.apache.org