Add TUI Preview screen for dry-run file transformations (#510) #1448
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: CI | |
| on: | |
| push: | |
| branches: [main] | |
| pull_request: | |
| branches: [main] | |
| # Cancel in-progress runs for the same branch/PR | |
| concurrency: | |
| group: ${{ github.workflow }}-${{ github.ref }} | |
| cancel-in-progress: true | |
| jobs: | |
| # ── Detect what changed to skip irrelevant jobs ── | |
| detect-changes: | |
| name: Detect Changes | |
| runs-on: ubuntu-latest | |
| outputs: | |
| engine: ${{ steps.filter.outputs.engine }} | |
| web: ${{ steps.filter.outputs.web }} | |
| steps: | |
| - uses: actions/checkout@v5 | |
| - uses: dorny/paths-filter@v4 | |
| id: filter | |
| with: | |
| filters: | | |
| engine: | |
| - 'engine/**' | |
| web: | |
| - 'apps/**' | |
| - 'packages/**' | |
| - 'pnpm-lock.yaml' | |
| - 'package.json' | |
| - 'tsconfig*.json' | |
| # ── Rust CI (only when engine files changed) ── | |
| rust: | |
| name: Rust Engine (fmt + lint + test + WASM) | |
| runs-on: ubuntu-latest | |
| needs: [detect-changes] | |
| if: needs.detect-changes.outputs.engine == 'true' | |
| defaults: | |
| run: | |
| working-directory: engine | |
| steps: | |
| - uses: actions/checkout@v5 | |
| - uses: dtolnay/rust-toolchain@stable | |
| with: | |
| targets: wasm32-unknown-unknown | |
| components: clippy, rustfmt | |
| - uses: Swatinem/rust-cache@v2 | |
| with: | |
| workspaces: engine | |
| - name: Install wasm-pack | |
| run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh | |
| - name: Format check | |
| run: cargo fmt --all -- --check | |
| - name: Clippy | |
| run: cargo clippy --workspace --all-targets -- -D warnings | |
| - name: Unit tests (native) | |
| run: cargo test --workspace --exclude bnto | |
| - name: CLI tests (unit + golden) | |
| run: cargo test --package bnto | |
| - name: WASM integration tests (bnto-wasm) | |
| run: wasm-pack test --node crates/bnto-wasm | |
| - name: WASM integration tests (bnto-spreadsheet) | |
| run: wasm-pack test --node crates/bnto-spreadsheet | |
| - name: WASM integration tests (bnto-file) | |
| run: wasm-pack test --node crates/bnto-file | |
| - name: WASM integration tests (bnto-image) | |
| run: wasm-pack test --node crates/bnto-image | |
| # ── TypeScript CI (only when web files changed) ── | |
| typescript: | |
| name: TypeScript (build + lint + test) | |
| runs-on: ubuntu-latest | |
| needs: [detect-changes] | |
| if: needs.detect-changes.outputs.web == 'true' | |
| env: | |
| NEXT_PUBLIC_CONVEX_URL: https://zealous-canary-422.convex.cloud | |
| NEXT_PUBLIC_CONVEX_SITE_URL: https://zealous-canary-422.convex.site | |
| steps: | |
| - uses: actions/checkout@v5 | |
| - uses: pnpm/action-setup@v5 | |
| - uses: actions/setup-node@v6 | |
| with: | |
| node-version: 24 | |
| cache: pnpm | |
| - name: Install dependencies | |
| run: pnpm install --frozen-lockfile | |
| # --- Build (type-check all packages) --- | |
| - name: "Build: @bnto/nodes" | |
| run: pnpm --filter @bnto/nodes run build | |
| - name: "Build: @bnto/registry" | |
| run: pnpm --filter @bnto/registry run build | |
| - name: "Build: @bnto/auth" | |
| run: pnpm --filter @bnto/auth run build | |
| - name: "Build: @bnto/backend" | |
| run: pnpm --filter @bnto/backend run build | |
| - name: "Build: @bnto/core" | |
| run: pnpm --filter @bnto/core run build | |
| - name: "Build: @bnto/form" | |
| run: pnpm --filter @bnto/form run build | |
| - name: "Build: @bnto/ui" | |
| run: pnpm --filter @bnto/ui run build | |
| - name: "Build: @bnto/editor" | |
| run: pnpm --filter @bnto/editor run build | |
| - name: "Build: @bnto/web" | |
| run: pnpm --filter @bnto/web run build | |
| # --- Monorepo hygiene --- | |
| - name: "Check: sherif (package.json consistency)" | |
| run: pnpm sherif -p @bnto/package.json | |
| # --- Lint --- | |
| - name: "Lint: @bnto/nodes" | |
| run: pnpm --filter @bnto/nodes run lint | |
| - name: "Lint: @bnto/registry" | |
| run: pnpm --filter @bnto/registry run lint | |
| - name: "Lint: @bnto/auth" | |
| run: pnpm --filter @bnto/auth run lint | |
| - name: "Lint: @bnto/core" | |
| run: pnpm --filter @bnto/core run lint | |
| - name: "Lint: @bnto/form" | |
| run: pnpm --filter @bnto/form run lint | |
| - name: "Lint: @bnto/ui" | |
| run: pnpm --filter @bnto/ui run lint | |
| - name: "Lint: @bnto/editor" | |
| run: pnpm --filter @bnto/editor run lint | |
| - name: "Lint: @bnto/backend" | |
| run: pnpm --filter @bnto/backend run lint | |
| - name: "Lint: @bnto/web" | |
| run: pnpm --filter @bnto/web run lint | |
| # --- Test --- | |
| - name: "Test: @bnto/nodes" | |
| run: pnpm --filter @bnto/nodes run test | |
| - name: "Test: @bnto/registry" | |
| run: pnpm --filter @bnto/registry run test | |
| - name: "Test: @bnto/backend" | |
| run: pnpm --filter @bnto/backend run test | |
| - name: "Test: @bnto/core" | |
| run: pnpm --filter @bnto/core run test | |
| - name: "Test: @bnto/form" | |
| run: pnpm --filter @bnto/form run test | |
| - name: "Test: @bnto/ui" | |
| run: pnpm --filter @bnto/ui run test | |
| - name: "Test: @bnto/editor" | |
| run: pnpm --filter @bnto/editor run test | |
| - name: "Test: @bnto/web" | |
| run: pnpm --filter @bnto/web run test | |
| # ── Validate release workflow matches workspace crates ── | |
| crate-publish-check: | |
| name: Crate Publish List | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v5 | |
| - name: Validate crate publish list | |
| run: ./scripts/check-crate-publish-list.sh | |
| # Gate job — single status check for branch protection. | |
| # Accepts skipped jobs when their surface didn't change. | |
| ci-gate: | |
| name: CI Gate | |
| runs-on: ubuntu-latest | |
| needs: [detect-changes, rust, typescript, crate-publish-check] | |
| if: always() | |
| steps: | |
| - name: Check job results | |
| run: | | |
| rust="${{ needs.rust.result }}" | |
| ts="${{ needs.typescript.result }}" | |
| crates="${{ needs.crate-publish-check.result }}" | |
| engine="${{ needs.detect-changes.outputs.engine }}" | |
| web="${{ needs.detect-changes.outputs.web }}" | |
| failed=0 | |
| # Crate publish list is always required | |
| if [ "$crates" != "success" ]; then | |
| echo "FAILED: Crate Publish List = $crates" | |
| failed=1 | |
| fi | |
| # Rust is required when engine files changed | |
| if [ "$engine" = "true" ] && [ "$rust" != "success" ]; then | |
| echo "FAILED: Rust Engine = $rust (engine files changed)" | |
| failed=1 | |
| fi | |
| # TypeScript is required when web files changed | |
| if [ "$web" = "true" ] && [ "$ts" != "success" ]; then | |
| echo "FAILED: TypeScript = $ts (web files changed)" | |
| failed=1 | |
| fi | |
| if [ "$failed" = "1" ]; then | |
| exit 1 | |
| fi | |
| echo "CI Gate passed." | |
| echo " Crates: $crates" | |
| echo " Rust: $rust (engine_changed: $engine)" | |
| echo " TypeScript: $ts (web_changed: $web)" | |
| # NOTE: Convex production deploy moved to release.yml (runs after release gate passes). | |
| # Convex functions only deploy to prod when a release tag is pushed and all checks pass. |