-
Notifications
You must be signed in to change notification settings - Fork 73
Add vitest-pool-bun: a Vitest 4.1 custom pool that runs tests in Bun (PoC) #800
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Draft
Copilot
wants to merge
6
commits into
main
Choose a base branch
from
copilot/vitest-pool-bun
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Draft
Changes from all commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
8d6880b
feat: gate-1 single test executes in Bun via custom Vitest pool
Copilot 07464b9
feat: gate-2 real modules, setupFiles, TS-mapped failure stacks in Bun
Copilot 8682072
feat: gate-4 Bun globals + actionable worker crash/spawn diagnostics
Copilot dd8425c
docs: gate-5 README, ENVIRONMENT.md, VALIDATION.md + demo scripts
Copilot f28d417
ci: add vitest-pool-bun test workflow
Copilot 0359256
Add vitest-pool-bun CI: run demo suite and selected Node unit tests i…
Copilot File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,59 @@ | ||
| name: 'vitest-pool-bun' | ||
|
|
||
| permissions: {} | ||
| on: | ||
| workflow_dispatch: | ||
| push: | ||
| branches: | ||
| - main | ||
| paths: | ||
| - 'vitest-pool-bun/**' | ||
| - '.github/workflows/vitest-pool-bun.yml' | ||
| pull_request: | ||
| paths: | ||
| - 'vitest-pool-bun/**' | ||
| - '.github/workflows/vitest-pool-bun.yml' | ||
|
|
||
| concurrency: | ||
| group: '${{ github.workflow }}-${{ github.ref }}' | ||
| cancel-in-progress: true | ||
|
|
||
| jobs: | ||
| tests: | ||
| timeout-minutes: 10 | ||
| runs-on: ubuntu-latest | ||
| defaults: | ||
| run: | ||
| working-directory: vitest-pool-bun | ||
| steps: | ||
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | ||
|
|
||
| - name: Setup NodeJS | ||
| uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0 | ||
| with: | ||
| node-version: 24 | ||
|
|
||
| - name: Setup Bun | ||
| uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0 | ||
| with: | ||
| bun-version: 1.3.14 | ||
|
|
||
| - name: Install dependencies | ||
| run: | | ||
| npm install | ||
|
|
||
|
|
||
| - name: Run tests (green example suite in Bun) | ||
| run: | | ||
| npm run demo | ||
|
|
||
| - name: Install dependencies (clickhouse-js root) | ||
| working-directory: . | ||
| run: | | ||
| npm install | ||
|
|
||
|
|
||
| - name: Run selected Node unit tests in Bun pool | ||
| working-directory: . | ||
| env: | ||
| CLICKHOUSE_TEST_SKIP_INIT: '1' | ||
| run: | | ||
| node vitest-pool-bun/node_modules/vitest/vitest.mjs run --config vitest-pool-bun/examples/clickhouse-node-unit.config.mjs | ||
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,28 @@ | ||
| # Environment | ||
|
|
||
| Exact versions used to develop and validate this proof of concept. Other | ||
| versions may work but are unverified. | ||
|
|
||
| | Component | Version | Role | | ||
| | --------- | ------- | ---- | | ||
| | Node.js | `v24.16.0` (host requires `>= 20`) | Host / orchestrator: owns the Vite transform pipeline, scheduling, reporters | | ||
| | Bun | `1.3.14` (requires `>= 1.2`, `1.3+` preferred) | Worker runtime: evaluates modules and runs the test callbacks | | ||
| | vitest | `4.1.8` (requires `^4.1`) | Custom-pool API (`vitest/node`, `vitest/worker`) | | ||
| | flatted | `3.4.2` | JSON-safe (circular-ref-tolerant) serialization across the Node ↔ Bun IPC channel | | ||
|
|
||
| ## Reproducing the version check | ||
|
|
||
| ```bash | ||
| node --version # v24.16.0 | ||
| bun --version # 1.3.14 | ||
| node -e 'console.log(require("vitest/package.json").version)' # 4.1.8 | ||
| ``` | ||
|
|
||
| ## Notes | ||
|
|
||
| - The **host process is always launched with `node`** (`node node_modules/vitest/vitest.mjs run`). Only the per-file worker is `bun`. | ||
| - Package manager: installing with `bun`, `npm`, or `pnpm` is fine; it does not | ||
| affect which runtime executes tests. | ||
| - Targets **macOS / Linux only**. Windows is an explicit non-goal for the PoC. | ||
| - The `bun` executable must be discoverable. Resolution order: | ||
| `bunBinary` pool option → `BUN_BINARY` env var → `bun` on `PATH`. |
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,140 @@ | ||
| # vitest-pool-bun | ||
|
|
||
| > **Proof of concept.** A custom [Vitest](https://vitest.dev) 4.1 pool that | ||
| > executes test files **inside the [Bun](https://bun.sh) runtime**, analogous to | ||
| > how `@cloudflare/vitest-pool-workers` executes them inside `workerd`. | ||
|
|
||
| The **Node host** owns the Vite transform pipeline (transforming modules, | ||
| scheduling, collecting results, running reporters); **Bun** owns test execution | ||
| (evaluating the transformed modules and running the test callbacks). The two | ||
| roles talk over a JSON-only IPC channel. | ||
|
|
||
| ``` | ||
| ┌────────────────────────┐ WorkerRequest / RPC (JSON IPC) ┌─────────────────────────┐ | ||
| │ Node host (Vitest) │ ───────────────────────────────► │ Bun worker │ | ||
| │ • Vite transform │ │ • vitest/worker init() │ | ||
| │ • scheduling │ ◄─────────────────────────────── │ • module runner │ | ||
| │ • reporters │ WorkerResponse / module code │ • runs test callbacks │ | ||
| └────────────────────────┘ └─────────────────────────┘ | ||
| src/pool-worker.ts (BunPoolWorker) src/worker-entry.ts | ||
| ``` | ||
|
|
||
| ## Why this works (and what made it non-trivial) | ||
|
|
||
| - Bun natively executes TypeScript and imports from disk, so almost none of the | ||
| elaborate module-fallback machinery that the `workerd` pool needs is required. | ||
| - Vitest's plain (non-`vm`) pool evaluates modules with Vite's | ||
| AsyncFunction-based `ESModulesEvaluator`, **not** `node:vm`. Bun's `vm` is only | ||
| ~90% conformant, but the AsyncFunction evaluator works cleanly under Bun — this | ||
| is the single most important reason the PoC is viable (de-risked in Phase 0). | ||
| - Node ↔ Bun IPC only supports JSON serialization. All channel traffic is routed | ||
| through `flatted` so circular object graphs and Vitest's serialized errors | ||
| survive a JSON-only channel. See [`src/channel.ts`](./src/channel.ts). | ||
|
|
||
| ## Requirements | ||
|
|
||
| See [`ENVIRONMENT.md`](./ENVIRONMENT.md) for pinned versions. In short: Node | ||
| `>= 20` (host), Bun `>= 1.2` (worker), `vitest@^4.1`. macOS / Linux only. | ||
|
|
||
| ## Install | ||
|
|
||
| ```bash | ||
| # from this package directory | ||
| npm install | ||
| # Bun must be installed and on PATH (https://bun.sh) | ||
| bun --version | ||
| ``` | ||
|
|
||
| ## Configure | ||
|
|
||
| Minimal config via the helper: | ||
|
|
||
| ```ts | ||
| // vitest.config.ts | ||
| import { defineBunPoolConfig } from 'vitest-pool-bun' | ||
|
|
||
| export default defineBunPoolConfig({ | ||
| test: { | ||
| include: ['tests/**/*.test.ts'], | ||
| }, | ||
| }) | ||
| ``` | ||
|
|
||
| Or wire the pool directly: | ||
|
|
||
| ```ts | ||
| import { defineConfig } from 'vitest/config' | ||
| import { bunPool } from 'vitest-pool-bun' | ||
|
|
||
| export default defineConfig({ | ||
| test: { | ||
| pool: bunPool({ | ||
| // bunBinary: '/custom/path/to/bun', // defaults to BUN_BINARY env or `bun` | ||
| // bunArgs: ['--smol'], | ||
| // env: { MY_FLAG: '1' }, | ||
| }), | ||
| }, | ||
| }) | ||
| ``` | ||
|
|
||
| ## Run | ||
|
|
||
| The host is launched with **node**; the pool spawns **bun** per test file: | ||
|
|
||
| ```bash | ||
| node node_modules/vitest/vitest.mjs run | ||
| ``` | ||
|
|
||
| ### Demo scripts | ||
|
|
||
| | Script | What it shows | | ||
| | ------ | ------------- | | ||
| | `npm run demo` | Green example suite executed in Bun (9 passing tests) | | ||
| | `npm run demo:failure` | A failing assertion reported with a stack trace pointing at the original `.ts` line | | ||
| | `npm run demo:diagnostics` | A crashed Bun worker surfaced as a clear host error (not a hang) | | ||
| | `npm run spike` | The throwaway Phase 0 de-risk spike (`bun run spikes/m0-runner.ts`) | | ||
|
|
||
| `npm run demo` performs a clean `build` first, so a fresh clone only needs | ||
| `npm install` followed by `npm run demo`. | ||
|
|
||
| ## Options (`BunPoolOptions`) | ||
|
|
||
| | Option | Type | Default | Description | | ||
| | ------ | ---- | ------- | ----------- | | ||
| | `bunBinary` | `string` | `BUN_BINARY` env, else `bun` | Path or command for the Bun executable | | ||
| | `bunArgs` | `string[]` | `[]` | Extra args passed to `bun run <worker-entry>` | | ||
| | `env` | `Record<string, string \| undefined>` | `{}` | Extra env vars for the spawned worker | | ||
|
|
||
| ## Layout | ||
|
|
||
| ``` | ||
| vitest-pool-bun/ | ||
| ├─ src/ | ||
| │ ├─ index.ts # bunPool() + defineBunPoolConfig() | ||
| │ ├─ pool-worker.ts # BunPoolWorker (host side, runs under Node) | ||
| │ ├─ worker-entry.ts # runs under Bun; calls init() from 'vitest/worker' | ||
| │ ├─ channel.ts # flatted-based JSON-safe (de)serialization | ||
| │ └─ types.ts # BunPoolOptions | ||
| ├─ spikes/m0-runner.ts # Phase 0 de-risk spike (throwaway) | ||
| ├─ examples/ # runnable example suite + configs | ||
| ├─ ENVIRONMENT.md # pinned versions | ||
| └─ VALIDATION.md # what works / partially works / unsupported | ||
| ``` | ||
|
|
||
| ## Known limitations | ||
|
|
||
| This is a proof of concept. See [`VALIDATION.md`](./VALIDATION.md) for the full | ||
| matrix. Highlights: | ||
|
|
||
| - **V8 coverage is unsupported** under Bun (`node:inspector` lacks the Profiler | ||
| APIs). Use the `istanbul` provider, which works. | ||
| - Isolation uses **one Bun process per file** (or a reused process when | ||
| `isolate: false`). Thread isolation is intentionally not used: Bun's | ||
| `worker_threads` cannot access the parent IPC channel. | ||
| - No watch/HMR rerun loop, browser mode, type-testing, or Windows support. | ||
| - Performance tuning, worker-reuse pooling, and full `vi.mock` parity are out of | ||
| scope for the PoC. | ||
|
|
||
| ## License | ||
|
|
||
| Apache-2.0. |
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,79 @@ | ||
| # Validation | ||
|
|
||
| What was actually exercised against this PoC, and the boundaries. Versions are | ||
| pinned in [`ENVIRONMENT.md`](./ENVIRONMENT.md) (Node 24, Bun 1.3.14, | ||
| vitest 4.1.8). Everything below was observed by running the host under `node` | ||
| and executing tests in `bun` via this pool. | ||
|
|
||
| Legend: ✅ works · ⚠️ works with caveats · ❌ unsupported · ⛔ not attempted (non-goal) | ||
|
|
||
| ## Core execution | ||
|
|
||
| | Capability | Status | Notes | | ||
| | ---------- | :----: | ----- | | ||
| | Sync tests | ✅ | `examples/tests/smoke.test.ts` | | ||
| | Async / `await` tests | ✅ | `examples/tests/async.test.ts`, `concurrent.test.ts` | | ||
| | `describe` / nested suites | ✅ | `examples/tests/concurrent.test.ts` | | ||
| | Importing local TS modules | ✅ | Resolved + transformed by the host module runner over the channel | | ||
| | Importing `node_modules` deps | ✅ | e.g. `vitest` matchers; externalized/transformed via host | | ||
| | `setupFiles` | ✅ | `examples/setup.ts` runs in the Bun worker | | ||
| | Pass/fail reporting to standard reporters | ✅ | Totals are correct across multiple files | | ||
| | Failing-assertion stack traces | ✅ | Point at the original `.ts` source line (host-side Vite source maps); see `npm run demo:failure` | | ||
| | Bun globals (`Bun`, `Bun.file`, `Bun.env`, `Bun.version`) | ✅ | `examples/tests/bun-api.test.ts` | | ||
|
|
||
| ## Isolation & lifecycle | ||
|
|
||
| | Capability | Status | Notes | | ||
| | ---------- | :----: | ----- | | ||
| | Process-per-file isolation (`isolate: true`, default) | ✅ | One spawned `bun` per file; Vitest's scheduler owns this | | ||
| | Reused-process mode (`isolate: false`) | ✅ | Correct totals; runner reuse handled by Vitest | | ||
| | No leaked Bun processes after a run | ✅ | Verified via `pgrep` after exit, both isolation modes | | ||
| | Thread isolation (`worker_threads`) | ❌ | Intentionally not used — Bun threads can't access the parent IPC channel | | ||
|
|
||
| ## Diagnostics (failure legibility) | ||
|
|
||
| | Scenario | Status | Behaviour | | ||
| | -------- | :----: | --------- | | ||
| | `bun` not found / bad `bunBinary` | ✅ | Fails fast with an actionable message naming `bunBinary` / `BUN_BINARY`; no hang | | ||
| | Soft crash (`process.exit` in a test) | ✅ | Reported as a test error with TS-mapped line | | ||
| | Hard crash / channel disconnect (worker `SIGKILL`'d mid-run) | ✅ | Surfaced as `[vitest-pool]: Worker bun emitted error. Caused by: Worker exited unexpectedly`; no indefinite hang | | ||
|
|
||
| ## Test-author features | ||
|
|
||
| | Feature | Status | Notes | | ||
| | ------- | :----: | ----- | | ||
| | Spies (`vi.fn`, `toHaveBeenCalledWith`) | ✅ | Verified | | ||
| | Fake timers (`vi.useFakeTimers`, `advanceTimersByTime`) | ✅ | Verified | | ||
| | Snapshots (inline & file) | ⚠️ | Mechanism works; not stress-tested for format parity across runtimes (a PoC non-goal) | | ||
| | Module mocking (`vi.mock` hoisting) | ⚠️ | Basic factory hoisting verified to work; full `vi.mock` parity is **not** guaranteed and edge cases are untested | | ||
|
|
||
| ## Coverage | ||
|
|
||
| | Provider | Status | Notes | | ||
| | -------- | :----: | ----- | | ||
| | `istanbul` (`@vitest/coverage-istanbul`) | ✅ | Works — instrumentation happens at transform time on the host, counters are plain JS collected in Bun. Reported 100% on the example source | | ||
| | `v8` (`@vitest/coverage-v8`) | ❌ | Fails with `Coverage APIs are not supported` — Bun's `node:inspector` lacks the Profiler/coverage APIs | | ||
|
|
||
| ## Explicit non-goals (not attempted) | ||
|
|
||
| | Area | Status | | ||
| | ---- | :----: | | ||
| | Watch mode / HMR rerun loop | ⛔ | | ||
| | Browser mode | ⛔ | | ||
| | Type testing (`expect-type` / `*.test-d.ts`) | ⛔ | | ||
| | Windows support | ⛔ | | ||
| | Performance / parallelism tuning, worker-reuse pooling | ⛔ | | ||
|
|
||
| ## Performance note | ||
|
|
||
| Independent benchmarks report Bun (JavaScriptCore) can be slower than Node (V8) | ||
| on heavily async test workloads. This is a performance characteristic, not a | ||
| correctness issue, and was **not** benchmarked here. Treat it as a known caveat | ||
| rather than a guarantee in either direction. | ||
|
|
||
| ## Topology used | ||
|
|
||
| The PoC uses the **target topology**: a Node host driving a spawned-process Bun | ||
| worker over an IPC channel (not the §7 fallback of running the entire Vitest | ||
| process under `bun`). The Phase 0 spike confirmed module evaluation works under | ||
| Bun before any pool plumbing was built, so the fallback was never needed. |
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,26 @@ | ||
| import { fileURLToPath } from 'node:url' | ||
| import { defineBunPoolConfig } from '../dist/index.js' | ||
|
|
||
| export default defineBunPoolConfig({ | ||
| test: { | ||
| root: fileURLToPath(new URL('../..', import.meta.url)), | ||
| include: [ | ||
| 'packages/client-node/__tests__/unit/node_user_agent.test.ts', | ||
| 'packages/client-node/__tests__/unit/node_default_logger.test.ts', | ||
| ], | ||
| watch: false, | ||
| }, | ||
| resolve: { | ||
| alias: { | ||
| '@clickhouse/client-common': fileURLToPath( | ||
| new URL('../../packages/client-common/src', import.meta.url), | ||
| ), | ||
| '@clickhouse/client-node': fileURLToPath( | ||
| new URL('../../packages/client-node/src', import.meta.url), | ||
| ), | ||
| '@test': fileURLToPath( | ||
| new URL('../../packages/client-common/__tests__', import.meta.url), | ||
| ), | ||
| }, | ||
| }, | ||
| }) |
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| import { defineBunPoolConfig } from '../dist/index.js' | ||
|
|
||
| // Separate config so the crash fixture is never picked up by the demo suite. | ||
| export default defineBunPoolConfig({ | ||
| test: { | ||
| root: __dirname, | ||
| include: ['diagnostics/**/*.test.ts'], | ||
| watch: false, | ||
| }, | ||
| }) |
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| import { expect, test } from 'vitest' | ||
|
|
||
| // Diagnostics fixture (NOT part of the default demo suite). | ||
| // | ||
| // When BUN_POOL_CRASH=1, the test abruptly kills the Bun worker mid-run to | ||
| // simulate a runtime crash / channel disconnect. The host (`BunPoolWorker` + | ||
| // Vitest's PoolRunner) must surface a clear, actionable error and terminate the | ||
| // run instead of hanging indefinitely (Phase 4 / STOP gate 4). | ||
| test('worker crash is surfaced, not hung', () => { | ||
| if (process.env.BUN_POOL_CRASH === '1') { | ||
| // Hard-kill this Bun process while the host is waiting for results. | ||
| process.exit(137) | ||
| } | ||
| expect(true).toBe(true) | ||
| }) |
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| import { defineBunPoolConfig } from '../dist/index.js' | ||
|
|
||
| // Separate config so the intentionally-failing fixture is never part of the | ||
| // green demo suite. Used to demonstrate failure reporting (STOP gate 2). | ||
| export default defineBunPoolConfig({ | ||
| test: { | ||
| root: __dirname, | ||
| include: ['expected-failures/**/*.test.ts'], | ||
| watch: false, | ||
| }, | ||
| }) |
12 changes: 12 additions & 0 deletions
12
vitest-pool-bun/examples/expected-failures/assertion.test.ts
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,12 @@ | ||
| import { expect, test } from 'vitest' | ||
| import { add } from '../src/math.js' | ||
|
|
||
| // Intentionally failing test (NOT part of the green demo suite). | ||
| // | ||
| // Demonstrates STOP gate 2: a failing assertion is reported as a real failure | ||
| // whose stack trace points at the original TypeScript source line below — the | ||
| // `expect(...)` call — proving host-side Vite source maps survive the Bun round | ||
| // trip. Run with `npm run demo:failure` (expected to exit non-zero). | ||
| test('failing assertion reports a TS-mapped stack', () => { | ||
| expect(add(2, 2)).toBe(5) | ||
| }) |
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| // Runs inside the Bun worker before each test file (Vitest `setupFiles`). | ||
| // Used by Phase 2 to prove setup files are executed in the Bun runtime. | ||
| ;(globalThis as Record<string, unknown>).__BUN_POOL_SETUP__ = true |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.