diff --git a/.config/make/coverage.mak b/.config/make/coverage.mak new file mode 100644 index 0000000000..fbaec0ed32 --- /dev/null +++ b/.config/make/coverage.mak @@ -0,0 +1,59 @@ +## —— Coverage (cargo-llvm-cov) ---------------------------------------------------------------- +## +## Prerequisites: +## cargo install cargo-llvm-cov +## rustup component add llvm-tools-preview +## +## Doctests are not run under coverage (they require nightly). Use stable for unit/e2e coverage. +## Optional: use COVERAGE_OUTPUT_DIR to change report dir (default: target/coverage) +## +## Use BFD linker for coverage builds when available to avoid LLD duplicate-symbol +## errors with -C instrument-coverage (e.g. arrow_array/arrow_arith in datafusion). +## If ld.bfd is not found, no linker override is set (may hit duplicate symbol on LLD). +## Override: make coverage-unit COVERAGE_RUSTFLAGS="-C link-arg=-fuse-ld=bfd" + +COVERAGE_RUSTFLAGS_DEFAULT := $(shell command -v ld.bfd >/dev/null 2>&1 && echo '-C link-arg=-fuse-ld=bfd' || true) +COVERAGE_RUSTFLAGS ?= $(COVERAGE_RUSTFLAGS_DEFAULT) +COVERAGE_OUTPUT_DIR ?= target/coverage +COVERAGE_E2E_DIR := $(COVERAGE_OUTPUT_DIR)/e2e +## LCOV file for editor integration (Cursor/VS Code Coverage Gutters). Default: repo root. +COVERAGE_LCOV_PATH ?= lcov.info + +.PHONY: coverage-check +coverage-check: ## Verify cargo-llvm-cov and llvm-tools are available + @cargo llvm-cov --version >/dev/null 2>&1 || (echo "Install: cargo install cargo-llvm-cov && rustup component add llvm-tools-preview"; exit 1) + +.PHONY: coverage-deps +coverage-deps: ## Install cargo-llvm-cov and llvm-tools-preview if missing + @command -v cargo >/dev/null 2>&1 || (echo "cargo not found. Ensure Rust is installed and in PATH."; exit 1) + @cargo llvm-cov --version >/dev/null 2>&1 || \ + (echo "Installing coverage tools..."; cargo install cargo-llvm-cov && rustup component add llvm-tools-preview) + @cargo llvm-cov --version >/dev/null 2>&1 || (echo "Install failed. Run: cargo install cargo-llvm-cov && rustup component add llvm-tools-preview"; exit 1) + +.PHONY: coverage-unit +coverage-unit: coverage-deps ## Run unit/integration tests with coverage (excludes e2e_test) + @echo "📊 Running unit/integration coverage..." + export RUSTFLAGS="$(COVERAGE_RUSTFLAGS)" && \ + cargo llvm-cov test --workspace --exclude e2e_test --no-fail-fast --no-report + export RUSTFLAGS="$(COVERAGE_RUSTFLAGS)" && \ + cargo llvm-cov report --lcov --output-path "$(COVERAGE_LCOV_PATH)" + @echo "📄 LCOV (editor): $(COVERAGE_LCOV_PATH)" + +.PHONY: coverage-e2e +coverage-e2e: coverage-deps ## Run e2e tests with coverage (e2e_test crate only) + @echo "📊 Running e2e coverage..." + @mkdir -p "$(COVERAGE_E2E_DIR)" + export RUSTFLAGS="$(COVERAGE_RUSTFLAGS)" && \ + cargo llvm-cov test -p e2e_test --no-fail-fast --no-report + export RUSTFLAGS="$(COVERAGE_RUSTFLAGS)" && \ + cargo llvm-cov report -p e2e_test --lcov --output-path "$(COVERAGE_E2E_DIR)/lcov.info" + @echo "📄 LCOV: $(COVERAGE_E2E_DIR)/lcov.info" + +.PHONY: coverage-combined +coverage-combined: coverage-deps ## Run all tests (unit + e2e) with a single combined coverage report + @echo "📊 Running combined coverage (unit + e2e)..." + export RUSTFLAGS="$(COVERAGE_RUSTFLAGS)" && \ + cargo llvm-cov test --workspace --no-fail-fast --no-report + export RUSTFLAGS="$(COVERAGE_RUSTFLAGS)" && \ + cargo llvm-cov report --lcov --output-path "$(COVERAGE_LCOV_PATH)" + @echo "📄 LCOV (editor): $(COVERAGE_LCOV_PATH)" diff --git a/.gitignore b/.gitignore index e54161a48b..bbf59e5b77 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ /target +lcov.info .DS_Store .idea .vscode diff --git a/Makefile b/Makefile index 42c9949cd3..bf7dd77dfc 100644 --- a/Makefile +++ b/Makefile @@ -68,6 +68,16 @@ How to use me: make test # Run tests make pre-commit # Run all pre-commit checks + 📚 Documentation: + make doc # Generate Rust API docs (target/doc) + make doc-serve # Serve docs at http://127.0.0.1:8765/ (links work) + make doc-open # Generate docs, serve, and open in browser + + 📊 Coverage (requires: cargo install cargo-llvm-cov; rustup component add llvm-tools-preview): + make coverage-unit # Unit/integration coverage (excludes e2e_test) + make coverage-e2e # E2E coverage (e2e_test crate) + make coverage-combined # All tests, single combined report + 🚀 Quick Start: make build # Build RustFS binary make docker-dev-local # Build development Docker image (local) diff --git a/doc/development.md b/doc/development.md new file mode 100644 index 0000000000..59e7d1ba52 --- /dev/null +++ b/doc/development.md @@ -0,0 +1,88 @@ +# Development Guide + +This page covers building, testing, and running quality checks for RustFS. For code formatting rules and PR expectations, see [CONTRIBUTING.md](../CONTRIBUTING.md). + +## Prerequisites + +- Rust (see root [Cargo.toml](../Cargo.toml) `rust-version`) +- For full quality gates: `make` (see [.config/make/](../.config/make/) and root [Makefile](../Makefile)) + +## Build + +```bash +# Build the RustFS binary +make build +# or +cargo build --release +``` + +## Testing + +```bash +# Run tests +make test +# or +cargo test --all-targets +``` + +## Code Quality (Mandatory Before Commit) + +Run all pre-commit checks: + +```bash +make pre-commit +``` + +If `make` is unavailable, run the equivalent steps from [.config/make/](../.config/make/). Typical steps: + +- Format: `cargo fmt --all` and `cargo fmt --all --check` +- Lint: `cargo clippy --all-targets --all-features -- -D warnings` +- Check: `cargo check --all-targets` +- Tests: `cargo test --all-targets` + +See [CONTRIBUTING.md](../CONTRIBUTING.md) for detailed formatting and clippy rules. + +## Make Targets + +- `make help` — Main help and categories +- `make help-build` — Build-related targets +- `make help-docker` — Docker and image targets +- `make fmt` / `make fmt-check` — Format and verify +- `make clippy` — Clippy +- `make check` — Compilation check +- `make test` — Tests +- `make pre-commit` — All checks required before commit +- `make doc` — Generate Rust API documentation (HTML in `target/doc`) +- `make doc-serve` — Generate docs and serve at http://127.0.0.1:8765/ (all links work; Ctrl+C to stop) +- `make doc-open` — Generate docs, start local server, and open browser (use this so cross-crate links work) + +## Coverage + +Coverage uses `cargo-llvm-cov`. Install once: + +```bash +cargo install cargo-llvm-cov +rustup component add llvm-tools-preview +``` + +Then run: + +- `make coverage-unit` — Unit and integration tests (all crates except `e2e_test`). Writes LCOV to `lcov.info` (repo root). +- `make coverage-e2e` — E2E tests only (`e2e_test` crate). Writes LCOV to `target/coverage/e2e/lcov.info`. +- `make coverage-combined` — All tests in one run. Writes LCOV to `lcov.info` (repo root). + +Use the LCOV file in Cursor or VS Code with a coverage extension (e.g. Coverage Gutters) for inline coverage; the extension looks for `lcov.info` in the workspace by default. Override the path with `COVERAGE_LCOV_PATH`, or for e2e use `COVERAGE_OUTPUT_DIR`. + +Doctests are not included in coverage (they require the nightly toolchain). + +Coverage builds use the BFD linker (`-fuse-ld=bfd`) by default to avoid LLD duplicate-symbol errors with `-C instrument-coverage` (e.g. with datafusion/arrow deps). This requires binutils (e.g. `ld.bfd`) on the system. To use another linker, set `COVERAGE_RUSTFLAGS` when invoking the target, e.g. `make coverage-unit COVERAGE_RUSTFLAGS=`. + +## CI + +Quality gates are defined in [.github/workflows/ci.yml](../.github/workflows/ci.yml). Keep local checks aligned with CI so `make pre-commit` matches what runs on the branch. + +## Branch and PR Baseline + +- Use feature branches from latest `main`. +- Follow [Conventional Commits](https://www.conventionalcommits.org/), subject ≤ 72 characters. +- Use [.github/pull_request_template.md](../.github/pull_request_template.md) for PRs; use `N/A` for non-applicable sections.