3 Commits

Author SHA1 Message Date
eric
90fefeb18e docs: define missing tests 2026-03-04 09:09:18 +01:00
copilot-swe-agent[bot]
48e3ab02d6 fix: harden phase 8 CI workflow and checks
Co-authored-by: Eriyc <50216491+Eriyc@users.noreply.github.com>
2026-03-04 08:04:30 +00:00
copilot-swe-agent[bot]
cb0b253753 feat: add phase 8 ci matrix workflow
Co-authored-by: Eriyc <50216491+Eriyc@users.noreply.github.com>
2026-03-04 08:01:05 +00:00
6 changed files with 135 additions and 22 deletions

3
.github/workflows/BUILD.bazel vendored Normal file
View File

@@ -0,0 +1,3 @@
package(default_visibility = ["//visibility:public"])
exports_files(["ci.yml"])

31
.github/workflows/ci.yml vendored Normal file
View File

@@ -0,0 +1,31 @@
name: CI
on:
push:
branches: ["main"]
pull_request:
jobs:
test:
permissions:
contents: read
strategy:
fail-fast: false
matrix:
include:
- os: ubuntu-latest
phase8_target: linux-x64
- os: macos-14
phase8_target: darwin-arm64
- os: windows-latest
phase8_target: windows
runs-on: ${{ matrix.os }}
env:
USE_BAZEL_VERSION: 9.0.0
steps:
- uses: actions/checkout@v4
- uses: bazel-contrib/setup-bazel@0.15.0
- name: Run tests (${{ matrix.phase8_target }})
run: |
echo "Phase 8 target: ${{ matrix.phase8_target }}"
bazel test //tests/...

View File

@@ -45,3 +45,9 @@ Phase 7 bootstrap is in place:
- Bzlmod `bun_install` module extension (`/bun/extensions.bzl`) using Bazel 9-compatible extension/tag syntax - Bzlmod `bun_install` module extension (`/bun/extensions.bzl`) using Bazel 9-compatible extension/tag syntax
- Focused module-extension shape test (`//tests/install_extension_test:all`) - Focused module-extension shape test (`//tests/install_extension_test:all`)
Phase 8 bootstrap is in place:
- CI matrix workflow for linux-x64, darwin-arm64, and windows (`/.github/workflows/ci.yml`)
- Bazel 9 pin in CI via `USE_BAZEL_VERSION=9.0.0`
- Focused CI matrix shape test (`//tests/ci_test:all`)

View File

@@ -15,6 +15,7 @@ A Bazel ruleset that integrates the [Bun](https://bun.sh) JavaScript runtime nat
**Where to start.** Every Bazel ruleset begins with the toolchain — nothing else works without it. **Where to start.** Every Bazel ruleset begins with the toolchain — nothing else works without it.
### 1.1 Repo Structure ### 1.1 Repo Structure
``` ```
bun_rules/ bun_rules/
├── MODULE.bazel # Bzlmod module definition ├── MODULE.bazel # Bzlmod module definition
@@ -39,6 +40,7 @@ bun_rules/
``` ```
### 1.2 Toolchain Rule (`toolchain.bzl`) ### 1.2 Toolchain Rule (`toolchain.bzl`)
```python ```python
BunToolchainInfo = provider(fields = ["bun_bin", "version"]) BunToolchainInfo = provider(fields = ["bun_bin", "version"])
@@ -52,7 +54,9 @@ bun_toolchain = rule(
``` ```
### 1.3 Binary Downloads (`repositories.bzl`) ### 1.3 Binary Downloads (`repositories.bzl`)
Use `http_file` to fetch platform-specific Bun binaries: Use `http_file` to fetch platform-specific Bun binaries:
- `bun-linux-x64`, `bun-linux-aarch64` - `bun-linux-x64`, `bun-linux-aarch64`
- `bun-darwin-x64`, `bun-darwin-aarch64` - `bun-darwin-x64`, `bun-darwin-aarch64`
- `bun-windows-x64.exe` - `bun-windows-x64.exe`
@@ -60,6 +64,7 @@ Use `http_file` to fetch platform-specific Bun binaries:
Use SHA256 checksums pinned per Bun release. Register via `register_toolchains()`. Use SHA256 checksums pinned per Bun release. Register via `register_toolchains()`.
**Tests needed:** **Tests needed:**
- `toolchain_resolution_test` — assert the correct binary is selected per `--platforms` - `toolchain_resolution_test` — assert the correct binary is selected per `--platforms`
- `bun --version` smoke test via a `sh_test` - `bun --version` smoke test via a `sh_test`
@@ -70,6 +75,7 @@ Use SHA256 checksums pinned per Bun release. Register via `register_toolchains()
Replaces `npm install` / `yarn`. This is the highest-leverage rule because every downstream rule depends on it. Replaces `npm install` / `yarn`. This is the highest-leverage rule because every downstream rule depends on it.
### Rule Design ### Rule Design
```python ```python
bun_install( bun_install(
name = "node_modules", name = "node_modules",
@@ -83,12 +89,14 @@ bun_install(
- Must be hermetic: no network in actions (vendor or use a repository rule to pre-fetch) - Must be hermetic: no network in actions (vendor or use a repository rule to pre-fetch)
### Key Challenges ### Key Challenges
- `bun.lockb` is binary — you need to commit it and treat it as a source file - `bun.lockb` is binary — you need to commit it and treat it as a source file
- Network access during `bun install` breaks Bazel's sandbox; solve with either: - Network access during `bun install` breaks Bazel's sandbox; solve with either:
- A **repository rule** that runs install at analysis time (like `npm_install` in rules_nodejs) - A **repository rule** that runs install at analysis time (like `npm_install` in rules_nodejs)
- Or a **module extension** in Bzlmod - Or a **module extension** in Bzlmod
**Tests needed:** **Tests needed:**
- Install succeeds with a valid `package.json` + `bun.lockb` - Install succeeds with a valid `package.json` + `bun.lockb`
- Build fails (with a clear error) when `bun.lockb` is out of date - Build fails (with a clear error) when `bun.lockb` is out of date
- Determinism test: run install twice, assert identical output digest - Determinism test: run install twice, assert identical output digest
@@ -112,6 +120,7 @@ bun_binary(
- Handles both `.js` and `.ts` natively (no transpile step needed) - Handles both `.js` and `.ts` natively (no transpile step needed)
**Tests needed:** **Tests needed:**
- `bun_binary` produces a runnable target (`bazel run`) - `bun_binary` produces a runnable target (`bazel run`)
- TypeScript entry points work without separate compilation - TypeScript entry points work without separate compilation
- `data` deps are available at runtime - `data` deps are available at runtime
@@ -134,6 +143,7 @@ bun_test(
- Outputs JUnit XML for `--test_output` compatibility (use `bun test --reporter junit`) - Outputs JUnit XML for `--test_output` compatibility (use `bun test --reporter junit`)
**Tests needed:** **Tests needed:**
- Passing test suite returns exit 0 - Passing test suite returns exit 0
- Failing test suite returns exit non-0 (Bazel marks as FAILED) - Failing test suite returns exit non-0 (Bazel marks as FAILED)
- Test filtering via `--test_filter` works - Test filtering via `--test_filter` works
@@ -161,6 +171,7 @@ bun_bundle(
- Supports splitting, external packages, define/env vars - Supports splitting, external packages, define/env vars
**Tests needed:** **Tests needed:**
- Output file exists and has non-zero size - Output file exists and has non-zero size
- `minify = True` produces smaller output than `minify = False` - `minify = True` produces smaller output than `minify = False`
- `external` packages are not bundled - `external` packages are not bundled
@@ -183,6 +194,7 @@ ts_library(
``` ```
**Tests needed:** **Tests needed:**
- `deps` correctly propagate transitive sources to `bun_bundle` and `bun_test` - `deps` correctly propagate transitive sources to `bun_bundle` and `bun_test`
- Circular dep detection (or at least graceful failure) - Circular dep detection (or at least graceful failure)
@@ -191,7 +203,7 @@ ts_library(
## Required Tests Summary ## Required Tests Summary
| Category | Test | | Category | Test |
|---|---| | ------------- | ----------------------------------------------------------- |
| Toolchain | Correct binary resolves per platform | | Toolchain | Correct binary resolves per platform |
| Toolchain | `bun --version` executes successfully | | Toolchain | `bun --version` executes successfully |
| `bun_install` | Clean install works | | `bun_install` | Clean install works |
@@ -212,6 +224,31 @@ ts_library(
| Integration | `examples/basic` builds end-to-end with `bazel build //...` | | Integration | `examples/basic` builds end-to-end with `bazel build //...` |
| Integration | `bazel test //...` passes all tests | | Integration | `bazel test //...` passes all tests |
### Gap-Closing Checklist (Concrete Targets)
Use this checklist to close the current coverage gaps with explicit test targets.
| Status | Gap | Proposed target | Location |
| ------- | ---------------------------------------------------------- | ---------------------------------- | ------------------------------------ |
| Partial | Toolchain resolves per platform is only host-select tested | `toolchain_resolution_matrix_test` | `tests/toolchain_test/BUILD.bazel` |
| Missing | `bun_install` deterministic output digest | `bun_install_determinism_test` | `tests/install_test/BUILD.bazel` |
| Missing | `bun_binary` runtime data files availability | `bun_binary_data_test` | `tests/binary_test/BUILD.bazel` |
| Partial | `bun_test` failing suite exists but is manual-only | `bun_test_failing_suite_test` | `tests/bun_test_test/BUILD.bazel` |
| Missing | `bun_test` cache hit (unchanged inputs) | `bun_test_cache_hit_test` | `tests/bun_test_test/BUILD.bazel` |
| Missing | `bun_test` cache miss (changed source) | `bun_test_cache_miss_test` | `tests/bun_test_test/BUILD.bazel` |
| Missing | `bun_test` JUnit XML parseability | `bun_test_junit_output_test` | `tests/bun_test_test/BUILD.bazel` |
| Missing | `bun_bundle` hermetic digest stability | `bundle_hermetic_digest_test` | `tests/bundle_test/BUILD.bazel` |
| Missing | `bun_bundle` external package exclusion | `bundle_external_exclusion_test` | `tests/bundle_test/BUILD.bazel` |
| Missing | `examples/basic` end-to-end build via Bazel | `examples_basic_e2e_build_test` | `tests/integration_test/BUILD.bazel` |
| Partial | CI currently runs `bazel test //tests/...` only | `repo_all_targets_test` | `tests/integration_test/BUILD.bazel` |
Recommended implementation order:
1. `bun_test_failing_suite_test` (remove/manual split) and `bun_binary_data_test`
2. `bun_install_determinism_test`, `bundle_hermetic_digest_test`
3. `bun_test_cache_hit_test`, `bun_test_cache_miss_test`, `bun_test_junit_output_test`
4. `bundle_external_exclusion_test`, `examples_basic_e2e_build_test`, `repo_all_targets_test`
--- ---
## Development Sequence ## Development Sequence
@@ -235,6 +272,7 @@ ts_library(
**Day 1:** Copy the pattern from [`rules_go`](https://github.com/bazelbuild/rules_go) or [`aspect-build/rules_js`](https://github.com/aspect-build/rules_js) for toolchain registration. Write `repositories.bzl` that fetches the Bun binary for your current platform only. Write a `sh_test` that calls `bun --version` and asserts it exits 0. Get that green. **Day 1:** Copy the pattern from [`rules_go`](https://github.com/bazelbuild/rules_go) or [`aspect-build/rules_js`](https://github.com/aspect-build/rules_js) for toolchain registration. Write `repositories.bzl` that fetches the Bun binary for your current platform only. Write a `sh_test` that calls `bun --version` and asserts it exits 0. Get that green.
**Reference implementations to study:** **Reference implementations to study:**
- `aspect-build/rules_js` — best modern reference for JS in Bazel - `aspect-build/rules_js` — best modern reference for JS in Bazel
- `bazelbuild/rules_nodejs` — older but battle-tested patterns - `bazelbuild/rules_nodejs` — older but battle-tested patterns
- `bazelbuild/rules_python` — excellent toolchain download pattern to copy - `bazelbuild/rules_python` — excellent toolchain download pattern to copy

View File

@@ -0,0 +1,8 @@
load("@rules_shell//shell:sh_test.bzl", "sh_test")
sh_test(
name = "phase8_ci_matrix_shape_test",
srcs = ["phase8_ci_matrix_shape_test.sh"],
args = ["$(location //.github/workflows:ci.yml)"],
data = ["//.github/workflows:ci.yml"],
)

View File

@@ -0,0 +1,27 @@
#!/usr/bin/env bash
set -euo pipefail
workflow_file="$1"
if [ -z "${workflow_file}" ]; then
echo "Error: workflow file path required as first argument" >&2
exit 1
fi
check_pattern() {
local pattern="$1"
local message="$2"
if ! grep -Eq "${pattern}" "${workflow_file}"; then
echo "Error: ${message}" >&2
exit 1
fi
}
check_pattern '^name:[[:space:]]+CI$' "missing workflow name CI"
check_pattern 'USE_BAZEL_VERSION:[[:space:]]+9\.0\.0' "missing Bazel 9.0.0 pin"
check_pattern 'os:[[:space:]]+ubuntu-latest' "missing ubuntu matrix entry"
check_pattern 'phase8_target:[[:space:]]+linux-x64' "missing linux-x64 matrix target"
check_pattern 'os:[[:space:]]+macos-14' "missing macos matrix entry"
check_pattern 'phase8_target:[[:space:]]+darwin-arm64' "missing darwin-arm64 matrix target"
check_pattern 'os:[[:space:]]+windows-latest' "missing windows matrix entry"
check_pattern 'phase8_target:[[:space:]]+windows' "missing windows matrix target"
echo "CI matrix shape checks passed"