Skip to content

Merge pull request #1164 from charityagbenu12-cmd/fix/somzilla-issues #75

Merge pull request #1164 from charityagbenu12-cmd/fix/somzilla-issues

Merge pull request #1164 from charityagbenu12-cmd/fix/somzilla-issues #75

Workflow file for this run

name: Coverage
# Per-package coverage collection, minimum thresholds and a PR comment with the
# delta against the target branch (issue #1090).
on:
push:
branches: [main]
pull_request:
branches: [main, develop]
permissions:
contents: read
pull-requests: write
jobs:
# ── Per-package collection ────────────────────────────────────────────────
# Each package uploads its coverage-summary.json; the report job aggregates
# them. Failures here are the package's own threshold, checked by its test
# runner. `continue-on-error` keeps one package's gate from hiding another's
# numbers — the aggregate `--check` in the report job is the blocking gate.
backend:
name: Backend
runs-on: ubuntu-latest
continue-on-error: true
steps:
- uses: actions/checkout@v6
- uses: actions/setup-node@v6
with:
node-version: "20"
cache: "npm"
cache-dependency-path: backend/package-lock.json
- run: npm ci
working-directory: backend
- name: Run tests with coverage
working-directory: backend
env:
NODE_ENV: test
JWT_SECRET: test-secret
ADMIN_API_KEY: test-admin-key
run: npm test -- --coverage --ci
- uses: actions/upload-artifact@v7
if: always()
with:
name: coverage-backend
path: backend/coverage/coverage-summary.json
if-no-files-found: warn
client:
name: Client
runs-on: ubuntu-latest
continue-on-error: true
steps:
- uses: actions/checkout@v6
- uses: actions/setup-node@v6
with:
node-version: "20"
cache: "npm"
cache-dependency-path: client/package-lock.json
- run: npm ci
working-directory: client
- name: Run tests with coverage
working-directory: client
run: npm run test:coverage
- uses: actions/upload-artifact@v7
if: always()
with:
name: coverage-client
path: client/coverage/coverage-summary.json
if-no-files-found: warn
sdk:
name: SDK
runs-on: ubuntu-latest
continue-on-error: true
steps:
- uses: actions/checkout@v6
- uses: actions/setup-node@v6
with:
node-version: "23.4.0"
cache: "npm"
cache-dependency-path: sdk/package-lock.json
- run: npm ci
working-directory: sdk
- name: Run tests with coverage
working-directory: sdk
env:
NODE_OPTIONS: --experimental-vm-modules
run: npm test -- --ci --coverage
- uses: actions/upload-artifact@v7
if: always()
with:
name: coverage-sdk
path: sdk/coverage/coverage-summary.json
if-no-files-found: warn
contracts:
name: Contracts
runs-on: ubuntu-latest
continue-on-error: true
steps:
- uses: actions/checkout@v6
- uses: dtolnay/rust-toolchain@stable
with:
components: llvm-tools-preview
- uses: Swatinem/rust-cache@v2
with:
workspaces: contracts
- name: Install cargo-llvm-cov
uses: taiki-e/install-action@cargo-llvm-cov
- name: Run tests with coverage
working-directory: contracts
run: |
mkdir -p coverage
cargo llvm-cov --workspace --summary-only --json --output-path coverage/llvm-cov.json
# Reduce to a single line-coverage percentage for the aggregator.
node -e "
const data = require('./coverage/llvm-cov.json');
const lines = data.data[0].totals.lines;
require('fs').writeFileSync('coverage/lines.txt', String(lines.percent));
"
- uses: actions/upload-artifact@v7
if: always()
with:
name: coverage-contracts
path: contracts/coverage/lines.txt
if-no-files-found: warn
# ── Aggregate, gate and comment ───────────────────────────────────────────
report:
name: Coverage Report
runs-on: ubuntu-latest
needs: [backend, client, sdk, contracts]
if: always()
steps:
- uses: actions/checkout@v6
- uses: actions/setup-node@v6
with:
node-version: "20"
- name: Download coverage artifacts
uses: actions/download-artifact@v7
with:
pattern: coverage-*
path: artifacts
- name: Place summaries where the aggregator expects them
run: |
set -e
for pkg in backend client sdk; do
if [ -f "artifacts/coverage-$pkg/coverage-summary.json" ]; then
mkdir -p "$pkg/coverage"
cp "artifacts/coverage-$pkg/coverage-summary.json" "$pkg/coverage/"
fi
done
if [ -f "artifacts/coverage-contracts/lines.txt" ]; then
mkdir -p contracts/coverage
cp artifacts/coverage-contracts/lines.txt contracts/coverage/
fi
# The delta needs the target branch's numbers. Restore them from the
# cache written by the last run on that branch; absent a cache hit the
# report simply omits the delta column.
- name: Restore baseline coverage
if: github.event_name == 'pull_request'
uses: actions/cache/restore@v4
with:
path: coverage-baseline.json
key: coverage-baseline-${{ github.base_ref }}-${{ github.sha }}
restore-keys: |
coverage-baseline-${{ github.base_ref }}-
- name: Build report
run: |
node scripts/coverage-report.js \
--baseline coverage-baseline.json \
--out coverage-report.md \
--json coverage-current.json
cat coverage-report.md >> "$GITHUB_STEP_SUMMARY"
- name: Comment on PR
if: github.event_name == 'pull_request'
uses: actions/github-script@v7
with:
script: |
const fs = require('fs');
const body = fs.readFileSync('coverage-report.md', 'utf8')
+ '\n<!-- syncro-coverage-report -->';
const { owner, repo } = context.repo;
const issue_number = context.issue.number;
// Update the existing comment rather than adding one per push.
const comments = await github.paginate(
github.rest.issues.listComments, { owner, repo, issue_number });
const existing = comments.find((c) =>
c.user.type === 'Bot' && c.body.includes('<!-- syncro-coverage-report -->'));
if (existing) {
await github.rest.issues.updateComment({ owner, repo, comment_id: existing.id, body });
} else {
await github.rest.issues.createComment({ owner, repo, issue_number, body });
}
# Save this branch's numbers so PRs targeting it can compute a delta.
# The cached filename must match what the restore step expects.
- name: Save baseline coverage
if: github.event_name == 'push'
run: cp coverage-current.json coverage-baseline.json
- name: Cache baseline coverage
if: github.event_name == 'push'
uses: actions/cache/save@v4
with:
path: coverage-baseline.json
key: coverage-baseline-${{ github.ref_name }}-${{ github.sha }}
- name: Enforce minimum coverage
run: node scripts/coverage-report.js --check