fixed_analytics 2.1.0

Fixed-point mathematical functions. Accurate, deterministic, and panic free.
Documentation
name: Publish

# Releases on merge to main: when Cargo.toml's version is not yet on
# crates.io, this workflow tests, tags, publishes, and creates the
# GitHub release in a single run.
#
# Everything happens in one workflow because tag pushes made with the
# default GITHUB_TOKEN deliberately do not trigger other workflows —
# that is what broke the old auto-tag.yml → publish.yml chain. Here the
# tag is an output of the run, not a trigger, so no PAT is needed.
#
# Every step is idempotent: an already-published version short-circuits
# the run, and an existing tag is left in place. A failed run can be
# retried from the Actions tab (or `gh workflow run publish.yml`).

on:
  push:
    branches: [main]
  workflow_dispatch:

env:
  CARGO_TERM_COLOR: always

concurrency:
  group: publish
  cancel-in-progress: false

jobs:
  check:
    name: Check release needed
    runs-on: ubuntu-latest
    outputs:
      version: ${{ steps.check.outputs.version }}
      release: ${{ steps.check.outputs.release }}
    steps:
      - uses: actions/checkout@v4
      - name: Compare Cargo.toml version against crates.io
        id: check
        run: |
          VERSION=$(cargo metadata --no-deps --format-version 1 | jq -r '.packages[0].version')
          echo "version=$VERSION" >> "$GITHUB_OUTPUT"
          # The sparse index needs no auth and serves one JSON line per
          # published version. A 404 means the crate has never been
          # published, which also means "release".
          if curl -sf "https://index.crates.io/fi/xe/fixed_analytics" \
              | jq -e --arg v "$VERSION" 'select(.vers == $v)' > /dev/null; then
            echo "release=false" >> "$GITHUB_OUTPUT"
            echo "v$VERSION is already on crates.io — nothing to release"
          else
            echo "release=true" >> "$GITHUB_OUTPUT"
            echo "v$VERSION is not on crates.io — releasing"
          fi

  test:
    name: Pre-publish Tests
    needs: check
    if: needs.check.outputs.release == 'true'
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: dtolnay/rust-toolchain@stable
      - uses: Swatinem/rust-cache@v2
      - run: cargo test --features std
      - run: cargo test --no-default-features
      - run: cargo doc --no-deps --features std
        env:
          RUSTDOCFLAGS: -Dwarnings

  release:
    name: Tag, publish, and release
    needs: [check, test]
    if: needs.check.outputs.release == 'true'
    runs-on: ubuntu-latest
    permissions:
      contents: write
    env:
      VERSION: ${{ needs.check.outputs.version }}
    steps:
      - uses: actions/checkout@v4
      - uses: dtolnay/rust-toolchain@stable
      - uses: Swatinem/rust-cache@v2

      # Tag before publishing: a tag without a crates.io release heals
      # on retry (the tag step skips, publish runs); the reverse order
      # would leave an already-published version that the check job
      # filters out, so the tag would never be created.
      - name: Create tag if missing
        run: |
          if git ls-remote --tags origin "refs/tags/v$VERSION" | grep -q .; then
            echo "Tag v$VERSION already exists, keeping it"
          else
            git tag "v$VERSION"
            git push origin "v$VERSION"
          fi

      - name: Publish to crates.io
        run: cargo publish
        env:
          CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}

      - name: Create GitHub release
        uses: softprops/action-gh-release@v1
        with:
          tag_name: v${{ needs.check.outputs.version }}
          generate_release_notes: true
          body: |
            ## Installation

            ```toml
            [dependencies]
            fixed_analytics = "${{ needs.check.outputs.version }}"
            ```

            For `no_std` environments:

            ```toml
            [dependencies]
            fixed_analytics = { version = "${{ needs.check.outputs.version }}", default-features = false }
            ```