Publish Claude Code Binaries / Stage and publish binaries (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-arm64 (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build linux-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build windows-amd64 (push) Canceled after 0s
Sync Tutti Agent Skills / sync (push) Canceled after 0s
Windows Agent Adapters / Test Windows agent adapters (push) Canceled after 0s
Windows Daemon Adapters / Test Windows daemon adapters (push) Canceled after 0s
Publish Tutti App Runtime / Publish runtime catalog (push) Canceled after 0s
285 lines
9.3 KiB
JavaScript
285 lines
9.3 KiB
JavaScript
import test from "node:test";
|
|
import assert from "node:assert/strict";
|
|
|
|
import {
|
|
buildCardPayload,
|
|
buildCandidatePromotionElements,
|
|
buildSummaryElements,
|
|
loadRelease,
|
|
resolveMirroredAssetUrl,
|
|
resolveReleaseAssetBaseUrl,
|
|
resolveIntroText,
|
|
resolveReleaseKind
|
|
} from "../../apps/desktop/scripts/send-release-feishu-card.mjs";
|
|
|
|
test("release Feishu card loads draft releases from the authenticated listing", async (t) => {
|
|
const originalFetch = globalThis.fetch;
|
|
t.after(() => {
|
|
globalThis.fetch = originalFetch;
|
|
});
|
|
|
|
const requests = [];
|
|
globalThis.fetch = async (url, options) => {
|
|
requests.push({ url, options });
|
|
if (url.includes("/releases/tags/")) {
|
|
return new Response(null, { status: 404 });
|
|
}
|
|
return Response.json([
|
|
{
|
|
assets: [{ name: "Tutti-0.1.0-rc.4-mac-universal.dmg" }],
|
|
draft: true,
|
|
tag_name: "v0.1.0-rc.4"
|
|
}
|
|
]);
|
|
};
|
|
|
|
const release = await loadRelease(
|
|
"tutti-os/tutti",
|
|
"v0.1.0-rc.4",
|
|
"test-token"
|
|
);
|
|
|
|
assert.equal(release.draft, true);
|
|
assert.equal(release.tag_name, "v0.1.0-rc.4");
|
|
assert.equal(requests.length, 2);
|
|
assert.match(requests[1].url, /\/releases\?per_page=100&page=1$/);
|
|
assert.equal(requests[1].options.headers.authorization, "Bearer test-token");
|
|
});
|
|
|
|
function extractFieldMap(payload) {
|
|
const fieldEntries = payload.card.elements
|
|
.find((element) => element.tag === "div" && Array.isArray(element.fields))
|
|
.fields.map((field) => {
|
|
const [label, value] = field.text.content.split("\n");
|
|
return [label.replace(/\*/g, ""), value];
|
|
});
|
|
|
|
return new Map(fieldEntries);
|
|
}
|
|
|
|
test("release Feishu card marks stable tags as latest releases", () => {
|
|
assert.equal(resolveReleaseKind("v1.12.20"), "Stable latest release");
|
|
assert.match(resolveIntroText("v1.12.20"), /GitHub Release/);
|
|
});
|
|
|
|
test("release Feishu card marks rc tags as prereleases", () => {
|
|
assert.equal(
|
|
resolveReleaseKind("v1.12.19-rc.0"),
|
|
"Release candidate prerelease"
|
|
);
|
|
assert.match(resolveIntroText("v1.12.19-rc.0"), /RC 预览通道/);
|
|
});
|
|
|
|
test("release Feishu card marks beta tags as prereleases", () => {
|
|
assert.equal(resolveReleaseKind("v1.12.19-beta.0"), "Beta prerelease");
|
|
assert.match(resolveIntroText("v1.12.19-beta.0"), /Beta 预览通道/);
|
|
});
|
|
|
|
test("release Feishu card clearly marks candidates without claiming public publication", () => {
|
|
assert.equal(resolveReleaseKind("v1.12.20", "candidate"), "Stable candidate");
|
|
assert.match(resolveIntroText("v1.12.20", "candidate"), /候选版本/);
|
|
assert.match(resolveIntroText("v1.12.20", "candidate"), /尚未向用户开放更新/);
|
|
|
|
const payload = buildCardPayload({
|
|
actor: "jomeswang",
|
|
branch: "release/0704",
|
|
macUrl: "https://example.com/tutti.dmg",
|
|
publicationStatus: "candidate",
|
|
promotionUrl:
|
|
"https://github.com/tutti-os/tutti/actions/workflows/desktop-release-promote.yml",
|
|
releaseUrl: "https://github.com/tutti-os/tutti/releases/tag/v1.12.20",
|
|
runUrl: "https://github.com/tutti-os/tutti/actions/runs/1",
|
|
tag: "v1.12.20",
|
|
target: "4039186abcdef0"
|
|
});
|
|
|
|
assert.equal(payload.card.header.title.content, "Tutti 候选版本待确认");
|
|
assert.equal(payload.card.header.template, "orange");
|
|
assert.equal(extractFieldMap(payload).get("构建类型"), "Stable candidate");
|
|
assert.equal(extractFieldMap(payload).has("Commit"), false);
|
|
assert.equal(extractFieldMap(payload).has("部署分支"), false);
|
|
|
|
const promotionInstructions = payload.card.elements.find((element) =>
|
|
element.text?.content?.includes("发布审核操作")
|
|
);
|
|
assert.match(
|
|
promotionInstructions.text.content,
|
|
/Branch 选择 `release\/0704`/
|
|
);
|
|
assert.match(
|
|
promotionInstructions.text.content,
|
|
/`release_tag` 填写 `v1\.12\.20`/
|
|
);
|
|
|
|
const actionLabels = payload.card.elements
|
|
.find((element) => element.tag === "action")
|
|
.actions.map((action) => action.text.content);
|
|
assert.ok(actionLabels.includes("打开发布审核流水线"));
|
|
assert.ok(!actionLabels.includes("提交发布审核"));
|
|
});
|
|
|
|
test("release Feishu card omits promotion instructions without a workflow URL", () => {
|
|
assert.deepEqual(
|
|
buildCandidatePromotionElements({
|
|
branch: "release/0704",
|
|
promotionUrl: "",
|
|
tag: "v1.12.20"
|
|
}),
|
|
[]
|
|
);
|
|
});
|
|
|
|
test("release Feishu card includes tsh-aligned release context fields", () => {
|
|
const payload = buildCardPayload({
|
|
actor: "jomeswang",
|
|
branch: "main",
|
|
linuxUrl: "https://example.com/tutti.AppImage",
|
|
macUrl: "https://example.com/tutti.dmg",
|
|
releaseUrl: "https://github.com/tutti-os/tutti/releases/tag/v1.12.20",
|
|
runUrl: "https://github.com/tutti-os/tutti/actions/runs/1",
|
|
tag: "v1.12.20",
|
|
target: "4039186abcdef0",
|
|
winUrl: "https://example.com/tutti.exe"
|
|
});
|
|
|
|
const fields = extractFieldMap(payload);
|
|
|
|
assert.equal(payload.card.header.title.content, "Tutti 发布完成");
|
|
assert.equal(fields.get("版本号"), "v1.12.20");
|
|
assert.equal(fields.get("构建类型"), "Stable latest release");
|
|
assert.equal(fields.get("部署人"), "jomeswang");
|
|
|
|
const actionLabels = payload.card.elements
|
|
.find((element) => element.tag === "action")
|
|
.actions.map((action) => action.text.content);
|
|
|
|
assert.deepEqual(actionLabels, [
|
|
"下载 macOS",
|
|
"下载 Windows",
|
|
"查看完整更新日志",
|
|
"查看技术详情"
|
|
]);
|
|
});
|
|
|
|
test("release Feishu card uses the mirrored Windows installer URL", () => {
|
|
const payload = buildCardPayload({
|
|
actor: "jomeswang",
|
|
branch: "main",
|
|
macUrl: "https://example.com/tutti.dmg",
|
|
releaseUrl: "https://github.com/tutti-os/tutti/releases/tag/v1.12.20-rc.0",
|
|
runUrl: "https://github.com/tutti-os/tutti/actions/runs/1",
|
|
tag: "v1.12.20-rc.0",
|
|
target: "4039186abcdef0",
|
|
winUrl:
|
|
"https://downloads.example.com/v1.12.20-rc.0/Tutti-1.12.20-rc.0-win-x64.exe"
|
|
});
|
|
|
|
const windowsAction = payload.card.elements
|
|
.find((element) => element.tag === "action")
|
|
.actions.find((action) => action.text.content === "下载 Windows");
|
|
|
|
assert.equal(
|
|
windowsAction?.url,
|
|
"https://downloads.example.com/v1.12.20-rc.0/Tutti-1.12.20-rc.0-win-x64.exe"
|
|
);
|
|
});
|
|
|
|
test("release Feishu card includes Chinese release summary when available", () => {
|
|
const payload = buildCardPayload({
|
|
actor: "jomeswang",
|
|
branch: "main",
|
|
macUrl: "https://example.com/tutti.dmg",
|
|
releaseUrl: "https://github.com/tutti-os/tutti/releases/tag/v1.12.20",
|
|
runUrl: "https://github.com/tutti-os/tutti/actions/runs/1",
|
|
summary: {
|
|
zh: {
|
|
headline: "本次版本聚焦桌面端发布链路稳定性。",
|
|
sections: [
|
|
{
|
|
title: "发布与下载",
|
|
items: ["稳定包下载入口只指向正式 release。"]
|
|
}
|
|
],
|
|
qaFocus: ["验证 macOS 首次安装和自动更新。"]
|
|
}
|
|
},
|
|
tag: "v1.12.20",
|
|
target: "4039186abcdef0"
|
|
});
|
|
const summaryElement = payload.card.elements.find((element) =>
|
|
element.text?.content?.includes("本次更新")
|
|
);
|
|
|
|
assert.ok(summaryElement);
|
|
assert.match(summaryElement.text.content, /稳定包下载入口只指向正式 release/);
|
|
assert.doesNotMatch(summaryElement.text.content, /QA 重点/);
|
|
});
|
|
|
|
test("release Feishu card skips summary elements when summary is missing", () => {
|
|
assert.deepEqual(buildSummaryElements(null), []);
|
|
});
|
|
|
|
test("release Feishu card can prefer mirrored asset links over GitHub asset URLs", () => {
|
|
assert.equal(
|
|
resolveReleaseAssetBaseUrl({
|
|
bucket: "tutti-release-assets",
|
|
explicitBaseUrl:
|
|
"https://d111111abcdef8.cloudfront.net/desktop-release-assets",
|
|
prefix: "desktop-release-assets"
|
|
}),
|
|
"https://d111111abcdef8.cloudfront.net/desktop-release-assets"
|
|
);
|
|
|
|
assert.equal(
|
|
resolveReleaseAssetBaseUrl({
|
|
bucket: "tutti-release-assets",
|
|
explicitBaseUrl: "",
|
|
prefix: "desktop-release-assets"
|
|
}),
|
|
"https://tutti-release-assets.s3-accelerate.amazonaws.com/desktop-release-assets"
|
|
);
|
|
});
|
|
|
|
test("release Feishu card resolves mirrored macOS URLs from local artifact names", () => {
|
|
assert.equal(
|
|
resolveMirroredAssetUrl(
|
|
[
|
|
"Tutti-0.1.0-rc.4-mac-arm64.dmg",
|
|
"Tutti-0.1.0-rc.4-mac-universal.dmg",
|
|
"Tutti-0.1.0-rc.4-mac-x64.dmg",
|
|
"Tutti-0.1.0-rc.4-win-x64.exe"
|
|
],
|
|
/\.dmg$/i,
|
|
"https://d1x7gb6wqsqmnm.cloudfront.net/tutti-desktop-release-assets",
|
|
"v0.1.0-rc.4"
|
|
),
|
|
"https://d1x7gb6wqsqmnm.cloudfront.net/tutti-desktop-release-assets/v0.1.0-rc.4/Tutti-0.1.0-rc.4-mac-universal.dmg"
|
|
);
|
|
assert.equal(
|
|
resolveMirroredAssetUrl(
|
|
[
|
|
"Tutti-0.1.0-rc.4-mac-arm64.dmg",
|
|
"Tutti-0.1.0-rc.4-mac-universal.dmg",
|
|
"Tutti-0.1.0-rc.4-mac-x64.dmg",
|
|
"Tutti-0.1.0-rc.4-win-x64.exe"
|
|
],
|
|
/-win-x64\.exe$/i,
|
|
"https://d1x7gb6wqsqmnm.cloudfront.net/tutti-desktop-release-assets",
|
|
"v0.1.0-rc.4"
|
|
),
|
|
"https://d1x7gb6wqsqmnm.cloudfront.net/tutti-desktop-release-assets/v0.1.0-rc.4/Tutti-0.1.0-rc.4-win-x64.exe"
|
|
);
|
|
});
|
|
|
|
test("release Feishu card keeps candidate path segments while encoding asset names", () => {
|
|
assert.equal(
|
|
resolveMirroredAssetUrl(
|
|
["Tutti 1.2.3-mac-universal.dmg"],
|
|
/\.dmg$/i,
|
|
"https://downloads.example.com/desktop",
|
|
"candidates/v1.2.3-abcdef0-run42"
|
|
),
|
|
"https://downloads.example.com/desktop/candidates/v1.2.3-abcdef0-run42/Tutti%201.2.3-mac-universal.dmg"
|
|
);
|
|
});
|