planr 0.3.1

planr -- trunk-based, markdown-formatted backlog for both solo and concurrent development
name: CI

on:
  push:
    branches: [main]
    # Release tags only (v1.2.3). Glob dialect, not regex: `.` is literal,
    # `[0-9]+` = one or more digits, pattern must match the whole tag, so
    # prerelease tags like v1.2.3-rc.1 never trigger publish.
    tags: ["v[0-9]+.[0-9]+.[0-9]+"]
  pull_request:
    branches: [main]

env:
  CARGO_TERM_COLOR: always
  RUSTFLAGS: "-D warnings"

permissions:
  contents: read

jobs:
  fmt:
    name: fmt
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262
        with:
          persist-credentials: false
      - uses: dtolnay/rust-toolchain@e97e2d8cc328f1b50210efc529dca0028893a2d9
        with:
          toolchain: stable
          components: rustfmt
      - run: cargo fmt --all -- --check

  clippy:
    name: clippy
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262
        with:
          persist-credentials: false
      - uses: dtolnay/rust-toolchain@e97e2d8cc328f1b50210efc529dca0028893a2d9
        with:
          toolchain: stable
          components: clippy
      - run: cargo clippy --workspace --all-targets -- -D warnings

  test:
    name: test
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262
        with:
          persist-credentials: false
      - uses: dtolnay/rust-toolchain@e97e2d8cc328f1b50210efc529dca0028893a2d9
        with:
          toolchain: stable
      - run: cargo test --workspace

  publish:
    name: publish
    # Only runs on release-tag pushes; fmt/clippy/test still gate on them.
    if: github.ref_type == 'tag'
    needs: [fmt, clippy, test]
    runs-on: ubuntu-latest
    environment: publish
    permissions:
      contents: read
      # OIDC token for crates.io trusted publishing — no long-lived secret.
      id-token: write
    steps:
      - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262
        with:
          # Full history so cargo semvertag check can read tags
          fetch-depth: 0
          persist-credentials: false
      - uses: dtolnay/rust-toolchain@e97e2d8cc328f1b50210efc529dca0028893a2d9
        with:
          toolchain: stable
      # Exchange the GitHub Actions OIDC token for a short-lived crates.io access token.
      - uses: rust-lang/crates-io-auth-action@f14f407dad32919804d8e0550a5e471a82249cee
        id: auth
      - name: Install cargo-semvertag and validate version matches tag
        run: |
          cargo install cargo-semvertag --quiet
          cargo semvertag check
      - name: Publish crate
        run: cargo publish -p planr
        env:
          CARGO_REGISTRY_TOKEN: ${{ steps.auth.outputs.token }}

  release:
    name: release (${{ matrix.target }})
    if: github.ref_type == 'tag'
    needs: [fmt, clippy, test]
    strategy:
      fail-fast: false
      matrix:
        include:
          - target: x86_64-unknown-linux-gnu
            os: ubuntu-latest
          - target: aarch64-unknown-linux-gnu
            os: ubuntu-latest
            deps: gcc-aarch64-linux-gnu
            linker: aarch64-linux-gnu-gcc
          - target: x86_64-apple-darwin
            os: macos-latest
          - target: aarch64-apple-darwin
            os: macos-latest
          - target: x86_64-pc-windows-msvc
            os: windows-latest
    runs-on: ${{ matrix.os }}
    permissions:
      contents: write
    steps:
      - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262
        with:
          persist-credentials: false
      - uses: dtolnay/rust-toolchain@e97e2d8cc328f1b50210efc529dca0028893a2d9
        with:
          toolchain: stable
          targets: ${{ matrix.target }}
      - name: Install cross-compilation dependencies
        if: matrix.deps != ''
        env:
          DEPS: ${{ matrix.deps }}
        run: sudo apt-get update && sudo apt-get install -y "$DEPS"
      - name: Build release binary
        shell: bash
        env:
          TARGET: ${{ matrix.target }}
          CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER: ${{ matrix.linker }}
        run: cargo build --release --target "$TARGET"
      - name: Package archive
        shell: bash
        env:
          TARGET: ${{ matrix.target }}
          TAG: ${{ github.ref_name }}
        run: |
          version="${TAG#v}"
          pkgdir="planr-${TARGET}-v${version}"
          mkdir -p "${pkgdir}"
          if [[ "${TARGET}" == *-windows-* ]]; then
            cp "target/${TARGET}/release/planr.exe" "${pkgdir}/"
          else
            cp "target/${TARGET}/release/planr" "${pkgdir}/"
          fi
          tar czf "${pkgdir}.tgz" "${pkgdir}"
          echo "archive=${pkgdir}.tgz" >> "${GITHUB_ENV}"
      - name: Upload release asset
        uses: softprops/action-gh-release@3bb12739c298aeb8a4eeaf626c5b8d85266b0e65
        with:
          files: ${{ env.archive }}