mirror of
https://github.com/aiclientproxy/proxycast.git
synced 2026-09-24 23:10:56 +08:00
chore: release v1.39.0
This commit is contained in:
@@ -202,6 +202,17 @@ function readImageLaunch(metadata) {
|
||||
return { launch, imageTask };
|
||||
}
|
||||
|
||||
function isImageGenerateSkillExecution(invoke) {
|
||||
return (
|
||||
invoke?.cmd === "execute_skill" &&
|
||||
invoke.args?.skillName === "image_generate"
|
||||
);
|
||||
}
|
||||
|
||||
function isLegacyImageRuntimeSubmit(invoke) {
|
||||
return invoke?.cmd === "agent_runtime_submit_turn";
|
||||
}
|
||||
|
||||
function parseInvokeRequest(request, invokeUrl) {
|
||||
const requestUrl = request.url();
|
||||
const normalizedInvokeUrl = invokeUrl.replace(/\/$/, "");
|
||||
@@ -507,59 +518,110 @@ async function main() {
|
||||
});
|
||||
|
||||
const submitInvoke = await waitForCondition(
|
||||
"等待 @配图 提交 agent_runtime_submit_turn",
|
||||
"等待 @配图 提交 image_generate 执行请求",
|
||||
() =>
|
||||
invokes
|
||||
.slice(submitStart)
|
||||
.find((item) => item.cmd === "agent_runtime_submit_turn") || null,
|
||||
.find(
|
||||
(item) =>
|
||||
isImageGenerateSkillExecution(item) ||
|
||||
isLegacyImageRuntimeSubmit(item),
|
||||
) || null,
|
||||
options.timeoutMs,
|
||||
options.intervalMs,
|
||||
);
|
||||
const request = submitInvoke.args?.request || {};
|
||||
const turnConfig = request.turn_config || {};
|
||||
const metadata = turnConfig.metadata || {};
|
||||
const { launch, imageTask } = readImageLaunch(metadata);
|
||||
const runtimeContract = readNestedObject(imageTask, [
|
||||
"runtime_contract",
|
||||
"runtimeContract",
|
||||
]);
|
||||
const contractKey =
|
||||
imageTask?.modality_contract_key ||
|
||||
imageTask?.modalityContractKey ||
|
||||
runtimeContract?.contract_key ||
|
||||
runtimeContract?.contractKey;
|
||||
|
||||
assert(launch, "@配图 提交缺少 harness.image_skill_launch");
|
||||
assert(imageTask, "@配图 提交缺少 image_task");
|
||||
assert(
|
||||
String(imageTask.prompt || "").includes(IMAGE_PROMPT),
|
||||
"@配图 image_task.prompt 未保留用户输入",
|
||||
);
|
||||
assert(
|
||||
contractKey === "image_generation",
|
||||
`@配图 image_task 合同应为 image_generation,实际为 ${String(contractKey)}`,
|
||||
);
|
||||
assert(
|
||||
turnConfig.provider_preference == null,
|
||||
"@配图 不应把当前聊天 provider 提交为 request provider_preference",
|
||||
);
|
||||
assert(
|
||||
turnConfig.model_preference == null,
|
||||
"@配图 不应把当前聊天 model 提交为 request model_preference",
|
||||
);
|
||||
if (isImageGenerateSkillExecution(submitInvoke)) {
|
||||
const args = submitInvoke.args || {};
|
||||
const userInput = String(args.userInput || "");
|
||||
assert(
|
||||
userInput.includes("@配图"),
|
||||
"@配图 execute_skill.userInput 应保留命令标签",
|
||||
);
|
||||
assert(
|
||||
userInput.includes(IMAGE_PROMPT),
|
||||
"@配图 execute_skill.userInput 未保留用户输入",
|
||||
);
|
||||
assert(
|
||||
typeof args.executionId === "string" && args.executionId.trim(),
|
||||
"@配图 execute_skill 缺少 executionId",
|
||||
);
|
||||
assert(
|
||||
typeof args.sessionId === "string" && args.sessionId.trim(),
|
||||
"@配图 execute_skill 缺少 sessionId",
|
||||
);
|
||||
|
||||
summary.assertions.imageSkillLaunchSubmitted = true;
|
||||
summary.assertions.imageGenerationContractPreserved = true;
|
||||
summary.assertions.chatModelPreferenceSuppressed = true;
|
||||
summary.submitRequest = {
|
||||
message: request.message,
|
||||
sessionId: request.session_id || null,
|
||||
turnId: request.turn_id || null,
|
||||
providerPreference: turnConfig.provider_preference ?? null,
|
||||
modelPreference: turnConfig.model_preference ?? null,
|
||||
contractKey,
|
||||
imagePrompt: imageTask.prompt,
|
||||
};
|
||||
await page
|
||||
.getByText("先执行技能 image_generate", { exact: false })
|
||||
.first()
|
||||
.waitFor({ state: "visible", timeout: options.timeoutMs });
|
||||
await page
|
||||
.getByText("图片生成", { exact: false })
|
||||
.first()
|
||||
.waitFor({ state: "visible", timeout: options.timeoutMs });
|
||||
|
||||
summary.assertions.imageSkillExecutionSubmitted = true;
|
||||
summary.assertions.imageCommandTagPreserved = true;
|
||||
summary.assertions.imagePromptPreserved = true;
|
||||
summary.assertions.imageGenerateProcessVisible = true;
|
||||
summary.submitRequest = {
|
||||
routeMode: "skill_execution",
|
||||
command: submitInvoke.cmd,
|
||||
skillName: args.skillName,
|
||||
userInput,
|
||||
sessionId: args.sessionId || null,
|
||||
executionId: args.executionId || null,
|
||||
providerOverride: args.providerOverride ?? null,
|
||||
modelOverride: args.modelOverride ?? null,
|
||||
};
|
||||
} else {
|
||||
const request = submitInvoke.args?.request || {};
|
||||
const turnConfig = request.turn_config || {};
|
||||
const metadata = turnConfig.metadata || {};
|
||||
const { launch, imageTask } = readImageLaunch(metadata);
|
||||
const runtimeContract = readNestedObject(imageTask, [
|
||||
"runtime_contract",
|
||||
"runtimeContract",
|
||||
]);
|
||||
const contractKey =
|
||||
imageTask?.modality_contract_key ||
|
||||
imageTask?.modalityContractKey ||
|
||||
runtimeContract?.contract_key ||
|
||||
runtimeContract?.contractKey;
|
||||
|
||||
assert(launch, "@配图 提交缺少 harness.image_skill_launch");
|
||||
assert(imageTask, "@配图 提交缺少 image_task");
|
||||
assert(
|
||||
String(imageTask.prompt || "").includes(IMAGE_PROMPT),
|
||||
"@配图 image_task.prompt 未保留用户输入",
|
||||
);
|
||||
assert(
|
||||
contractKey === "image_generation",
|
||||
`@配图 image_task 合同应为 image_generation,实际为 ${String(contractKey)}`,
|
||||
);
|
||||
assert(
|
||||
turnConfig.provider_preference == null,
|
||||
"@配图 不应把当前聊天 provider 提交为 request provider_preference",
|
||||
);
|
||||
assert(
|
||||
turnConfig.model_preference == null,
|
||||
"@配图 不应把当前聊天 model 提交为 request model_preference",
|
||||
);
|
||||
|
||||
summary.assertions.imageSkillLaunchSubmitted = true;
|
||||
summary.assertions.imageGenerationContractPreserved = true;
|
||||
summary.assertions.chatModelPreferenceSuppressed = true;
|
||||
summary.submitRequest = {
|
||||
routeMode: "agent_runtime_submit_turn",
|
||||
message: request.message,
|
||||
sessionId: request.session_id || null,
|
||||
turnId: request.turn_id || null,
|
||||
providerPreference: turnConfig.provider_preference ?? null,
|
||||
modelPreference: turnConfig.model_preference ?? null,
|
||||
contractKey,
|
||||
imagePrompt: imageTask.prompt,
|
||||
};
|
||||
}
|
||||
|
||||
await page.screenshot({
|
||||
path: path.join(
|
||||
@@ -569,7 +631,17 @@ async function main() {
|
||||
fullPage: true,
|
||||
});
|
||||
|
||||
summary.cleanup = await interruptSubmittedTurn(options, request);
|
||||
if (summary.submitRequest?.routeMode === "agent_runtime_submit_turn") {
|
||||
summary.cleanup = await interruptSubmittedTurn(
|
||||
options,
|
||||
submitInvoke.args?.request || {},
|
||||
);
|
||||
} else {
|
||||
summary.cleanup = {
|
||||
attempted: false,
|
||||
reason: "skill-execution-route",
|
||||
};
|
||||
}
|
||||
|
||||
const summaryPath = path.join(
|
||||
options.evidenceDir,
|
||||
|
||||
@@ -312,10 +312,68 @@ function collectDefaultMockCommands() {
|
||||
for (const match of objectBody.matchAll(/^ ([A-Za-z0-9_]+)\s*:/gm)) {
|
||||
mockCommands.add(match[1]);
|
||||
}
|
||||
for (const spreadMatch of objectBody.matchAll(
|
||||
/^ \.\.\.([A-Za-z0-9_]+),/gm,
|
||||
)) {
|
||||
const registryName = spreadMatch[1];
|
||||
for (const command of collectSpreadMockRegistryCommands(
|
||||
sourceCode,
|
||||
registryName,
|
||||
)) {
|
||||
mockCommands.add(command);
|
||||
}
|
||||
}
|
||||
|
||||
return mockCommands;
|
||||
}
|
||||
|
||||
function collectSpreadMockRegistryCommands(sourceCode, registryName) {
|
||||
const importPattern =
|
||||
/import\s+(?:type\s+)?\{([^}]*)\}\s+from\s+["'`]([^"'`]+)["'`]/g;
|
||||
let importSource;
|
||||
for (const importMatch of sourceCode.matchAll(importPattern)) {
|
||||
const namedImports = importMatch[1];
|
||||
if (new RegExp(`\\b${registryName}\\b`).test(namedImports)) {
|
||||
importSource = importMatch[2];
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!importSource?.startsWith("./")) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const registrySourcePath = path.resolve(
|
||||
repoRoot,
|
||||
"src/lib/tauri-mock",
|
||||
`${importSource.replace(/^\.\//, "")}.ts`,
|
||||
);
|
||||
if (!fs.existsSync(registrySourcePath)) {
|
||||
throw new Error(`未找到 spread mock registry 文件: ${registrySourcePath}`);
|
||||
}
|
||||
|
||||
const registrySourceCode = fs.readFileSync(registrySourcePath, "utf8");
|
||||
const markerPattern = new RegExp(
|
||||
`export\\s+const\\s+${registryName}\\b[\\s\\S]*?=\\s*\\{`,
|
||||
);
|
||||
const markerMatch = markerPattern.exec(registrySourceCode);
|
||||
if (!markerMatch) {
|
||||
throw new Error(`未找到 spread mock registry 定义: ${registryName}`);
|
||||
}
|
||||
|
||||
const braceStart = markerMatch.index + markerMatch[0].length - 1;
|
||||
const registryBody = extractBalancedBlock(
|
||||
registrySourceCode,
|
||||
braceStart,
|
||||
"{",
|
||||
"}",
|
||||
);
|
||||
const commands = [];
|
||||
for (const match of registryBody.matchAll(/^ ([A-Za-z0-9_]+)\s*:/gm)) {
|
||||
commands.push(match[1]);
|
||||
}
|
||||
return commands;
|
||||
}
|
||||
|
||||
function readAgentCommandCatalog() {
|
||||
const catalogPath = path.join(
|
||||
repoRoot,
|
||||
|
||||
@@ -17,6 +17,28 @@ const PLATFORM_BY_TARGET_TRIPLE = {
|
||||
"x86_64-pc-windows-msvc": "windows-x86_64",
|
||||
};
|
||||
|
||||
const TARGET_TRIPLE_BY_PLATFORM = Object.fromEntries(
|
||||
Object.entries(PLATFORM_BY_TARGET_TRIPLE).map(([targetTriple, platform]) => [
|
||||
platform,
|
||||
targetTriple,
|
||||
]),
|
||||
);
|
||||
|
||||
const INSTALLER_ASSET_BY_PLATFORM = {
|
||||
"darwin-aarch64": {
|
||||
required: true,
|
||||
assetName: (version) => `Lime_${version}_aarch64.dmg`,
|
||||
},
|
||||
"darwin-x86_64": {
|
||||
required: true,
|
||||
assetName: (version) => `Lime_${version}_x64.dmg`,
|
||||
},
|
||||
"windows-x86_64": {
|
||||
required: false,
|
||||
assetName: (version) => `Lime_${version}_x64-setup.exe`,
|
||||
},
|
||||
};
|
||||
|
||||
function parseArgs(argv) {
|
||||
const args = {};
|
||||
for (let index = 0; index < argv.length; index += 1) {
|
||||
@@ -176,6 +198,86 @@ function platformKeyFromAssetFile(assetsDir, assetFile) {
|
||||
return PLATFORM_BY_TARGET_TRIPLE[targetTriple] || "";
|
||||
}
|
||||
|
||||
function targetTripleFromAssetFile(assetsDir, assetFile) {
|
||||
const relativeDir = path.relative(assetsDir, path.dirname(assetFile));
|
||||
return relativeDir.split(path.sep).find(Boolean) || "";
|
||||
}
|
||||
|
||||
function resolveInstallerAssetFile({
|
||||
assetsDir,
|
||||
filesByBasename,
|
||||
platformKey,
|
||||
referenceFile,
|
||||
version,
|
||||
}) {
|
||||
const spec = INSTALLER_ASSET_BY_PLATFORM[platformKey];
|
||||
if (!spec) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const assetName = spec.assetName(version);
|
||||
const candidates = filesByBasename.get(assetName) || [];
|
||||
if (candidates.length === 0) {
|
||||
if (spec.required) {
|
||||
throw new Error(
|
||||
`platform ${platformKey} is missing installer asset: ${assetName}`,
|
||||
);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
const expectedTargetTriple = TARGET_TRIPLE_BY_PLATFORM[platformKey];
|
||||
return (
|
||||
(referenceFile &&
|
||||
candidates.find(
|
||||
(candidate) => path.dirname(candidate) === path.dirname(referenceFile),
|
||||
)) ||
|
||||
candidates.find(
|
||||
(candidate) =>
|
||||
targetTripleFromAssetFile(assetsDir, candidate) === expectedTargetTriple,
|
||||
) ||
|
||||
candidates[0]
|
||||
);
|
||||
}
|
||||
|
||||
function addReferencedFile(referencedFiles, item) {
|
||||
referencedFiles.set(item.targetPath, item);
|
||||
}
|
||||
|
||||
function addInstallerUrlIfAvailable({
|
||||
assetsDir,
|
||||
baseUrl,
|
||||
channel,
|
||||
filesByBasename,
|
||||
platform,
|
||||
platformKey,
|
||||
referenceFile,
|
||||
referencedFiles,
|
||||
version,
|
||||
versionTag,
|
||||
}) {
|
||||
const installerFile = resolveInstallerAssetFile({
|
||||
assetsDir,
|
||||
filesByBasename,
|
||||
platformKey,
|
||||
referenceFile,
|
||||
version,
|
||||
});
|
||||
if (!installerFile) {
|
||||
return;
|
||||
}
|
||||
|
||||
const installerName = path.basename(installerFile);
|
||||
const installerAssetPath = buildPlatformAssetPath(platformKey, installerName);
|
||||
platform.installer_url = `${baseUrl}/lime/${channel}/${versionTag}/${installerAssetPath}`;
|
||||
addReferencedFile(referencedFiles, {
|
||||
assetName: installerName,
|
||||
file: installerFile,
|
||||
platformKey,
|
||||
targetPath: installerAssetPath,
|
||||
});
|
||||
}
|
||||
|
||||
function collectSignedUpdaterArtifacts(files, assetsDir) {
|
||||
const fileSet = new Set(files);
|
||||
return files
|
||||
@@ -277,12 +379,24 @@ function collectUpdaterManifest(options) {
|
||||
signature,
|
||||
url: targetUrl,
|
||||
};
|
||||
referencedFiles.set(platformAssetPath, {
|
||||
addReferencedFile(referencedFiles, {
|
||||
assetName,
|
||||
file: assetFile,
|
||||
platformKey,
|
||||
targetPath: platformAssetPath,
|
||||
});
|
||||
addInstallerUrlIfAvailable({
|
||||
assetsDir,
|
||||
baseUrl,
|
||||
channel,
|
||||
filesByBasename,
|
||||
platform: platforms[platformKey],
|
||||
platformKey,
|
||||
referenceFile: manifestFile,
|
||||
referencedFiles,
|
||||
version,
|
||||
versionTag,
|
||||
});
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -306,12 +420,23 @@ function collectUpdaterManifest(options) {
|
||||
signature: artifact.signature,
|
||||
url: targetUrl,
|
||||
};
|
||||
referencedFiles.set(platformAssetPath, {
|
||||
addReferencedFile(referencedFiles, {
|
||||
assetName: artifact.assetName,
|
||||
file: artifact.assetFile,
|
||||
platformKey: artifact.platformKey,
|
||||
targetPath: platformAssetPath,
|
||||
});
|
||||
addInstallerUrlIfAvailable({
|
||||
assetsDir,
|
||||
baseUrl,
|
||||
channel,
|
||||
filesByBasename,
|
||||
platform: platforms[artifact.platformKey],
|
||||
platformKey: artifact.platformKey,
|
||||
referencedFiles,
|
||||
version,
|
||||
versionTag,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -26,9 +26,15 @@ describe("release updater manifest", () => {
|
||||
const assetsDir = path.join(root, "release-assets");
|
||||
|
||||
writeFile(path.join(assetsDir, "aarch64-apple-darwin", "Lime.app.tar.gz"));
|
||||
writeFile(
|
||||
path.join(assetsDir, "aarch64-apple-darwin", "Lime_1.20.0_aarch64.dmg"),
|
||||
);
|
||||
writeFile(
|
||||
path.join(assetsDir, "x86_64-apple-darwin", "Lime-x64.app.tar.gz"),
|
||||
);
|
||||
writeFile(
|
||||
path.join(assetsDir, "x86_64-apple-darwin", "Lime_1.20.0_x64.dmg"),
|
||||
);
|
||||
writeFile(path.join(assetsDir, "x86_64-pc-windows-msvc", "Lime.nsis.zip"));
|
||||
|
||||
writeJson(path.join(assetsDir, "aarch64-apple-darwin", "latest.json"), {
|
||||
@@ -78,7 +84,19 @@ describe("release updater manifest", () => {
|
||||
expect(result.manifest.platforms["darwin-aarch64"].url).toBe(
|
||||
"https://updates.limecloud.com/lime/stable/v1.20.0/darwin-aarch64/Lime.app.tar.gz",
|
||||
);
|
||||
expect(result.r2UploadPlan).toHaveLength(3);
|
||||
expect(result.manifest.platforms["darwin-aarch64"].installer_url).toBe(
|
||||
"https://updates.limecloud.com/lime/stable/v1.20.0/darwin-aarch64/Lime_1.20.0_aarch64.dmg",
|
||||
);
|
||||
expect(result.manifest.platforms["darwin-x86_64"].installer_url).toBe(
|
||||
"https://updates.limecloud.com/lime/stable/v1.20.0/darwin-x86_64/Lime_1.20.0_x64.dmg",
|
||||
);
|
||||
expect(result.r2UploadPlan.map((item) => item.key).sort()).toEqual([
|
||||
"lime/stable/v1.20.0/darwin-aarch64/Lime.app.tar.gz",
|
||||
"lime/stable/v1.20.0/darwin-aarch64/Lime_1.20.0_aarch64.dmg",
|
||||
"lime/stable/v1.20.0/darwin-x86_64/Lime-x64.app.tar.gz",
|
||||
"lime/stable/v1.20.0/darwin-x86_64/Lime_1.20.0_x64.dmg",
|
||||
"lime/stable/v1.20.0/windows-x86_64/Lime.nsis.zip",
|
||||
]);
|
||||
|
||||
const output = writeOutputs(result, path.join(root, "out"), "stable");
|
||||
expect(fs.existsSync(output.latestPath)).toBe(true);
|
||||
@@ -91,6 +109,9 @@ describe("release updater manifest", () => {
|
||||
);
|
||||
const assetsDir = path.join(root, "release-assets");
|
||||
writeFile(path.join(assetsDir, "aarch64-apple-darwin", "Lime.app.tar.gz"));
|
||||
writeFile(
|
||||
path.join(assetsDir, "aarch64-apple-darwin", "Lime_1.20.0_aarch64.dmg"),
|
||||
);
|
||||
writeJson(path.join(assetsDir, "aarch64-apple-darwin", "latest.json"), {
|
||||
version: "1.20.0",
|
||||
platforms: {
|
||||
@@ -147,10 +168,18 @@ describe("release updater manifest", () => {
|
||||
path.join(assetsDir, "aarch64-apple-darwin", "Lime.app.tar.gz"),
|
||||
"arm",
|
||||
);
|
||||
writeFile(
|
||||
path.join(assetsDir, "aarch64-apple-darwin", "Lime_1.20.0_aarch64.dmg"),
|
||||
"arm-dmg",
|
||||
);
|
||||
writeFile(
|
||||
path.join(assetsDir, "x86_64-apple-darwin", "Lime.app.tar.gz"),
|
||||
"x64",
|
||||
);
|
||||
writeFile(
|
||||
path.join(assetsDir, "x86_64-apple-darwin", "Lime_1.20.0_x64.dmg"),
|
||||
"x64-dmg",
|
||||
);
|
||||
|
||||
writeJson(path.join(assetsDir, "aarch64-apple-darwin", "latest.json"), {
|
||||
version: "1.20.0",
|
||||
@@ -185,15 +214,23 @@ describe("release updater manifest", () => {
|
||||
expect(result.manifest.platforms["darwin-x86_64"].url).toBe(
|
||||
"https://updates.limecloud.com/lime/stable/v1.20.0/darwin-x86_64/Lime.app.tar.gz",
|
||||
);
|
||||
expect(result.manifest.platforms["darwin-aarch64"].installer_url).toBe(
|
||||
"https://updates.limecloud.com/lime/stable/v1.20.0/darwin-aarch64/Lime_1.20.0_aarch64.dmg",
|
||||
);
|
||||
expect(result.manifest.platforms["darwin-x86_64"].installer_url).toBe(
|
||||
"https://updates.limecloud.com/lime/stable/v1.20.0/darwin-x86_64/Lime_1.20.0_x64.dmg",
|
||||
);
|
||||
expect(result.r2UploadPlan.map((item) => item.key).sort()).toEqual([
|
||||
"lime/stable/v1.20.0/darwin-aarch64/Lime.app.tar.gz",
|
||||
"lime/stable/v1.20.0/darwin-aarch64/Lime_1.20.0_aarch64.dmg",
|
||||
"lime/stable/v1.20.0/darwin-x86_64/Lime.app.tar.gz",
|
||||
"lime/stable/v1.20.0/darwin-x86_64/Lime_1.20.0_x64.dmg",
|
||||
]);
|
||||
expect(
|
||||
result.r2UploadPlan
|
||||
.map((item) => fs.readFileSync(item.file, "utf8"))
|
||||
.sort(),
|
||||
).toEqual(["arm", "x64"]);
|
||||
).toEqual(["arm", "arm-dmg", "x64", "x64-dmg"]);
|
||||
});
|
||||
|
||||
it("没有 latest.json 时应从 Tauri 签名产物生成清单", () => {
|
||||
@@ -216,11 +253,17 @@ describe("release updater manifest", () => {
|
||||
path.join(assetsDir, "aarch64-apple-darwin", "Lime.app.tar.gz.sig"),
|
||||
encodedSignature,
|
||||
);
|
||||
writeFile(
|
||||
path.join(assetsDir, "aarch64-apple-darwin", "Lime_1.20.0_aarch64.dmg"),
|
||||
);
|
||||
writeFile(path.join(assetsDir, "x86_64-apple-darwin", "Lime.app.tar.gz"));
|
||||
writeFile(
|
||||
path.join(assetsDir, "x86_64-apple-darwin", "Lime.app.tar.gz.sig"),
|
||||
rawSignature,
|
||||
);
|
||||
writeFile(
|
||||
path.join(assetsDir, "x86_64-apple-darwin", "Lime_1.20.0_x64.dmg"),
|
||||
);
|
||||
writeFile(
|
||||
path.join(
|
||||
assetsDir,
|
||||
@@ -257,12 +300,49 @@ describe("release updater manifest", () => {
|
||||
expect(result.manifest.platforms["windows-x86_64"].url).toBe(
|
||||
"https://updates.limecloud.com/lime/stable/v1.20.0/windows-x86_64/Lime_1.20.0_x64-setup.exe",
|
||||
);
|
||||
expect(result.manifest.platforms["darwin-aarch64"].installer_url).toBe(
|
||||
"https://updates.limecloud.com/lime/stable/v1.20.0/darwin-aarch64/Lime_1.20.0_aarch64.dmg",
|
||||
);
|
||||
expect(result.manifest.platforms["darwin-x86_64"].installer_url).toBe(
|
||||
"https://updates.limecloud.com/lime/stable/v1.20.0/darwin-x86_64/Lime_1.20.0_x64.dmg",
|
||||
);
|
||||
expect(result.manifest.platforms["windows-x86_64"].installer_url).toBe(
|
||||
"https://updates.limecloud.com/lime/stable/v1.20.0/windows-x86_64/Lime_1.20.0_x64-setup.exe",
|
||||
);
|
||||
expect(result.r2UploadPlan.map((item) => item.key).sort()).toEqual([
|
||||
"lime/stable/v1.20.0/darwin-aarch64/Lime.app.tar.gz",
|
||||
"lime/stable/v1.20.0/darwin-aarch64/Lime_1.20.0_aarch64.dmg",
|
||||
"lime/stable/v1.20.0/darwin-x86_64/Lime.app.tar.gz",
|
||||
"lime/stable/v1.20.0/darwin-x86_64/Lime_1.20.0_x64.dmg",
|
||||
"lime/stable/v1.20.0/windows-x86_64/Lime_1.20.0_x64-setup.exe",
|
||||
]);
|
||||
});
|
||||
|
||||
it("macOS 平台缺少 DMG 时失败,避免官网回退下载 updater 包", () => {
|
||||
const root = fs.mkdtempSync(
|
||||
path.join(os.tmpdir(), "lime-release-missing-dmg-"),
|
||||
);
|
||||
const assetsDir = path.join(root, "release-assets");
|
||||
writeFile(path.join(assetsDir, "aarch64-apple-darwin", "Lime.app.tar.gz"));
|
||||
writeJson(path.join(assetsDir, "aarch64-apple-darwin", "latest.json"), {
|
||||
version: "1.20.0",
|
||||
platforms: {
|
||||
"darwin-aarch64": {
|
||||
signature: "sig-arm",
|
||||
url: "https://example.com/Lime.app.tar.gz",
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
expect(() =>
|
||||
collectUpdaterManifest({
|
||||
assetsDir,
|
||||
baseUrl: "https://updates.limecloud.com",
|
||||
requiredPlatforms: ["darwin-aarch64"],
|
||||
version: "v1.20.0",
|
||||
}),
|
||||
).toThrow(/missing installer asset/);
|
||||
});
|
||||
});
|
||||
|
||||
describe("R2 release cleanup", () => {
|
||||
|
||||
Reference in New Issue
Block a user