feat(deploy): publish-libs CI + full clone (C1.3)
publish-libs.ts: --clone <dir> shallow-clones kicad-symbols + kicad-footprints at --lib-tag (full, all libs) and uses them as sources, so CI publishes the whole set with one command. publish-libs.yml: decoupled workflow_dispatch (mirrors publish-wasm.yml) — lib_tag input (default 10.0.3) + force; clones + publishes to R2, skip-if-exists keyed by the tag. Dependency-free import chain ⇒ no workspace install (just node + npx tsx + git + wrangler). deploy-demo.yml: LIB_TAG=10.0.3 → build-demo --lib-tag, so the demo serves the full library set from libs/kicad/<LIB_TAG>. Validated locally over .cache: publish then skip-if-exists; both workflows valid YAML. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
55f8d79a78
commit
6b737f95ed
3 changed files with 109 additions and 4 deletions
11
.github/workflows/deploy-demo.yml
vendored
11
.github/workflows/deploy-demo.yml
vendored
|
|
@ -25,6 +25,9 @@ concurrency:
|
||||||
env:
|
env:
|
||||||
CDN: https://cdn.pcbjam.com
|
CDN: https://cdn.pcbjam.com
|
||||||
BUCKET: pcbjam-cdn
|
BUCKET: pcbjam-cdn
|
||||||
|
# KiCad library snapshot the demo points at (published once by publish-libs.yml
|
||||||
|
# to libs/kicad/<LIB_TAG>/). Bump when moving to a newer KiCad library release.
|
||||||
|
LIB_TAG: "10.0.3"
|
||||||
PAGES_PROJECT: pcbjam-demo
|
PAGES_PROJECT: pcbjam-demo
|
||||||
# MUST be the Pages project's PRODUCTION branch — any other value makes
|
# MUST be the Pages project's PRODUCTION branch — any other value makes
|
||||||
# `wrangler pages deploy` a PREVIEW deploy and demo.pcbjam.com won't update.
|
# `wrangler pages deploy` a PREVIEW deploy and demo.pcbjam.com won't update.
|
||||||
|
|
@ -82,9 +85,13 @@ jobs:
|
||||||
node scripts/deploy/publish-content.mjs --tag "${{ steps.tag.outputs.tag }}"
|
node scripts/deploy/publish-content.mjs --tag "${{ steps.tag.outputs.tag }}"
|
||||||
--gallery deploy/demo/gallery.json --driver r2 --bucket "$BUCKET" --remote
|
--gallery deploy/demo/gallery.json --driver r2 --bucket "$BUCKET" --remote
|
||||||
|
|
||||||
# 3) Build the standalone pinned to the CDN + this tag's manifests.
|
# 3) Build the standalone pinned to the CDN + this tag's manifests. The
|
||||||
|
# full KiCad library set is served read-only from libs/kicad/$LIB_TAG
|
||||||
|
# (published once by publish-libs.yml — run it first for a new lib tag).
|
||||||
- name: Build demo
|
- name: Build demo
|
||||||
run: node scripts/deploy/build-demo.mjs --tag "${{ steps.tag.outputs.tag }}" --cdn "$CDN"
|
run: >
|
||||||
|
node scripts/deploy/build-demo.mjs --tag "${{ steps.tag.outputs.tag }}"
|
||||||
|
--cdn "$CDN" --lib-tag "$LIB_TAG"
|
||||||
|
|
||||||
# 4) Ensure the Pages project exists (first deploy creates it; no-op after).
|
# 4) Ensure the Pages project exists (first deploy creates it; no-op after).
|
||||||
# Its production branch must equal PAGES_PROD_BRANCH or deploys land as
|
# Its production branch must equal PAGES_PROD_BRANCH or deploys land as
|
||||||
|
|
|
||||||
61
.github/workflows/publish-libs.yml
vendored
Normal file
61
.github/workflows/publish-libs.yml
vendored
Normal file
|
|
@ -0,0 +1,61 @@
|
||||||
|
name: publish-libs
|
||||||
|
|
||||||
|
# On-demand, decoupled: clone the full upstream KiCad symbol + footprint
|
||||||
|
# libraries at a tag and publish them to the CDN (cdn.pcbjam.com, R2 pcbjam-cdn)
|
||||||
|
# as version-pinned r2-idb-sync STATIC ORIGINS — one immutable manifest+bundle
|
||||||
|
# per lib under libs/kicad/<lib_tag>/. The demo's cdnLibsSource opens these
|
||||||
|
# read-only + IDB-cached. See docs/features/r2-idb-sync + the demo-adjustments
|
||||||
|
# feature; wasm/libs/cdn-source.ts (client) + scripts/deploy/publish-libs.ts.
|
||||||
|
#
|
||||||
|
# Keyed by the KiCad library tag and idempotent: if the snapshot already exists
|
||||||
|
# the script SKIPS the whole run, so re-running for the same tag is a near no-op.
|
||||||
|
# Run this ONLY when the library tag changes; deploy-demo.yml just pins the demo
|
||||||
|
# build at the chosen tag (build-demo --lib-tag).
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
lib_tag:
|
||||||
|
description: "KiCad library tag to publish (kicad-symbols/footprints), e.g. 10.0.3"
|
||||||
|
required: true
|
||||||
|
default: "10.0.3"
|
||||||
|
force:
|
||||||
|
description: "Re-publish even if the snapshot already exists (true/false)"
|
||||||
|
default: "false"
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: publish-libs
|
||||||
|
cancel-in-progress: false
|
||||||
|
|
||||||
|
env:
|
||||||
|
BUCKET: pcbjam-cdn
|
||||||
|
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
|
||||||
|
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
|
||||||
|
# publish-libs.ts shells wrangler (R2) via cdn-store; fetch it on demand.
|
||||||
|
WRANGLER_CMD: npx --yes wrangler@4
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
publish:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
timeout-minutes: 60
|
||||||
|
steps:
|
||||||
|
# Only the MIT pcbjam-shared submodule is needed (publish-libs imports the
|
||||||
|
# self-contained sync-wire codecs from it); kicad/wxwidgets are not.
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
submodules: false
|
||||||
|
- name: Init pcbjam-shared submodule
|
||||||
|
run: git submodule update --init --depth 1 web/pcbjam-shared
|
||||||
|
- uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: 20
|
||||||
|
|
||||||
|
# Clone the full libs at <lib_tag>, extract every lib, build the static
|
||||||
|
# origins, upload to R2. The import chain (extract-libs parsers +
|
||||||
|
# sync-wire) is dependency-free, so no workspace install is needed.
|
||||||
|
- name: Publish libs to CDN
|
||||||
|
run: >
|
||||||
|
npx --yes tsx scripts/deploy/publish-libs.ts
|
||||||
|
--lib-tag "${{ github.event.inputs.lib_tag }}"
|
||||||
|
--clone "$RUNNER_TEMP/kicad-libs"
|
||||||
|
--driver r2 --bucket "$BUCKET" --remote
|
||||||
|
${{ github.event.inputs.force == 'true' && '--force' || '' }}
|
||||||
|
|
@ -19,14 +19,22 @@
|
||||||
// + top `<prefix>/<libTag>/manifest.json` { schema, tag, libs:[{id,name,kind,itemCount}] }
|
// + top `<prefix>/<libTag>/manifest.json` { schema, tag, libs:[{id,name,kind,itemCount}] }
|
||||||
// All immutable (content is pinned by the tag).
|
// All immutable (content is pinned by the tag).
|
||||||
|
|
||||||
|
import { execFileSync } from "node:child_process";
|
||||||
|
import { existsSync, mkdirSync } from "node:fs";
|
||||||
|
import { dirname, join } from "node:path";
|
||||||
import { extractAllLibs } from "../../web/backend/src/extract/extract-libs.js";
|
import { extractAllLibs } from "../../web/backend/src/extract/extract-libs.js";
|
||||||
import { encodeBundle, type SyncManifest } from "../../web/pcbjam-shared/src/sync-wire.js";
|
import { encodeBundle, type SyncManifest } from "../../web/pcbjam-shared/src/sync-wire.js";
|
||||||
import { IMMUTABLE, makeStore, putJSON, sha256hex } from "./lib/cdn-store.mjs";
|
import { IMMUTABLE, makeStore, putJSON, sha256hex } from "./lib/cdn-store.mjs";
|
||||||
|
|
||||||
|
// Upstream KiCad library repos (full set lives here; tagged per KiCad release).
|
||||||
|
const SYMBOLS_URL = "https://gitlab.com/kicad/libraries/kicad-symbols.git";
|
||||||
|
const FOOTPRINTS_URL = "https://gitlab.com/kicad/libraries/kicad-footprints.git";
|
||||||
|
|
||||||
interface Args {
|
interface Args {
|
||||||
libTag: string | null;
|
libTag: string | null;
|
||||||
symbolsSrc: string | null;
|
symbolsSrc: string | null;
|
||||||
footprintsSrc: string | null;
|
footprintsSrc: string | null;
|
||||||
|
clone: string | null;
|
||||||
driver: string;
|
driver: string;
|
||||||
out: string | null;
|
out: string | null;
|
||||||
bucket: string;
|
bucket: string;
|
||||||
|
|
@ -40,6 +48,7 @@ function parseArgs(argv: string[]): Args {
|
||||||
libTag: null,
|
libTag: null,
|
||||||
symbolsSrc: null,
|
symbolsSrc: null,
|
||||||
footprintsSrc: null,
|
footprintsSrc: null,
|
||||||
|
clone: null,
|
||||||
driver: "local",
|
driver: "local",
|
||||||
out: null,
|
out: null,
|
||||||
bucket: "pcbjam-cdn",
|
bucket: "pcbjam-cdn",
|
||||||
|
|
@ -53,6 +62,9 @@ function parseArgs(argv: string[]): Args {
|
||||||
case "--lib-tag": a.libTag = next(); break;
|
case "--lib-tag": a.libTag = next(); break;
|
||||||
case "--symbols-src": a.symbolsSrc = next(); break;
|
case "--symbols-src": a.symbolsSrc = next(); break;
|
||||||
case "--footprints-src": a.footprintsSrc = next(); break;
|
case "--footprints-src": a.footprintsSrc = next(); break;
|
||||||
|
// Clone both upstream repos at --lib-tag into <dir>/{kicad-symbols,
|
||||||
|
// kicad-footprints} (full, shallow) and use them as the sources.
|
||||||
|
case "--clone": a.clone = next(); break;
|
||||||
case "--driver": a.driver = next(); break;
|
case "--driver": a.driver = next(); break;
|
||||||
case "--out": a.out = next(); break;
|
case "--out": a.out = next(); break;
|
||||||
case "--bucket": a.bucket = next(); break;
|
case "--bucket": a.bucket = next(); break;
|
||||||
|
|
@ -63,12 +75,25 @@ function parseArgs(argv: string[]): Args {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!a.libTag) throw new Error("--lib-tag <kicad library tag> is required");
|
if (!a.libTag) throw new Error("--lib-tag <kicad library tag> is required");
|
||||||
if (!a.symbolsSrc && !a.footprintsSrc)
|
if (!a.symbolsSrc && !a.footprintsSrc && !a.clone)
|
||||||
throw new Error("at least one of --symbols-src / --footprints-src is required");
|
throw new Error("need --clone <dir>, or --symbols-src / --footprints-src");
|
||||||
if (a.driver === "local" && !a.out) a.out = ".cdn-out";
|
if (a.driver === "local" && !a.out) a.out = ".cdn-out";
|
||||||
return a;
|
return a;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Shallow full clone of a lib repo at a tag (idempotent: skip if present). */
|
||||||
|
function cloneFull(url: string, dest: string, ref: string): void {
|
||||||
|
if (existsSync(dest)) {
|
||||||
|
console.log(`clone: ${dest} present — reusing`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
mkdirSync(dirname(dest), { recursive: true });
|
||||||
|
console.log(`clone: ${url} @ ${ref} → ${dest}`);
|
||||||
|
execFileSync("git", ["clone", "--depth", "1", "--branch", ref, url, dest], {
|
||||||
|
stdio: "inherit",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
async function main(): Promise<void> {
|
async function main(): Promise<void> {
|
||||||
const a = parseArgs(process.argv);
|
const a = parseArgs(process.argv);
|
||||||
const store = makeStore(a.driver, a);
|
const store = makeStore(a.driver, a);
|
||||||
|
|
@ -82,6 +107,18 @@ async function main(): Promise<void> {
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log(`publish-libs: tag=${a.libTag} driver=${store.kind} → ${a.prefix}/${a.libTag}/`);
|
console.log(`publish-libs: tag=${a.libTag} driver=${store.kind} → ${a.prefix}/${a.libTag}/`);
|
||||||
|
|
||||||
|
// Source the full set from upstream when asked (CI path); --symbols-src /
|
||||||
|
// --footprints-src still win if also given (local checkouts).
|
||||||
|
if (a.clone) {
|
||||||
|
const symDest = join(a.clone, "kicad-symbols");
|
||||||
|
const fpDest = join(a.clone, "kicad-footprints");
|
||||||
|
cloneFull(SYMBOLS_URL, symDest, a.libTag);
|
||||||
|
cloneFull(FOOTPRINTS_URL, fpDest, a.libTag);
|
||||||
|
a.symbolsSrc ??= symDest;
|
||||||
|
a.footprintsSrc ??= fpDest;
|
||||||
|
}
|
||||||
|
|
||||||
const libs = await extractAllLibs({
|
const libs = await extractAllLibs({
|
||||||
symbolsSrc: a.symbolsSrc ?? undefined,
|
symbolsSrc: a.symbolsSrc ?? undefined,
|
||||||
footprintsSrc: a.footprintsSrc ?? undefined,
|
footprintsSrc: a.footprintsSrc ?? undefined,
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue