Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,11 @@ jobs:

- name: Build docs (includes dead-link validation)
run: pnpm build
env:
# Authenticate downstream GitHub API/asset fetches to avoid the
# unauthenticated rate limit. Missing release assets are non-fatal
# on PR builds (GITHUB_EVENT_NAME=pull_request) — see fetch-metrics.mjs.
GITHUB_TOKEN: ${{ github.token }}

ok:
name: ok
Expand Down
5 changes: 5 additions & 0 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,11 @@ jobs:
- run: pnpm install --frozen-lockfile

- run: pnpm build
env:
# Authenticate downstream GitHub API/asset fetches to avoid the
# unauthenticated rate limit. On main (push) builds, missing assets
# remain fatal so the published site is complete.
GITHUB_TOKEN: ${{ github.token }}

# Note: VitePress validates dead links at build time (ignoreDeadLinks: false).
# Lychee was removed — it struggles with VitePress clean URLs and root-relative
Expand Down
3 changes: 0 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,5 @@
},
"devDependencies": {
"vitepress": "^1.6.4"
},
"pnpm": {
"onlyBuiltDependencies": ["esbuild"]
}
}
2 changes: 1 addition & 1 deletion pnpm-workspace.yaml
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
allowBuilds:
esbuild: false
esbuild: true
39 changes: 30 additions & 9 deletions scripts/fetch-metrics.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,12 @@
* Fetches metrics.json from the latest release of each anolishq repo and
* writes them to docs/public/metrics/{repo}.json for use at build time.
*
* Runs unauthenticated against public GitHub APIs — no token required.
* Called as part of the `build` script before generate-metrics.mjs.
* Authenticates with GITHUB_TOKEN when present (set in CI) to avoid the low
* unauthenticated rate limit. On pull-request builds a missing release or
* asset is non-fatal: the repo is skipped with a warning rather than failing
* the whole build, so a docs-only PR cannot red-fail for reasons outside this
* repo. On main/deploy builds any miss is still fatal so the published site is
* complete. Called as part of the `build` script before generate-metrics.mjs.
*/

import fs from "fs/promises";
Expand All @@ -27,12 +31,22 @@ const REPOS = [

const GITHUB_API = "https://api.github.com";

// Authenticate when a token is available (CI sets GITHUB_TOKEN) to lift the
// unauthenticated rate limit that otherwise makes PR builds flaky.
const TOKEN = process.env.GITHUB_TOKEN || process.env.GH_TOKEN;
const AUTH_HEADERS = TOKEN ? { Authorization: `Bearer ${TOKEN}` } : {};

// On pull-request builds, a missing downstream asset is non-fatal: skip the
// repo rather than fail a docs-only PR for reasons outside this repo.
const PR_BUILD = process.env.GITHUB_EVENT_NAME === "pull_request";

async function fetchJson(url) {
const res = await fetch(url, {
headers: {
Accept: "application/vnd.github+json",
"User-Agent": "anolishq-docs-build",
"X-GitHub-Api-Version": "2022-11-28",
...AUTH_HEADERS,
},
});
if (!res.ok) {
Expand All @@ -43,14 +57,24 @@ async function fetchJson(url) {

async function fetchText(url) {
const res = await fetch(url, {
headers: { "User-Agent": "anolishq-docs-build" },
headers: { "User-Agent": "anolishq-docs-build", ...AUTH_HEADERS },
});
if (!res.ok) {
throw new Error(`HTTP ${res.status} fetching ${url}`);
}
return res.text();
}

// Fail the build on a miss, unless this is a PR build — then warn and skip.
function failOrSkip(message) {
if (PR_BUILD) {
console.warn(` WARN (skipped on PR build): ${message}`);
return "skip";
}
console.error(` ERROR: ${message}`);
process.exit(1);
}

await fs.mkdir(OUT_DIR, { recursive: true });

const results = [];
Expand All @@ -65,8 +89,7 @@ for (const repo of REPOS) {
);
tagName = release.tag_name;
} catch (err) {
console.error(` ERROR: could not fetch latest release for ${repo}: ${err.message}`);
process.exit(1);
if (failOrSkip(`could not fetch latest release for ${repo}: ${err.message}`) === "skip") continue;
}

const assetUrl = `https://github.com/anolishq/${repo}/releases/download/${tagName}/metrics.json`;
Expand All @@ -75,16 +98,14 @@ for (const repo of REPOS) {
try {
metricsText = await fetchText(assetUrl);
} catch (err) {
console.error(` ERROR: could not fetch metrics.json for ${repo} @ ${tagName}: ${err.message}`);
process.exit(1);
if (failOrSkip(`could not fetch metrics.json for ${repo} @ ${tagName}: ${err.message}`) === "skip") continue;
}

let metrics;
try {
metrics = JSON.parse(metricsText);
} catch (err) {
console.error(` ERROR: invalid JSON in metrics.json for ${repo} @ ${tagName}: ${err.message}`);
process.exit(1);
if (failOrSkip(`invalid JSON in metrics.json for ${repo} @ ${tagName}: ${err.message}`) === "skip") continue;
}

const outFile = path.join(OUT_DIR, `${repo}.json`);
Expand Down