name: PR Checks on: pull_request: types: - opened - synchronize - reopened - ready_for_review jobs: verify: runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v6 - name: Install native build tools run: sudo apt-get update && sudo apt-get install -y build-essential python3 zlib1g-dev zsh - name: Setup Node.js uses: actions/setup-node@v6 with: node-version-file: package.json - name: Setup pnpm uses: pnpm/action-setup@v6 with: run_install: false # Why: pnpm's bundled node-gyp ships gyp_main.py without execute # permission, which breaks native module builds (e.g. node-pty's # postinstall) with "/bin/sh: gyp_main.py: Permission denied". # Pin the fallback to the lockfile's node-gyp version so CI stays # reproducible while forcing pnpm to bypass its broken bundled copy. # Gate on runner.os == 'Linux' to match release.yml — the # npm-global path layout this step assumes is POSIX-shaped, and the # failure has only been observed on Linux runners. Today this job # pins runs-on: ubuntu-latest so the guard is a no-op, but it # prevents a silent break if a Windows/macOS matrix is added later. - name: Use external node-gyp to avoid pnpm's bundled copy (Linux only) if: runner.os == 'Linux' run: | npm install -g node-gyp@11.5.0 echo "npm_config_node_gyp=$(npm root -g)/node-gyp/bin/node-gyp.js" >> "$GITHUB_ENV" - name: Prepare dependency install run: | if [ -e node_modules ]; then ls -ld node_modules rm -rf node_modules fi - name: Install dependencies # Why: pnpm 10.24's frozen headless fast path can fail on fresh Ubuntu # runners while creating the root node_modules. Use the normal resolver # path, then verify package metadata stayed unchanged. run: | pnpm install --no-frozen-lockfile --prefer-frozen-lockfile=false git diff --exit-code package.json pnpm-lock.yaml - name: Lint run: pnpm exec oxlint --format github - name: Check styled scrollbars run: pnpm check:styled-scrollbars - name: Check reliability gate manifest run: pnpm run check:reliability-gates # Why: oxlint fails any file over max-lines that is NOT suppressed, so this # ratchet forbids ADDING a new suppression (inline disable or mobile max # bump). Existing oversized files are grandfathered in # config/max-lines-baseline.txt, which may only shrink — new bypasses fail # here with a clear message instead of silently growing the debt. - name: Enforce max-lines ratchet (no new bypasses) run: pnpm run check:max-lines-ratchet # Why: project-owned type declarations must live in .ts so tsc # actually checks them. TypeScript's skipLibCheck: true (inherited # from @electron-toolkit/tsconfig) silently widens unresolved names # in .d.ts to `any`, which is how #1186 shipped a broken IPC signature # past typecheck. See docs/preload-typecheck-hole.md. - name: Guard against project-owned .d.ts in preload/shared run: | matches=$(find src/preload src/shared -name '*.d.ts' 2>/dev/null || true) if [ -n "$matches" ]; then echo "::error::Project-owned .d.ts files are not allowed under src/preload or src/shared." echo "Move type declarations into a .ts file so skipLibCheck does not hide errors." echo "See docs/preload-typecheck-hole.md." echo "Found:" echo "$matches" exit 1 fi - name: Check feature wall asset budget run: pnpm check:feature-wall-assets - name: Verify macOS entitlements run: pnpm verify:macos-entitlements - name: Typecheck run: pnpm typecheck # Why: real old Git diagnostics differ from mocked errors. Keep the # fallback predicates executable across the baseline, transition, and # current command shapes so a newly added flag cannot silently regress. - name: Verify Git binary compatibility matrix run: | archive="$RUNNER_TEMP/git-2.25.5.tar.gz" source="$RUNNER_TEMP/git-2.25.5" curl -fsSL https://www.kernel.org/pub/software/scm/git/git-2.25.5.tar.gz -o "$archive" echo "41662c52fc16fec4963bfc41075e71f8ead6b5e386797eb6f9a1111ff95a8ddf $archive" \ | sha256sum --check mkdir -p "$source" tar -xzf "$archive" -C "$source" --strip-components=1 make -C "$source" -j2 NO_GETTEXT=YesPlease NO_TCLTK=YesPlease NO_PYTHON=YesPlease git ORCA_GIT_COMPAT_BINARY="$source/git" ORCA_GIT_COMPAT_VERSION="2.25.5" \ pnpm exec vitest run --config config/vitest.config.ts \ src/shared/git-binary-compatibility.test.ts for spec in \ "alpine/git:edge-2.38.1|2.38.1" \ "alpine/git:v2.49.1|2.49.1"; do image="${spec%%|*}" version="${spec#*|}" ORCA_GIT_COMPAT_IMAGE="$image" ORCA_GIT_COMPAT_VERSION="$version" \ pnpm exec vitest run --config config/vitest.config.ts \ src/shared/git-binary-compatibility.test.ts done # Why: postinstall rebuilds better-sqlite3 for Electron's ABI via # @electron/rebuild, but vitest runs under system Node.js. Rebuild # it for Node so orchestration tests can load the native module. - name: Rebuild better-sqlite3 for Node run: pnpm rebuild better-sqlite3 # Why: install intentionally blocks Electron's package postinstall, but # some unit tests import `electron` under Node and require path.txt. - name: Install Electron package binary for tests run: node config/scripts/install-electron-package-binary.mjs - name: Test run: pnpm test - name: Build unpacked app run: pnpm build:unpack # Why: the packaged CLI runs outside Electron's asar integration, so # bare runtime imports must be present in the package itself. Run from a # temp copy so Node cannot mask missing package deps with repo node_modules. - name: Smoke packaged CLI run: node config/scripts/smoke-packaged-cli.mjs --app-dir=dist/linux-unpacked