asic-rs 0.5.4

Simple ASIC management in Rust
Documentation
name: Publish Release
on:
  workflow_dispatch:
    inputs:
      version:
        description: 'Version to release, without leading v (for example: 0.5.1)'
        required: true
        type: string

jobs:
  prepare-release:
    runs-on: ubuntu-latest
    permissions:
      contents: write
    outputs:
      version: ${{ steps.release.outputs.version }}
      tag: ${{ steps.release.outputs.tag }}
    steps:
      - uses: actions/checkout@v6
        with:
          fetch-depth: 0
      - name: Configure git
        run: |
          git config user.name "github-actions[bot]"
          git config user.email "github-actions[bot]@users.noreply.github.com"
      - name: Bump versions, commit, and tag
        id: release
        env:
          VERSION: ${{ inputs.version }}
        run: |
          set -euo pipefail

          if ! [[ "$VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
            echo "Version must be in X.Y.Z format, got: $VERSION" >&2
            exit 1
          fi

          TAG="v${VERSION}"
          if git rev-parse "$TAG" >/dev/null 2>&1; then
            echo "Tag $TAG already exists" >&2
            exit 1
          fi

          CURRENT_VERSION=$(sed -n '/^\[workspace\.package\]/,/^\[/{s/^version = "\(.*\)"/\1/p}' Cargo.toml)

          sed -i '/^\[workspace\.package\]/,/^\[/{s/^version = ".*"/version = "'"$VERSION"'"/}' Cargo.toml
          sed -i '/^\[workspace\.dependencies\]/,/^\[/{s/version = "'"$CURRENT_VERSION"'"/version = "'"$VERSION"'"/g}' Cargo.toml
          sed -i '/^\[project\]/,/^\[/{s/^version = ".*"/version = "'"$VERSION"'"/}' pyproject.toml

          # Update every Cargo.lock owned by the repo, including nested independent
          # workspaces. A Cargo.lock belongs to the Cargo.toml in the same directory.
          declare -A CARGO_MANIFESTS=()
          CARGO_MANIFESTS["./Cargo.toml"]=1

          while IFS= read -r -d '' manifest; do
          dir="$(dirname "$manifest")"

          # Include workspace roots, plus any manifest sitting next to a Cargo.lock.
          # This catches nested independent workspaces and standalone Rust packages.
          if grep -q '^[[:space:]]*\[workspace\]' "$manifest" || [ -f "$dir/Cargo.lock" ]; then
          CARGO_MANIFESTS["$manifest"]=1
          fi
          done < <(
          find . \
          \( -path './.git' -o -path '*/target' \) -prune -o \
          -name Cargo.toml -print0
          )

          for manifest in "${!CARGO_MANIFESTS[@]}"; do
          echo "::group::cargo update --workspace --manifest-path ${manifest}"
          cargo update --workspace --manifest-path "$manifest"
          echo "::endgroup::"
          done

          docker run --rm -v "$PWD:/workspace" -w /workspace codeberg.org/msrd0/cargo-doc2readme cargo doc2readme

          git add Cargo.toml pyproject.toml README.md

          # Stage all lockfiles, not just ./Cargo.lock.
          while IFS= read -r -d '' lockfile; do
          git add "$lockfile"
          done < <(
          find . \
          \( -path './.git' -o -path '*/target' \) -prune -o \
          -name Cargo.lock -print0
          )

          # Safety check: fail before tagging if generated changes were missed.
          if ! git diff --quiet; then
          echo "Unstaged generated changes remain:" >&2
          git status --short
          exit 1
          fi
          if git diff --cached --quiet; then
            echo "No version changes to commit" >&2
            exit 1
          fi

          git commit -m "chore(release): prepare for ${TAG}"
          git tag "$TAG"
          git push origin "HEAD:${GITHUB_REF}"
          git push origin "$TAG"

          echo "version=$VERSION" >> "$GITHUB_OUTPUT"
          echo "tag=$TAG" >> "$GITHUB_OUTPUT"

  build-python-linux:
    needs: prepare-release
    runs-on: ${{ matrix.platform.runner }}
    strategy:
      fail-fast: false
      matrix:
        platform:
          - runner: ubuntu-22.04
            target: x86_64
          - runner: ubuntu-22.04
            target: x86
          - runner: ubuntu-22.04
            target: aarch64
          - runner: ubuntu-22.04
            target: armv7
          - runner: ubuntu-22.04
            target: s390x
          - runner: ubuntu-22.04
            target: ppc64le
    steps:
      - uses: actions/checkout@v6
        with:
          ref: ${{ needs.prepare-release.outputs.tag }}
      - uses: actions/setup-python@v6
        with:
          python-version: 3.x
      - name: Build wheels
        uses: PyO3/maturin-action@v1
        with:
          target: ${{ matrix.platform.target }}
          args: --release --out dist --find-interpreter --generate-stubs
          sccache: true
          manylinux: 2_28
      - name: Upload wheels
        uses: actions/upload-artifact@v4
        with:
          name: wheels-linux-${{ matrix.platform.target }}
          path: dist

  build-python-musllinux:
    needs: prepare-release
    runs-on: ${{ matrix.platform.runner }}
    strategy:
      fail-fast: false
      matrix:
        platform:
          - runner: ubuntu-22.04
            target: x86_64
          - runner: ubuntu-22.04
            target: x86
          - runner: ubuntu-22.04
            target: aarch64
          - runner: ubuntu-22.04
            target: armv7
    steps:
      - uses: actions/checkout@v6
        with:
          ref: ${{ needs.prepare-release.outputs.tag }}
      - uses: actions/setup-python@v6
        with:
          python-version: 3.x
      - name: Build wheels
        uses: PyO3/maturin-action@v1
        with:
          target: ${{ matrix.platform.target }}
          args: --release --out dist --find-interpreter --generate-stubs
          sccache: true
          manylinux: musllinux_1_2
      - name: Upload wheels
        uses: actions/upload-artifact@v4
        with:
          name: wheels-musllinux-${{ matrix.platform.target }}
          path: dist

  build-python-windows:
    needs: prepare-release
    runs-on: ${{ matrix.platform.runner }}
    strategy:
      fail-fast: false
      matrix:
        platform:
          - runner: windows-latest
            target: x64
          - runner: windows-latest
            target: x86
    steps:
      - uses: actions/checkout@v6
        with:
          ref: ${{ needs.prepare-release.outputs.tag }}
      - uses: actions/setup-python@v6
        with:
          python-version: 3.x
          architecture: ${{ matrix.platform.target }}
      - name: Build wheels
        uses: PyO3/maturin-action@v1
        with:
          target: ${{ matrix.platform.target }}
          args: --release --out dist --find-interpreter --generate-stubs
          sccache: true
      - name: Upload wheels
        uses: actions/upload-artifact@v4
        with:
          name: wheels-windows-${{ matrix.platform.target }}
          path: dist

  build-python-macos:
    needs: prepare-release
    runs-on: ${{ matrix.platform.runner }}
    strategy:
      fail-fast: false
      matrix:
        platform:
          - runner: macos-14
            target: aarch64
    steps:
      - uses: actions/checkout@v6
        with:
          ref: ${{ needs.prepare-release.outputs.tag }}
      - uses: actions/setup-python@v6
        with:
          python-version: 3.x
      - name: Build wheels
        uses: PyO3/maturin-action@v1
        with:
          target: ${{ matrix.platform.target }}
          args: --release --out dist --find-interpreter --generate-stubs
          sccache: true
      - name: Upload wheels
        uses: actions/upload-artifact@v4
        with:
          name: wheels-macos-${{ matrix.platform.target }}
          path: dist

  build-python-sdist:
    needs: prepare-release
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v6
        with:
          ref: ${{ needs.prepare-release.outputs.tag }}
      - name: Build sdist
        uses: PyO3/maturin-action@v1
        with:
          command: sdist
          args: --out dist
      - name: Upload sdist
        uses: actions/upload-artifact@v4
        with:
          name: wheels-sdist
          path: dist

  publish-rust:
    needs: prepare-release
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          ref: ${{ needs.prepare-release.outputs.tag }}
      - name: Install cargo-workspaces
        run: cargo install cargo-workspaces
      - name: Publish crates
        run: cargo workspaces publish --from-git --yes --token ${{ secrets.CARGO_REGISTRY_TOKEN }}

  release:
    runs-on: ubuntu-latest
    needs: [ prepare-release, build-python-linux, build-python-musllinux, build-python-windows, build-python-macos, build-python-sdist, publish-rust ]
    permissions:
      id-token: write
      contents: write
      attestations: write
    steps:
      - uses: actions/checkout@v4
        with:
          ref: ${{ needs.prepare-release.outputs.tag }}
          fetch-depth: 0
      - uses: actions/download-artifact@v4
      - name: Generate artifact attestation
        uses: actions/attest-build-provenance@v2
        with:
          subject-path: 'wheels-*/*'
      - name: Publish to PyPI
        uses: PyO3/maturin-action@v1
        env:
          MATURIN_PYPI_TOKEN: ${{ secrets.PYPI_TOKEN }}
        with:
          command: upload
          args: --non-interactive --skip-existing wheels-*/*
      - name: Generate changelog
        id: changelog
        uses: orhun/git-cliff-action@v4
        with:
          args: --latest
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
      - name: Create GitHub Release
        uses: softprops/action-gh-release@v2
        with:
          tag_name: ${{ needs.prepare-release.outputs.tag }}
          body: ${{ steps.changelog.outputs.content }}
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}