rusty-ts 0.1.0

Prefix each line of stdin with a timestamp — a Rust port of moreutils `ts` with strict-compat mode, IANA timezone control, and a reusable byte-typed library API.
Documentation
# Tag-driven release per DDR-002. Inline implementation per T001 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

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-ts -- completions bash       > dist/completions/rusty-ts.bash
          cargo run --release --features cli --bin rusty-ts -- completions zsh        > dist/completions/_rusty-ts
          cargo run --release --features cli --bin rusty-ts -- completions fish       > dist/completions/rusty-ts.fish
          cargo run --release --features cli --bin rusty-ts -- completions powershell > dist/completions/rusty-ts.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 }}
      - name: Install cross
        if: matrix.cross
        run: cargo install cross --locked
      - name: Build (with ts-alias)
        shell: bash
        run: |
          if [ "${{ matrix.cross }}" = "true" ]; then
            cross build --release --target ${{ matrix.target }} --features ts-alias
          else
            cargo build --release --target ${{ matrix.target }} --features ts-alias
          fi
      - name: Download completions
        uses: actions/download-artifact@v4
        with:
          name: completions
          path: dist/completions/
      - name: Package archive
        shell: bash
        run: |
          ARCHIVE="rusty-ts-${GITHUB_REF_NAME}-${{ matrix.target }}"
          mkdir -p "$ARCHIVE"
          if [ "${{ matrix.target }}" = "x86_64-pc-windows-msvc" ]; then
            cp target/${{ matrix.target }}/release/rusty-ts.exe "$ARCHIVE/"
            cp target/${{ matrix.target }}/release/ts.exe "$ARCHIVE/" 2>/dev/null || true
            cp -r dist/completions "$ARCHIVE/"
            cp README.md LICENSE LICENSE-APACHE "$ARCHIVE/"
            7z a "$ARCHIVE.zip" "$ARCHIVE"
          else
            cp target/${{ matrix.target }}/release/rusty-ts "$ARCHIVE/"
            cp target/${{ matrix.target }}/release/ts "$ARCHIVE/" 2>/dev/null || true
            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-ts-${{ matrix.target }}
          path: rusty-ts-*.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-ts-${{ matrix.target }}-zip
          path: rusty-ts-*.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-ts-*.tar.gz
            artifacts/**/rusty-ts-*.zip
          body_path: CHANGELOG.md
          draft: false
          prerelease: false