alimentar 0.2.8

Data Loading, Distribution and Tooling in Pure Rust
Documentation
# Per-repo release workflow — tagged releases only
# Generated by machines/clean-room/deploy-workflows.sh — do not edit manually.
# Spec: docs/specifications/sovereign-stack-protected-branch-strategy.md
#
# Flow: tag push → clean-room gate → package verify → trusted publish → GitHub Release
#       → cross-compiled binaries (4 Linux targets) → SHA256SUMS
#
# Tag formats:
#   v1.0.0              — single-crate repos
#   v-<crate>-1.0.0     — workspace repos (e.g. v-apr-cli-0.4.0)
#
# IMPORTANT: Tags must be pushed with a PAT or deploy key (not GITHUB_TOKEN),
# otherwise this workflow will not trigger (GitHub anti-recursion measure).

name: Release

on:
  push:
    tags: ['v*']

permissions:
  contents: write    # create GitHub Release + upload assets
  id-token: write    # OIDC for crates.io Trusted Publishing

# One release at a time per repo
concurrency:
  group: release-${{ github.repository }}
  cancel-in-progress: false

jobs:
  # ── Gate: clean-room must pass before publish ───────────
  gate:
    uses: paiml/infra/.github/workflows/clean-room-gate.yml@main
    with:
      repo: ${{ github.event.repository.name }}
      pr_sha: ${{ github.sha }}
    secrets: inherit

  # ── Verify: tag-version match + package tarball ─────────
  verify:
    needs: gate
    runs-on: [self-hosted, clean-room]
    outputs:
      crate_name: ${{ steps.parse.outputs.crate_name }}
      version: ${{ steps.parse.outputs.version }}
      has_binaries: ${{ steps.bincheck.outputs.has_binaries }}
    steps:
      - name: Checkout
        uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683  # v4.2.2

      - name: Parse tag and verify version
        id: parse
        run: |
          TAG="${GITHUB_REF_NAME}"

          # Parse tag format: v1.0.0 or v-cratename-1.0.0
          if [[ "$TAG" =~ ^v-([a-z][a-z0-9_-]*)-([0-9]+\..+)$ ]]; then
            CRATE_NAME="${BASH_REMATCH[1]}"
            TAG_VER="${BASH_REMATCH[2]}"
            echo "Workspace release: crate=$CRATE_NAME version=$TAG_VER"
          elif [[ "$TAG" =~ ^v([0-9]+\..+)$ ]]; then
            CRATE_NAME=""
            TAG_VER="${BASH_REMATCH[1]}"
            echo "Single-crate release: version=$TAG_VER"
          else
            echo "::error::Tag '$TAG' does not match expected format (v1.0.0 or v-crate-1.0.0)"
            exit 1
          fi

          # Use cargo metadata for reliable version extraction
          if [ -n "$CRATE_NAME" ]; then
            CARGO_VER=$(cargo metadata --format-version 1 --no-deps \
              | jq -r ".packages[] | select(.name == \"$CRATE_NAME\") | .version")
            if [ -z "$CARGO_VER" ] || [ "$CARGO_VER" = "null" ]; then
              echo "::error::Crate '$CRATE_NAME' not found in workspace"
              exit 1
            fi
          else
            CARGO_VER=$(cargo metadata --format-version 1 --no-deps \
              | jq -r '.packages[0].version')
          fi

          if [ "$TAG_VER" != "$CARGO_VER" ]; then
            echo "::error::Tag version $TAG_VER != Cargo.toml version $CARGO_VER"
            exit 1
          fi

          echo "crate_name=$CRATE_NAME" >> "$GITHUB_OUTPUT"
          echo "version=$TAG_VER" >> "$GITHUB_OUTPUT"
          echo "Version verified: $TAG_VER"

      - name: Detect binary targets
        id: bincheck
        run: |
          HAS_BINS=$(cargo metadata --format-version 1 --no-deps \
            | jq '[.packages[].targets[] | select(.kind[] == "bin")] | length')
          echo "has_binaries=$( [ "$HAS_BINS" -gt 0 ] && echo true || echo false )" >> "$GITHUB_OUTPUT"
          echo "Binary targets found: $HAS_BINS"

      - name: Verify package tarball
        run: |
          CRATE="${{ steps.parse.outputs.crate_name }}"
          if [ -n "$CRATE" ]; then
            cargo package --verify -p "$CRATE"
          else
            cargo package --verify
          fi

  # ── Publish: OIDC trusted publishing to crates.io ──────
  publish:
    needs: verify
    runs-on: [self-hosted, clean-room]
    steps:
      - name: Checkout
        uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683  # v4.2.2

      - name: Authenticate to crates.io (OIDC)
        uses: rust-lang/crates-io-auth-action@b7e9a28eded4986ec6b1fa40eeee8f8f165559ec  # v1.0.3

      - name: Publish
        run: |
          CRATE="${{ needs.verify.outputs.crate_name }}"
          if [ -n "$CRATE" ]; then
            cargo publish -p "$CRATE"
          else
            cargo publish
          fi

      - name: Create GitHub Release
        env:
          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        run: |
          gh release create "$GITHUB_REF_NAME" \
            --title "$GITHUB_REF_NAME" \
            --generate-notes

  # ── Build cross-compiled binaries (4 Linux targets) ────
  build-binaries:
    needs: [verify, publish]
    if: needs.verify.outputs.has_binaries == 'true'
    runs-on: [self-hosted, clean-room]
    strategy:
      fail-fast: false
      matrix:
        target:
          - x86_64-unknown-linux-gnu
          - x86_64-unknown-linux-musl
          - aarch64-unknown-linux-gnu
          - aarch64-unknown-linux-musl
    steps:
      - name: Checkout
        uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683  # v4.2.2

      - name: Install target prerequisites
        run: |
          case "${{ matrix.target }}" in
            *-musl)
              sudo apt-get update -qq
              sudo apt-get install -y -qq musl-tools >/dev/null
              ;;
          esac
          case "${{ matrix.target }}" in
            aarch64-*)
              # cross handles the toolchain via Docker; ensure it's installed
              if ! command -v cross &>/dev/null; then
                cargo install cross --locked
              fi
              ;;
            *-musl)
              rustup target add "${{ matrix.target }}"
              ;;
          esac

      - name: Discover binary names
        id: bins
        run: |
          BINS=$(cargo metadata --format-version 1 --no-deps \
            | jq -r '[.packages[].targets[] | select(.kind[] == "bin") | .name] | join(" ")')
          echo "names=$BINS" >> "$GITHUB_OUTPUT"
          echo "Binaries to build: $BINS"

      - name: Build release binaries
        run: |
          case "${{ matrix.target }}" in
            aarch64-*)
              cross build --release --target "${{ matrix.target }}"
              ;;
            *)
              cargo build --release --target "${{ matrix.target }}"
              ;;
          esac

      - name: Package binaries
        run: |
          VERSION="${{ needs.verify.outputs.version }}"
          TARGET="${{ matrix.target }}"
          STAGING="/tmp/release-staging"
          mkdir -p "$STAGING"

          for BIN in ${{ steps.bins.outputs.names }}; do
            ARCHIVE="${BIN}-${VERSION}-${TARGET}.tar.gz"
            tar -czf "${STAGING}/${ARCHIVE}" \
              -C "target/${TARGET}/release" "$BIN"
            echo "Packaged: $ARCHIVE"
          done

      - name: Upload artifacts
        uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02  # v4.6.0
        with:
          name: binaries-${{ matrix.target }}
          path: /tmp/release-staging/*.tar.gz
          retention-days: 5

  # ── Generate checksums and upload to GitHub Release ─────
  checksums:
    needs: [verify, publish, build-binaries]
    if: needs.verify.outputs.has_binaries == 'true'
    runs-on: [self-hosted, clean-room]
    steps:
      - name: Download all binary artifacts
        uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093  # v4.3.0
        with:
          pattern: binaries-*
          merge-multiple: true
          path: /tmp/release-assets

      - name: Generate SHA256SUMS
        working-directory: /tmp/release-assets
        run: |
          sha256sum *.tar.gz > SHA256SUMS
          echo "=== SHA256SUMS ==="
          cat SHA256SUMS

      - name: Upload to GitHub Release
        env:
          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        working-directory: /tmp/release-assets
        run: |
          gh release upload "$GITHUB_REF_NAME" \
            *.tar.gz SHA256SUMS \
            --repo "${{ github.repository }}" \
            --clobber