rusty-figlet 0.2.0

Render ASCII-art banners from text — a Rust port of cmatsuoka's `figlet(6)` v2.2.5 with an in-house FIGfont 2.0 parser, all six horizontal smush rules + universal, 12 bundled `.flf` fonts via `include_bytes!`, terminal-width-aware layout, color/rainbow output, byte-equal Strict-mode upstream compatibility, and a typed library API. v0.2: feature layout reorganized — see CHANGELOG.
Documentation
# rusty-figlet CI workflow.
#
# v0.2.0 (E011 Phase 2 reference port) expands the v0.1.0 pipeline with the
# portfolio-wide Cargo Features Convention 5-tier matrix per spec 00011
# §Per-Port v0.2.0 CI Matrix + FR-010..FR-014:
#
#   Tier 1 — test-default                (full DDR-003 cross-compile matrix)
#   Tier 2 — test-no-default             (Linux x86_64 only)
#   Tier 3 — test-<bundle>               (per preset, Linux only)
#   Tier 4 — check-leaf-<leaf>           (per leaf, Linux only)
#   Tier 5 — lint-convention             (umbrella feature-lint, Linux only)
#
# Pre-existing v0.1.0 gates (rustfmt, clippy, audit, deny, MSRV) are
# preserved unchanged.

name: CI

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

env:
  CARGO_TERM_COLOR: always
  RUST_BACKTRACE: 1
  # Pinned locale for byte-equality fixture assertions (see
  # tests/common/mod.rs and fixtures/README.md). MUST be inherited by every
  # job that runs `cargo test`.
  LC_ALL: C.UTF-8

# Minimum permissions for the default GITHUB_TOKEN. `contents: read` is what
# `actions/checkout` needs to fetch the repo; declaring it explicitly avoids
# auth failures under restrictive org/repo workflow-permission defaults.
permissions:
  contents: read

jobs:
  fmt:
    name: rustfmt
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: dtolnay/rust-toolchain@stable
        with:
          components: rustfmt
      - run: cargo fmt --all -- --check

  clippy:
    name: clippy (deny warnings)
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: dtolnay/rust-toolchain@stable
        with:
          components: clippy
      - uses: Swatinem/rust-cache@v2
      - run: cargo clippy --all-targets --all-features -- -D warnings

  audit:
    name: cargo audit
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: dtolnay/rust-toolchain@stable
      - uses: taiki-e/install-action@v2
        with:
          tool: cargo-audit
      - run: cargo audit
        env:
          RUSTUP_TOOLCHAIN: stable

  deny:
    name: cargo deny (licenses)
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: dtolnay/rust-toolchain@stable
      - uses: taiki-e/install-action@v2
        with:
          tool: cargo-deny
      - run: cargo deny check licenses
        env:
          RUSTUP_TOOLCHAIN: stable

  msrv:
    name: MSRV (1.85)
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: dtolnay/rust-toolchain@1.85
      - uses: Swatinem/rust-cache@v2
      - run: cargo build --all-features
      - run: cargo test --all-features

  # -----------------------------------------------------------------------------
  # Tier 1 — test-default: full DDR-003 cross-compile matrix on `default`
  # features. `default = ["full"]` post-v0.2.0; the kitchen-sink test
  # covers every leaf.
  # -----------------------------------------------------------------------------
  test-default:
    name: test-default ${{ matrix.target }}
    needs: [fmt, clippy]
    runs-on: ${{ matrix.os }}
    strategy:
      fail-fast: false
      matrix:
        include:
          - { os: ubuntu-latest, target: x86_64-unknown-linux-gnu }
          - { os: ubuntu-latest, target: aarch64-unknown-linux-gnu, cross: true }
          - { os: macos-latest, target: x86_64-apple-darwin }
          - { os: macos-latest, target: aarch64-apple-darwin }
          - { os: windows-latest, target: x86_64-pc-windows-msvc }
    env:
      LC_ALL: C.UTF-8
    steps:
      - uses: actions/checkout@v4
      - uses: dtolnay/rust-toolchain@stable
        with:
          targets: ${{ matrix.target }}
      - name: Add cross-compile target to 1.85 toolchain
        if: '!matrix.cross'
        run: rustup target add ${{ matrix.target }} --toolchain 1.85
        shell: bash
      - uses: Swatinem/rust-cache@v2
        with:
          key: ${{ matrix.target }}
      - name: Install cross
        if: matrix.cross
        run: cargo install cross --locked
      - name: Build
        run: |
          if [ "${{ matrix.cross }}" = "true" ]; then
            cross build --release --target ${{ matrix.target }} --all-features
          else
            cargo build --release --target ${{ matrix.target }} --all-features
          fi
        shell: bash
      - name: Test
        if: matrix.cross != true
        run: cargo test --release --target ${{ matrix.target }} --all-features

  # -----------------------------------------------------------------------------
  # Tier 2 — test-no-default: bare library on Linux x86_64. Verifies CLI-only
  # deps are absent from the library build (SC-001 evidence).
  # -----------------------------------------------------------------------------
  test-no-default:
    name: test-no-default (linux-x86_64)
    needs: [fmt, clippy]
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: dtolnay/rust-toolchain@stable
      - uses: Swatinem/rust-cache@v2
      - run: cargo build --no-default-features
      - run: cargo test --no-default-features --lib
      - name: Dep-tree audit (SC-001)
        run: |
          # Assert no CLI-only deps leak into the bare-library build.
          if cargo tree --no-default-features --prefix none --edges normal --no-dedupe \
              | grep -E '^(clap|clap_complete|anstyle|termcolor|terminal_size)'; then
            echo "::error::CLI-only dep leaked into --no-default-features build"
            exit 1
          fi

  # -----------------------------------------------------------------------------
  # Tier 3 — test-<bundle>: one job per preset bundle. Linux x86_64 only.
  # -----------------------------------------------------------------------------
  test-figlet-classic:
    name: test-figlet-classic (linux-x86_64)
    needs: [fmt, clippy]
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: dtolnay/rust-toolchain@stable
      - uses: Swatinem/rust-cache@v2
      - run: cargo build --no-default-features --features figlet-classic
      - run: cargo test --no-default-features --features figlet-classic --lib

  test-figlet-minimal:
    name: test-figlet-minimal (linux-x86_64)
    needs: [fmt, clippy]
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: dtolnay/rust-toolchain@stable
      - uses: Swatinem/rust-cache@v2
      - run: cargo build --no-default-features --features figlet-minimal
      - run: cargo test --no-default-features --features figlet-minimal --lib

  test-figlet-toilet-compat:
    name: test-figlet-toilet-compat (linux-x86_64)
    needs: [fmt, clippy]
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: dtolnay/rust-toolchain@stable
      - uses: Swatinem/rust-cache@v2
      - run: cargo build --no-default-features --features figlet-toilet-compat
      - run: cargo test --no-default-features --features figlet-toilet-compat --lib

  # -----------------------------------------------------------------------------
  # Tier 4 — check-leaf-<leaf>: one job per declared leaf. Linux x86_64 only.
  # Each job verifies the leaf compiles in isolation (cli + the one leaf).
  # -----------------------------------------------------------------------------
  check-leaf-color:
    name: check-leaf-color (linux-x86_64)
    needs: [fmt, clippy]
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: dtolnay/rust-toolchain@stable
      - uses: Swatinem/rust-cache@v2
      - run: cargo check --no-default-features --features "cli color"

  check-leaf-rainbow:
    name: check-leaf-rainbow (linux-x86_64)
    needs: [fmt, clippy]
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: dtolnay/rust-toolchain@stable
      - uses: Swatinem/rust-cache@v2
      - run: cargo check --no-default-features --features "cli rainbow"

  check-leaf-terminal-width:
    name: check-leaf-terminal-width (linux-x86_64)
    needs: [fmt, clippy]
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: dtolnay/rust-toolchain@stable
      - uses: Swatinem/rust-cache@v2
      - run: cargo check --no-default-features --features "cli terminal-width"

  check-leaf-completions:
    name: check-leaf-completions (linux-x86_64)
    needs: [fmt, clippy]
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: dtolnay/rust-toolchain@stable
      - uses: Swatinem/rust-cache@v2
      - run: cargo check --no-default-features --features "cli completions"

  check-leaf-strict-compat:
    name: check-leaf-strict-compat (linux-x86_64)
    needs: [fmt, clippy]
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: dtolnay/rust-toolchain@stable
      - uses: Swatinem/rust-cache@v2
      - run: cargo check --no-default-features --features "cli strict-compat"

  # -----------------------------------------------------------------------------
  # Tier 5 — lint-convention: feature-lint script is vendored into the port
  # (tools/feature-lint/) so the CI does not depend on cross-repo checkout
  # of the (private) umbrella. Each port keeps its own copy in sync with
  # the umbrella source of truth.
  # -----------------------------------------------------------------------------
  lint-convention:
    name: lint-convention (linux-x86_64)
    needs: [fmt, clippy]
    runs-on: ubuntu-latest
    steps:
      - name: Checkout port
        uses: actions/checkout@v4

      - name: Run feature-lint
        env:
          UMBRELLA_PATH: ${{ github.workspace }}
          PORT_PATH: ${{ github.workspace }}
        run: bash tools/feature-lint/run.sh

  # -----------------------------------------------------------------------------
  # Convention-violation self-test (SC-007 evidence). Manually triggered;
  # creates a temp Cargo.toml without `figlet-classic` and asserts the lint
  # script catches the violation. Spec 00011 T032.
  # -----------------------------------------------------------------------------
  convention-lint-self-test:
    name: convention-lint-self-test
    if: github.event_name == 'workflow_dispatch'
    runs-on: ubuntu-latest
    steps:
      - name: Checkout port
        uses: actions/checkout@v4

      - name: Remove figlet-classic umbrella from Cargo.toml
        run: |
          sed -i '/^figlet-classic\s*=/d' Cargo.toml
          # Verify removal
          if grep -E '^figlet-classic\s*=' Cargo.toml; then
            echo "::error::figlet-classic removal failed"
            exit 1
          fi

      - name: Invoke feature-lint and expect non-zero exit
        env:
          UMBRELLA_PATH: ${{ github.workspace }}
          PORT_PATH: ${{ github.workspace }}
        run: |
          set +e
          bash tools/feature-lint/run.sh 2>stderr.log
          rc=$?
          set -e
          cat stderr.log
          if [ "$rc" = "0" ]; then
            echo "::error::feature-lint should have failed with exit 2 but returned 0"
            exit 1
          fi
          if ! grep -q "required umbrella 'figlet-classic' missing" stderr.log; then
            echo "::error::expected diagnostic 'required umbrella figlet-classic missing' not found"
            exit 1
          fi
          echo "convention-lint-self-test: PASS"

  # -----------------------------------------------------------------------------
  # Publish-dry-run + final gate. Runs after every tier above.
  # -----------------------------------------------------------------------------
  publish-dry-run:
    name: cargo publish --dry-run
    needs:
      - fmt
      - clippy
      - audit
      - deny
      - msrv
      - test-default
      - test-no-default
      - test-figlet-classic
      - test-figlet-minimal
      - test-figlet-toilet-compat
      - check-leaf-color
      - check-leaf-rainbow
      - check-leaf-terminal-width
      - check-leaf-completions
      - check-leaf-strict-compat
      - lint-convention
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: dtolnay/rust-toolchain@stable
      - run: cargo publish --dry-run --all-features