ci: build + anchors + inline-js guard
Some checks failed
CI / build-and-anchors (push) Failing after 5m4s
Some checks failed
CI / build-and-anchors (push) Failing after 5m4s
This commit is contained in:
35
.gitea/workflows/ci.yml
Normal file
35
.gitea/workflows/ci.yml
Normal file
@@ -0,0 +1,35 @@
|
||||
name: CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: ["**"]
|
||||
pull_request:
|
||||
branches: ["master"]
|
||||
|
||||
jobs:
|
||||
build-and-anchors:
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
image: node:20-bookworm-slim
|
||||
|
||||
steps:
|
||||
- name: Install git (needed by checkout)
|
||||
run: |
|
||||
apt-get update
|
||||
apt-get install -y --no-install-recommends git ca-certificates
|
||||
git --version
|
||||
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Install deps
|
||||
run: npm ci
|
||||
|
||||
- name: Inline scripts syntax check
|
||||
run: node scripts/check-inline-js.mjs
|
||||
|
||||
- name: Build
|
||||
run: npm run build
|
||||
|
||||
- name: Anchors contract
|
||||
run: npm run test:anchors
|
||||
@@ -10,6 +10,7 @@
|
||||
"postbuild": "npx pagefind --site dist",
|
||||
"import": "node scripts/import-docx.mjs",
|
||||
"apply:ticket": "node scripts/apply-ticket.mjs",
|
||||
"test": "npm run build && npm run test:anchors && node scripts/check-inline-js.mjs",
|
||||
"test:anchors": "node scripts/check-anchors.mjs",
|
||||
"test:anchors:update": "node scripts/check-anchors.mjs --update"
|
||||
},
|
||||
|
||||
70
scripts/check-inline-js.mjs
Normal file
70
scripts/check-inline-js.mjs
Normal file
@@ -0,0 +1,70 @@
|
||||
#!/usr/bin/env node
|
||||
import fs from "node:fs/promises";
|
||||
import path from "node:path";
|
||||
import os from "node:os";
|
||||
import { spawnSync } from "node:child_process";
|
||||
|
||||
const ROOT = process.cwd();
|
||||
const SRC = path.join(ROOT, "src");
|
||||
|
||||
async function* walk(dir) {
|
||||
const entries = await fs.readdir(dir, { withFileTypes: true });
|
||||
for (const e of entries) {
|
||||
const full = path.join(dir, e.name);
|
||||
if (e.isDirectory()) yield* walk(full);
|
||||
else yield full;
|
||||
}
|
||||
}
|
||||
|
||||
function extractInlineScripts(astroText) {
|
||||
// capture <script ... is:inline ...> ... </script>
|
||||
const re = /<script\b[^>]*\bis:inline\b[^>]*>([\s\S]*?)<\/script>/gi;
|
||||
const out = [];
|
||||
let m;
|
||||
while ((m = re.exec(astroText))) out.push(m[1] ?? "");
|
||||
return out;
|
||||
}
|
||||
|
||||
function checkSyntax(js, label) {
|
||||
const tmp = path.join(os.tmpdir(), `inline-js-check-${Date.now()}-${Math.random().toString(16).slice(2)}.mjs`);
|
||||
const payload = `// ${label}\n${js}\n`;
|
||||
return fs.writeFile(tmp, payload, "utf-8").then(() => {
|
||||
const r = spawnSync(process.execPath, ["--check", tmp], { encoding: "utf-8" });
|
||||
fs.unlink(tmp).catch(() => {});
|
||||
if (r.status !== 0) {
|
||||
const msg = (r.stderr || r.stdout || "").trim();
|
||||
throw new Error(`${label}\n${msg}`);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async function main() {
|
||||
const targets = [];
|
||||
for await (const f of walk(SRC)) {
|
||||
if (f.endsWith(".astro")) targets.push(f);
|
||||
}
|
||||
|
||||
let checked = 0;
|
||||
|
||||
for (const file of targets) {
|
||||
const txt = await fs.readFile(file, "utf-8");
|
||||
const scripts = extractInlineScripts(txt);
|
||||
if (!scripts.length) continue;
|
||||
|
||||
for (let i = 0; i < scripts.length; i++) {
|
||||
const js = (scripts[i] || "").trim();
|
||||
if (!js) continue;
|
||||
const label = `${path.relative(ROOT, file)} :: <script is:inline> #${i + 1}`;
|
||||
await checkSyntax(js, label);
|
||||
checked++;
|
||||
}
|
||||
}
|
||||
|
||||
console.log(`OK inline-js: scripts checked=${checked}`);
|
||||
}
|
||||
|
||||
main().catch((e) => {
|
||||
console.error("❌ inline-js syntax check failed");
|
||||
console.error(e?.message || e);
|
||||
process.exit(1);
|
||||
});
|
||||
Reference in New Issue
Block a user