strest 0.1.10

Blazing-fast async HTTP load tester in Rust - lock-free design, real-time stats, distributed runs, and optional chart exports for high-load API testing.
Documentation
name: Release

on:
  push:
    branches:
      - main
    tags:
      - 'v*'
  workflow_dispatch:
    inputs:
      tag:
        description: 'Release tag to attach artifacts to (e.g., v0.1.6)'
        required: true
        type: string

jobs:
  validate:
    name: Validate Release
    if: github.event_name != 'workflow_dispatch'
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - uses: dtolnay/rust-toolchain@stable
        with:
          components: clippy, rustfmt

      - uses: Swatinem/rust-cache@v2

      - name: Install system dependencies
        run: sudo apt-get update && sudo apt-get install -y libfontconfig1-dev libfreetype6-dev pkg-config

      - name: Install cargo-make
        uses: davidB/rust-cargo-make@v1

      - name: Install cargo-audit
        uses: taiki-e/install-action@v2
        with:
          tool: cargo-audit

      - name: Install cargo-deny
        uses: taiki-e/install-action@v2
        with:
          tool: cargo-deny

      - name: Verify Tag Matches Cargo.toml Version
        if: startsWith(github.ref, 'refs/tags/v')
        shell: bash
        run: |
          VERSION="${{ github.ref_name }}"
          VERSION_CLEAN="${VERSION#v}"
          VERSION_BASE="${VERSION_CLEAN%%-*}"
          TOML_VERSION="$(sed -n 's/^version = "\(.*\)"/\1/p' Cargo.toml | head -n 1)"
          if [[ -z "$TOML_VERSION" ]]; then
            echo "Failed to read Cargo.toml version."
            exit 1
          fi
          EXPECT_VERSION="$VERSION_CLEAN"
          if [[ "$VERSION_CLEAN" == *"-"* ]]; then
            EXPECT_VERSION="$VERSION_BASE"
          fi
          if [[ "$TOML_VERSION" != "$EXPECT_VERSION" ]]; then
            echo "Tag version ($VERSION_CLEAN) does not match Cargo.toml ($TOML_VERSION)."
            exit 1
          fi

      - name: Verify Changelog Section
        if: startsWith(github.ref, 'refs/tags/v')
        shell: bash
        run: |
          VERSION="${{ github.ref_name }}"
          VERSION_CLEAN="${VERSION#v}"
          VERSION_BASE="${VERSION_CLEAN%%-*}"
          if ! grep -qE "^## ${VERSION_BASE}$" CHANGELOG.md; then
            echo "Missing CHANGELOG.md section for ${VERSION_BASE}."
            exit 1
          fi

      - name: Release Tag Info
        if: startsWith(github.ref, 'refs/tags/v')
        shell: bash
        run: |
          VERSION="${{ github.ref_name }}"
          VERSION_CLEAN="${VERSION#v}"
          VERSION_BASE="${VERSION_CLEAN%%-*}"
          if [[ "$VERSION_CLEAN" == *"-"* ]]; then
            echo "Detected pre-release tag: $VERSION" >> "$GITHUB_STEP_SUMMARY"
            echo "Using base version for changelog/Cargo.toml checks: $VERSION_BASE" >> "$GITHUB_STEP_SUMMARY"
            echo "Publish/build jobs are skipped for prerelease tags." >> "$GITHUB_STEP_SUMMARY"
          else
            echo "Detected release tag: $VERSION" >> "$GITHUB_STEP_SUMMARY"
            echo "Publish/build jobs will run." >> "$GITHUB_STEP_SUMMARY"
          fi

      - name: Audit Dependencies
        run: cargo make audit

      - name: Deny Check
        run: cargo make deny

      - name: Run Tests
        run: cargo make test

      - name: Run WASM Tests
        run: cargo make test-wasm

      - name: Lint
        run: cargo make clippy

      - name: Format Check
        run: cargo make format-check

      - name: Architecture Guardrails
        run: cargo make architecture-check

      - name: Verify Publish Readiness
        run: cargo publish --dry-run --locked

      - name: Package Check
        run: cargo package --locked

  publish:
    if: github.event_name != 'workflow_dispatch' && startsWith(github.ref, 'refs/tags/v') && !contains(github.ref_name, '-')
    name: Publish to Crates.io
    needs: validate
    runs-on: ubuntu-latest
    permissions:
      contents: write
    outputs:
      changelog: ${{ steps.changelog_reader.outputs.changes }}
    steps:
      - uses: actions/checkout@v4

      - name: Install system dependencies
        run: sudo apt-get update && sudo apt-get install -y libfontconfig1-dev libfreetype6-dev pkg-config
      
      - name: Extract Changelog Section
        id: changelog_reader
        run: |
          VERSION="${{ github.ref_name }}"
          VERSION_CLEAN="${VERSION#v}"
          VERSION_BASE="${VERSION_CLEAN%%-*}"
          
          CHANGES=$(sed -n "/^## $VERSION_BASE/,/^## /p" CHANGELOG.md | sed '1d;$d')
          
          echo "changes<<EOF" >> "$GITHUB_OUTPUT"
          echo "$CHANGES" >> "$GITHUB_OUTPUT"
          echo "EOF" >> "$GITHUB_OUTPUT"

      - uses: dtolnay/rust-toolchain@stable
      
      - name: Ensure Changelog Has Notes
        shell: bash
        run: |
          if [[ -z "${{ steps.changelog_reader.outputs.changes }}" ]]; then
            echo "Changelog section is empty for ${{ github.ref_name }}."
            exit 1
          fi

      - name: Publish to Cargo
        env:
          CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}
        run: cargo publish --locked

      - name: Create GitHub Release
        uses: ncipollo/release-action@v1
        with:
          tag: ${{ github.ref_name }}
          name: Release ${{ github.ref_name }}
          body: |
            ### 🚀 What's New
            ${{ steps.changelog_reader.outputs.changes }}
            
            ### 📦 Installation
            ```bash
            cargo install strest
            ```
          makeLatest: true

  build-binaries:
    name: Build Binaries
    needs: publish
    if: (github.event_name == 'workflow_dispatch') || (startsWith(github.ref, 'refs/tags/v') && !contains(github.ref_name, '-'))
    strategy:
      matrix:
        include:
          - os: ubuntu-latest
            target: x86_64-unknown-linux-gnu
            suffix: linux-x86_64
            archive: tar.gz
          - os: windows-latest
            target: x86_64-pc-windows-msvc
            suffix: windows-x86_64
            archive: zip
          - os: macos-latest
            target: x86_64-apple-darwin
            suffix: macos-x86_64
            archive: tar.gz
          - os: macos-latest
            target: aarch64-apple-darwin
            suffix: macos-arm64
            archive: tar.gz
            rust_min_stack: 16777216
    runs-on: ${{ matrix.os }}
    steps:
      - uses: actions/checkout@v4
      - uses: dtolnay/rust-toolchain@stable
        with:
          targets: ${{ matrix.target }}

      - name: Install system dependencies (Linux)
        if: startsWith(matrix.os, 'ubuntu')
        run: sudo apt-get update && sudo apt-get install -y libfontconfig1-dev libfreetype6-dev pkg-config
      
      - name: Build Release
        env:
          RUST_MIN_STACK: ${{ matrix.rust_min_stack }}
        run: cargo build --release --target ${{ matrix.target }} --locked

      - name: Package Assets
        shell: bash
        run: |
          RELEASE_TAG="${{ github.event_name == 'workflow_dispatch' && inputs.tag || github.ref_name }}"
          mkdir dist
          # Determine binary name
          BIN_NAME="strest"
          if [[ "${{ matrix.os }}" == "windows-latest" ]]; then BIN_NAME="strest.exe"; fi
          
          # Copy binary and metadata
          cp "target/${{ matrix.target }}/release/$BIN_NAME" dist/
          cp README.md LICENSE dist/ 2>/dev/null || :

          # Create Archive
          cd dist
          if [[ "${{ matrix.archive }}" == "tar.gz" ]]; then
            tar -czf "../strest-${RELEASE_TAG}-${{ matrix.suffix }}.tar.gz" *
          else
            7z a "../strest-${RELEASE_TAG}-${{ matrix.suffix }}.zip" *
          fi

      - name: Upload to Release
        uses: svenstaro/upload-release-action@v2
        with:
          repo_token: ${{ secrets.GITHUB_TOKEN }}
          file: strest-${{ github.event_name == 'workflow_dispatch' && inputs.tag || github.ref_name }}-${{ matrix.suffix }}.${{ matrix.archive }}
          asset_name: strest-${{ github.event_name == 'workflow_dispatch' && inputs.tag || github.ref_name }}-${{ matrix.suffix }}.${{ matrix.archive }}
          tag: ${{ github.event_name == 'workflow_dispatch' && inputs.tag || github.ref_name }}