asic-rs 0.7.2

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

permissions:
  contents: read

env:
  CARGO_TERM_COLOR: always

jobs:
  prepare-release:
    runs-on: ubuntu-24.04
    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

          declare -A CARGO_MANIFESTS=()
          CARGO_MANIFESTS["./Cargo.toml"]=1

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

            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:nightly \
            cargo doc2readme --expand-macros

          git add Cargo.toml pyproject.toml README.md

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

          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-wheels:
    needs: prepare-release
    name: Build Python wheels (${{ matrix.artifact }})
    runs-on: ${{ matrix.os }}
    strategy:
      fail-fast: false
      matrix:
        include:
          - artifact: manylinux-x86_64
            os: ubuntu-24.04
            target: x86_64
            manylinux: "2_28"
            python_architecture: x64
          - artifact: manylinux-x86
            os: ubuntu-24.04
            target: x86
            manylinux: "2_28"
            python_architecture: x64
          - artifact: manylinux-aarch64
            os: ubuntu-24.04
            target: aarch64
            manylinux: "2_28"
            python_architecture: x64
          - artifact: manylinux-armv7
            os: ubuntu-24.04
            target: armv7
            manylinux: "2_28"
            python_architecture: x64
          - artifact: manylinux-s390x
            os: ubuntu-24.04
            target: s390x
            manylinux: "2_28"
            python_architecture: x64
          - artifact: manylinux-ppc64le
            os: ubuntu-24.04
            target: ppc64le
            manylinux: "2_28"
            python_architecture: x64
          - artifact: musllinux-x86_64
            os: ubuntu-24.04
            target: x86_64
            manylinux: musllinux_1_2
            python_architecture: x64
          - artifact: musllinux-x86
            os: ubuntu-24.04
            target: x86
            manylinux: musllinux_1_2
            python_architecture: x64
          - artifact: musllinux-aarch64
            os: ubuntu-24.04
            target: aarch64
            manylinux: musllinux_1_2
            python_architecture: x64
          - artifact: musllinux-armv7
            os: ubuntu-24.04
            target: armv7
            manylinux: musllinux_1_2
            python_architecture: x64
          - artifact: windows-x64
            os: windows-latest
            target: x64
            python_architecture: x64
          - artifact: windows-x86
            os: windows-latest
            target: x86
            python_architecture: x86
          - artifact: macos-aarch64
            os: macos-14
            target: aarch64
            python_architecture: arm64
    steps:
      - uses: actions/checkout@v6
        with:
          ref: ${{ needs.prepare-release.outputs.tag }}

      - uses: actions/setup-python@v6
        with:
          python-version: "3.x"
          architecture: ${{ matrix.python_architecture }}

      - name: Build wheels
        uses: PyO3/maturin-action@v1
        with:
          target: ${{ matrix.target }}
          args: --release --out dist --find-interpreter
          sccache: true
          manylinux: ${{ matrix.manylinux }}

      - name: Upload wheels
        uses: actions/upload-artifact@v6
        with:
          name: wheels-${{ matrix.artifact }}
          path: dist/*.whl
          if-no-files-found: error

  build-python-sdist:
    needs: prepare-release
    runs-on: ubuntu-24.04
    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@v6
        with:
          name: wheels-sdist
          path: dist/*.tar.gz
          if-no-files-found: error

  publish-rust:
    needs: prepare-release
    runs-on: ubuntu-24.04
    steps:
      - uses: actions/checkout@v6
        with:
          ref: ${{ needs.prepare-release.outputs.tag }}

      - name: Install cargo-workspaces
        run: cargo install cargo-workspaces --locked

      - name: Publish crates
        env:
          CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}
        run: cargo workspaces publish --from-git --yes --allow-dirty

  release:
    runs-on: ubuntu-24.04
    needs:
      - prepare-release
      - build-python-wheels
      - build-python-sdist
      - publish-rust
    permissions:
      contents: write
      id-token: write
      attestations: write
    steps:
      - uses: actions/checkout@v6
        with:
          ref: ${{ needs.prepare-release.outputs.tag }}
          fetch-depth: 0

      - uses: actions/download-artifact@v4
        with:
          pattern: wheels-*
          path: dist
          merge-multiple: true

      - name: Generate artifact attestation
        uses: actions/attest-build-provenance@v2
        with:
          subject-path: "dist/*"

      - name: Install uv
        uses: astral-sh/setup-uv@v8.2.0

      - name: Publish to PyPI
        env:
          UV_PUBLISH_TOKEN: ${{ secrets.PYPI_TOKEN }}
        run: uv publish --trusted-publishing automatic --check-url https://pypi.org/simple/ dist/*

      - 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 }}