rusty-pv 0.1.0

Pipe viewer — a Rust port of Andrew Wood's `pv(1)` with progress bar, ETA, rate display, token-bucket rate limiting, IEC/SI unit math, SIGWINCH-aware terminal redraw, SIGUSR1 size refresh, multi-instance cursor coordination, and a typed library API.
Documentation
# Tag-driven release per DDR-002. Inline implementation per T015 pragmatic
# path — to be replaced by a thin caller of E003 v1.0.0 once the umbrella
# reusable workflow ships.

name: Release

on:
  push:
    tags: ["v[0-9]+.[0-9]+.[0-9]+"]

env:
  CARGO_TERM_COLOR: always
  RUST_BACKTRACE: 1

# Default permissions: read-only for the build/publish jobs. The
# `github-release` job overrides this with `contents: write` to upload assets.
permissions:
  contents: read

jobs:
  verify-tag-matches-cargo-version:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Check tag matches Cargo.toml version
        run: |
          TAG_VERSION="${GITHUB_REF_NAME#v}"
          CARGO_VERSION=$(grep -m1 '^version' Cargo.toml | cut -d'"' -f2)
          if [ "$TAG_VERSION" != "$CARGO_VERSION" ]; then
            echo "Tag $GITHUB_REF_NAME does not match Cargo.toml version $CARGO_VERSION" >&2
            exit 1
          fi

  generate-completions:
    name: generate shell completions
    needs: verify-tag-matches-cargo-version
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: dtolnay/rust-toolchain@stable
      - uses: Swatinem/rust-cache@v2
      - name: Generate completions via host build
        run: |
          mkdir -p dist/completions
          # Run via `cargo run` on the host toolchain so this works regardless
          # of any target the build-binaries matrix later cross-compiles for.
          # The completion scripts are derived from the CLI definition and are
          # identical regardless of build target — generate once, ship to all.
          cargo run --release --features cli --bin rusty-pv -- completions bash       > dist/completions/rusty-pv.bash
          cargo run --release --features cli --bin rusty-pv -- completions zsh        > dist/completions/_rusty-pv
          cargo run --release --features cli --bin rusty-pv -- completions fish       > dist/completions/rusty-pv.fish
          cargo run --release --features cli --bin rusty-pv -- completions powershell > dist/completions/rusty-pv.ps1
      - uses: actions/upload-artifact@v4
        with:
          name: completions
          path: dist/completions/
          retention-days: 1

  build-binaries:
    name: build ${{ matrix.target }}
    needs: [verify-tag-matches-cargo-version, generate-completions]
    runs-on: ${{ matrix.os }}
    strategy:
      fail-fast: false
      matrix:
        include:
          - { os: ubuntu-latest, target: x86_64-unknown-linux-gnu, cross: false }
          - { os: ubuntu-latest, target: aarch64-unknown-linux-gnu, cross: true }
          - { os: macos-latest, target: x86_64-apple-darwin, cross: false }
          - { os: macos-latest, target: aarch64-apple-darwin, cross: false }
          - { os: windows-latest, target: x86_64-pc-windows-msvc, cross: false }
    steps:
      - uses: actions/checkout@v4
      - uses: dtolnay/rust-toolchain@stable
        with:
          targets: ${{ matrix.target }}
      # Workspace pins to 1.85 via rust-toolchain.toml. dtolnay added the
      # target to the stable channel but cargo will switch to 1.85 when run
      # from the workspace — 1.85 doesn't have the cross-compile target
      # installed. Add it explicitly here.
      - name: Add cross-compile target to 1.85 toolchain
        if: '!matrix.cross'
        run: rustup target add ${{ matrix.target }} --toolchain 1.85
        shell: bash
      - name: Install cross
        if: matrix.cross
        run: cargo install cross --locked
      - name: Build
        shell: bash
        run: |
          if [ "${{ matrix.cross }}" = "true" ]; then
            cross build --release --target ${{ matrix.target }} --all-features
          else
            cargo build --release --target ${{ matrix.target }} --all-features
          fi
      - name: Download completions
        uses: actions/download-artifact@v4
        with:
          name: completions
          path: dist/completions/
      - name: Package archive
        shell: bash
        run: |
          ARCHIVE="rusty-pv-${GITHUB_REF_NAME}-${{ matrix.target }}"
          mkdir -p "$ARCHIVE"
          if [ "${{ matrix.target }}" = "x86_64-pc-windows-msvc" ]; then
            cp target/${{ matrix.target }}/release/rusty-pv.exe "$ARCHIVE/"
            cp -r dist/completions "$ARCHIVE/"
            cp README.md LICENSE LICENSE-APACHE "$ARCHIVE/"
            7z a "$ARCHIVE.zip" "$ARCHIVE"
          else
            cp target/${{ matrix.target }}/release/rusty-pv "$ARCHIVE/"
            cp -r dist/completions "$ARCHIVE/"
            cp README.md LICENSE LICENSE-APACHE "$ARCHIVE/"
            tar czf "$ARCHIVE.tar.gz" "$ARCHIVE"
          fi
      - name: Upload artifact
        uses: actions/upload-artifact@v4
        with:
          name: rusty-pv-${{ matrix.target }}
          path: rusty-pv-*.tar.gz
          if-no-files-found: ignore
      - name: Upload Windows artifact
        if: matrix.target == 'x86_64-pc-windows-msvc'
        uses: actions/upload-artifact@v4
        with:
          name: rusty-pv-${{ matrix.target }}-zip
          path: rusty-pv-*.zip

  publish-crates-io:
    name: cargo publish
    needs: build-binaries
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: dtolnay/rust-toolchain@stable
      - run: cargo publish --all-features
        env:
          CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}

  github-release:
    name: GitHub Release
    needs: [build-binaries, publish-crates-io]
    runs-on: ubuntu-latest
    permissions:
      contents: write
    steps:
      - uses: actions/checkout@v4
      - uses: actions/download-artifact@v4
        with:
          path: artifacts
      - name: Create release
        uses: softprops/action-gh-release@v2
        with:
          files: |
            artifacts/**/rusty-pv-*.tar.gz
            artifacts/**/rusty-pv-*.zip
          body_path: CHANGELOG.md
          draft: false
          prerelease: false