Skip to content

feat(tracker): Support for Beads-Rust-BV plugin #852

feat(tracker): Support for Beads-Rust-BV plugin

feat(tracker): Support for Beads-Rust-BV plugin #852

Workflow file for this run

name: CI
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Bun
uses: oven-sh/setup-bun@v2
with:
bun-version: latest
- name: Clear TypeScript build cache
run: |
rm -rf node_modules/.cache
rm -rf .tsbuildinfo
- name: Install dependencies
run: bun install
- name: Type check
run: bun run typecheck
- name: Lint
run: bun run lint
- name: Build
run: bun run build
test:
runs-on: ubuntu-latest
needs: build
steps:
- uses: actions/checkout@v4
- name: Setup Bun
uses: oven-sh/setup-bun@v2
with:
bun-version: latest
- name: Install dependencies
run: bun install
- name: Run tests with coverage
run: |
set -euo pipefail
mkdir -p coverage-parts
# Run tests in batches to avoid mock.module() conflicts between test files
# Each batch outputs its own lcov file for later merging
echo "=== Running tests/ (excluding commands/info.test.ts) ===" | tee -a coverage-output.txt
mapfile -t TEST_FILES < <(find tests -type f -name '*.test.ts' ! -path 'tests/commands/info.test.ts' | sort)
bun test "${TEST_FILES[@]}" --coverage --coverage-reporter=text --coverage-reporter=lcov 2>&1 | tee -a coverage-output.txt
cp coverage/lcov.info coverage-parts/tests.lcov
echo "=== Running tests/commands/info.test.ts (isolated) ===" | tee -a coverage-output.txt
bun test tests/commands/info.test.ts --coverage --coverage-reporter=text --coverage-reporter=lcov 2>&1 | tee -a coverage-output.txt
cp coverage/lcov.info coverage-parts/tests-info.lcov
echo "=== Running doctor.test.ts ===" | tee -a coverage-output.txt
bun test src/commands/doctor.test.ts --coverage --coverage-reporter=text --coverage-reporter=lcov 2>&1 | tee -a coverage-output.txt
cp coverage/lcov.info coverage-parts/doctor.lcov
echo "=== Running info.test.ts ===" | tee -a coverage-output.txt
bun test src/commands/info.test.ts --coverage --coverage-reporter=text --coverage-reporter=lcov 2>&1 | tee -a coverage-output.txt
cp coverage/lcov.info coverage-parts/info.lcov
echo "=== Running skills tests ===" | tee -a coverage-output.txt
bun test src/commands/skills.test.ts src/commands/skills-install.test.ts --coverage --coverage-reporter=text --coverage-reporter=lcov 2>&1 | tee -a coverage-output.txt
cp coverage/lcov.info coverage-parts/skills.lcov
echo "=== Running run.test.ts ===" | tee -a coverage-output.txt
bun test src/commands/run.test.ts --coverage --coverage-reporter=text --coverage-reporter=lcov 2>&1 | tee -a coverage-output.txt
cp coverage/lcov.info coverage-parts/run.lcov
echo "=== Running src/config/ ===" | tee -a coverage-output.txt
bun test src/config/ --coverage --coverage-reporter=text --coverage-reporter=lcov 2>&1 | tee -a coverage-output.txt
cp coverage/lcov.info coverage-parts/config.lcov
echo "=== Running src/engine/ ===" | tee -a coverage-output.txt
bun test src/engine/ --coverage --coverage-reporter=text --coverage-reporter=lcov 2>&1 | tee -a coverage-output.txt
cp coverage/lcov.info coverage-parts/engine.lcov
# Run beads-bv and beads-rust tests in isolation due to ES module mock conflicts
# Both mock node:fs/promises which pollutes other tests when run together
echo "=== Running beads-bv test (isolated) ===" | tee -a coverage-output.txt
bun test src/plugins/trackers/builtin/beads-bv/index.test.ts --coverage --coverage-reporter=text --coverage-reporter=lcov 2>&1 | tee -a coverage-output.txt
cp coverage/lcov.info coverage-parts/beads-bv.lcov
echo "=== Running beads-rust test (isolated) ===" | tee -a coverage-output.txt
bun test src/plugins/trackers/builtin/beads-rust/index.test.ts --coverage --coverage-reporter=text --coverage-reporter=lcov 2>&1 | tee -a coverage-output.txt
cp coverage/lcov.info coverage-parts/beads-rust.lcov
echo "=== Running beads test (isolated) ===" | tee -a coverage-output.txt
bun test src/plugins/trackers/builtin/beads/index.test.ts --coverage --coverage-reporter=text --coverage-reporter=lcov 2>&1 | tee -a coverage-output.txt
cp coverage/lcov.info coverage-parts/beads.lcov
echo "=== Running src/plugins/ (excluding beads-bv and beads-rust) ===" | tee -a coverage-output.txt
bun test src/plugins/agents/ src/plugins/trackers/builtin/beads.test.ts --coverage --coverage-reporter=text --coverage-reporter=lcov 2>&1 | tee -a coverage-output.txt || true
cp coverage/lcov.info coverage-parts/plugins.lcov || true
echo "=== Running src/session/ ===" | tee -a coverage-output.txt
bun test src/session/ --coverage --coverage-reporter=text --coverage-reporter=lcov 2>&1 | tee -a coverage-output.txt
cp coverage/lcov.info coverage-parts/session.lcov
echo "=== Running src/sandbox/ ===" | tee -a coverage-output.txt
bun test src/sandbox/ --coverage --coverage-reporter=text --coverage-reporter=lcov 2>&1 | tee -a coverage-output.txt
cp coverage/lcov.info coverage-parts/sandbox.lcov
# Run wizard.test.ts in isolation because it mocks skill-installer.js
# which leaks into skill-installer.test.ts via bun's process-level mock.module()
echo "=== Running wizard.test.ts (isolated) ===" | tee -a coverage-output.txt
bun test src/setup/wizard.test.ts --coverage --coverage-reporter=text --coverage-reporter=lcov 2>&1 | tee -a coverage-output.txt
cp coverage/lcov.info coverage-parts/wizard.lcov
echo "=== Running src/setup/ (excluding wizard and spawn-mocked tests) ===" | tee -a coverage-output.txt
bun test src/setup/skill-installer.test.ts src/setup/migration.test.ts src/setup/prompts.test.ts --coverage --coverage-reporter=text --coverage-reporter=lcov 2>&1 | tee -a coverage-output.txt
cp coverage/lcov.info coverage-parts/setup.lcov
# Run spawn-mocked tests isolated: they mock node:child_process which conflicts with migration.test.ts
echo "=== Running skill-installer-spawn.test.ts (isolated) ===" | tee -a coverage-output.txt
bun test src/setup/skill-installer-spawn.test.ts --coverage --coverage-reporter=text --coverage-reporter=lcov 2>&1 | tee -a coverage-output.txt
cp coverage/lcov.info coverage-parts/skill-installer-spawn.lcov
# Run migration-install test isolated: it mocks config/registry which conflicts with migration.test.ts
echo "=== Running migration-install.test.ts (isolated) ===" | tee -a coverage-output.txt
bun test src/setup/migration-install.test.ts --coverage --coverage-reporter=text --coverage-reporter=lcov 2>&1 | tee -a coverage-output.txt
cp coverage/lcov.info coverage-parts/migration-install.lcov
echo "=== Running src/templates/ ===" | tee -a coverage-output.txt
bun test src/templates/ --coverage --coverage-reporter=text --coverage-reporter=lcov 2>&1 | tee -a coverage-output.txt
cp coverage/lcov.info coverage-parts/templates.lcov
echo "=== Running src/tui/ ===" | tee -a coverage-output.txt
bun test src/tui/ --coverage --coverage-reporter=text --coverage-reporter=lcov 2>&1 | tee -a coverage-output.txt
cp coverage/lcov.info coverage-parts/tui.lcov
echo "=== Running src/prd/ ===" | tee -a coverage-output.txt
bun test src/prd/ --coverage --coverage-reporter=text --coverage-reporter=lcov 2>&1 | tee -a coverage-output.txt
cp coverage/lcov.info coverage-parts/prd.lcov
echo "=== Running src/chat/ ===" | tee -a coverage-output.txt
bun test src/chat/ --coverage --coverage-reporter=text --coverage-reporter=lcov 2>&1 | tee -a coverage-output.txt
cp coverage/lcov.info coverage-parts/chat.lcov
echo "=== Running src/parallel/ ===" | tee -a coverage-output.txt
bun test src/parallel/ --coverage --coverage-reporter=text --coverage-reporter=lcov 2>&1 | tee -a coverage-output.txt
cp coverage/lcov.info coverage-parts/parallel.lcov
echo "=== All test batches completed ===" | tee -a coverage-output.txt
ls -la coverage-parts/
- name: Check coverage threshold
run: |
# Use bun's text output to check coverage. Bun reports per-file average
# line coverage under "All files | % Funcs | % Lines". Each batch prints
# this line. We use the tests/ batch (first line, 1400+ tests) as the
# primary indicator since it loads the most code paths.
#
# Note: we intentionally use bun's text output (per-file average) rather
# than lcov --summary (raw line totals). Raw totals are misleadingly low
# because a few large UI/server files with ~0% coverage contain thousands
# of lines that dwarf the well-tested files. Per-file average treats each
# source file equally, which better reflects actual test quality.
echo "Coverage breakdown by batch:"
echo " %-Funcs %-Lines"
grep "^All files" coverage-output.txt | awk '{printf " %6s %6s\n", $4, $6}'
echo ""
# Extract line coverage (% Lines, field $6) from the tests/ batch (first "All files" line)
LINES_COV=$(awk '/^All files/{print $6; exit}' coverage-output.txt)
echo "Primary line coverage (tests/ batch): $LINES_COV%"
# Check if coverage is below 38%
# Note: Threshold lowered from 40% to 38% when parallel execution was added.
# The tests/ batch doesn't exercise src/parallel/ code (which has its own tests
# in src/parallel/*.test.ts with 87-100% coverage). A better approach would be
# to use combined coverage from all batches.
if [ -z "$LINES_COV" ] || [ "$(echo "$LINES_COV < 38" | bc -l)" -eq 1 ]; then
echo "❌ Line coverage $LINES_COV% is below 38% threshold"
exit 1
fi
echo "✅ Line coverage $LINES_COV% meets 38% threshold"
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v4
with:
# Upload all batch coverage files - Codecov will merge them correctly
files: ./coverage-parts/tests.lcov,./coverage-parts/tests-info.lcov,./coverage-parts/doctor.lcov,./coverage-parts/info.lcov,./coverage-parts/skills.lcov,./coverage-parts/run.lcov,./coverage-parts/config.lcov,./coverage-parts/engine.lcov,./coverage-parts/beads-bv.lcov,./coverage-parts/beads-rust.lcov,./coverage-parts/beads.lcov,./coverage-parts/plugins.lcov,./coverage-parts/session.lcov,./coverage-parts/sandbox.lcov,./coverage-parts/wizard.lcov,./coverage-parts/setup.lcov,./coverage-parts/skill-installer-spawn.lcov,./coverage-parts/migration-install.lcov,./coverage-parts/templates.lcov,./coverage-parts/tui.lcov,./coverage-parts/prd.lcov,./coverage-parts/chat.lcov,./coverage-parts/parallel.lcov
fail_ci_if_error: false
verbose: true
env:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
# Determine which paths changed
changes:
runs-on: ubuntu-latest
outputs:
website: ${{ steps.filter.outputs.website }}
steps:
- uses: actions/checkout@v4
- uses: dorny/paths-filter@v3
id: filter
with:
filters: |
website:
- 'website/**'
website:
needs: changes
if: ${{ needs.changes.outputs.website == 'true' }}
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Bun
uses: oven-sh/setup-bun@v2
with:
bun-version: latest
- name: Clear TypeScript build cache
run: |
cd website
rm -rf node_modules/.cache
rm -rf .tsbuildinfo
- name: Install website dependencies
run: cd website && bun install
- name: Type check website
run: cd website && bun run typecheck
- name: Lint website
run: cd website && bun run lint
- name: Build website
run: cd website && bun run build