Skip to content

Commit 10ac9f7

Browse files
refactor: unify tarball resolution and optimize download latency
1 parent 3fd239e commit 10ac9f7

File tree

9 files changed

+229
-271
lines changed

9 files changed

+229
-271
lines changed

packages/app/e2e.test.ts

Lines changed: 85 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import type { Response } from "@cloudflare/workers-types";
21
import ezSpawn from "@jsdevtools/ez-spawn";
32
import { simulation } from "@simulacrum/github-api-simulator";
43
import fs from "node:fs/promises";
@@ -14,11 +13,20 @@ const E2E_TEMP_DIR_PREFIX = "pkg-pr-new-e2e-";
1413

1514
let server: Awaited<ReturnType<ReturnType<typeof simulation>["listen"]>>;
1615
let workerUrl: string;
17-
let githubOutputDir: string;
16+
let tempDir: string;
1817
let githubOutputPath: string;
1918

2019
let worker: UnstableDevWorker;
20+
21+
const { stdout: gitHeadSha } = await ezSpawn.async("git rev-parse HEAD", {
22+
stdio: "overlapped",
23+
});
24+
const fullSha = gitHeadSha.trim();
25+
const sha = fullSha.substring(0, 7);
26+
2127
beforeAll(async () => {
28+
tempDir = await fs.mkdtemp(path.join(os.tmpdir(), E2E_TEMP_DIR_PREFIX));
29+
2230
const app = simulation({
2331
initialState: {
2432
users: [],
@@ -51,15 +59,12 @@ beforeAll(async () => {
5159
`${import.meta.dirname}/dist/_worker.js/index.js`,
5260
{
5361
config: `${import.meta.dirname}/wrangler.toml`,
62+
persistTo: path.join(tempDir, "worker"),
5463
},
5564
);
5665
const url = `${worker.proxyData.userWorkerUrl.protocol}//${worker.proxyData.userWorkerUrl.hostname}:${worker.proxyData.userWorkerUrl.port}`;
5766
workerUrl = url;
58-
59-
githubOutputDir = await fs.mkdtemp(
60-
path.join(os.tmpdir(), E2E_TEMP_DIR_PREFIX),
61-
);
62-
githubOutputPath = path.join(githubOutputDir, "output");
67+
githubOutputPath = path.join(tempDir, "output");
6368
await fs.writeFile(githubOutputPath, "");
6469

6570
await ezSpawn.async(
@@ -74,8 +79,8 @@ beforeAll(async () => {
7479

7580
afterAll(async () => {
7681
await server.ensureClose();
77-
if (githubOutputDir?.includes(E2E_TEMP_DIR_PREFIX)) {
78-
await fs.rm(githubOutputDir, { recursive: true, force: true });
82+
if (tempDir?.includes(E2E_TEMP_DIR_PREFIX)) {
83+
await fs.rm(tempDir, { recursive: true, force: true });
7984
}
8085
});
8186

@@ -147,14 +152,10 @@ describe.sequential.each([
147152
expect(process.stderr).toContain("pkg-pr-new:");
148153
expect(process.stderr).toContain("playground-a:");
149154
expect(process.stderr).toContain("playground-b:");
150-
}, 10_000);
155+
}, 20_000);
151156

152157
it(`serves and installs playground-a for ${mode}`, async () => {
153158
const [owner, repo] = payload.repository.full_name.split("/");
154-
const { stdout: gitHeadSha } = await ezSpawn.async("git rev-parse HEAD", {
155-
stdio: "overlapped",
156-
});
157-
const sha = gitHeadSha.trim().substring(0, 7);
158159
const ref = pr?.payload.number ?? payload.workflow_run.head_branch;
159160

160161
// Test download with SHA
@@ -166,9 +167,15 @@ describe.sequential.each([
166167
expect(shaBlob.size).toBeGreaterThan(0);
167168

168169
// Test download with ref matches SHA content
169-
const refResponse = await fetchWithRedirect(
170+
const refResponse = await worker.fetch(
170171
`/${owner}/${repo}/playground-a@${ref}`,
171172
);
173+
expect(refResponse.status).toBe(200);
174+
expect(refResponse.headers.get("x-pkg-name-key")).toBe("playground-a");
175+
expect(refResponse.headers.get("x-commit-key")).toBe(
176+
`${owner}:${repo}:${fullSha}`,
177+
);
178+
172179
const refBlob = await refResponse.blob();
173180
const shaBlobSize = await shaBlob.arrayBuffer();
174181
const refBlobSize = await refBlob.arrayBuffer();
@@ -190,14 +197,31 @@ describe.sequential.each([
190197
expect(installProcess.stdout).toContain(
191198
"playground-a installed successfully!",
192199
);
193-
}, 10_000);
200+
}, 20_000);
201+
202+
it(`returns metadata for HEAD requests (${mode})`, async () => {
203+
const [owner, repo] = payload.repository.full_name.split("/");
204+
205+
const headResponse = await worker.fetch(
206+
`/${owner}/${repo}/playground-a@${sha}`,
207+
{ method: "HEAD" },
208+
);
209+
210+
expect(headResponse.status).toBe(200);
211+
expect(headResponse.headers.get("x-pkg-name-key")).toBe("playground-a");
212+
expect(headResponse.headers.get("x-commit-key")).toBe(
213+
`${owner}:${repo}:${sha}`,
214+
);
215+
expect(headResponse.headers.get("content-type")).toBe(
216+
"application/tar+gzip",
217+
);
218+
expect(headResponse.headers.get("etag")).toBeDefined();
219+
const lastModified = headResponse.headers.get("last-modified");
220+
expect(new Date(lastModified!).toString()).not.toBe("Invalid Date");
221+
});
194222

195223
it(`serves and installs playground-b for ${mode}`, async () => {
196224
const [owner, repo] = payload.repository.full_name.split("/");
197-
const { stdout: gitHeadSha } = await ezSpawn.async("git rev-parse HEAD", {
198-
stdio: "overlapped",
199-
});
200-
const sha = gitHeadSha.trim().substring(0, 7);
201225

202226
// Test download
203227
const response = await worker.fetch(
@@ -225,51 +249,60 @@ describe.sequential.each([
225249
expect(installProcess.stdout).toContain(
226250
"playground-b installed successfully!",
227251
);
228-
}, 10_000);
252+
}, 20_000);
229253
});
230254

231-
describe("URL redirects", () => {
255+
describe("URL resolution", () => {
232256
describe("standard packages", () => {
233-
it("redirects full URLs correctly", async () => {
234-
const response = await fetchWithRedirect("/tinylibs/tinybench@a832a55");
235-
expect(response.url).toContain("/tinylibs/tinybench/tinybench@a832a55");
257+
it.each([
258+
["full", "/tinylibs/tinybench/tinybench@a832a55"],
259+
["compact", "/tinybench@a832a55"],
260+
["with .tgz extension", "/tinybench@a832a55.tgz"],
261+
])("resolves %s URLs", async (_, url) => {
262+
const response = await worker.fetch(url);
263+
264+
expect(response.headers.get("x-commit-key")).toBe(
265+
"tinylibs:tinybench:a832a55",
266+
);
267+
expect(response.headers.get("x-pkg-name-key")).toBe("tinybench");
236268
});
237269

238-
it("redirects compact URLs correctly", async () => {
239-
const response = await fetchWithRedirect("/tinybench@a832a55");
240-
expect(response.url).toContain("/tinylibs/tinybench/tinybench@a832a55");
270+
it("resolves URL with full Git SHA", async () => {
271+
const response = await worker.fetch(
272+
"/tinylibs/tinybench/tinybench@a832a55e8f50c419ed8414024899e37e69b1f999",
273+
);
274+
275+
expect(response.headers.get("x-pkg-name-key")).toBe("tinybench");
276+
expect(response.headers.get("x-commit-key")).toBe(
277+
"tinylibs:tinybench:a832a55e8f50c419ed8414024899e37e69b1f999",
278+
);
241279
});
242280
});
243281

244282
describe("scoped packages", () => {
245-
const expectedPath = `/stackblitz/sdk/${encodeURIComponent("@stackblitz/sdk")}@a832a55`;
283+
it.each([
284+
["full", "/stackblitz/sdk/@stackblitz/sdk@a832a55"],
285+
["encoded", "/stackblitz/sdk/%40stackblitz%2Fsdk@a832a55"],
286+
["compact", "/@stackblitz/sdk@a832a55"],
287+
["compact encoded", "/%40stackblitz%2Fsdk@a832a55"],
288+
])("resolves %s URLs", async (_, url) => {
289+
const response = await worker.fetch(url);
246290

247-
it("redirects full scoped package URLs correctly", async () => {
248-
const response = await fetchWithRedirect(
249-
"/stackblitz/sdk/@stackblitz/sdk@a832a55",
291+
expect(response.headers.get("x-pkg-name-key")).toBe("@stackblitz:sdk");
292+
expect(response.headers.get("x-commit-key")).toBe(
293+
"stackblitz:sdk:a832a55",
250294
);
251-
expect(response.url).toContain(expectedPath);
252295
});
253296

254-
it("redirects compact scoped package URLs correctly", async () => {
255-
const response = await fetchWithRedirect("/@stackblitz/sdk@a832a55");
256-
expect(response.url).toContain(expectedPath);
297+
it("resolves URL with full Git SHA", async () => {
298+
const response = await worker.fetch(
299+
"/stackblitz/sdk/@stackblitz/sdk@a832a55e8f50c419ed8414024899e37e69b1f999",
300+
);
301+
302+
expect(response.headers.get("x-pkg-name-key")).toBe("@stackblitz:sdk");
303+
expect(response.headers.get("x-commit-key")).toBe(
304+
"stackblitz:sdk:a832a55e8f50c419ed8414024899e37e69b1f999",
305+
);
257306
});
258307
});
259308
});
260-
261-
async function fetchWithRedirect(
262-
url: string,
263-
maxRedirects = 999,
264-
): Promise<Response> {
265-
const response = await worker.fetch(url, { redirect: "manual" });
266-
267-
if (response.status >= 300 && response.status < 400 && maxRedirects > 0) {
268-
const location = response.headers.get("location");
269-
if (location) {
270-
return fetchWithRedirect(location, maxRedirects - 1);
271-
}
272-
}
273-
274-
return response as unknown as Response;
275-
}

packages/app/fixtures/workflow_run.in_progress.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
"id": 9394452824,
77
"name": "Preview & Release",
88
"node_id": "WFR_kwLOLiqblM8AAAACL_P5WA",
9-
"head_branch": "main",
9+
"head_branch": "@test/@chaotic.branch/name-@v1.@",
1010
"head_sha": "ded05e838c418096e5dd77a29101c8af9e73daea",
1111
"path": ".github/workflows/ci.yml",
1212
"display_title": "chore: 007 (#94)",

packages/app/nuxt.config.ts

Lines changed: 0 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,3 @@
1-
// import ncb from "nitro-cloudflare-dev";
2-
import { resolve } from "pathe";
3-
41
// https://nuxt.com/docs/api/configuration/nuxt-config
52
export default defineNuxtConfig({
63
sourcemap: true,
@@ -57,23 +54,6 @@ export default defineNuxtConfig({
5754
test: "",
5855
},
5956

60-
hooks: {
61-
"nitro:build:before": (nitro) => {
62-
// Override the server routes with the client routes so they are higher priority
63-
const clientRenderer = resolve(
64-
"node_modules/nuxt/dist/core/runtime/nitro/renderer",
65-
);
66-
nitro.options.handlers.unshift({
67-
route: "/",
68-
handler: clientRenderer,
69-
});
70-
nitro.options.handlers.unshift({
71-
route: "/~/**",
72-
handler: clientRenderer,
73-
});
74-
},
75-
},
76-
7757
icon: {
7858
clientBundle: {
7959
icons: ["mdi-github"],

0 commit comments

Comments
 (0)