diff --git a/.github/workflows/release-fast.yml b/.github/workflows/release-fast.yml new file mode 100644 index 0000000..c43ab7f --- /dev/null +++ b/.github/workflows/release-fast.yml @@ -0,0 +1,93 @@ +name: Release Fast + +on: + workflow_dispatch: + inputs: + reddb_version: + description: "Pinned RedDB release tag to smoke-package with" + required: true + default: "v1.11.0" + +permissions: + contents: read + +concurrency: + group: release-fast-${{ github.ref }} + cancel-in-progress: true + +env: + REDDB_VERSION: ${{ github.event.inputs.reddb_version }} + +jobs: + linux-deb: + name: linux-x86_64 deb smoke + runs-on: ubuntu-22.04 + steps: + - uses: actions/checkout@v7 + with: + persist-credentials: false + + - name: Linux system dependencies + run: | + sudo apt-get update + sudo apt-get install -y \ + libwebkit2gtk-4.1-dev libgtk-3-dev libayatana-appindicator3-dev \ + librsvg2-dev build-essential curl wget file libssl-dev libxdo-dev \ + clang mold + + - uses: pnpm/action-setup@v6 + with: + version: 10.33.3 + + - uses: actions/setup-node@v6 + with: + node-version: "22" + cache: pnpm + + - uses: oven-sh/setup-bun@v2 + with: + bun-version: "1.3.14" + + - uses: dtolnay/rust-toolchain@stable + with: + targets: x86_64-unknown-linux-gnu + + - uses: swatinem/rust-cache@v2 + with: + workspaces: "apps/desktop/src-tauri -> target" + + - name: Install + run: pnpm install --frozen-lockfile + + - name: Check RedDB sidecar release asset + run: node scripts/check-reddb-release-assets.mjs x86_64-unknown-linux-gnu + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Brand sync + run: pnpm brand:sync + + - name: Brand icons + run: pnpm brand:icons + + - name: Build core contract + run: pnpm --filter @red-request/core build + + - name: Build engine sidecar + run: pnpm engine:build + + - name: Provision RedDB sidecar + run: pnpm reddb:fetch + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + REDDB_TARGET: x86_64-unknown-linux-gnu + + - name: Build Linux deb only + run: pnpm --filter @red-request/desktop tauri build --bundles deb + + - name: Upload deb artifact + uses: actions/upload-artifact@v5 + with: + name: red-request-linux-x86_64-deb + path: apps/desktop/src-tauri/target/release/bundle/deb/*.deb + if-no-files-found: error diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 4c65594..f21d950 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -26,8 +26,27 @@ env: NO_STRIP: "1" jobs: + preflight: + name: release preflight + runs-on: ubuntu-22.04 + steps: + - uses: actions/checkout@v7 + with: + ref: ${{ github.event.inputs.tag || github.ref }} + persist-credentials: false + + - uses: actions/setup-node@v6 + with: + node-version: "22" + + - name: Check RedDB sidecar release assets + run: node scripts/check-reddb-release-assets.mjs x86_64-unknown-linux-gnu x86_64-pc-windows-msvc + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + build: name: ${{ matrix.label }} + needs: preflight runs-on: ${{ matrix.os }} strategy: fail-fast: false diff --git a/CLAUDE.md b/CLAUDE.md index 442ec73..7d4e486 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -12,6 +12,8 @@ - Prefer indexed lookups, single-pass loops, lazy or partial rendering, storage-side filtering, and realistic fixtures over speculative rewrites. - Add or update lightweight perf workloads when touching hot paths. Benchmarks can start non-blocking, but visible regressions should become hard to ignore. - For Rust/Tauri performance work, profile release builds before invasive changes; keep `cargo fmt`, Clippy, frame-pointer/debug-info profiling, LTO, allocator, and PGO decisions tied to evidence. +- Use `Release Fast` for a Linux `.deb` packaging smoke test; keep `Release` as the full Linux/macOS/Windows publishing path. RedDB sidecar assets must pass preflight before spending matrix time. +- Treat `lto`, `codegen-units`, `strip`, allocator swaps, and PGO as measured release-profile experiments. Avoid `target-cpu=native` for public binaries unless distribution compatibility is intentionally narrowed. ## Agent skills diff --git a/package.json b/package.json index 9eb0249..15f7a6f 100644 --- a/package.json +++ b/package.json @@ -14,6 +14,7 @@ "desktop:dev": "pnpm brand:sync && pnpm --filter @red-request/core build && pnpm --filter @red-request/engine build && pnpm --filter @red-request/desktop tauri dev", "desktop:build": "pnpm brand:sync && pnpm brand:icons && pnpm --filter @red-request/core build && pnpm engine:build && pnpm --filter @red-request/desktop tauri build", "engine:build": "node scripts/build-engine.mjs", + "reddb:preflight": "node scripts/check-reddb-release-assets.mjs x86_64-unknown-linux-gnu x86_64-pc-windows-msvc", "reddb:sync": "node scripts/sync-reddb.mjs", "reddb:fetch": "node scripts/fetch-reddb.mjs", "reddb:migration-demo": "node scripts/reddb-migration-demo.mjs", diff --git a/scripts/check-reddb-release-assets.mjs b/scripts/check-reddb-release-assets.mjs new file mode 100644 index 0000000..96c9ff3 --- /dev/null +++ b/scripts/check-reddb-release-assets.mjs @@ -0,0 +1,87 @@ +#!/usr/bin/env node +// Fast release preflight for the embedded RedDB sidecar. +// +// The desktop app cannot be packaged for Linux/Windows unless the pinned RedDB +// release exposes the prebuilt `red--` assets that fetch-reddb.mjs +// downloads. Check that up front so release jobs fail before runner setup, +// dependency install, and Tauri packaging work. +// +// REDDB_VERSION=v1.11.0 node scripts/check-reddb-release-assets.mjs \ +// x86_64-unknown-linux-gnu x86_64-pc-windows-msvc +import { env, exit } from "node:process"; + +const REPO = "reddb-io/reddb"; + +function assetName(triple) { + const [arch] = triple.split("-"); + const os = triple.includes("linux") + ? "linux" + : triple.includes("darwin") + ? "darwin" + : triple.includes("windows") + ? "windows" + : null; + if (!os) throw new Error(`unsupported target triple: ${triple}`); + const ext = os === "windows" ? ".exe" : ""; + return `red-${os}-${arch}${ext}`; +} + +async function ghJson(path) { + const controller = new AbortController(); + const timeout = setTimeout(() => controller.abort(), 30_000); + const headers = { + Accept: "application/vnd.github+json", + "User-Agent": "red-request-reddb-preflight", + }; + if (env.GITHUB_TOKEN) headers.Authorization = `Bearer ${env.GITHUB_TOKEN}`; + try { + const res = await fetch(`https://api.github.com/${path}`, { + headers, + signal: controller.signal, + }); + if (!res.ok) throw new Error(`${path} -> ${res.status} ${res.statusText}`); + return res.json(); + } finally { + clearTimeout(timeout); + } +} + +const targets = process.argv.slice(2); +if (targets.length === 0) { + console.error("usage: check-reddb-release-assets.mjs [...]"); + exit(2); +} + +const required = targets.map(assetName); +const tag = env.REDDB_VERSION; + +let release; +try { + release = tag + ? await ghJson(`repos/${REPO}/releases/tags/${encodeURIComponent(tag)}`) + : await ghJson(`repos/${REPO}/releases/latest`); +} catch (err) { + console.error(`RedDB release preflight failed: ${err.message}`); + console.error( + "Publish the pinned RedDB release, fix REDDB_VERSION, or build the sidecar from source." + ); + exit(1); +} + +const available = new Set((release.assets ?? []).map((asset) => asset.name)); +const missing = required.filter((name) => !available.has(name)); + +if (missing.length > 0) { + console.error( + `RedDB ${release.tag_name} is missing required release assets:` + ); + for (const name of missing) console.error(` - ${name}`); + console.error(""); + console.error("Available assets:"); + for (const name of [...available].sort()) console.error(` - ${name}`); + exit(1); +} + +console.log( + `RedDB ${release.tag_name} has required assets: ${required.join(", ")}` +);