Skip to content

Commit 343b70c

Browse files
committed
ci: retry spec fetch with backoff, move dependabot to the bun ecosystem
- generate.ts: a transient CDN 520 failed the 2026-07-07 scheduled release run; retry up to 5 times with exponential backoff - dependabot: npm ecosystem bumps only touch package.json and leave bun.lock stale, so the frozen-lockfile CI gate rejected every dependabot PR; the bun ecosystem updates both. Groups switch to a catch-all pattern since bun lacks dependency-type grouping.
1 parent ab9a1e4 commit 343b70c

2 files changed

Lines changed: 29 additions & 6 deletions

File tree

.github/dependabot.yml

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
version: 2
22
updates:
3-
- package-ecosystem: npm
3+
# bun ecosystem (not npm): the repo lockfile is bun.lock, and npm-ecosystem
4+
# bumps touch only package.json, so CI's frozen-lockfile install rejects
5+
# every dependabot PR.
6+
- package-ecosystem: bun
47
directory: /
58
schedule:
69
interval: weekly
@@ -9,9 +12,11 @@ updates:
912
# a chance to be flagged for supply-chain issues before they land.
1013
cooldown:
1114
default-days: 3
15+
# bun does not support dependency-type grouping; every dep here is a
16+
# devDependency, so a catch-all pattern is equivalent.
1217
groups:
1318
dev-dependencies:
14-
dependency-type: development
19+
patterns: ["*"]
1520
# hey-api is the pinned code generator and its paired runtime client.
1621
# Bumps change generated output and break the codegen drift check, so
1722
# they are upgraded deliberately at release time, never by dependabot.

scripts/generate.ts

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,29 @@ import { mkdirSync, writeFileSync } from 'node:fs';
99
const SPEC_URL = 'https://roxyapi.com/api/v2/openapi.json';
1010
const SPEC_PATH = 'specs/openapi.json';
1111

12-
console.log('Fetching OpenAPI spec from', SPEC_URL);
13-
const res = await fetch(SPEC_URL, { headers: { 'Cache-Control': 'no-cache' } });
14-
if (!res.ok) throw new Error(`Fetch failed: ${res.status} ${res.statusText}`);
12+
/** Retry with exponential backoff: a transient upstream error (e.g. a CDN 520) must not fail the daily release run. */
13+
async function fetchSpec(url: string, attempts = 5): Promise<string> {
14+
for (let attempt = 1; ; attempt++) {
15+
try {
16+
const res = await fetch(url, {
17+
headers: { 'Cache-Control': 'no-cache' },
18+
});
19+
if (!res.ok)
20+
throw new Error(`Fetch failed: ${res.status} ${res.statusText}`);
21+
return await res.text();
22+
} catch (err) {
23+
if (attempt === attempts) throw err;
24+
const delay = 2 ** attempt;
25+
console.warn(
26+
`Attempt ${attempt}/${attempts} failed (${err instanceof Error ? err.message : err}), retrying in ${delay}s`,
27+
);
28+
await new Promise((resolve) => setTimeout(resolve, delay * 1000));
29+
}
30+
}
31+
}
1532

16-
const spec = JSON.parse(await res.text());
33+
console.log('Fetching OpenAPI spec from', SPEC_URL);
34+
const spec = JSON.parse(await fetchSpec(SPEC_URL));
1735

1836
// Patch server URL to absolute production URL so the generated default client
1937
// works out of the box without users specifying baseUrl

0 commit comments

Comments
 (0)