Repository navigation
feat(plugins): add native-default engine selection infrastructure #2657
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: Publish Package to npm | |
| on: | |
| push: | |
| branches: | |
| - main | |
| pull_request: | |
| branches: | |
| - main | |
| - feat/napi-binding | |
| # Pull requests and every job below run read-only. Only the `release` and | |
| # `deploy-pages` jobs get write permissions, and they run on pushes to main | |
| # alone, so no step a pull request controls can publish, tag, comment or deploy. | |
| permissions: | |
| contents: read | |
| # CI always runs the latest releases: the `ubuntu-latest` runner, the newest | |
| # major version of every action, and the latest stable Rust, Bun, Node.js, | |
| # wasm-pack, cargo-binstall, cargo-tarpaulin and changepacks. | |
| concurrency: | |
| group: ${{ github.workflow }}-${{ github.ref }} | |
| cancel-in-progress: false | |
| jobs: | |
| # Independent read-only lane; no existing validation job waits on it. | |
| native-build: | |
| runs-on: ${{ matrix.runner }} | |
| timeout-minutes: 45 | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| - { suffix: linux-x64-gnu, target: x86_64-unknown-linux-gnu, runner: ubuntu-latest } | |
| - { suffix: linux-arm64-gnu, target: aarch64-unknown-linux-gnu, runner: ubuntu-latest } | |
| - { suffix: linux-x64-musl, target: x86_64-unknown-linux-musl, runner: ubuntu-latest } | |
| - { suffix: linux-arm64-musl, target: aarch64-unknown-linux-musl, runner: ubuntu-latest } | |
| - { suffix: darwin-x64, target: x86_64-apple-darwin, runner: macos-latest } | |
| - { suffix: darwin-arm64, target: aarch64-apple-darwin, runner: macos-latest } | |
| - { suffix: win32-x64-msvc, target: x86_64-pc-windows-msvc, runner: windows-latest } | |
| # Windows ARM has no -latest alias; this is its newest exposed image, not a pin. | |
| - { suffix: win32-arm64-msvc, target: aarch64-pc-windows-msvc, runner: windows-11-vs2026-arm } | |
| env: | |
| GIT_CONFIG_COUNT: "1" | |
| GIT_CONFIG_KEY_0: core.autocrlf | |
| GIT_CONFIG_VALUE_0: "false" | |
| CARGO_BUILD_JOBS: "2" | |
| RUSTUP_TOOLCHAIN: stable | |
| steps: | |
| - name: Start durable build evidence | |
| shell: bash | |
| run: | | |
| mkdir -p "$RUNNER_TEMP/native-build-${{ matrix.suffix }}" | |
| printf '%s\n' "$GITHUB_SHA $RUNNER_OS $RUNNER_ARCH $ImageOS $ImageVersion" > "$RUNNER_TEMP/native-build-${{ matrix.suffix }}/runner.txt" | |
| - uses: actions/checkout@v7 | |
| with: | |
| persist-credentials: false | |
| - uses: actions/setup-node@v7 | |
| with: | |
| node-version: '*' | |
| check-latest: true | |
| - uses: oven-sh/setup-bun@v2 | |
| with: | |
| bun-version: latest | |
| - uses: actions-rust-lang/setup-rust-toolchain@v2 | |
| with: | |
| toolchain: stable | |
| target: ${{ matrix.target }} | |
| cache: false | |
| - name: Install latest stable Zig and cargo-zigbuild | |
| if: runner.os == 'Linux' | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| curl -fsSL https://ziglang.org/download/index.json -o "$RUNNER_TEMP/zig-index.json" | |
| version=$(jq -r 'keys[] | select(test("^[0-9]+\\.[0-9]+\\.[0-9]+$"))' "$RUNNER_TEMP/zig-index.json" | sort -V | tail -1) | |
| jq --arg v "$version" '.[$v]["x86_64-linux"]' "$RUNNER_TEMP/zig-index.json" > "$RUNNER_TEMP/zig-asset.json" | |
| cp "$RUNNER_TEMP/zig-asset.json" "$RUNNER_TEMP/native-build-${{ matrix.suffix }}/zig-asset.json" | |
| curl -fsSL "$(jq -r .tarball "$RUNNER_TEMP/zig-asset.json")" -o "$RUNNER_TEMP/zig.tar.xz" | |
| echo "$(jq -r .shasum "$RUNNER_TEMP/zig-asset.json") $RUNNER_TEMP/zig.tar.xz" | sha256sum -c - | |
| mkdir "$RUNNER_TEMP/zig" | |
| tar -xf "$RUNNER_TEMP/zig.tar.xz" --strip-components=1 -C "$RUNNER_TEMP/zig" | |
| echo "$RUNNER_TEMP/zig" >> "$GITHUB_PATH" | |
| CARGO_TARGET_DIR="$RUNNER_TEMP/native-zigbuild-tool-target" cargo install cargo-zigbuild --locked --jobs 2 | |
| - name: Build fresh target and retain exact receipt | |
| shell: bash | |
| env: | |
| CARGO_TARGET_DIR: ${{ runner.temp }}/native-target-${{ github.run_id }}-${{ github.run_attempt }}-${{ matrix.suffix }} | |
| NATIVE_SUFFIX: ${{ matrix.suffix }} | |
| NATIVE_TARGET: ${{ matrix.target }} | |
| run: | | |
| set -euo pipefail | |
| test "$GITHUB_RUN_ATTEMPT" = 1 # Never replace original payloads on release-only retries. | |
| test ! -e "$CARGO_TARGET_DIR" | |
| if [[ "$RUNNER_OS" == macOS ]]; then export SDKROOT="$(xcrun --sdk macosx --show-sdk-path)"; fi | |
| if [[ "$NATIVE_SUFFIX" == win32-arm64-msvc ]]; then node -e "require('node:assert/strict').equal(process.arch,'arm64')"; fi | |
| flags=() | |
| if [[ "$RUNNER_OS" == Linux ]]; then flags+=(--zigbuild); fi | |
| node e2e/binding/package/provenance.mjs "$NATIVE_TARGET" "$RUNNER_TEMP/native-build-$NATIVE_SUFFIX/payload" "$GITHUB_RUN_ID/1" "${flags[@]}" | |
| - uses: actions/upload-artifact@v7 | |
| if: always() | |
| with: | |
| name: native-build-${{ matrix.suffix }}-${{ github.run_id }} | |
| path: ${{ runner.temp }}/native-build-${{ matrix.suffix }}/* | |
| if-no-files-found: error | |
| retention-days: 7 | |
| native-packs: | |
| needs: [native-build] | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 20 | |
| env: | |
| GIT_CONFIG_COUNT: "1" | |
| GIT_CONFIG_KEY_0: core.autocrlf | |
| GIT_CONFIG_VALUE_0: "false" | |
| steps: | |
| - name: Start durable collector evidence | |
| shell: bash | |
| run: | | |
| mkdir -p "$RUNNER_TEMP/native-pack-evidence" | |
| printf '%s\n' "$GITHUB_SHA $GITHUB_RUN_ID $GITHUB_RUN_ATTEMPT $RUNNER_OS $RUNNER_ARCH $ImageOS $ImageVersion" > "$RUNNER_TEMP/native-pack-evidence/runner.txt" | |
| - uses: actions/checkout@v7 | |
| with: | |
| persist-credentials: false | |
| - uses: actions/setup-node@v7 | |
| with: | |
| node-version: '*' | |
| check-latest: true | |
| - uses: oven-sh/setup-bun@v2 | |
| with: | |
| bun-version: latest | |
| - uses: actions/download-artifact@v8 | |
| with: | |
| pattern: native-build-*-${{ github.run_id }} | |
| path: ${{ runner.temp }}/native-inputs | |
| - name: Collect once from clean source and run real-artifact controls | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| test "$GITHUB_RUN_ATTEMPT" = 1 | |
| mkdir "$RUNNER_TEMP/native-artifacts" | |
| for suffix in $(node --input-type=module -e "import {targets} from './e2e/binding/package/matrix.mjs'; console.log(targets.map(r=>r.suffix).join(' '))"); do | |
| mv "$RUNNER_TEMP/native-inputs/native-build-$suffix-$GITHUB_RUN_ID/payload" "$RUNNER_TEMP/native-artifacts/$suffix" | |
| done | |
| mkdir -p bindings/devup-ui-binding/pkg | |
| node bindings/devup-ui-binding/script.cjs --public "$PWD/bindings/devup-ui-binding/pkg/index.cjs" | |
| node e2e/binding/package/collect.mjs "$RUNNER_TEMP/native-artifacts" "$RUNNER_TEMP/native-bundle" "$GITHUB_RUN_ID/1" | |
| mkdir "$RUNNER_TEMP/native-controls" | |
| cp -R "$RUNNER_TEMP/native-artifacts/linux-x64-gnu" "$RUNNER_TEMP/native-controls/linux-x64-gnu" | |
| NATIVE_PROOF_ARTIFACTS="$RUNNER_TEMP/native-controls" NATIVE_PROOF_BUNDLE="$RUNNER_TEMP/native-bundle" node --test e2e/binding/package/package.test.mjs e2e/binding/package/publish.test.mjs e2e/binding/package/elf.test.mjs | |
| sha256sum "$RUNNER_TEMP/native-bundle/"*.tgz "$RUNNER_TEMP/native-bundle/bundle.json" | tee "$RUNNER_TEMP/native-bundle/SHA256SUMS" | |
| du -b "$RUNNER_TEMP/native-bundle/"* | |
| - uses: actions/upload-artifact@v7 | |
| if: always() | |
| with: | |
| name: native-packs-${{ github.run_id }} | |
| path: ${{ runner.temp }}/native-bundle/* | |
| if-no-files-found: error | |
| retention-days: 7 | |
| - uses: actions/upload-artifact@v7 | |
| if: always() | |
| with: | |
| name: native-pack-evidence-${{ github.run_id }} | |
| path: ${{ runner.temp }}/native-pack-evidence/* | |
| if-no-files-found: error | |
| retention-days: 7 | |
| native-consumer: | |
| needs: [native-packs] | |
| runs-on: ${{ matrix.runner }} | |
| timeout-minutes: 30 | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| - { suffix: linux-x64-gnu, runner: ubuntu-latest, cpu: x64, docker: amd64, image: "node:current", bun: bun-linux-x64.zip, mode: native-container } | |
| - { suffix: linux-arm64-gnu, runner: ubuntu-latest, cpu: arm64, docker: arm64, image: "node:current", bun: bun-linux-aarch64.zip, mode: QEMU-emulated } | |
| - { suffix: linux-x64-musl, runner: ubuntu-latest, cpu: x64, docker: amd64, image: "node:current-alpine", bun: bun-linux-x64-musl.zip, mode: native-container } | |
| - { suffix: linux-arm64-musl, runner: ubuntu-latest, cpu: arm64, docker: arm64, image: "node:current-alpine", bun: bun-linux-aarch64-musl.zip, mode: QEMU-emulated } | |
| - { suffix: darwin-x64, runner: macos-latest, cpu: x64, bun: bun-darwin-x64.zip, mode: Rosetta } | |
| - { suffix: darwin-arm64, runner: macos-latest, cpu: arm64, bun: bun-darwin-aarch64.zip, mode: native } | |
| - { suffix: win32-x64-msvc, runner: windows-latest, cpu: x64, bun: bun-windows-x64.zip, mode: native } | |
| # Windows ARM has no -latest alias; this is its newest exposed image, not a pin. | |
| - { suffix: win32-arm64-msvc, runner: windows-11-vs2026-arm, cpu: arm64, bun: bun-windows-aarch64.zip, mode: native } | |
| env: | |
| NATIVE_SUFFIX: ${{ matrix.suffix }} | |
| NATIVE_CPU: ${{ matrix.cpu }} | |
| NATIVE_MODE: ${{ matrix.mode }} | |
| steps: | |
| - name: Start durable consumer evidence | |
| shell: bash | |
| run: | | |
| mkdir -p "$RUNNER_TEMP/native-evidence" | |
| printf '%s\n' "$NATIVE_MODE $GITHUB_SHA $RUNNER_OS $RUNNER_ARCH" > "$RUNNER_TEMP/native-evidence/start.txt" | |
| - uses: actions/checkout@v7 | |
| with: | |
| persist-credentials: false | |
| - uses: actions/download-artifact@v8 | |
| with: | |
| name: native-packs-${{ github.run_id }} | |
| path: ${{ runner.temp }}/native-bundle | |
| - name: Enable current ARM emulation | |
| if: runner.os == 'Linux' && matrix.cpu == 'arm64' | |
| uses: docker/setup-qemu-action@v4 | |
| with: | |
| platforms: arm64 | |
| - name: Enable Rosetta for both x64 runtimes | |
| if: matrix.mode == 'Rosetta' | |
| run: sudo softwareupdate --install-rosetta --agree-to-license | |
| - uses: actions/setup-node@v7 | |
| with: | |
| node-version: '*' | |
| check-latest: true | |
| architecture: ${{ runner.os == 'Linux' && 'x64' || matrix.cpu }} | |
| - name: Download matching latest official Bun with digest | |
| shell: bash | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| BUN_ASSET: ${{ matrix.bun }} | |
| run: | | |
| set -euo pipefail | |
| mkdir "$RUNNER_TEMP/native-tools" | |
| gh api repos/oven-sh/bun/releases/latest > "$RUNNER_TEMP/native-evidence/bun-release.json" | |
| node -e "const fs=require('node:fs'),r=JSON.parse(fs.readFileSync(process.env.RUNNER_TEMP+'/native-evidence/bun-release.json'));const a=r.assets.find(a=>a.name===process.env.BUN_ASSET);if(!a?.digest?.startsWith('sha256:'))throw Error('missing official digest');fs.writeFileSync(process.env.RUNNER_TEMP+'/native-evidence/bun-asset.json',JSON.stringify(a))" | |
| url=$(node -p "JSON.parse(require('node:fs').readFileSync(process.env.RUNNER_TEMP+'/native-evidence/bun-asset.json')).browser_download_url") | |
| curl -fsSL "$url" -o "$RUNNER_TEMP/native-tools/bun.zip" | |
| node -e "const fs=require('node:fs'),c=require('node:crypto'),p=process.env.RUNNER_TEMP;require('node:assert/strict').equal('sha256:'+c.createHash('sha256').update(fs.readFileSync(p+'/native-tools/bun.zip')).digest('hex'),JSON.parse(fs.readFileSync(p+'/native-evidence/bun-asset.json')).digest)" | |
| unzip -q "$RUNNER_TEMP/native-tools/bun.zip" -d "$RUNNER_TEMP/native-tools" | |
| bun_dir="$RUNNER_TEMP/native-tools/${BUN_ASSET%.zip}" | |
| echo "$bun_dir" >> "$GITHUB_PATH" | |
| printf '%s\n' "$NATIVE_MODE" > "$RUNNER_TEMP/native-evidence/execution-mode.txt" | |
| node -e "require('node:fs').writeFileSync(process.env.RUNNER_TEMP+'/native-evidence/runner.json',JSON.stringify(Object.fromEntries(['GITHUB_SHA','GITHUB_RUN_ID','GITHUB_RUN_ATTEMPT','RUNNER_OS','RUNNER_ARCH','ImageOS','ImageVersion','NATIVE_MODE','NATIVE_SUFFIX'].map(k=>[k,process.env[k]]))))" | |
| - name: Consume on matching macOS or Windows runtimes | |
| if: runner.os != 'Linux' | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| bun install --frozen-lockfile --ignore-scripts | |
| node --input-type=module <<'NODE' 2>&1 | tee "$RUNNER_TEMP/native-evidence/consumer.log" | |
| import assert from 'node:assert/strict' | |
| import { dirname, join } from 'node:path' | |
| import { realpathSync } from 'node:fs' | |
| import getExePath from './node_modules/@typescript/native/lib/getExePath.js' | |
| import { command } from './e2e/binding/package/provenance.mjs' | |
| import { consume } from './e2e/binding/package/consumer.mjs' | |
| assert.equal(process.arch, process.env.NATIVE_CPU) | |
| assert.equal(command('bun', ['-p', 'process.arch']), process.env.NATIVE_CPU) | |
| const tsc = getExePath() | |
| console.log({ mode: process.env.NATIVE_MODE, tsc, version: command(tsc, ['--version']) }) | |
| const npmCli = process.platform === 'win32' ? join(dirname(process.execPath), 'node_modules/npm/bin/npm-cli.js') : realpathSync(command('which', ['npm'])) | |
| await consume({ bundle: join(process.env.RUNNER_TEMP, 'native-bundle'), suffix: process.env.NATIVE_SUFFIX, report: join(process.env.RUNNER_TEMP, 'native-evidence/consumer.json'), tsc, npmCli }) | |
| NODE | |
| - name: Consume current GNU or musl container with matching Node and Bun | |
| if: runner.os == 'Linux' | |
| shell: bash | |
| env: | |
| CONTAINER_IMAGE: ${{ matrix.image }} | |
| CONTAINER_CPU: ${{ matrix.docker }} | |
| BUN_ASSET: ${{ matrix.bun }} | |
| run: | | |
| set -euo pipefail | |
| docker pull --platform "linux/$CONTAINER_CPU" "$CONTAINER_IMAGE" | |
| docker image inspect "$CONTAINER_IMAGE" > "$RUNNER_TEMP/native-evidence/container.json" | |
| docker run --rm -i --platform "linux/$CONTAINER_CPU" -v "$PWD:/repo" -v "$RUNNER_TEMP:/evidence" -w /repo -e NATIVE_SUFFIX -e NATIVE_CPU -e NATIVE_MODE -e BUN_ASSET "$CONTAINER_IMAGE" sh -eu <<'SH' 2>&1 | tee "$RUNNER_TEMP/native-evidence/consumer.log" | |
| if command -v apk >/dev/null; then apk add --no-cache libstdc++ tar; else apt-get update && apt-get install -y --no-install-recommends libatomic1; fi | |
| export PATH="/evidence/native-tools/${BUN_ASSET%.zip}:$PATH" | |
| bun install --frozen-lockfile --ignore-scripts | |
| node --input-type=module <<'NODE' | |
| import assert from 'node:assert/strict' | |
| import { realpathSync } from 'node:fs' | |
| import getExePath from './node_modules/@typescript/native/lib/getExePath.js' | |
| import { command } from './e2e/binding/package/provenance.mjs' | |
| import { consume } from './e2e/binding/package/consumer.mjs' | |
| assert.equal(process.arch, process.env.NATIVE_CPU) | |
| assert.equal(command('bun', ['-p', 'process.arch']), process.env.NATIVE_CPU) | |
| const tsc = getExePath() | |
| console.log({ mode: process.env.NATIVE_MODE, tsc, version: command(tsc, ['--version']) }) | |
| await consume({ bundle: '/evidence/native-bundle', suffix: process.env.NATIVE_SUFFIX, report: '/evidence/native-evidence/consumer.json', tsc, npmCli: realpathSync(command('which', ['npm'])) }) | |
| NODE | |
| SH | |
| - uses: actions/upload-artifact@v7 | |
| if: always() | |
| with: | |
| name: native-consumer-${{ matrix.suffix }}-${{ github.run_id }}-${{ github.run_attempt }} | |
| path: ${{ runner.temp }}/native-evidence/* | |
| if-no-files-found: error | |
| retention-days: 7 | |
| benchmark: | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 60 | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v7 | |
| - uses: actions-rust-lang/setup-rust-toolchain@v2 | |
| with: | |
| toolchain: stable | |
| components: clippy, rustfmt | |
| - name: Cache cargo registry + target | |
| uses: actions/cache@v6 | |
| with: | |
| path: | | |
| ~/.cargo/registry/index/ | |
| ~/.cargo/registry/cache/ | |
| ~/.cargo/git/db/ | |
| target/ | |
| key: cargo-benchmark-${{ runner.os }}-${{ hashFiles('**/Cargo.lock') }} | |
| - uses: oven-sh/setup-bun@v2 | |
| with: | |
| bun-version: latest | |
| name: Install bun | |
| - name: Cache bun dependencies | |
| uses: actions/cache@v6 | |
| with: | |
| path: ~/.bun/install/cache | |
| key: bun-benchmark-${{ runner.os }}-${{ hashFiles('**/bun.lock') }} | |
| - &install-wasm-pack | |
| name: Install and verify latest stable wasm-pack | |
| shell: bash | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| run: | | |
| set -euo pipefail | |
| curl -L --proto '=https' --tlsv1.2 -sSf https://raw.githubusercontent.com/cargo-bins/cargo-binstall/main/install-from-binstall-release.sh | bash | |
| export PATH="${CARGO_HOME:-$HOME/.cargo}/bin:$PATH" | |
| cargo binstall wasm-pack --no-confirm --force | |
| latest="$(curl -fsSL -A 'devup-ui CI (https://github.com/dev-five-git/devup-ui)' https://crates.io/api/v1/crates/wasm-pack | jq -er '.crate.max_stable_version | select(type == "string" and length > 0)')" | |
| installed="$(wasm-pack --version)" | |
| echo "Installed $installed; crates.io latest stable: $latest" | |
| test "$installed" = "wasm-pack $latest" | |
| - name: Install Node.js | |
| uses: actions/setup-node@v7 | |
| with: | |
| registry-url: "https://registry.npmjs.org" | |
| # `latest` can select alphas from https://nodejs.org/dist/index.json; | |
| # see https://github.com/actions/setup-node/issues/1657. | |
| # The stable manifest can briefly trail nodejs.org after a stable release. | |
| node-version: '*' | |
| check-latest: true | |
| - run: bun install | |
| - run: bun run build | |
| # Every row is the median of the same number of cold samples taken in | |
| # rotating order (benchmark-manifest.json). The run goes to an artifact and | |
| # the Devup UI rows are compared with the checked baseline at the end of the | |
| # job, so the profile and the Rust measurement still run when it fails. | |
| - name: Benchmark | |
| run: bun run benchmark | |
| - name: Profile Devup UI Turbopack | |
| env: | |
| DEVUP_UI_PROFILE: "1" | |
| run: | | |
| rm -rf benchmark/next-devup-ui-single-turbo/.next \ | |
| benchmark/next-devup-ui-single-turbo/df \ | |
| benchmark/next-devup-ui-single-turbo/tsconfig.tsbuildinfo | |
| bun run --filter next-devup-ui-single-turbo-benchmark build | |
| - name: Upload the measured run | |
| uses: actions/upload-artifact@v7 | |
| if: ${{ !cancelled() }} | |
| with: | |
| name: benchmark-run | |
| path: benchmark-run.json | |
| if-no-files-found: ignore | |
| retention-days: 30 | |
| - name: Measure the SemanticBuilder passes of the extractor | |
| run: cargo bench -p extractor --bench semantic_pass_benchmark -- --quick | |
| - name: Compare the Devup UI rows with the baseline | |
| run: bun benchmark-check.js | |
| wasm-size: | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 60 | |
| permissions: | |
| contents: read | |
| env: | |
| CARGO_BUILD_JOBS: "2" | |
| RUSTUP_TOOLCHAIN: stable | |
| steps: | |
| - name: Checkout the tested source and both histories | |
| uses: actions/checkout@v7 | |
| with: | |
| fetch-depth: 0 | |
| persist-credentials: false | |
| - uses: actions-rust-lang/setup-rust-toolchain@v2 | |
| with: | |
| toolchain: stable | |
| target: wasm32-unknown-unknown | |
| cache: false | |
| - uses: oven-sh/setup-bun@v2 | |
| with: | |
| bun-version: latest | |
| - uses: actions/setup-node@v7 | |
| with: | |
| node-version: '*' | |
| check-latest: true | |
| - name: Resolve and report exact WASM comparison sources | |
| run: node resolve-wasm-size-sources.js | |
| - *install-wasm-pack | |
| - name: Cache registry downloads only | |
| uses: actions/cache@v6 | |
| with: | |
| path: | | |
| ~/.cargo/registry/index/ | |
| ~/.cargo/registry/cache/ | |
| ~/.cargo/git/db/ | |
| key: cargo-wasm-size-${{ runner.os }}-${{ hashFiles('**/Cargo.lock') }} | |
| - name: Install the latest shared optimizer once | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| run: | | |
| set -euo pipefail | |
| mkdir -p "$RUNNER_TEMP/wasm-size-tools/binaryen" | |
| gh release download --repo WebAssembly/binaryen --pattern '*-x86_64-linux.tar.gz' --dir "$RUNNER_TEMP/wasm-size-tools" | |
| tar -xzf "$RUNNER_TEMP"/wasm-size-tools/*.tar.gz --strip-components=1 -C "$RUNNER_TEMP/wasm-size-tools/binaryen" | |
| echo "$RUNNER_TEMP/wasm-size-tools/binaryen/bin" >> "$GITHUB_PATH" | |
| - name: Build exact sources with shared tools and lock-matched bindgen | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| run: | | |
| set -euo pipefail | |
| export SIZE_ROOT="$RUNNER_TEMP/wasm-size" | |
| mkdir -p "$SIZE_ROOT" | |
| stage=source | |
| trap 'echo "## WASM size: FAIL - $stage build or provenance failed; no comparison was skipped or substituted." >> "$GITHUB_STEP_SUMMARY"' ERR | |
| for side in base candidate; do | |
| if [[ "$side" == base ]]; then sha="$BASE_SHA"; else sha="$CANDIDATE_SHA"; fi | |
| git cat-file -e "$sha^{commit}" | |
| mkdir -p "$SIZE_ROOT/$side" | |
| git archive "$sha" | tar -x -C "$SIZE_ROOT/$side" | |
| done | |
| cat > "$SIZE_ROOT/provenance.mjs" <<'NODE' | |
| import { execFileSync } from 'node:child_process' | |
| import { createHash } from 'node:crypto' | |
| import { readFileSync, writeFileSync } from 'node:fs' | |
| import { join } from 'node:path' | |
| const run = (command, args) => execFileSync(command, args, { encoding: 'utf8' }).trim() | |
| const tools = Object.fromEntries([ | |
| ['rustc', 'rustc', ['--version', '--verbose']], | |
| ['wasmPack', 'wasm-pack', ['--version']], | |
| ['wasmBindgen', 'wasm-bindgen', ['--version']], | |
| ['wasmOpt', 'wasm-opt', ['--version']], | |
| ['bun', 'bun', ['--version']], | |
| ['node', 'node', ['--version']], | |
| ].map(([key, command, args]) => { | |
| const path = run('which', [command]) | |
| const hash = createHash('sha256').update(readFileSync(path)).digest('hex') | |
| return [key, `${run(command, args)}\n${path}\nsha256:${hash}`] | |
| })) | |
| const side = process.argv[2] | |
| const file = join(process.env.SIZE_ROOT, 'metadata.json') | |
| const metadata = side === 'base' ? { | |
| jobId: `${process.env.GITHUB_RUN_ID}/${process.env.GITHUB_RUN_ATTEMPT}/${process.env.GITHUB_JOB}`, | |
| buildCommand: 'cargo metadata --locked --format-version 1 > /dev/null && wasm-pack build --mode no-install --release --target nodejs --out-dir ./pkg --out-name index --locked && node script.js', | |
| } : JSON.parse(readFileSync(file, 'utf8')) | |
| const sha = side === 'base' ? process.env.BASE_SHA : process.env.CANDIDATE_SHA | |
| metadata[side] = { | |
| commit: run('git', ['rev-parse', `${sha}^{commit}`]), | |
| tree: run('git', ['rev-parse', `${sha}^{tree}`]), | |
| wasmBindgenVersion: process.env.WASM_BINDGEN_VERSION, | |
| packageDir: join(process.env.SIZE_ROOT, side, 'bindings/devup-ui-wasm/pkg'), tools, | |
| } | |
| writeFileSync(file, JSON.stringify(metadata, null, 2) + '\n') | |
| NODE | |
| shared_path="$PATH" | |
| for side in base candidate; do | |
| stage="$side" | |
| ( | |
| WASM_BINDGEN_VERSION="$(bun resolve-wasm-bindgen.js "$SIZE_ROOT/$side/Cargo.lock")" | |
| export WASM_BINDGEN_VERSION | |
| bindgen_root="$SIZE_ROOT/abi-tools/$WASM_BINDGEN_VERSION" | |
| if [[ ! -x "$bindgen_root/bin/wasm-bindgen" ]]; then | |
| cargo binstall wasm-bindgen-cli --version "=$WASM_BINDGEN_VERSION" --root "$bindgen_root" --no-confirm --force | |
| fi | |
| export PATH="$bindgen_root/bin:$shared_path" | |
| node "$SIZE_ROOT/provenance.mjs" "$side" | |
| cd "$SIZE_ROOT/$side/bindings/devup-ui-wasm" | |
| export CARGO_TARGET_DIR="$SIZE_ROOT/$side-target" | |
| cargo metadata --locked --format-version 1 > /dev/null | |
| wasm-pack build --mode no-install --release --target nodejs --out-dir ./pkg --out-name index --locked | |
| node script.js | |
| ) 2>&1 | tee "$SIZE_ROOT/$side-build.log" | |
| done | |
| - name: Compare all four relative size metrics | |
| run: | | |
| node verify-wasm-size.js \ | |
| --base-pkg "$RUNNER_TEMP/wasm-size/base/bindings/devup-ui-wasm/pkg" \ | |
| --candidate-pkg "$RUNNER_TEMP/wasm-size/candidate/bindings/devup-ui-wasm/pkg" \ | |
| --metadata "$RUNNER_TEMP/wasm-size/metadata.json" \ | |
| --report "$RUNNER_TEMP/wasm-size/wasm-size.json" | |
| - name: Upload size measurements and build evidence | |
| uses: actions/upload-artifact@v7 | |
| if: ${{ !cancelled() }} | |
| with: | |
| name: wasm-size | |
| path: | | |
| ${{ runner.temp }}/wasm-size/metadata.json | |
| ${{ runner.temp }}/wasm-size/wasm-size.json | |
| ${{ runner.temp }}/wasm-size/*-build.log | |
| if-no-files-found: error | |
| retention-days: 30 | |
| # The landing app is the only real-scale acceptance target in this repo, and | |
| # `publish` runs it against the deployed vinext/@devup-ui/vite-plugin build. | |
| # This job runs the SAME 128 assertions and the SAME screenshot baselines | |
| # against a Next 16 + Turbopack build, so @devup-ui/next-plugin's production | |
| # CSS path stays gated at 64 routes - the scale where extraction-wave races | |
| # actually reproduce. It runs in parallel so it stays off the publish critical | |
| # path, and its artifact is never deployed. | |
| landing-next-e2e: | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 60 | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v7 | |
| - uses: actions-rust-lang/setup-rust-toolchain@v2 | |
| with: | |
| toolchain: stable | |
| components: clippy, rustfmt | |
| - name: Cache cargo registry + target | |
| uses: actions/cache@v6 | |
| with: | |
| path: | | |
| ~/.cargo/registry/index/ | |
| ~/.cargo/registry/cache/ | |
| ~/.cargo/git/db/ | |
| target/ | |
| key: cargo-landing-next-${{ runner.os }}-${{ hashFiles('**/Cargo.lock') }} | |
| - uses: oven-sh/setup-bun@v2 | |
| with: | |
| bun-version: latest | |
| name: Install bun | |
| - name: Cache bun dependencies | |
| uses: actions/cache@v6 | |
| with: | |
| path: ~/.bun/install/cache | |
| key: bun-landing-next-${{ runner.os }}-${{ hashFiles('**/bun.lock') }} | |
| - *install-wasm-pack | |
| - name: Install Node.js | |
| uses: actions/setup-node@v7 | |
| with: | |
| node-version: '*' | |
| check-latest: true | |
| - run: bun install | |
| - run: bun run build | |
| - name: Build Landing (Next) | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: | | |
| bun run --filter @devup-ui/components build-storybook | |
| mv ./packages/components/storybook-static ./apps/landing/public/storybook | |
| bun run --filter landing build:next | |
| - name: Cache Playwright Browsers | |
| uses: actions/cache@v6 | |
| with: | |
| path: ~/.cache/ms-playwright | |
| key: playwright-landing-next-${{ runner.os }}-${{ hashFiles('**/bun.lock') }} | |
| - name: Install Playwright Browsers | |
| run: bunx playwright install chromium --with-deps | |
| - name: Run E2E Tests (Next) | |
| run: bun run test:e2e:next | |
| - name: Run Landing dev navigation tests (Next) | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| LANDING_BUILD_MODE: next | |
| run: bunx playwright test -c playwright.landing-dev.config.ts | |
| - name: Build Landing (Next, singleCss) | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: | | |
| rm -rf apps/landing/out apps/landing/.next apps/landing/df | |
| DEVUP_SINGLE_CSS=1 bun run --filter landing build:next | |
| - name: Run E2E Tests (Next, singleCss) | |
| run: bun run test:e2e:next | |
| - name: Upload Next Playwright Report | |
| uses: actions/upload-artifact@v7 | |
| if: ${{ !cancelled() }} | |
| with: | |
| name: playwright-report-next | |
| path: playwright-report/ | |
| retention-days: 1 | |
| # The packages take React ^18 || ^19 as a peer. This builds a React 18.3 app | |
| # with the Vite plugin and the UI kit, then checks refs, context and events | |
| # in Chromium, so React-19-only APIs cannot slip back in. | |
| react-18: | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 45 | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v7 | |
| - uses: actions-rust-lang/setup-rust-toolchain@v2 | |
| with: | |
| toolchain: stable | |
| components: clippy, rustfmt | |
| - name: Cache cargo registry + target | |
| uses: actions/cache@v6 | |
| with: | |
| path: | | |
| ~/.cargo/registry/index/ | |
| ~/.cargo/registry/cache/ | |
| ~/.cargo/git/db/ | |
| target/ | |
| key: cargo-react-18-${{ runner.os }}-${{ hashFiles('**/Cargo.lock') }} | |
| - uses: oven-sh/setup-bun@v2 | |
| with: | |
| bun-version: latest | |
| name: Install bun | |
| - name: Cache bun dependencies | |
| uses: actions/cache@v6 | |
| with: | |
| path: ~/.bun/install/cache | |
| key: bun-react-18-${{ runner.os }}-${{ hashFiles('**/bun.lock') }} | |
| - *install-wasm-pack | |
| - name: Install Node.js | |
| uses: actions/setup-node@v7 | |
| with: | |
| node-version: '*' | |
| check-latest: true | |
| - run: bun install | |
| - run: bun run build | |
| - name: Type-check and build the React 18 app | |
| working-directory: apps/react-18 | |
| run: | | |
| bun ../../node_modules/@typescript/native/bin/tsc | |
| bun run build | |
| - name: Cache Playwright Browsers | |
| uses: actions/cache@v6 | |
| with: | |
| path: ~/.cache/ms-playwright | |
| key: playwright-react-18-${{ runner.os }}-${{ hashFiles('**/bun.lock') }} | |
| - name: Install Playwright Browsers | |
| run: bunx playwright install chromium --with-deps | |
| - name: Run React 18 E2E Tests | |
| working-directory: apps/react-18 | |
| run: bun run test:e2e | |
| # @devup-ui/vite-plugin must keep the CSS every server page needs when the | |
| # build is vinext/RSC. The fixture shares one Devup UI header between server | |
| # list pages and a client page, and the tests read the styles the browser | |
| # actually applies when each route is entered directly, so a dropped | |
| # stylesheet dependency fails here whatever the CSS files are called. | |
| vinext-rsc-css-e2e: | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 30 | |
| permissions: | |
| contents: read | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v7 | |
| - uses: actions-rust-lang/setup-rust-toolchain@v2 | |
| with: | |
| toolchain: stable | |
| components: clippy, rustfmt | |
| - name: Cache cargo registry + target | |
| uses: actions/cache@v6 | |
| with: | |
| path: | | |
| ~/.cargo/registry/index/ | |
| ~/.cargo/registry/cache/ | |
| ~/.cargo/git/db/ | |
| target/ | |
| key: cargo-vinext-rsc-css-${{ runner.os }}-${{ hashFiles('**/Cargo.lock') }} | |
| - uses: oven-sh/setup-bun@v2 | |
| with: | |
| bun-version: latest | |
| name: Install bun | |
| - name: Cache bun dependencies | |
| uses: actions/cache@v6 | |
| with: | |
| path: ~/.bun/install/cache | |
| key: bun-vinext-rsc-css-${{ runner.os }}-${{ hashFiles('**/bun.lock') }} | |
| - *install-wasm-pack | |
| - name: Install Node.js | |
| uses: actions/setup-node@v7 | |
| with: | |
| node-version: '*' | |
| check-latest: true | |
| - run: bun install | |
| - run: bun run build | |
| - name: Cache Playwright Browsers | |
| uses: actions/cache@v6 | |
| with: | |
| path: ~/.cache/ms-playwright | |
| key: playwright-vinext-rsc-css-${{ runner.os }}-${{ hashFiles('**/bun.lock') }} | |
| - name: Install Playwright Browsers | |
| run: bunx playwright install chromium --with-deps | |
| - name: Build fixture (per-file CSS) | |
| run: bun run --filter vinext-rsc-css-repro build | |
| - name: Run E2E Tests (per-file CSS) | |
| run: bun run test:e2e:rsc-css | |
| - name: Build fixture (singleCss) | |
| run: | | |
| rm -rf apps/vinext-rsc-css-repro/dist apps/vinext-rsc-css-repro/.vinext apps/vinext-rsc-css-repro/df | |
| DEVUP_SINGLE_CSS=1 bun run --filter vinext-rsc-css-repro build | |
| - name: Run E2E Tests (singleCss) | |
| run: bun run test:e2e:rsc-css | |
| release-compat: | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 30 | |
| env: | |
| CARGO_BUILD_JOBS: "2" | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v7 | |
| - uses: actions-rust-lang/setup-rust-toolchain@v2 | |
| with: | |
| toolchain: stable | |
| components: clippy, rustfmt | |
| - name: Cache cargo registry + target | |
| uses: actions/cache@v6 | |
| with: | |
| path: | | |
| ~/.cargo/registry/index/ | |
| ~/.cargo/registry/cache/ | |
| ~/.cargo/git/db/ | |
| target/ | |
| key: cargo-release-compat-${{ runner.os }}-${{ hashFiles('**/Cargo.lock') }} | |
| - uses: oven-sh/setup-bun@v2 | |
| with: | |
| bun-version: latest | |
| - name: Cache bun dependencies | |
| uses: actions/cache@v6 | |
| with: | |
| path: ~/.bun/install/cache | |
| key: bun-release-compat-${{ runner.os }}-${{ hashFiles('**/bun.lock') }} | |
| - *install-wasm-pack | |
| - uses: actions/setup-node@v7 | |
| with: | |
| node-version: '*' | |
| check-latest: true | |
| - run: bun install | |
| - name: Test exited-process memory sampling | |
| run: node --test e2e/release/process-memory.test.mjs | |
| - name: Build packages under the memory watchdog | |
| run: node e2e/release/build-packages.mjs | |
| - name: Cache Playwright browsers | |
| uses: actions/cache@v6 | |
| with: | |
| path: ~/.cache/ms-playwright | |
| key: playwright-release-compat-${{ runner.os }}-${{ hashFiles('**/bun.lock') }} | |
| - name: Install Playwright browsers | |
| run: bunx playwright install chromium firefox webkit --with-deps | |
| - name: Build packed consumers and check production computed styles | |
| run: bun run test:release | |
| - name: Upload release compatibility evidence | |
| if: ${{ !cancelled() }} | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: release-compat-results | |
| path: | | |
| release-package-build.json | |
| release-results.json | |
| if-no-files-found: error | |
| retention-days: 30 | |
| webpack-extends-theme: | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 45 | |
| permissions: | |
| contents: read | |
| env: | |
| CARGO_BUILD_JOBS: "2" | |
| steps: | |
| - name: Configure isolated paths | |
| run: | | |
| printf 'DEVUP_PLAYWRIGHT_ROOT=%s/webpack-extends-playwright\n' "$RUNNER_TEMP" >> "$GITHUB_ENV" | |
| printf 'PLAYWRIGHT_BROWSERS_PATH=%s/webpack-extends-browsers\n' "$RUNNER_TEMP" >> "$GITHUB_ENV" | |
| printf 'DEVUP_EXTENDS_RESULTS=%s/webpack-extends-results\n' "$RUNNER_TEMP" >> "$GITHUB_ENV" | |
| - name: Checkout | |
| uses: actions/checkout@v7 | |
| - uses: actions-rust-lang/setup-rust-toolchain@v2 | |
| with: | |
| toolchain: stable | |
| components: clippy, rustfmt | |
| - name: Cache cargo registry + target | |
| uses: actions/cache@v6 | |
| with: | |
| path: | | |
| ~/.cargo/registry/index/ | |
| ~/.cargo/registry/cache/ | |
| ~/.cargo/git/db/ | |
| target/ | |
| key: cargo-webpack-extends-${{ runner.os }}-${{ hashFiles('**/Cargo.lock') }} | |
| - uses: oven-sh/setup-bun@v2 | |
| with: | |
| bun-version: latest | |
| - name: Cache bun dependencies | |
| uses: actions/cache@v6 | |
| with: | |
| path: ~/.bun/install/cache | |
| key: bun-webpack-extends-${{ runner.os }}-${{ hashFiles('**/bun.lock') }} | |
| - *install-wasm-pack | |
| - name: Install Node.js | |
| uses: actions/setup-node@v7 | |
| with: | |
| node-version: '*' | |
| check-latest: true | |
| - run: bun install | |
| - name: Build fresh WASM | |
| working-directory: bindings/devup-ui-wasm | |
| run: bun run build | |
| - run: bun run build | |
| - name: Install latest private Playwright and Chromium | |
| run: | | |
| mkdir -p "$DEVUP_PLAYWRIGHT_ROOT" "$DEVUP_EXTENDS_RESULTS" | |
| printf '{"private":true,"type":"module"}\n' > "$DEVUP_PLAYWRIGHT_ROOT/package.json" | |
| bun add --cwd "$DEVUP_PLAYWRIGHT_ROOT" @playwright/test@latest | |
| node "$DEVUP_PLAYWRIGHT_ROOT/node_modules/@playwright/test/cli.js" install chromium --with-deps | |
| - name: Installed formats and production theme delivery regressions | |
| run: | | |
| set -euo pipefail | |
| env -u CI node --test packages/webpack-plugin/src/__tests__/extends-theme/extends-theme-regression.mjs 2>&1 | tee "$DEVUP_EXTENDS_RESULTS/matrix.log" | |
| - name: Upload packed-consumer matrix evidence | |
| if: always() | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: webpack-extends-theme-evidence | |
| path: | | |
| ${{ runner.temp }}/webpack-extends-results/matrix.log | |
| ${{ runner.temp }}/webpack-extends-results/extends-theme-*/*.json | |
| ${{ runner.temp }}/webpack-extends-results/extends-theme-*/*/identity-*.json | |
| ${{ runner.temp }}/webpack-extends-results/extends-theme-*/*/bun.lock | |
| ${{ runner.temp }}/webpack-extends-results/extends-theme-*/packs/*/*.tgz | |
| if-no-files-found: error | |
| retention-days: 7 | |
| # Validation: runs on pull requests and on pushes to main, read-only. The job | |
| # id stays `publish` because it is the status check the repository requires; | |
| # the privileged release steps live in `release` and `deploy-pages` below. | |
| publish: | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 90 | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v7 | |
| with: | |
| # changepacks diffs HEAD against the previous release commit. The | |
| # default shallow fetch grafts away every parent, so that lookup dies | |
| # with "Could not find a merge-base". | |
| fetch-depth: 0 | |
| fetch-tags: true | |
| - uses: actions-rust-lang/setup-rust-toolchain@v2 | |
| with: | |
| toolchain: stable | |
| components: clippy, rustfmt | |
| - *install-wasm-pack | |
| - name: Install cargo-tarpaulin | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| run: cargo binstall cargo-tarpaulin --no-confirm --force | |
| - name: Cache cargo registry + target | |
| uses: actions/cache@v6 | |
| with: | |
| path: | | |
| ~/.cargo/registry/index/ | |
| ~/.cargo/registry/cache/ | |
| ~/.cargo/git/db/ | |
| target/ | |
| key: cargo-publish-${{ runner.os }}-${{ hashFiles('**/Cargo.lock') }} | |
| - uses: oven-sh/setup-bun@v2 | |
| with: | |
| bun-version: latest | |
| name: Install bun | |
| - name: Cache bun dependencies | |
| uses: actions/cache@v6 | |
| with: | |
| path: ~/.bun/install/cache | |
| key: bun-publish-${{ runner.os }}-${{ hashFiles('**/bun.lock') }} | |
| - name: Install Node.js | |
| uses: actions/setup-node@v7 | |
| with: | |
| registry-url: "https://registry.npmjs.org" | |
| node-version: '*' | |
| check-latest: true | |
| - run: bun install --frozen-lockfile | |
| - run: bun run build | |
| - name: Verify built package entry points | |
| run: bun run verify:dist | |
| - name: Verify the README benchmark tables | |
| run: bun render-benchmark-readme.js --check | |
| - name: Verify publish tarballs | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| for manifest in bindings/*/package.json packages/*/package.json; do | |
| # Exactly the nine native names delegate to native-packs/consumer. | |
| name=$(node -p "require('./$manifest').name") | |
| case "$name" in | |
| @devup-ui/binding|@devup-ui/binding-linux-x64-gnu|@devup-ui/binding-linux-arm64-gnu|@devup-ui/binding-linux-x64-musl|@devup-ui/binding-linux-arm64-musl|@devup-ui/binding-darwin-x64|@devup-ui/binding-darwin-arm64|@devup-ui/binding-win32-x64-msvc|@devup-ui/binding-win32-arm64-msvc) continue ;; | |
| esac | |
| package_dir="$(dirname "$manifest")" | |
| pack_dir="$RUNNER_TEMP/publish-verify/${package_dir//\//-}" | |
| mkdir -p "$pack_dir" | |
| (cd "$package_dir" && bun pm pack --quiet --destination "$pack_dir") | |
| tarballs=("$pack_dir"/*.tgz) | |
| if [[ "${#tarballs[@]}" -ne 1 ]]; then | |
| echo "Expected one tarball for $package_dir" >&2 | |
| exit 1 | |
| fi | |
| packed_manifest="$(tar -xOf "${tarballs[0]}" package/package.json)" | |
| if grep -q 'workspace:' <<< "$packed_manifest"; then | |
| echo "Unresolved workspace dependency in $package_dir" >&2 | |
| exit 1 | |
| fi | |
| done | |
| - run: | | |
| bun run lint | |
| # rust coverage issue | |
| echo 'max_width = 100000' > .rustfmt.toml | |
| echo 'tab_spaces = 4' >> .rustfmt.toml | |
| echo 'newline_style = "Unix"' >> .rustfmt.toml | |
| echo 'fn_call_width = 100000' >> .rustfmt.toml | |
| echo 'fn_params_layout = "Compressed"' >> .rustfmt.toml | |
| echo 'chain_width = 100000' >> .rustfmt.toml | |
| echo 'merge_derives = true' >> .rustfmt.toml | |
| echo 'use_small_heuristics = "Default"' >> .rustfmt.toml | |
| cargo fmt | |
| - run: bun run test | |
| - name: Regression test (bun-plugin preload race) | |
| run: bun run --filter @devup-ui/bun-plugin test:regression | |
| - name: Format Rollback | |
| run: | | |
| rm -rf .rustfmt.toml | |
| # Formatting with the temporary coverage config and then with the | |
| # default config is not a reversible round trip. Restore the exact | |
| # checked-in sources so the checkout is clean again. | |
| git restore --source=HEAD --staged --worktree -- . | |
| cargo fmt --all -- --check | |
| git diff --exit-code | |
| - name: Check the changepacks of this change | |
| if: github.event_name == 'pull_request' | |
| run: | | |
| # changepacks compares the change against a local main, which a pull request checkout does not have | |
| git fetch --no-tags origin main:refs/heads/main | |
| bunx @changepacks/cli@latest check --format json | |
| - name: Build Landing | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: | | |
| bun run --filter @devup-ui/components build-storybook | |
| mv ./packages/components/storybook-static ./apps/landing/public/storybook | |
| bun run --filter landing build | |
| - name: Cache Playwright Browsers | |
| id: playwright-cache | |
| uses: actions/cache@v6 | |
| with: | |
| path: ~/.cache/ms-playwright | |
| key: playwright-publish-${{ runner.os }}-${{ hashFiles('**/bun.lock') }} | |
| - name: Install Playwright Browsers | |
| run: bunx playwright install chromium --with-deps | |
| # A run only compares against the screenshots checked into the repository: | |
| # it never creates or commits them. A new visual test needs its baselines | |
| # generated by a maintainer (`bun run test:e2e:update`) and committed. | |
| - name: Require the E2E baselines | |
| run: | | |
| SNAPSHOT_COUNT=$(find e2e -name '*-linux.png' -path '*-snapshots/*' 2>/dev/null | wc -l) | |
| echo "Found $SNAPSHOT_COUNT linux baseline snapshot(s)" | |
| if [ "$SNAPSHOT_COUNT" -eq 0 ]; then | |
| echo "No checked-in baselines under e2e/**/*-snapshots; generate them with 'bun run test:e2e:update' and commit them." >&2 | |
| exit 1 | |
| fi | |
| - name: Run E2E Tests | |
| run: bun run test:e2e | |
| - name: Run Landing dev navigation tests | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: bunx playwright test -c playwright.landing-dev.config.ts | |
| - name: Build Landing (singleCss) | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: | | |
| rm -rf apps/landing/dist apps/landing/.next apps/landing/.vinext apps/landing/df | |
| DEVUP_SINGLE_CSS=1 bun run --filter landing build | |
| - name: Run E2E Tests (singleCss) | |
| run: bun run test:e2e | |
| - name: Upload singleCss Playwright Report | |
| uses: actions/upload-artifact@v7 | |
| if: ${{ !cancelled() }} | |
| with: | |
| name: playwright-report-singlecss | |
| path: playwright-report/ | |
| retention-days: 1 | |
| - name: Upload the site for deployment | |
| uses: actions/upload-pages-artifact@v5 | |
| with: | |
| path: ./apps/landing/dist/client | |
| retention-days: 1 | |
| if: github.event_name == 'push' && github.ref == 'refs/heads/main' | |
| - name: Upload to codecov.io | |
| uses: codecov/codecov-action@v7 | |
| with: | |
| token: ${{ secrets.CODECOV_TOKEN }} | |
| fail_ci_if_error: true | |
| files: ./coverage/root/lcov.info,./coverage/vite/lcov.info | |
| # Pages deployment: the only job with `pages` and `id-token` write, and it | |
| # only runs for a push to main whose validation passed. | |
| deploy-pages: | |
| needs: [publish] | |
| if: github.event_name == 'push' && github.ref == 'refs/heads/main' | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 15 | |
| permissions: | |
| contents: read | |
| pages: write | |
| id-token: write | |
| steps: | |
| - uses: actions/deploy-pages@v5 | |
| # Publishes through npm OIDC trusted publishing. The job's `id-token: write` | |
| # permission lets npm exchange GitHub's short-lived OIDC token, and public | |
| # packages receive provenance automatically. | |
| # | |
| # PREREQUISITE: every @devup-ui/* package must be registered as a Trusted | |
| # Publisher on npmjs.com against repo dev-five-git/devup-ui and workflow | |
| # file `publish.yml`. npm matches that filename exactly, so renaming or | |
| # moving this file breaks publishing until the entries are updated. | |
| # | |
| # The publish command itself is selected in .changepacks/config.json. | |
| # Bun packs each workspace so dependency ranges are materialized, then | |
| # npm publishes that tarball with OIDC (Bun cannot do OIDC itself: | |
| # oven-sh/bun#22423). | |
| # | |
| # It runs only for a push to main whose validation and end-to-end jobs | |
| # passed, and is the only job that can write contents, open pull requests or | |
| # mint an OIDC token for npm. | |
| release: | |
| needs: [publish, landing-next-e2e, react-18, release-compat, native-consumer] | |
| if: github.event_name == 'push' && github.ref == 'refs/heads/main' | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 45 | |
| env: | |
| GIT_CONFIG_COUNT: "1" | |
| GIT_CONFIG_KEY_0: core.autocrlf | |
| GIT_CONFIG_VALUE_0: "false" | |
| permissions: | |
| contents: write | |
| id-token: write | |
| pull-requests: write | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v7 | |
| with: | |
| # changepacks diffs HEAD against the previous release commit. The | |
| # default shallow fetch grafts away every parent, so that lookup dies | |
| # with "Could not find a merge-base" and the release never publishes. | |
| fetch-depth: 0 | |
| fetch-tags: true | |
| - uses: oven-sh/setup-bun@v2 | |
| with: | |
| bun-version: latest | |
| name: Install bun | |
| - uses: actions-rust-lang/setup-rust-toolchain@v2 | |
| with: | |
| toolchain: stable | |
| components: clippy, rustfmt | |
| - name: Cache cargo registry + target | |
| uses: actions/cache@v6 | |
| with: | |
| path: | | |
| ~/.cargo/registry/index/ | |
| ~/.cargo/registry/cache/ | |
| ~/.cargo/git/db/ | |
| target/ | |
| key: cargo-release-${{ runner.os }}-${{ hashFiles('**/Cargo.lock') }} | |
| - name: Cache bun dependencies | |
| uses: actions/cache@v6 | |
| with: | |
| path: ~/.bun/install/cache | |
| key: bun-release-${{ runner.os }}-${{ hashFiles('**/bun.lock') }} | |
| - *install-wasm-pack | |
| - name: Install Node.js | |
| uses: actions/setup-node@v7 | |
| with: | |
| registry-url: "https://registry.npmjs.org" | |
| node-version: '*' | |
| check-latest: true | |
| - run: bun install --frozen-lockfile | |
| - run: bun run build | |
| - name: Verify built package entry points | |
| run: bun run verify:dist | |
| - name: Verify clean publish checkout | |
| run: git diff --exit-code | |
| # Stable artifact name deliberately survives a release-only run_attempt retry. | |
| - uses: actions/download-artifact@v8 | |
| with: | |
| name: native-packs-${{ github.run_id }} | |
| path: ${{ runner.temp }}/native-release-bundle | |
| - uses: changepacks/action@main | |
| id: changepacks | |
| env: | |
| NATIVE_RELEASE_BUNDLE: ${{ runner.temp }}/native-release-bundle | |
| with: | |
| publish: true |