源码快照 @ 2026-09-01 (source-only, 剔除非源码素材)
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
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
This commit is contained in:
@@ -0,0 +1,116 @@
|
||||
import assert from "node:assert/strict";
|
||||
import { mkdir, mkdtemp, rm, writeFile } from "node:fs/promises";
|
||||
import { tmpdir } from "node:os";
|
||||
import path from "node:path";
|
||||
import test from "node:test";
|
||||
|
||||
import {
|
||||
resolveUploadUrl,
|
||||
uploadReleaseAssets
|
||||
} from "../../apps/desktop/scripts/upload-github-release-assets.mjs";
|
||||
|
||||
test("release asset upload uses the REST upload URL returned for the release", async () => {
|
||||
const dir = await mkdtemp(path.join(tmpdir(), "desktop-release-upload-"));
|
||||
const releasePath = path.join(dir, "release.json");
|
||||
const assetsDirectory = path.join(dir, "assets");
|
||||
await mkdir(assetsDirectory);
|
||||
await writeFile(
|
||||
releasePath,
|
||||
JSON.stringify({
|
||||
id: 42,
|
||||
upload_url:
|
||||
"https://uploads.github.test/repos/tutti-os/tutti/releases/42/assets{?name,label}"
|
||||
})
|
||||
);
|
||||
await writeFile(path.join(assetsDirectory, "b file.zip"), "second");
|
||||
await writeFile(path.join(assetsDirectory, "a.dmg"), "first");
|
||||
|
||||
const requests = [];
|
||||
const fetchImpl = async (url, init) => {
|
||||
const chunks = [];
|
||||
for await (const chunk of init.body) chunks.push(chunk);
|
||||
requests.push({
|
||||
url: String(url),
|
||||
method: init.method,
|
||||
headers: init.headers,
|
||||
body: Buffer.concat(chunks).toString("utf8")
|
||||
});
|
||||
return new Response(null, { status: 201 });
|
||||
};
|
||||
|
||||
try {
|
||||
const result = await uploadReleaseAssets({
|
||||
releasePath,
|
||||
assetsDirectory,
|
||||
token: "test-token",
|
||||
fetchImpl
|
||||
});
|
||||
|
||||
assert.deepEqual(result, {
|
||||
releaseId: "42",
|
||||
assetNames: ["a.dmg", "b file.zip"]
|
||||
});
|
||||
assert.deepEqual(
|
||||
requests.map(({ url, body }) => ({ url, body })),
|
||||
[
|
||||
{
|
||||
url: "https://uploads.github.test/repos/tutti-os/tutti/releases/42/assets?name=a.dmg",
|
||||
body: "first"
|
||||
},
|
||||
{
|
||||
url: "https://uploads.github.test/repos/tutti-os/tutti/releases/42/assets?name=b+file.zip",
|
||||
body: "second"
|
||||
}
|
||||
]
|
||||
);
|
||||
for (const request of requests) {
|
||||
assert.equal(request.method, "POST");
|
||||
assert.equal(request.headers.Authorization, "Bearer test-token");
|
||||
assert.equal(request.headers["Content-Type"], "application/octet-stream");
|
||||
assert.equal(
|
||||
request.headers["Content-Length"],
|
||||
String(request.body.length)
|
||||
);
|
||||
}
|
||||
} finally {
|
||||
await rm(dir, { force: true, recursive: true });
|
||||
}
|
||||
});
|
||||
|
||||
test("release asset upload reports the release id and failed asset", async () => {
|
||||
const dir = await mkdtemp(path.join(tmpdir(), "desktop-release-upload-"));
|
||||
const releasePath = path.join(dir, "release.json");
|
||||
await writeFile(
|
||||
releasePath,
|
||||
JSON.stringify({
|
||||
id: 99,
|
||||
upload_url:
|
||||
"https://uploads.github.test/repos/tutti-os/tutti/releases/99/assets{?name,label}"
|
||||
})
|
||||
);
|
||||
await writeFile(path.join(dir, "broken.zip"), "payload");
|
||||
|
||||
try {
|
||||
await assert.rejects(
|
||||
uploadReleaseAssets({
|
||||
releasePath,
|
||||
assetsDirectory: dir,
|
||||
token: "test-token",
|
||||
fetchImpl: async () => new Response("upstream failure", { status: 502 })
|
||||
}),
|
||||
/Failed to upload broken\.zip to GitHub release 99: 502 upstream failure/
|
||||
);
|
||||
} finally {
|
||||
await rm(dir, { force: true, recursive: true });
|
||||
}
|
||||
});
|
||||
|
||||
test("release upload URL preserves the endpoint and encodes the asset name", () => {
|
||||
assert.equal(
|
||||
resolveUploadUrl(
|
||||
"https://uploads.github.com/releases/7/assets{?name,label}",
|
||||
"Tutti Setup.exe"
|
||||
).href,
|
||||
"https://uploads.github.com/releases/7/assets?name=Tutti+Setup.exe"
|
||||
);
|
||||
});
|
||||
Reference in New Issue
Block a user