Skip to content
Closed
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .githooks/install.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#!/bin/sh
#
# Sets up .githooks/ as the git hooks directory for this repository.
#
cd "$(git rev-parse --show-toplevel)" || exit 1
git config core.hooksPath .githooks
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[AUTOMATED]

Setting core.hooksPath silently disables existing git hooks (confidence: 97/100)

git config core.hooksPath .githooks causes Git to exclusively use .githooks/ for hook resolution, completely bypassing .git/hooks/. This means any hooks previously installed via .github/hooks/install.sh are silently disabled:

  • .github/hooks/pre-push (blocking): runs cargo fmt --check, cargo clippy -- -D warnings, and cargo test — these quality gates are lost
  • .github/hooks/commit-msg: enforces Angular conventional commit format — also lost

The new .githooks/pre-push does not chain to or invoke the old hooks, and .githooks/ has no commit-msg hook at all. A developer who previously had the old hooks installed and follows the README to install these new hooks will unknowingly lose their quality gates.

Suggested fix (pick one):

  1. Consolidate (recommended): Add the coverage logic to the existing .github/hooks/pre-push instead of creating a parallel hooks system.

  2. Chain hooks: Have .githooks/pre-push invoke the old hook first:

    OLD_HOOK="$(git rev-parse --show-toplevel)/.github/hooks/pre-push"
    if [ -x "$OLD_HOOK" ]; then
        "$OLD_HOOK" "$@" || exit $?
    fi

    And add a commit-msg passthrough in .githooks/ as well.

  3. At minimum: Warn the user in install.sh and the README that this replaces the default hooks directory.

Copy link
Copy Markdown
Contributor Author

@PanGan21 PanGan21 Mar 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since the existing githook for fmt and clippy seems broken I keep the existing directory and only warn the user about overriding.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added both hooks in the same directory and the developer has a choice to install one githook or both.

chmod +x .githooks/pre-push
echo "Git hooks installed: using .githooks/ directory"
87 changes: 87 additions & 0 deletions .githooks/pre-push
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
#!/bin/sh
#
# Pre-push hook: checks that a fresh coverage report exists
# when pushing coprocessor changes. Non-blocking (always exits 0).
#

# Preserve Git LFS functionality
command -v git-lfs >/dev/null 2>&1 && git lfs pre-push "$@"

# Get the repo root
REPO_ROOT=$(git rev-parse --show-toplevel)
REPORT_FILE="$REPO_ROOT/coprocessor/fhevm-engine/coverage-report.txt"
COPROCESSOR_DIR="coprocessor/fhevm-engine/"

# Determine the merge base to compare against (what's being pushed)
CURRENT_BRANCH=$(git rev-parse --abbrev-ref HEAD)
MERGE_BASE=$(git merge-base main HEAD 2>/dev/null || true)
if [ -z "$MERGE_BASE" ]; then
exit 0
fi

# Get files changed on this branch vs main, filtered to crate subdirectories only
# (ignores root-level config: Makefile, scripts/, Cargo.toml, etc.)
CRATE_CHANGES=$(git diff --name-only "$MERGE_BASE"...HEAD -- "$COPROCESSOR_DIR" 2>/dev/null | \
while read -r f; do
# Strip the coprocessor/fhevm-engine/ prefix
rel=$(echo "$f" | sed "s|^$COPROCESSOR_DIR||")
# Extract top-level directory name
crate_name=$(echo "$rel" | cut -d/ -f1)
# Only include if it's an actual crate (has Cargo.toml)
if [ -f "$REPO_ROOT/$COPROCESSOR_DIR$crate_name/Cargo.toml" ]; then
echo "$crate_name"
fi
done | sort -u)

if [ -z "$CRATE_CHANGES" ]; then
# No crate-level changes on this branch — nothing to check
exit 0
fi

# Get the timestamp of the latest crate-related commit on this branch
LAST_COMMIT_TIME=""
for crate in $CRATE_CHANGES; do
t=$(git log -1 --format=%ct "$MERGE_BASE"..HEAD -- "$COPROCESSOR_DIR$crate/" 2>/dev/null)
if [ -n "$t" ] && { [ -z "$LAST_COMMIT_TIME" ] || [ "$t" -gt "$LAST_COMMIT_TIME" ]; }; then
LAST_COMMIT_TIME="$t"
fi
done

if [ -z "$LAST_COMMIT_TIME" ]; then
exit 0
fi

# Check if coverage report exists
if [ ! -f "$REPORT_FILE" ]; then
echo ""
echo "WARNING: No coverage report found for coprocessor."
echo " Run 'make coverage-changed' in coprocessor/fhevm-engine/ to generate it."
echo ""
exit 0
fi

# Check report freshness: compare file mtime vs latest coprocessor commit time
# Handle both macOS (stat -f %m) and Linux (stat -c %Y)
if stat -f %m "$REPORT_FILE" >/dev/null 2>&1; then
REPORT_TIME=$(stat -f %m "$REPORT_FILE")
else
REPORT_TIME=$(stat -c %Y "$REPORT_FILE")
fi

if [ "$REPORT_TIME" -lt "$LAST_COMMIT_TIME" ]; then
echo ""
echo "WARNING: Coverage report is stale (generated before latest coprocessor commit)."
echo " Run 'make coverage' in coprocessor/fhevm-engine/ to regenerate."
echo ""
exit 0
fi

# Report is fresh — print summary
TOTAL_LINE=$(grep "^TOTAL" "$REPORT_FILE" 2>/dev/null)
if [ -n "$TOTAL_LINE" ]; then
echo ""
echo "Coverage: $TOTAL_LINE"
echo ""
fi

exit 0
7 changes: 7 additions & 0 deletions .githooks/uninstall.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#!/bin/sh
#
# Restores the default git hooks directory (.git/hooks/).
#
cd "$(git rev-parse --show-toplevel)" || exit 1
git config --unset core.hooksPath
echo "Git hooks uninstalled: reverted to default .git/hooks/ directory"
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -89,3 +89,6 @@ mochawesome-report/
#-------------------------------------------------------------------------------
# Build artifacts directory
target/

# Coverage reports (generated locally via `make coverage`)
coverage-report.txt
39 changes: 39 additions & 0 deletions coprocessor/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,45 @@ When using the `aws-kms` signer type, standard `AWS_*` environment variables are
- **AWS_SECRET_ACCESS_KEY** (i.e. password)
- etc.

## Code Coverage

### Setup (one-time)

Install the git hooks to enable pre-push coverage checks:

```bash
sh .githooks/install.sh
```

To uninstall and revert to the default `.git/hooks/` directory:

```bash
sh .githooks/uninstall.sh
```

### Running coverage locally

```bash
cd coprocessor/fhevm-engine

# Only cover crates you changed (auto-detects vs main branch)
make coverage-changed

# Cover a specific crate
make coverage-crate CRATE=host-listener

# Cover the full workspace
make coverage
```

All commands save the report to `coverage-report.txt`. If `fhevm-engine-common` is among the changed crates, `coverage-changed` automatically falls back to full workspace coverage since all crates depend on it.

**Prerequisites:** PostgreSQL and LocalStack must be running (same as for regular tests).

### Pre-push hook

When pushing changes that touch `coprocessor/fhevm-engine/`, the pre-push hook checks for a fresh `coverage-report.txt`. If the report is missing or older than your latest commit, it prints a warning reminding you to run `make coverage-changed`. The hook is **non-blocking** and will never prevent a push.

## Telemetry Style Guide (Tracing + OTEL)

Use `tracing` spans as the default telemetry API.
Expand Down
29 changes: 29 additions & 0 deletions coprocessor/fhevm-engine/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
.PHONY: coverage coverage-crate coverage-changed

# Run coverage for the full workspace
coverage:
cargo llvm-cov clean --workspace --profile coverage
DATABASE_URL=postgresql://postgres:postgres@localhost:5432/coprocessor \
TEST_GLOBAL_LOCALSTACK=1 \
cargo llvm-cov --no-report --workspace --profile coverage -- --test-threads=1
cargo llvm-cov report --profile coverage 2>&1 | tee coverage-report.txt
@echo ""
@echo "Coverage report saved to coverage-report.txt"
@tail -1 coverage-report.txt

# Run coverage for a specific crate
# Usage: make coverage-crate CRATE=host-listener
coverage-crate:
@test -n "$(CRATE)" || (echo "Usage: make coverage-crate CRATE=<crate-name>" && exit 1)
cargo llvm-cov clean --workspace --profile coverage
DATABASE_URL=postgresql://postgres:postgres@localhost:5432/coprocessor \
TEST_GLOBAL_LOCALSTACK=1 \
cargo llvm-cov --no-report --package $(CRATE) --profile coverage -- --test-threads=1
cargo llvm-cov report --profile coverage 2>&1 | tee coverage-report.txt
@echo ""
@echo "Coverage report saved to coverage-report.txt"
@tail -1 coverage-report.txt

# Auto-detect changed crates vs main and run coverage only for them
coverage-changed:
@sh scripts/coverage-changed.sh
91 changes: 91 additions & 0 deletions coprocessor/fhevm-engine/scripts/coverage-changed.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
#!/bin/sh
#
# Detect which workspace crates have changed vs main and run coverage
# only for those crates. If fhevm-engine-common changes, run all.
#
set -e

BASE_BRANCH="${BASE_BRANCH:-main}"
REPO_ROOT="$(git rev-parse --show-toplevel)"
ENGINE_DIR="$REPO_ROOT/coprocessor/fhevm-engine"

cd "$ENGINE_DIR"

# Get changed files relative to the engine directory
CHANGED_FILES=$(git diff --name-only "$BASE_BRANCH"...HEAD -- "$ENGINE_DIR" 2>/dev/null | \
sed "s|^coprocessor/fhevm-engine/||" || true)

if [ -z "$CHANGED_FILES" ]; then
# Fallback: compare working tree if no commits ahead
CHANGED_FILES=$(git diff --name-only "$BASE_BRANCH" -- "$ENGINE_DIR" 2>/dev/null | \
sed "s|^coprocessor/fhevm-engine/||" || true)
fi

if [ -z "$CHANGED_FILES" ]; then
echo "No changes detected vs $BASE_BRANCH. Nothing to cover."
exit 0
fi

# Extract unique crate names from changed file paths
# e.g. "host-listener/src/cmd/mod.rs" → "host-listener"
# Root-level files (Cargo.toml, etc.) don't match and are skipped
CHANGED_CRATES=$(echo "$CHANGED_FILES" | sed -n 's|^\([^/]*\)/.*|\1|p' | sort -u)

# Check for root-level changes that affect all crates (e.g. Cargo.lock)
# Cargo.toml profile/toolchain changes don't require full workspace coverage
ROOT_CRITICAL=$(echo "$CHANGED_FILES" | grep -v '/' | grep -v '\.toml$' || true)
if echo "$CHANGED_FILES" | grep -q '^Cargo\.lock$'; then
ROOT_CRITICAL="Cargo.lock"
fi
if [ -n "$ROOT_CRITICAL" ]; then
echo "Workspace config changed ($ROOT_CRITICAL) — running full workspace coverage."
echo ""
exec make coverage
fi

if [ -z "$CHANGED_CRATES" ]; then
echo "No crate-level changes detected. Nothing to cover."
exit 0
fi

echo "Changed crates:"
echo "$CHANGED_CRATES" | sed 's/^/ - /'
echo ""

# If fhevm-engine-common changed, run full workspace (all crates depend on it)
if echo "$CHANGED_CRATES" | grep -q "^fhevm-engine-common$"; then
echo "fhevm-engine-common changed — running full workspace coverage."
echo ""
exec make coverage
fi

# Build --package flags for each changed crate
PKG_FLAGS=""
for crate in $CHANGED_CRATES; do
# Skip non-crate directories (e.g. db-migration, scripts)
if [ -f "$crate/Cargo.toml" ]; then
PKG_FLAGS="$PKG_FLAGS --package $crate"
else
echo " Skipping $crate (not a Cargo crate)"
fi
done

if [ -z "$PKG_FLAGS" ]; then
echo "No Cargo crates changed. Nothing to cover."
exit 0
fi

echo "Running coverage for:$PKG_FLAGS"
echo ""

cargo llvm-cov clean --workspace --profile coverage

DATABASE_URL=postgresql://postgres:postgres@localhost:5432/coprocessor \
TEST_GLOBAL_LOCALSTACK=1 \
cargo llvm-cov --no-report $PKG_FLAGS --profile coverage -- --test-threads=1

cargo llvm-cov report --profile coverage 2>&1 | tee coverage-report.txt

echo ""
echo "Coverage report saved to coverage-report.txt"
tail -1 coverage-report.txt
Loading