wherror 2.4.0

The same derive(Error) macro thiserror provides + the features you want!
Documentation
set positional-arguments
set quiet

# List all just recipes
list:
    just --list

# Run cargo semver-checks against the public API.
semver-checks:
    which cargo-semver-checks 2>&1 >/dev/null || cargo binstall -y cargo-semver-checks || cargo install --locked cargo-semver-checks
    cargo semver-checks check-release

# Generate README.md from lib.rs
readme watch="":
    #!/usr/bin/env bash
    set -euo pipefail
    which cargo-readme || cargo binstall cargo-readme
    if [ "{{watch}}" == "--watch" ]; then
        watchexec --exts rs -- cargo readme --output README.md
    else
        cargo readme --output README.md
    fi

# Serve and watch documentation
docs:
    cargo doc --open
    watchexec --exts rs -- cargo doc

# Fail loudly if the nightly toolchain is missing
require-nightly:
    #!/usr/bin/env bash
    set -euo pipefail
    if ! rustup toolchain list | grep -q '^nightly-'; then
        echo "❌ The UI tests require the nightly toolchain, which is not installed."
        echo "   Install it with: rustup toolchain install nightly"
        exit 1
    fi

# Run the UI tests (expected compiler output only matches nightly)
ui: require-nightly
    cargo +nightly test --test compiletest

# Verify the library (not tests) still compiles at the declared MSRV
msrv-check:
    #!/usr/bin/env bash
    set -euo pipefail
    MSRV=$(grep '^rust-version = ' Cargo.toml | head -1 | sed 's/rust-version = "\(.*\)"/\1/')
    if ! rustup toolchain list | grep -q "^$MSRV"; then
        echo "📦 Installing MSRV toolchain $MSRV..."
        rustup toolchain install "$MSRV"
    fi
    echo "🔍 Checking MSRV (rust-version = $MSRV)..."
    cargo "+$MSRV" check -p wherror -p wherror-impl

# Bless (re-generate .stderr files for UI tests)
bless: require-nightly
    TRYBUILD=overwrite cargo +nightly test --test compiletest

# Run the nightly-only tests (backtrace / error_generic_member_access)
test-nightly: require-nightly
    env RUSTFLAGS="--cfg=thiserror_nightly_testing" cargo +nightly test --workspace --exclude wherror_no_std_test

# Run tests
test *args: ui
    cargo test "{{ args }}"

# Run clippy and cargo fmt
fix:
    cargo clippy --fix --allow-dirty --allow-staged -- -D warnings
    cargo fmt --all

# Publish workspace to crates.io
publish *args: preflight
    cargo +nightly publish -Z package-workspace --package wherror-impl --package wherror {{args}}

# Preflight checks before publishing
preflight: test fix readme semver-checks msrv-check
    #!/usr/bin/env bash
    set -euo pipefail

    echo "🔍 Running preflight checks for version bump..."

    # Get current version from Cargo.toml
    CURRENT_VERSION=$(grep '^version = ' Cargo.toml | head -1 | sed 's/version = "\(.*\)"/\1/')
    IMPL_VERSION=$(grep '^version = ' impl/Cargo.toml | head -1 | sed 's/version = "\(.*\)"/\1/')

    echo "📦 Current version in Cargo.toml: $CURRENT_VERSION"
    echo "📦 Current version in impl/Cargo.toml: $IMPL_VERSION"

    # Check that both Cargo.toml versions match
    if [ "$CURRENT_VERSION" != "$IMPL_VERSION" ]; then
        echo "❌ Version mismatch: Cargo.toml ($CURRENT_VERSION) != impl/Cargo.toml ($IMPL_VERSION)"
        exit 1
    fi

    # Get latest version from crates.io
    echo "🌐 Checking latest version on crates.io..."
    LATEST_CRATES_VERSION=$(cargo search wherror --limit 1 2>/dev/null | grep '^wherror = ' | sed 's/wherror = "\(.*\)".*/\1/' || echo "0.0.0")
    echo "📦 Latest version on crates.io: $LATEST_CRATES_VERSION"

    # Check that we've bumped the version
    if [ "$CURRENT_VERSION" = "$LATEST_CRATES_VERSION" ]; then
        echo "❌ Version not bumped: current version ($CURRENT_VERSION) matches crates.io version"
        exit 1
    fi

    # Check the wherror-impl pin in Cargo.toml matches the current version
    echo "🔍 Checking wherror-impl pin..."
    PIN_VERSION=$(grep -oP 'wherror-impl = \{ version = "=\K[^"]+' Cargo.toml)
    if [ "$PIN_VERSION" != "$CURRENT_VERSION" ]; then
        echo "❌ wherror-impl pin in Cargo.toml is =$PIN_VERSION, expected =$CURRENT_VERSION"
        exit 1
    fi

    # Check CHANGELOG.md has entry for current version
    echo "📝 Checking CHANGELOG.md..."
    if ! grep -q "## \[$CURRENT_VERSION\]" CHANGELOG.md; then
        echo "❌ No changelog entry found for version $CURRENT_VERSION"
        exit 1
    fi

    # Check git status - ensure all changes are committed
    echo "📋 Checking git status..."
    if [ -n "$(git status --porcelain)" ]; then
        echo "❌ Uncommitted changes found. Please commit all changes before release."
        git status
        exit 1
    fi

    # Check that git tag exists for current version
    echo "🏷️  Checking git tag..."
    if ! git tag -l | grep -q "^v$CURRENT_VERSION$"; then
        echo "❌ Git tag v$CURRENT_VERSION not found. Please tag the release:"
        echo "   git tag v$CURRENT_VERSION"
        echo "   git push origin v$CURRENT_VERSION"
        exit 1
    fi

    echo "✅ All preflight checks passed! Ready to publish version $CURRENT_VERSION"