@@ -17,6 +17,20 @@ function jsonResponse(body: unknown, init: ResponseInit = {}): Response {
|
17 | 17 | return new Response(JSON.stringify(body), init); |
18 | 18 | } |
19 | 19 | |
| 20 | +async function withGithubApiTimeoutEnv<T>(value: string, fn: () => Promise<T>): Promise<T> { |
| 21 | +const previous = process.env.OPENCLAW_RELEASE_CANDIDATE_GITHUB_API_TIMEOUT_MS; |
| 22 | +process.env.OPENCLAW_RELEASE_CANDIDATE_GITHUB_API_TIMEOUT_MS = value; |
| 23 | +try { |
| 24 | +return await fn(); |
| 25 | +} finally { |
| 26 | +if (previous === undefined) { |
| 27 | +delete process.env.OPENCLAW_RELEASE_CANDIDATE_GITHUB_API_TIMEOUT_MS; |
| 28 | +} else { |
| 29 | +process.env.OPENCLAW_RELEASE_CANDIDATE_GITHUB_API_TIMEOUT_MS = previous; |
| 30 | +} |
| 31 | +} |
| 32 | +} |
| 33 | + |
20 | 34 | describe("release candidate checklist", () => { |
21 | 35 | it("infers validation profiles from candidate tags", () => { |
22 | 36 | expect(parseArgs(["--tag", "v2026.5.14-beta.3"]).releaseProfile).toBe("beta"); |
@@ -387,6 +401,42 @@ describe("release candidate checklist", () => {
|
387 | 401 | ); |
388 | 402 | }); |
389 | 403 | |
| 404 | +it("uses a positive integer GitHub API timeout env", async () => { |
| 405 | +const fetchImpl = vi.fn(async (_url: string, init?: RequestInit) => { |
| 406 | +expect(init?.signal).toBeInstanceOf(AbortSignal); |
| 407 | +return jsonResponse({ workflow_runs: [] }); |
| 408 | +}); |
| 409 | + |
| 410 | +await withGithubApiTimeoutEnv("2500", async () => { |
| 411 | +await expect( |
| 412 | +githubApi("repos/openclaw/openclaw/actions/runs", { |
| 413 | + fetchImpl, |
| 414 | +token: "test-token", |
| 415 | +}), |
| 416 | +).resolves.toEqual({ workflow_runs: [] }); |
| 417 | +}); |
| 418 | +expect(fetchImpl).toHaveBeenCalledOnce(); |
| 419 | +}); |
| 420 | + |
| 421 | +it.each(["1e3", "10.5", "0", "soon"])( |
| 422 | +"rejects malformed GitHub API timeout env %s", |
| 423 | +async (raw) => { |
| 424 | +const fetchImpl = vi.fn(); |
| 425 | + |
| 426 | +await withGithubApiTimeoutEnv(raw, async () => { |
| 427 | +await expect( |
| 428 | +githubApi("repos/openclaw/openclaw/actions/runs", { |
| 429 | + fetchImpl, |
| 430 | +token: "test-token", |
| 431 | +}), |
| 432 | +).rejects.toThrow( |
| 433 | +"OPENCLAW_RELEASE_CANDIDATE_GITHUB_API_TIMEOUT_MS must be a positive integer", |
| 434 | +); |
| 435 | +}); |
| 436 | +expect(fetchImpl).not.toHaveBeenCalled(); |
| 437 | +}, |
| 438 | +); |
| 439 | + |
390 | 440 | it("bounds GitHub API error bodies", async () => { |
391 | 441 | const fetchImpl = vi.fn(async () => { |
392 | 442 | return new Response("x".repeat(65), { |
|