From ed944cc23bcaf02bc6a2c9347c54de2149cea572 Mon Sep 17 00:00:00 2001 From: Zahary Karadjov Date: Thu, 5 Jun 2025 17:48:54 +0300 Subject: [PATCH] feat: better linting commands and pre-commit hooks Additions: * Many just targets for formatting, linting and fixing issues * The pre-commit hooks now show helpful error messages with guidance when they fail --- .github/CONTRIBUTING.md | 178 ++++++++++++++++++++++++- .github/SETUP.md | 47 +++++++ Justfile | 113 ++++++++++++++++ libs/sdk/wit/deps/filesystem/types.wit | 8 +- libs/sdk/wit/deps/sockets/tcp.wit | 6 +- libs/sdk/wit/deps/sockets/udp.wit | 12 +- nix/shells/pkg-sets/pre-commit.nix | 91 ++++++++++--- scripts/clippy-with-help.sh | 31 +++++ scripts/deadnix-with-help.sh | 31 +++++ scripts/editorconfig-with-help.sh | 35 +++++ scripts/statix-with-help.sh | 31 +++++ 11 files changed, 545 insertions(+), 38 deletions(-) create mode 100755 scripts/clippy-with-help.sh create mode 100755 scripts/deadnix-with-help.sh create mode 100755 scripts/editorconfig-with-help.sh create mode 100755 scripts/statix-with-help.sh diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 562af6aec6..213e33994b 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -112,15 +112,151 @@ Please see our [security policy](/.github/SECURITY.md). --- -### ๐Ÿ’พ Formatting & Saving Code Before Commit +## ๐Ÿ’พ Formatting & Saving Code Before Commit -Before committing, **format your code** using: +### ๐Ÿ“ Editor Configuration -**yarn format:write** +1. **Install EditorConfig plugin** for your editor +2. **Configure your editor** to: + - Use spaces (not tabs) for indentation + - Trim trailing whitespace on save + - Ensure files end with a newline + - Use LF line endings (not CRLF) + +### Recommended VS Code Extensions + +- EditorConfig for VS Code +- Prettier - Code formatter +- rust-analyzer +- Nix IDE + +### ๐Ÿ”ง Pre-commit Hooks + +This project uses pre-commit hooks to maintain code quality and consistency. When you make a commit, several tools automatically check your code: + +#### Enabled Tools + +| Tool | Purpose | Files Checked | +| ---------------- | -------------------------- | -------------------------------- | +| **Prettier** | Code formatting | TypeScript, JavaScript, Markdown | +| **Rustfmt** | Code formatting | Rust files (\*.rs) | +| **Nixfmt** | Code formatting | Nix files (\*.nix) | +| **Clippy** | Rust linting | Rust files (\*.rs) | +| **Statix** | Nix linting | Nix files (\*.nix) | +| **Deadnix** | Dead code detection | Nix files (\*.nix) | +| **EditorConfig** | Consistent editor settings | All files | + +#### When Hooks Fail + +Pre-commit hooks behave differently depending on their purpose: + +##### ๐Ÿ”ง Auto-Fixing Hooks (Fix and Reject) + +These hooks automatically fix issues but reject the commit so you can review changes: + +| Hook | What it fixes | Next steps | +| ------------ | ------------------------- | --------------------------------------------------------- | +| **Prettier** | JS/TS/Markdown formatting | Review with `git diff`, then `git add .` and commit again | +| **Rustfmt** | Rust code formatting | Review with `git diff`, then `git add .` and commit again | +| **Nixfmt** | Nix code formatting | Review with `git diff`, then `git add .` and commit again | + +##### โŒ Check-Only Hooks (Reject Only) + +These hooks only check and reject commits - you must fix issues manually: + +| Hook | What it checks | How to fix | +| ---------------- | --------------------------- | ------------------------------------------------ | +| **Clippy** | Rust code quality | `just fix-lint-rust` (auto-fixes some issues) | +| **Statix** | Nix best practices | `just fix-lint-nix` (auto-fixes most issues) | +| **Deadnix** | Unused Nix code | `just fix-lint-nix-deadcode` (removes dead code) | +| **EditorConfig** | File formatting consistency | Manual fixes for whitespace, line endings, etc. | + +### Quick Fixes Through the Lint Tool Itself + +```bash +# After auto-fixing hooks (prettier, rustfmt, nixfmt): +git diff # Review the automatic changes +git add . # Stage the fixes +git commit # Try committing again + +# After check-only hooks (clippy, statix, deadnix): +just fix-lint-rust # Fix Clippy issues (auto-fixable ones) +just fix-lint-nix # Fix Statix issues +just fix-lint-nix-deadcode # Remove dead Nix code + +# For EditorConfig issues: +just check-editorconfig # See specific violations +# Then manually fix whitespace, line endings, etc. +``` + +### Composite Commands + +```bash +# Fix all formatting at once +just format + +# Fix all linting at once +just lint-fix + +# Fix everything +just fix-all + +# Check everything (without fixes) +just check-all +``` + +### Manual Hook Management + +```bash +# Run hooks manually on all files +pre-commit run --all-files + +# Run specific hook +pre-commit run prettier --all-files + +# Skip hooks for a commit (use sparingly) +git commit --no-verify +``` + +### ๐Ÿ” Code Quality Commands + +#### Formatting + +| Command | Description | +| ------------------ | ------------------------------------- | +| `just format` | Format all code (JS/TS, Rust, Nix) | +| `just format-js` | Format JavaScript/TypeScript/Markdown | +| `just format-rust` | Format Rust code | +| `just format-nix` | Format Nix code | + +#### Linting + +| Command | Description | +| ------------------------ | ---------------------------- | +| `just lint` | Run all linters (check only) | +| `just lint-rust` | Run Clippy on Rust code | +| `just lint-nix` | Run Statix on Nix code | +| `just lint-nix-deadcode` | Check for dead Nix code | + +#### Linting with Fixes + +| Command | Description | +| ---------------------------- | ------------------------------- | +| `just lint-fix` | Run all linters with auto-fixes | +| `just fix-lint-rust` | Fix Rust issues with Clippy | +| `just fix-lint-nix` | Fix Nix issues with Statix | +| `just fix-lint-nix-deadcode` | Remove dead Nix code | + +#### Combined Commands + +| Command | Description | +| ---------------- | ------------------------------------ | +| `just check-all` | Run all checks without fixes | +| `just fix-all` | Run all formatting and linting fixes | --- -### โœจ Commit Messages +## โœจ Commit Messages ``` : @@ -154,7 +290,7 @@ Before committing, **format your code** using: - Must be parse-able by git interpret-trailers - BREAKING CHANGE: - needed for commits -#### Commit Types +### Commit Types - feat (_feature_) - Add new user-facing functionality or update a public API. - If the commit changes a library (and so its users are developers, not actual end-users), feat relates to its public API @@ -211,4 +347,36 @@ Before committing, **format your code** using: Whenever you're stuck or do not know how to proceed, you can always ask for help. We invite you to use our [public Discord](https://discord.gg/b3xmcWs4Qp) to ask questions. +## ๐Ÿ› Troubleshooting + +### Common Issues + +#### Pre-commit hooks taking too long + +```bash +# Clear pre-commit cache +pre-commit clean +pre-commit install +``` + +#### Nix development shell issues + +```bash +# Reload the environment +direnv reload + +# Force rebuild +nix develop --rebuild +``` + +#### Cargo/Rust build issues + +```bash +# Clean build artifacts +cargo clean + +# Update dependencies +cargo update +``` + ## [Git Tips & Tricks](./GITTIPS.md) diff --git a/.github/SETUP.md b/.github/SETUP.md index f98cc1aed6..e63ad30c25 100644 --- a/.github/SETUP.md +++ b/.github/SETUP.md @@ -17,6 +17,53 @@ direnv allow --- +## ๐Ÿš€ Development Workflow + +### Building and Testing + +```bash +# Build TypeScript packages +just build-ts + +# Test TypeScript packages +just test-ts + +# Build Rust workspace +cargo build --release + +# Build the full Blocksense system +just build-blocksense + +# Start the system +just start-blocksense +``` + +### Oracle Development + +```bash +# Build a specific oracle +just build-oracle crypto-price-feeds + +# Start an oracle with hot reload +just start-oracle crypto-price-feeds +``` + +### Working with Smart Contracts + +```bash +# Navigate to contracts directory +cd libs/ts/contracts + +# Compile contracts +yarn hardhat compile + +# Run tests +yarn hardhat test + +# Deploy to a network +yarn hardhat run scripts/deploy.ts --network +``` + # โšก Running the System ## โœ… Supported Deployment Options diff --git a/Justfile b/Justfile index f301d5b3da..c5fb4ed1f9 100644 --- a/Justfile +++ b/Justfile @@ -56,3 +56,116 @@ clean: -e .vscode \ -e .pre-commit-config.yaml \ -- {{root-dir}} + +# === FORMATTING COMMANDS === + +format-js: + #!/usr/bin/env bash + set -euo pipefail + echo "๐Ÿ“ Formatting TypeScript/JavaScript/Markdown files..." + yarn prettier --write . + +format-rust: + #!/usr/bin/env bash + set -euo pipefail + echo "๐Ÿฆ€ Formatting Rust files..." + cargo fmt + +format-nix: + #!/usr/bin/env bash + set -euo pipefail + echo "โ„๏ธ Formatting Nix files..." + nix fmt + +format: + #!/usr/bin/env bash + set -euo pipefail + echo "๐Ÿ”ง Running all formatters..." + just format-js + just format-rust + just format-nix + echo "โœ… All formatting complete!" + +# === LINTING COMMANDS === + +lint-rust: + #!/usr/bin/env bash + set -euo pipefail + echo "๐Ÿฆ€ Running Clippy (Rust linter)..." + cargo clippy --all-targets --all-features + +lint-nix: + #!/usr/bin/env bash + set -euo pipefail + echo "โ„๏ธ Running Statix (Nix linter)..." + statix check . + +lint-nix-deadcode: + #!/usr/bin/env bash + set -euo pipefail + echo "๐Ÿงน Checking for dead Nix code..." + deadnix . + +lint: + #!/usr/bin/env bash + set -euo pipefail + echo "๐Ÿ” Running all linters..." + just lint-rust + just lint-nix + just lint-nix-deadcode + echo "โœ… All linting complete!" + +# === LINTING FIX COMMANDS === + +fix-lint-rust: + #!/usr/bin/env bash + set -euo pipefail + echo "๐Ÿฆ€ Running Clippy with fixes..." + cargo clippy --fix --allow-dirty --allow-staged + +fix-lint-nix: + #!/usr/bin/env bash + set -euo pipefail + echo "โ„๏ธ Running Statix fixes..." + statix fix . + +fix-lint-nix-deadcode: + #!/usr/bin/env bash + set -euo pipefail + echo "๐Ÿงน Running Deadnix cleanup..." + deadnix --edit . + +lint-fix: + #!/usr/bin/env bash + set -euo pipefail + echo "๐Ÿ” Running linters with auto-fix..." + just fix-lint-rust + just fix-lint-nix + just fix-lint-nix-deadcode + echo "โœ… All linting fixes complete!" + +# === EDITORCONFIG === + +check-editorconfig: + #!/usr/bin/env bash + set -euo pipefail + echo "โš™๏ธ Checking EditorConfig compliance..." + editorconfig-checker + +# === COMBINED COMMANDS === + +check-all: + #!/usr/bin/env bash + set -euo pipefail + echo "๐Ÿ” Running all checks (formatting + linting + editorconfig)..." + just lint + just check-editorconfig + echo "โœ… All checks complete!" + +fix-all: + #!/usr/bin/env bash + set -euo pipefail + echo "๐Ÿ”ง Running all fixes (formatting + linting)..." + just format + just lint-fix + echo "โœ… All fixes complete!" diff --git a/libs/sdk/wit/deps/filesystem/types.wit b/libs/sdk/wit/deps/filesystem/types.wit index 11108fcda2..120724af05 100644 --- a/libs/sdk/wit/deps/filesystem/types.wit +++ b/libs/sdk/wit/deps/filesystem/types.wit @@ -272,10 +272,10 @@ interface types { /// A 128-bit hash value, split into parts because wasm doesn't have a /// 128-bit integer type. record metadata-hash-value { - /// 64 bits of a 128-bit hash value. - lower: u64, - /// Another 64 bits of a 128-bit hash value. - upper: u64, + /// 64 bits of a 128-bit hash value. + lower: u64, + /// Another 64 bits of a 128-bit hash value. + upper: u64, } /// A descriptor is a reference to a filesystem object, which may be a file, diff --git a/libs/sdk/wit/deps/sockets/tcp.wit b/libs/sdk/wit/deps/sockets/tcp.wit index 5902b9ee05..63627e40ed 100644 --- a/libs/sdk/wit/deps/sockets/tcp.wit +++ b/libs/sdk/wit/deps/sockets/tcp.wit @@ -15,7 +15,7 @@ interface tcp { /// Similar to `SHUT_RDWR` in POSIX. both, } - + /// A TCP socket resource. /// /// The socket can be in one of the following states: @@ -59,10 +59,10 @@ interface tcp { /// - `address-not-bindable`: `local-address` is not an address that the `network` can bind to. (EADDRNOTAVAIL) /// - `not-in-progress`: A `bind` operation is not in progress. /// - `would-block`: Can't finish the operation, it is still in progress. (EWOULDBLOCK, EAGAIN) - /// + /// /// # Implementors note /// When binding to a non-zero port, this bind operation shouldn't be affected by the TIME_WAIT - /// state of a recently closed socket on the same local address. In practice this means that the SO_REUSEADDR + /// state of a recently closed socket on the same local address. In practice this means that the SO_REUSEADDR /// socket option should be set implicitly on all platforms, except on Windows where this is the default behavior /// and SO_REUSEADDR performs something different entirely. /// diff --git a/libs/sdk/wit/deps/sockets/udp.wit b/libs/sdk/wit/deps/sockets/udp.wit index d987a0a908..48722faa15 100644 --- a/libs/sdk/wit/deps/sockets/udp.wit +++ b/libs/sdk/wit/deps/sockets/udp.wit @@ -6,7 +6,7 @@ interface udp { /// A received datagram. record incoming-datagram { /// The payload. - /// + /// /// Theoretical max size: ~64 KiB. In practice, typically less than 1500 bytes. data: list, @@ -79,7 +79,7 @@ interface udp { /// This method may be called multiple times on the same socket to change its association, but /// only the most recently returned pair of streams will be operational. Implementations may trap if /// the streams returned by a previous invocation haven't been dropped yet before calling `stream` again. - /// + /// /// The POSIX equivalent in pseudo-code is: /// ```text /// if (was previously connected) { @@ -91,7 +91,7 @@ interface udp { /// ``` /// /// Unlike in POSIX, the socket must already be explicitly bound. - /// + /// /// # Typical errors /// - `invalid-argument`: The `remote-address` has the wrong address family. (EAFNOSUPPORT) /// - `invalid-argument`: The IP address in `remote-address` is set to INADDR_ANY (`0.0.0.0` / `::`). (EDESTADDRREQ, EADDRNOTAVAIL) @@ -115,7 +115,7 @@ interface udp { /// > stored in the object pointed to by `address` is unspecified. /// /// WASI is stricter and requires `local-address` to return `invalid-state` when the socket hasn't been bound yet. - /// + /// /// # Typical errors /// - `invalid-state`: The socket is not bound to any local address. /// @@ -217,7 +217,7 @@ interface udp { /// When this function returns ok(0), the `subscribe` pollable will /// become ready when this function will report at least ok(1), or an /// error. - /// + /// /// Never returns `would-block`. check-send: func() -> result; @@ -256,7 +256,7 @@ interface udp { /// - /// - send: func(datagrams: list) -> result; - + /// Create a `pollable` which will resolve once the stream is ready to send again. /// /// Note: this function is here for WASI Preview2 only. diff --git a/nix/shells/pkg-sets/pre-commit.nix b/nix/shells/pkg-sets/pre-commit.nix index 85ffc254fd..5bada09e63 100644 --- a/nix/shells/pkg-sets/pre-commit.nix +++ b/nix/shells/pkg-sets/pre-commit.nix @@ -1,13 +1,25 @@ -{ self', ... }: { - # Libraries used when cargo-check builds libraries - packages = self'.legacyPackages.commonLibDeps; + self', + pkgs, + ... +}: +{ + # Libraries used when cargo-check builds libraries plus linting tools + packages = self'.legacyPackages.commonLibDeps ++ [ + pkgs.statix + pkgs.deadnix + pkgs.editorconfig-checker + ]; pre-commit.hooks = { - nixfmt-rfc-style.enable = true; - editorconfig-checker = { - excludes = [ "libs/sdk/wit/deps" ]; + nixfmt-rfc-style = { enable = true; + verbose = true; + # Show specific help when this hook fails + fail_fast = false; + }; + editorconfig-checker = { + enable = false; # Disable built-in, use custom below }; rustfmt = { enable = true; @@ -15,29 +27,22 @@ cargo = self'.legacyPackages.rustToolchain; rustfmt = self'.legacyPackages.rustToolchain; }; + verbose = true; + fail_fast = false; }; clippy = { - enable = true; - packageOverrides = { - cargo = self'.legacyPackages.cargoWrapped; - clippy = self'.legacyPackages.rustToolchain; - }; - - settings = { - allFeatures = true; - denyWarnings = true; - extraArgs = "--tests"; - offline = false; - }; + enable = false; # Disable built-in, use custom below }; statix = { - enable = true; + enable = false; # Disable built-in, use custom below }; deadnix = { - enable = true; + enable = false; # Disable built-in, use custom below }; prettier = { enable = true; + verbose = true; + fail_fast = false; args = [ "--check" "--list-different=false" @@ -46,5 +51,51 @@ "--write" ]; }; + + # Custom hooks with helpful error messages + clippy-with-help = { + enable = true; + name = "Clippy (Rust linter)"; + entry = "./scripts/clippy-with-help.sh"; + language = "system"; + types = [ "rust" ]; + pass_filenames = false; + verbose = true; + fail_fast = false; + }; + + statix-with-help = { + enable = true; + name = "Statix (Nix linter)"; + entry = "./scripts/statix-with-help.sh"; + language = "system"; + types = [ "nix" ]; + pass_filenames = false; + verbose = true; + fail_fast = false; + }; + + deadnix-with-help = { + enable = true; + name = "Deadnix (dead Nix code)"; + entry = "./scripts/deadnix-with-help.sh"; + language = "system"; + types = [ "nix" ]; + pass_filenames = false; + verbose = true; + fail_fast = false; + }; + + editorconfig-with-help = { + enable = true; + name = "EditorConfig compliance"; + entry = "./scripts/editorconfig-with-help.sh"; + language = "system"; + types = [ "text" ]; + pass_filenames = false; + verbose = true; + fail_fast = false; + excludes = [ "libs/sdk/wit/deps" ]; + }; }; } diff --git a/scripts/clippy-with-help.sh b/scripts/clippy-with-help.sh new file mode 100755 index 0000000000..fc6697d626 --- /dev/null +++ b/scripts/clippy-with-help.sh @@ -0,0 +1,31 @@ +#!/usr/bin/env bash +# Wrapper for clippy that provides helpful error messages on failure + +set -euo pipefail + +echo "๐Ÿฆ€ Running Clippy (Rust linter)..." + +# Run clippy and capture both exit code and output +if cargo clippy --all-targets --all-features --tests -- -D warnings; then + echo "โœ… Clippy passed!" + exit 0 +else + exit_code=$? + echo "" + echo "โŒ Clippy (Rust linting) failed!" + echo "" + echo "๐Ÿ”ง The commit was rejected due to Rust code issues." + echo "" + echo "๐Ÿ” To fix the issues:" + echo " just fix-lint-rust # Auto-fix what's possible" + echo "" + echo "๐Ÿ“ Manual review may be needed:" + echo " just lint-rust # See all issues" + echo " cargo clippy --tests # Run clippy directly" + echo "" + echo "๐Ÿ’ก Some Clippy issues require manual fixes (logic, performance, style)." + echo "" + echo "๐Ÿ’ก TIP: Run 'just --list' to see all available commands" + echo "" + exit $exit_code +fi diff --git a/scripts/deadnix-with-help.sh b/scripts/deadnix-with-help.sh new file mode 100755 index 0000000000..87fad89e57 --- /dev/null +++ b/scripts/deadnix-with-help.sh @@ -0,0 +1,31 @@ +#!/usr/bin/env bash +# Wrapper for deadnix that provides helpful error messages on failure + +set -euo pipefail + +echo "๐Ÿงน Running Deadnix (dead Nix code detection)..." + +# Run deadnix and capture both exit code and output +if deadnix --fail .; then + echo "โœ… Deadnix passed!" + exit 0 +else + exit_code=$? + echo "" + echo "โŒ Deadnix (dead Nix code detection) failed!" + echo "" + echo "๐Ÿ”ง The commit was rejected due to unused Nix code." + echo "" + echo "๐Ÿ” To fix the issues:" + echo " just fix-lint-nix-deadcode # Remove dead code automatically" + echo "" + echo "๐Ÿ“ Check what was found:" + echo " just lint-nix-deadcode # See unused code" + echo " deadnix . # Run deadnix directly" + echo "" + echo "๐Ÿ’ก Deadnix finds unused variable bindings and imports in Nix files." + echo "" + echo "๐Ÿ’ก TIP: Run 'just --list' to see all available commands" + echo "" + exit $exit_code +fi diff --git a/scripts/editorconfig-with-help.sh b/scripts/editorconfig-with-help.sh new file mode 100755 index 0000000000..95f66185cf --- /dev/null +++ b/scripts/editorconfig-with-help.sh @@ -0,0 +1,35 @@ +#!/usr/bin/env bash +# Wrapper for editorconfig-checker that provides helpful error messages on failure + +set -euo pipefail + +echo "โš™๏ธ Running EditorConfig checker..." + +# Run editorconfig-checker and capture both exit code and output +if editorconfig-checker; then + echo "โœ… EditorConfig passed!" + exit 0 +else + exit_code=$? + echo "" + echo "โŒ EditorConfig compliance failed!" + echo "" + echo "๐Ÿ”ง The commit was rejected due to formatting inconsistencies." + echo "" + echo "๐Ÿ” Common issues and manual fixes:" + echo " โ€ข Trailing whitespace: Remove spaces at end of lines" + echo " โ€ข Wrong line endings: Ensure LF (not CRLF) line endings" + echo " โ€ข Tabs vs spaces: Use spaces for indentation" + echo " โ€ข Missing final newline: Add newline at end of files" + echo "" + echo "๐Ÿ” Check specific issues:" + echo " just check-editorconfig" + echo "" + echo "โš™๏ธ Prevention:" + echo " โ€ข Install EditorConfig plugin in your editor" + echo " โ€ข Configure editor to trim trailing whitespace on save" + echo "" + echo "๐Ÿ’ก TIP: Run 'just --list' to see all available commands" + echo "" + exit $exit_code +fi diff --git a/scripts/statix-with-help.sh b/scripts/statix-with-help.sh new file mode 100755 index 0000000000..9f2ce3a902 --- /dev/null +++ b/scripts/statix-with-help.sh @@ -0,0 +1,31 @@ +#!/usr/bin/env bash +# Wrapper for statix that provides helpful error messages on failure + +set -euo pipefail + +echo "โ„๏ธ Running Statix (Nix linter)..." + +# Run statix and capture both exit code and output +if statix check .; then + echo "โœ… Statix passed!" + exit 0 +else + exit_code=$? + echo "" + echo "โŒ Statix (Nix linting) failed!" + echo "" + echo "๐Ÿ”ง The commit was rejected due to Nix code issues." + echo "" + echo "๐Ÿ” To fix the issues:" + echo " just fix-lint-nix # Auto-fix most issues" + echo "" + echo "๐Ÿ“ Check what was found:" + echo " just lint-nix # See all issues" + echo " statix check . # Run statix directly" + echo "" + echo "๐Ÿ’ก Statix checks for deprecated patterns and best practices in Nix." + echo "" + echo "๐Ÿ’ก TIP: Run 'just --list' to see all available commands" + echo "" + exit $exit_code +fi