mirror of
https://github.com/stablyai/orca.git
synced 2026-10-31 09:07:40 +00:00
* ci: restore main's Vitest transform cache in PR unit shards Main produces per-shard transform caches on a schedule; PR shards restore the newest one for the same config/lockfile/runtime policy. A Vitest cache key generator folds each literal specifier's resolution candidates into the per-module key so newly added files that shadow a resolution invalidate the importer, and bails on glob-expanded dynamic imports. * ci: list the resolution key plugin in the node tsconfig project * ci: accept Vitest's CACHEDIR.TAG when sealing the unit module cache Vitest 5.0.5 tags its cache root, which made every seal fail with 'invalid cache entry name' so no producer cache was ever saved. * ci: reseed the unit module cache when any cache-key input lands on main Co-Authored-By: Claude <noreply@anthropic.com> --------- Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com> Co-authored-by: Claude <noreply@anthropic.com>
254 lines
9.5 KiB
YAML
254 lines
9.5 KiB
YAML
name: Unit tests
|
|
|
|
on:
|
|
workflow_call:
|
|
inputs:
|
|
node_versions:
|
|
description: JSON array of Node.js major versions to test.
|
|
required: true
|
|
type: string
|
|
|
|
runner:
|
|
description: Hosted runner for the unit shards.
|
|
required: false
|
|
default: blacksmith-4vcpu-ubuntu-2404
|
|
type: string
|
|
|
|
browser_contract:
|
|
description: Include the PR external Chromium browser contract in relay integration.
|
|
required: false
|
|
default: false
|
|
type: boolean
|
|
|
|
run_shards:
|
|
description: Run the planned root unit shards.
|
|
required: false
|
|
default: true
|
|
type: boolean
|
|
|
|
shards:
|
|
description: JSON array of shard assignments, produced by unit-plan.yml.
|
|
required: true
|
|
type: string
|
|
|
|
module_cache:
|
|
description: Transform cache policy (off, cold producer, or warm restore).
|
|
default: 'off'
|
|
type: string
|
|
|
|
module_cache_namespace:
|
|
description: Isolate a same-source cache comparison from existing archives.
|
|
default: ''
|
|
type: string
|
|
|
|
module_cache_seed:
|
|
description: Publish comparison caches from a manually dispatched workflow.
|
|
default: false
|
|
type: boolean
|
|
|
|
phase_diagnostics:
|
|
description: Attach bounded per-file worker phase diagnostics.
|
|
default: false
|
|
type: boolean
|
|
|
|
artifact_prefix:
|
|
description: Distinguish evidence from repeated same-source comparison lanes.
|
|
default: unit
|
|
type: string
|
|
|
|
run_relay_integration:
|
|
description: Run relay contracts alongside normal unit checks.
|
|
default: true
|
|
type: boolean
|
|
|
|
permissions:
|
|
contents: read
|
|
|
|
jobs:
|
|
test:
|
|
if: inputs.run_shards
|
|
name: ${{ inputs.artifact_prefix != 'unit' && format('{0} ', inputs.artifact_prefix) || '' }}tests node ${{ matrix.node }} ${{ matrix.shard.index }}/${{ matrix.shard.count }}
|
|
runs-on: ${{ inputs.runner }}
|
|
timeout-minutes: 60
|
|
strategy:
|
|
fail-fast: false
|
|
matrix:
|
|
node: ${{ fromJSON(inputs.node_versions) }}
|
|
shard: ${{ fromJSON(inputs.shards) }}
|
|
|
|
steps:
|
|
- name: Checkout
|
|
uses: actions/checkout@v6
|
|
with:
|
|
persist-credentials: false
|
|
|
|
- uses: ./.github/actions/install-node-dependencies
|
|
with:
|
|
native-runtime: node
|
|
node-version: ${{ matrix.node }}
|
|
cache-electron-package: 'true'
|
|
|
|
- name: Install Electron package binary for tests
|
|
run: node config/scripts/install-electron-package-binary.mjs
|
|
|
|
- name: Verify Blacksmith unit runner environment
|
|
if: runner.os == 'Linux' && startsWith(inputs.runner, 'blacksmith-')
|
|
run: |
|
|
ELECTRON_RUN_AS_NODE=1 "$(node -p "require('electron')")" --version
|
|
|
|
- uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0
|
|
with:
|
|
bun-version-file: config/.bun-version
|
|
no-cache: true
|
|
|
|
- name: Resolve unit module cache
|
|
id: module-cache
|
|
if: inputs.module_cache == 'cold' || inputs.module_cache == 'warm'
|
|
env:
|
|
ORCA_UNIT_SHARD_INDEX: ${{ matrix.shard.index }}
|
|
ORCA_UNIT_SHARD_COUNT: ${{ matrix.shard.count }}
|
|
ORCA_UNIT_CACHE_NAMESPACE: ${{ inputs.module_cache_namespace }}
|
|
run: node config/scripts/ci-unit-module-cache.mjs identity
|
|
|
|
# The key pins config, plugins, lockfile and runtimes; the newest producer for it wins.
|
|
# Source edits are keyed per module by Vitest plus vitest-module-cache-resolution-key.ts.
|
|
- name: Restore unit module cache
|
|
id: module-cache-restore
|
|
if: inputs.module_cache == 'warm' && steps.module-cache.outputs.key != ''
|
|
continue-on-error: true
|
|
uses: actions/cache/restore@v5
|
|
with:
|
|
path: ${{ steps.module-cache.outputs.path }}
|
|
key: ${{ steps.module-cache.outputs.key }}-${{ github.sha }}
|
|
restore-keys: ${{ steps.module-cache.outputs.key }}-
|
|
|
|
- name: Validate restored unit module cache or use cold transforms
|
|
if: steps.module-cache.outputs.key != ''
|
|
env:
|
|
ORCA_UNIT_CACHE_RESTORE_HIT: ${{ steps.module-cache-restore.outputs.cache-matched-key != '' }}
|
|
run: node config/scripts/ci-unit-module-cache.mjs prepare
|
|
|
|
- uses: actions/download-artifact@v8
|
|
continue-on-error: true
|
|
with:
|
|
name: unit-selection-attempt-${{ github.run_attempt }}
|
|
path: ci-shards/
|
|
|
|
- name: Record full unit discovery
|
|
if: inputs.phase_diagnostics
|
|
continue-on-error: true
|
|
run: >-
|
|
node --input-type=module -e '
|
|
import { discoverUnitFiles } from "./config/scripts/ci-unit-files.mjs";
|
|
import { writeAssignment } from "./config/scripts/ci-shard-assignment.mjs";
|
|
writeAssignment("ci-shards/unit-discovery.json", { files: discoverUnitFiles() });'
|
|
|
|
- name: Test shard
|
|
env:
|
|
NODE_COMPILE_CACHE: ${{ runner.temp }}/orca-node-compile-cache-${{ github.run_id }}-${{ github.run_attempt }}-${{ matrix.node }}-${{ matrix.shard.index }}
|
|
ORCA_BALANCE_UNIT_SHARDS: '1'
|
|
ORCA_BACKGROUND_LAUNCH: '1'
|
|
ORCA_UNIT_PHASE_REPORT: ${{ inputs.phase_diagnostics && 'ci-shards/unit-phases.json' || '' }}
|
|
run: |
|
|
ORCA_SHARD_SOURCE_SHA="$(git rev-parse HEAD)"
|
|
export ORCA_SHARD_SOURCE_SHA
|
|
node config/scripts/run-vitest.mjs run --config config/vitest.config.ts \
|
|
--shard=${{ matrix.shard.index }}/${{ matrix.shard.count }} \
|
|
${{ inputs.runner == 'blacksmith-8vcpu-ubuntu-2404' && '--maxWorkers=8' || (runner.arch == 'ARM64' || inputs.runner == 'blacksmith-4vcpu-ubuntu-2404' || inputs.runner == 'ubuntu-24.04') && '--maxWorkers=4' || '' }}
|
|
|
|
- name: Seal unit module cache
|
|
id: module-cache-seal
|
|
# Only cold main/seeded producers publish; PRs consume and never seed each other.
|
|
if: >-
|
|
success() && steps.module-cache.outputs.key != '' &&
|
|
inputs.module_cache == 'cold' &&
|
|
(github.ref == 'refs/heads/main' && github.event_name != 'pull_request' ||
|
|
inputs.module_cache_seed && github.event_name == 'workflow_dispatch')
|
|
run: node config/scripts/ci-unit-module-cache.mjs seal
|
|
|
|
- name: Save unit module cache
|
|
if: steps.module-cache-seal.outputs.ready == 'true'
|
|
continue-on-error: true
|
|
uses: actions/cache/save@v5
|
|
with:
|
|
path: ${{ steps.module-cache.outputs.path }}
|
|
key: ${{ steps.module-cache.outputs.key }}-${{ github.run_id }}-${{ github.run_attempt }}
|
|
|
|
- name: Upload unit shard assignment
|
|
if: always()
|
|
# Diagnostic upload outages must not change the test verdict.
|
|
continue-on-error: true
|
|
uses: actions/upload-artifact@v7
|
|
with:
|
|
name: ${{ inputs.artifact_prefix }}-shard-node-${{ matrix.node }}-${{ matrix.shard.index }}-attempt-${{ github.run_attempt }}
|
|
path: ci-shards/
|
|
retention-days: 14
|
|
if-no-files-found: warn
|
|
|
|
relay_integration:
|
|
if: inputs.run_relay_integration
|
|
name: relay integration node ${{ matrix.node }}
|
|
strategy:
|
|
fail-fast: false
|
|
matrix:
|
|
node: ${{ fromJSON(inputs.node_versions) }}
|
|
# Free hosted runner: ~1.2 min of work finishes well inside the ~7 min unit shards it runs beside.
|
|
runs-on: ubuntu-24.04
|
|
timeout-minutes: 60
|
|
|
|
steps:
|
|
- name: Checkout
|
|
uses: actions/checkout@v6
|
|
with:
|
|
persist-credentials: false
|
|
|
|
- uses: ./.github/actions/install-node-dependencies
|
|
id: root_dependencies
|
|
with:
|
|
native-runtime: none
|
|
node-version: ${{ matrix.node }}
|
|
cache-dependency-path: |
|
|
pnpm-lock.yaml
|
|
cloud/pnpm-lock.yaml
|
|
|
|
- name: Resolve Chrome for the browser provider
|
|
id: browser_executable
|
|
if: inputs.browser_contract && success()
|
|
run: |
|
|
set -euo pipefail
|
|
chrome="$(command -v google-chrome || command -v google-chrome-stable || true)"
|
|
if [ -z "$chrome" ]; then
|
|
echo "::error::No Google Chrome on the runner; the browser provider test would silently skip."
|
|
exit 1
|
|
fi
|
|
"$chrome" --version
|
|
echo "executable=$chrome" >> "$GITHUB_OUTPUT"
|
|
|
|
- name: Test external Chromium browser provider
|
|
if: inputs.browser_contract && success()
|
|
env:
|
|
ORCA_BACKGROUND_LAUNCH: '1'
|
|
ORCA_BROWSER_EXECUTABLE: ${{ steps.browser_executable.outputs.executable }}
|
|
run: |
|
|
pnpm exec vitest run --config config/vitest.config.ts \
|
|
src/main/orcad/external-chromium-browser-process.integration.test.ts
|
|
|
|
# These two tests import the cloud relay workspace directly. Keeping them in one job
|
|
# avoids installing and building the same workspace once per unit-test shard.
|
|
- name: Install relay integration dependencies
|
|
id: relay_dependencies
|
|
if: ${{ !cancelled() && steps.root_dependencies.outcome == 'success' }}
|
|
working-directory: cloud
|
|
run: |
|
|
pnpm --filter '@orca-cloud/relay...' install --frozen-lockfile --ignore-scripts
|
|
pnpm --filter '@orca-cloud/relay^...' build
|
|
|
|
- name: Test relay integration contracts
|
|
if: ${{ !cancelled() && steps.relay_dependencies.outcome == 'success' }}
|
|
env:
|
|
ORCA_BACKGROUND_LAUNCH: '1'
|
|
run: >-
|
|
pnpm exec vitest run --config config/vitest.config.ts
|
|
tests/e2e/relay-region-compatibility.unit.test.ts
|
|
tests/e2e/relay-region-correction.unit.test.ts
|