vm-rs 0.2.4

Cross-platform VM lifecycle management — Apple Virtualization.framework (macOS) + Cloud Hypervisor (Linux)
Documentation
name: Release

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

permissions:
  contents: write

env:
  CARGO_TERM_COLOR: always

jobs:
  # ── Gate: version consistency ─────────────────────────────────────
  validate:
    name: Validate version
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Check tag matches Cargo.toml
        run: |
          TAG="${GITHUB_REF#refs/tags/v}"
          CARGO_VER=$(sed -n 's/^version = "\(.*\)"/\1/p' Cargo.toml | head -1)
          if [ "$TAG" != "$CARGO_VER" ]; then
            echo "::error::Tag v${TAG} does not match Cargo.toml version ${CARGO_VER}"
            exit 1
          fi
          echo "VERSION=${TAG}" >> $GITHUB_ENV
          echo "Version validated: ${TAG}"

      - name: Check CHANGELOG has entry
        run: |
          TAG="${GITHUB_REF#refs/tags/v}"
          if ! grep -q "## \[${TAG}\]" CHANGELOG.md; then
            echo "::error::CHANGELOG.md has no entry for [${TAG}]"
            exit 1
          fi

  # ── Full test suite (both platforms) ──────────────────────────────
  test:
    name: Test (${{ matrix.os }})
    needs: validate
    runs-on: ${{ matrix.os }}
    strategy:
      fail-fast: true
      matrix:
        include:
          - os: macos-latest
            target: aarch64-apple-darwin
          - os: ubuntu-latest
            target: x86_64-unknown-linux-gnu
          - os: windows-latest
            target: x86_64-pc-windows-msvc
    steps:
      - uses: actions/checkout@v4
      - uses: dtolnay/rust-toolchain@stable
        with:
          targets: ${{ matrix.target }}
          components: clippy
      - uses: Swatinem/rust-cache@v2
        with:
          key: release-${{ matrix.os }}

      - name: Clippy
        run: cargo clippy --lib --target ${{ matrix.target }} -- -D warnings

      - name: Build
        run: cargo build --target ${{ matrix.target }}

      - name: Unit tests
        run: cargo test --lib --target ${{ matrix.target }}

      - name: Integration tests
        run: |
          cargo test --test vm_manager --target ${{ matrix.target }}
          cargo test --test disk_clone --target ${{ matrix.target }}

      - name: Integration tests (Unix only)
        if: runner.os != 'Windows'
        run: cargo test --test network_switch --target ${{ matrix.target }}

  # ── Publish to crates.io ──────────────────────────────────────────
  publish:
    name: Publish to crates.io
    needs: [validate, test]
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: dtolnay/rust-toolchain@stable

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

  # ── GitHub Release ────────────────────────────────────────────────
  release:
    name: GitHub Release
    needs: publish
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Extract changelog for this version
        id: changelog
        run: |
          TAG="${GITHUB_REF#refs/tags/v}"
          # Extract the section between this version header and the next
          awk "/^## \[${TAG}\]/{found=1; next} /^## \[/{if(found) exit} found" CHANGELOG.md > release_notes.md
          cat release_notes.md

      - name: Create GitHub Release
        run: |
          gh release create "${{ github.ref_name }}" \
            --title "${{ github.ref_name }}" \
            --notes-file release_notes.md
        env:
          GH_TOKEN: ${{ github.token }}