Site: read the newest version from Gitea; links follow releases/latest [skip ci]
A worker answers /release.json from the Gitea API (Gitea sends no CORS headers, so the page cannot ask it directly). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
48306fcd16
commit
87c42fde0e
14 files changed
+76
-16
No files matched your search
@@ -173,7 +173,7 @@ tests/scripts/show-fullscreen.sh 真窗口 ElyShow:F5 放映的窗口盖住
|
||||
tests/scripts/types.sh packaging/types.tsv 的文件类型在 Linux 桌面项、Windows 安装程序与 macOS 文档类型里一致,从不设为默认
|
||||
tests/scripts/layout.sh 真窗口:六个应用在 640、800、1100 宽下无元素越出窗口左右,留截图(需辅助功能与屏幕录制权限)
|
||||
tests/scripts/ooxml.py <用例> <文件> 不经 LibreOffice 读 DOCX、XLSX、PPTX 并按自算的预期核对(往返用例调用)
|
||||
cd site && pnpm deploy 官网构建并经 wrangler 发到 Cloudflare Workers(只有静态资源),地址 https://ely-office.zhangyanghaha0407.workers.dev
|
||||
cd site && pnpm deploy 官网构建并经 wrangler 发到 Cloudflare Workers(静态资源,另有 `site/worker` 只答 `/release.json`:Gitea API 的最新版本,缓存 5 分钟;下载链接指向 `releases/latest`),地址 https://ely-office.zhangyanghaha0407.workers.dev
|
||||
cd site && pnpm test && pnpm e2e 官网单测(几何、道路连通)与 Playwright 端到端(悬停、聚焦、按压、命中归属)
|
||||
cd site/video/scenes && npm run verify 发布视频:群像与离场两个渲染器在切场处屏幕角点一致,离场全程各屏播自己的录屏帧(真页面渲染)
|
||||
cargo check --workspace
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { expect, test, type Page } from "@playwright/test";
|
||||
import { expect, test, type Page } from "./fixtures.ts";
|
||||
|
||||
const PAGE = "/";
|
||||
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
import { test as base } from "@playwright/test";
|
||||
|
||||
export { expect, type Page } from "@playwright/test";
|
||||
|
||||
export const VERSION = "9.9.9";
|
||||
|
||||
// Every page reads this version.
|
||||
export const test = base.extend<{ release: void }>({
|
||||
release: [
|
||||
async ({ context }, use) => {
|
||||
await context.route("**/release.json", (r) => r.fulfill({ json: { version: VERSION } }));
|
||||
await use();
|
||||
},
|
||||
{ auto: true },
|
||||
],
|
||||
});
|
||||
@@ -1,4 +1,4 @@
|
||||
import { expect, test, type Page } from "@playwright/test";
|
||||
import { expect, test, type Page } from "./fixtures.ts";
|
||||
|
||||
const PAGE = "/";
|
||||
const DESK = { light: "rgb(230, 230, 226)", dark: "rgb(58, 58, 58)" };
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { expect, test, type Page } from "@playwright/test";
|
||||
import { expect, test, type Page } from "./fixtures.ts";
|
||||
|
||||
const TREE = "Open a Markdown file's history in ElyTree.";
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { expect, test, type Page } from "@playwright/test";
|
||||
import { expect, test, type Page } from "./fixtures.ts";
|
||||
|
||||
const APPS = ["ElyDoc", "ElyTable", "ElyShow", "ElyPDF", "ElyTree", "ElyMark"];
|
||||
|
||||
|
||||
+16
-2
@@ -1,9 +1,9 @@
|
||||
import { expect, test, type Page } from "@playwright/test";
|
||||
import { expect, test, VERSION, type Page } from "./fixtures.ts";
|
||||
import { TEXT, type Key, type Lang } from "../src/text.ts";
|
||||
|
||||
const REPO = "https://git.zacharyzhang.com/ZacharyZhang-NY/ElyOffice";
|
||||
const APPS = ["ElyDoc", "ElyTable", "ElyShow", "ElyPDF", "ElyTree", "ElyMark"];
|
||||
const RELEASES = `${REPO}/releases/tag/v0.1.4`;
|
||||
const RELEASES = `${REPO}/releases/latest`;
|
||||
|
||||
test.use({ reducedMotion: "reduce" });
|
||||
|
||||
@@ -93,6 +93,20 @@ test.describe("English locale", () => {
|
||||
expect(files).toEqual([]);
|
||||
});
|
||||
|
||||
test("the download area names the newest version", async ({ page }) => {
|
||||
await page.goto("/");
|
||||
await expect(page.locator("#download h2")).toHaveText(`Ely Office ${VERSION}`);
|
||||
});
|
||||
|
||||
test("a failed version read shows as an error", async ({ page }) => {
|
||||
await page.route("**/release.json", (r) => r.fulfill({ status: 502, body: "Gitea answered 500" }));
|
||||
await page.goto("/");
|
||||
await expect.poll(() => errors.length).toBe(1);
|
||||
expect(errors[0]).toContain("Gitea answered 500");
|
||||
await expect(page.locator("#download h2")).toHaveText("Ely Office");
|
||||
errors = [];
|
||||
});
|
||||
|
||||
test("every external link answers @net", async ({ page, request }) => {
|
||||
await page.goto("/");
|
||||
const hrefs = await page.locator("a[href^='http']").evaluateAll((as) => as.map((a) => (a as HTMLAnchorElement).href));
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { expect, test, type Page } from "@playwright/test";
|
||||
import { expect, test, type Page } from "./fixtures.ts";
|
||||
|
||||
const CELL = 28;
|
||||
const APPS = ["ElyDoc", "ElyTable", "ElyShow", "ElyPDF", "ElyTree", "ElyMark"];
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { expect, test, type Page } from "@playwright/test";
|
||||
import { expect, test, type Page } from "./fixtures.ts";
|
||||
|
||||
const APPS = ["ElyDoc", "ElyTable", "ElyShow", "ElyPDF", "ElyTree", "ElyMark"];
|
||||
|
||||
|
||||
+3
-2
@@ -8,7 +8,7 @@ import { rhythm } from "./rhythm.ts";
|
||||
import { playground } from "./play.ts";
|
||||
import { film } from "./film.ts";
|
||||
import { said, speak, type Lang } from "./text.ts";
|
||||
import { RELEASES, VERSION } from "./release.ts";
|
||||
import { RELEASES, latest } from "./release.ts";
|
||||
|
||||
const REPO = "https://git.zacharyzhang.com/ZacharyZhang-NY/ElyOffice";
|
||||
|
||||
@@ -35,7 +35,8 @@ const shelf = props();
|
||||
const footer = document.createElement("footer");
|
||||
footer.id = "download";
|
||||
const version = document.createElement("h2");
|
||||
version.textContent = `Ely Office ${VERSION}`;
|
||||
version.textContent = "Ely Office";
|
||||
void latest().then((v) => (version.textContent = `Ely Office ${v}`));
|
||||
const get = said("a", "get");
|
||||
get.href = RELEASES;
|
||||
footer.append(version, said("p", "platforms"), said("p", "needs"), said("p", "unsigned"), get);
|
||||
|
||||
+10
-3
@@ -1,3 +1,10 @@
|
||||
// This version's release page holds every download.
|
||||
export const VERSION = "0.1.4";
|
||||
export const RELEASES = "https://git.zacharyzhang.com/ZacharyZhang-NY/ElyOffice/releases/tag/v0.1.4";
|
||||
// Gitea redirects this to the newest release.
|
||||
export const RELEASES = "https://git.zacharyzhang.com/ZacharyZhang-NY/ElyOffice/releases/latest";
|
||||
|
||||
/** The newest release's version, from the worker. */
|
||||
export async function latest(): Promise<string> {
|
||||
const res = await fetch("/release.json");
|
||||
if (!res.ok) throw new Error(`release.json: ${res.status} ${await res.text()}`);
|
||||
const { version } = (await res.json()) as { version: string };
|
||||
return version;
|
||||
}
|
||||
+1
-1
@@ -16,5 +16,5 @@
|
||||
"erasableSyntaxOnly": true,
|
||||
"noFallthroughCasesInSwitch": true
|
||||
},
|
||||
"include": ["src"]
|
||||
"include": ["src", "worker"]
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
// Answers /release.json with the newest release.
|
||||
const API = "https://git.zacharyzhang.com/api/v1/repos/ZacharyZhang-NY/ElyOffice/releases/latest";
|
||||
|
||||
type Cached = RequestInit & { cf: { cacheTtl: number; cacheEverything: boolean } };
|
||||
|
||||
export default {
|
||||
async fetch(): Promise<Response> {
|
||||
const init: Cached = {
|
||||
headers: { accept: "application/json", "user-agent": "ely-office-site" },
|
||||
cf: { cacheTtl: 300, cacheEverything: true },
|
||||
};
|
||||
const res = await fetch(API, init);
|
||||
if (!res.ok) return new Response(`Gitea answered ${res.status}`, { status: 502 });
|
||||
const { tag_name: tag } = (await res.json()) as { tag_name: unknown };
|
||||
if (typeof tag !== "string" || !/^v\d+\.\d+\.\d+$/.test(tag)) {
|
||||
return new Response(`Gitea's latest tag is ${JSON.stringify(tag)}`, { status: 502 });
|
||||
}
|
||||
return Response.json({ version: tag.slice(1) }, { headers: { "cache-control": "public, max-age=300" } });
|
||||
},
|
||||
};
|
||||
+3
-1
@@ -1,8 +1,10 @@
|
||||
{
|
||||
"name": "ely-office",
|
||||
"main": "worker/index.ts",
|
||||
"compatibility_date": "2026-10-08",
|
||||
"assets": {
|
||||
"directory": "./dist",
|
||||
"not_found_handling": "404-page"
|
||||
"not_found_handling": "404-page",
|
||||
"run_worker_first": ["/release.json"]
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user