name: Rust crate

on:
  push:
    branches:
      - main
    tags:
      - "**"
  pull_request:
    branches:
      - "**"

concurrency:
  group: ${{ github.event_name == 'pull_request' && format('{0}-{1}', github.workflow_ref, github.event.pull_request.number) || github.run_id }}
  cancel-in-progress: true

permissions:
  contents: read
  actions: write
  id-token: write

jobs:
  build_crate:
    name: Build crate
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v5

      - name: Set up Rust
        uses: dtolnay/rust-toolchain@1.92.0
        with:
          components: rustfmt, clippy

      - name: Fmt
        run: cargo fmt --all -- --files-with-diff --check

      - name: Clippy
        run: cargo clippy --workspace --all-features --all-targets -- -D warnings

      - name: Install cargo-machete
        run: cargo install cargo-machete@0.8.0

      - name: Unused dependencies
        run: cargo machete

      - name: Tests (debug)
        run: cargo test --workspace --all-features

      - name: Tests (release)
        env:
          CARGO_PROFILE_RELEASE_DEBUG_ASSERTIONS: true
          CARGO_PROFILE_RELEASE_OVERFLOW_CHECKS: true
        run: cargo test --workspace --all-features --release --features=clvmr/allocator-debug -- --include-ignored

      - name: Build (release)
        run: cargo build --workspace --all-features --release

      - name: Install cargo-workspaces
        run: cargo install cargo-workspaces --locked

      - name: Publish (dry run)
        run: cargo ws publish --publish-as-is --dry-run

      - name: Upload crate artifacts
        uses: actions/upload-artifact@v4
        with:
          name: crate
          path: ./target/package/*-*.crate

      - uses: rust-lang/crates-io-auth-action@v1
        if: startsWith(github.event.ref, 'refs/tags')
        id: auth

      - name: Clean untracked files
        run: git clean -f

      - name: Publish (crates.io)
        if: startsWith(github.event.ref, 'refs/tags')
        env:
          CARGO_REGISTRY_TOKEN: ${{ steps.auth.outputs.token }}
        # We need to use --allow-dirty because the Cargo.lock is updated by cargo-workspaces to remove cyclic dev dependencies
        run: cargo ws publish --publish-as-is --allow-dirty

  fuzz_tests:
    name: Fuzz (${{ matrix.package.name }})
    runs-on: ubuntu-latest
    strategy:
      fail-fast: false
      matrix:
        package:
          - name: chia-consensus
            env:
              # EXAMPLE_ as an example and to appease actionlint
              EXAMPLE_LSAN_OPTIONS: detect_leaks=0
          - name: chia-bls
          - name: clvm-utils
          - name: chia-protocol
          - name: chia-puzzle-types
          - name: clvm-traits
          - name: chia-datalayer
        toolchain:
          - nightly-2026-01-12
        max_total_time:
          - 20
    env:
      CARGO_PROFILE_RELEASE_LTO: false
    steps:
      - uses: actions/checkout@v4

      - uses: dtolnay/rust-toolchain@nightly
        with:
          toolchain: ${{ matrix.toolchain }}

      - name: Install cargo-fuzz
        run: cargo +"${{ matrix.toolchain }}" install cargo-fuzz

      - name: Fuzz
        env: ${{ matrix.package.env || fromJSON('{}') }}
        run: |
          cd crates/"${{ matrix.package.name }}"
          cargo fuzz list | xargs -I "%" sh -c "cargo +'${{ matrix.toolchain }}' fuzz run % -- -max_total_time=${{ matrix.max_total_time}} || exit 255"
