edgefirst-imu 3.1.0

EdgeFirst IMU Service for BNO08x sensors
# GitHub Actions workflow for publishing releases
#
# This workflow orchestrates release publishing when a version tag is pushed:
# - Waits for build.yml and sbom.yml workflows to complete
# - Downloads build artifacts from the commit's workflow runs
# - Creates GitHub Release with binaries and SBOM
# - Publishes to crates.io using trusted publisher
#
# Release Process:
# 1. Update version in Cargo.toml
# 2. Update CHANGELOG.md with version entry
# 3. Commit and push changes (triggers build.yml and sbom.yml)
# 4. Create and push tag: git tag v3.0.0 && git push --tags
#    (release.yml waits for build.yml and sbom.yml to complete)
#
# crates.io Trusted Publisher Setup:
# 1. Go to https://crates.io/crates/edgefirst-imu/settings
# 2. Add trusted publisher: EdgeFirstAI/imu, release.yml, publish-crates
#
# Action Versions (hash-pinned, verified January 2026):
# - actions/checkout@v4 (34e11487)
# - lewagon/wait-on-check-action@v1.3.4 (ccfb013c)
# - dawidd6/action-download-artifact@v6 (bf251b5a)
# - softprops/action-gh-release@v2 (a06a81a0)
# - dtolnay/rust-toolchain@stable (4be9e76f)

name: Release

on:
  push:
    tags:
      - 'v[0-9]+.[0-9]+.[0-9]+'
      - 'v[0-9]+.[0-9]+.[0-9]+-*'

permissions:
  contents: write
  id-token: write
  checks: read

jobs:
  prepare-release:
    name: Prepare Release
    runs-on: ubuntu-22.04
    outputs:
      version: ${{ steps.version.outputs.version }}
      changelog: ${{ steps.changelog.outputs.changelog }}

    steps:
      - name: Checkout code
        uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
        with:
          fetch-depth: 0

      - name: Extract version from tag
        id: version
        run: |
          VERSION=${GITHUB_REF#refs/tags/v}
          echo "version=$VERSION" >> $GITHUB_OUTPUT
          echo "Extracted version: $VERSION"

      - name: Extract changelog for this version
        id: changelog
        run: |
          VERSION=${GITHUB_REF#refs/tags/v}

          # Extract changelog section for this version
          if [ -f CHANGELOG.md ]; then
            CHANGELOG=$(awk -v ver="$VERSION" '
              /^## \['"$VERSION"'\]/ { found=1; next }
              found && /^## \[/ { exit }
              found { print }
            ' CHANGELOG.md)
          fi

          if [ -z "$CHANGELOG" ]; then
            echo "WARNING: No changelog entry found for version $VERSION"
            CHANGELOG="See commit history for details."
          fi

          echo "changelog<<EOF" >> $GITHUB_OUTPUT
          echo "$CHANGELOG" >> $GITHUB_OUTPUT
          echo "EOF" >> $GITHUB_OUTPUT

  wait-for-ci:
    name: Wait for CI Workflows
    needs: prepare-release
    runs-on: ubuntu-22.04
    steps:
      - name: Wait for Build workflow
        uses: lewagon/wait-on-check-action@ccfb013c15c8afb7bf2b7c028fb74dc5a068cccc # v1.3.4
        with:
          ref: ${{ github.sha }}
          check-name: 'Build (x86_64)'
          repo-token: ${{ secrets.GITHUB_TOKEN }}
          wait-interval: 10

      - name: Wait for Build workflow (aarch64)
        uses: lewagon/wait-on-check-action@ccfb013c15c8afb7bf2b7c028fb74dc5a068cccc # v1.3.4
        with:
          ref: ${{ github.sha }}
          check-name: 'Build (aarch64)'
          repo-token: ${{ secrets.GITHUB_TOKEN }}
          wait-interval: 10

      - name: Wait for SBOM workflow
        uses: lewagon/wait-on-check-action@ccfb013c15c8afb7bf2b7c028fb74dc5a068cccc # v1.3.4
        with:
          ref: ${{ github.sha }}
          check-name: 'Generate SBOM & Check License Compliance'
          repo-token: ${{ secrets.GITHUB_TOKEN }}
          wait-interval: 10

  create-github-release:
    name: Create GitHub Release
    runs-on: ubuntu-22.04
    needs:
      - prepare-release
      - wait-for-ci
    permissions:
      contents: write

    steps:
      - name: Checkout code
        uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4

      - name: Download build artifacts from commit
        uses: dawidd6/action-download-artifact@bf251b5aa9c2f7eeb574a96ee720e24f801b7c11 # v6
        with:
          workflow: build.yml
          commit: ${{ github.sha }}
          path: artifacts

      - name: Download SBOM artifact from commit
        uses: dawidd6/action-download-artifact@bf251b5aa9c2f7eeb574a96ee720e24f801b7c11 # v6
        with:
          workflow: sbom.yml
          commit: ${{ github.sha }}
          path: artifacts

      - name: Organize release assets
        run: |
          mkdir -p release-assets
          VERSION=${{ needs.prepare-release.outputs.version }}

          # REQUIRED: SBOM must be included in every release (per SPS-10)
          if [ -f artifacts/sbom/sbom.json ]; then
            cp artifacts/sbom/sbom.json \
               release-assets/edgefirst-imu-v${VERSION}-sbom.json
          else
            echo "❌ ERROR: sbom.json not found - SBOM is REQUIRED for all releases"
            exit 1
          fi

          # Copy x86_64 binary
          if [ -f artifacts/packages-x86_64/edgefirst-imu-x86_64 ]; then
            cp artifacts/packages-x86_64/edgefirst-imu-x86_64 \
               release-assets/edgefirst-imu-linux-x86_64
          fi

          # Copy ARM64 binary
          if [ -f artifacts/packages-aarch64/edgefirst-imu-aarch64 ]; then
            cp artifacts/packages-aarch64/edgefirst-imu-aarch64 \
               release-assets/edgefirst-imu-linux-aarch64
          fi

          # Copy default configuration file
          cp imu.default release-assets/imu.default

          echo "Release assets prepared:"
          ls -lh release-assets/

      - name: Create GitHub Release
        uses: softprops/action-gh-release@a06a81a03ee405af7f2048a818ed3f03bbf83c7b # v2
        with:
          name: EdgeFirst IMU v${{ needs.prepare-release.outputs.version }}
          body: |
            # EdgeFirst IMU v${{ needs.prepare-release.outputs.version }}

            ## Installation

            ### From crates.io (Recommended)

            ```bash
            cargo install edgefirst-imu
            ```

            ### Download Binaries

            | Platform | Binary |
            |----------|--------|
            | Linux x86_64 | `edgefirst-imu-linux-x86_64` |
            | Linux ARM64 | `edgefirst-imu-linux-aarch64` |
            | Configuration | `imu.default` |

            ```bash
            # Download and install (ARM64 example)
            wget https://github.com/EdgeFirstAI/imu/releases/download/v${{ needs.prepare-release.outputs.version }}/edgefirst-imu-linux-aarch64
            chmod +x edgefirst-imu-linux-aarch64
            sudo mv edgefirst-imu-linux-aarch64 /usr/local/bin/edgefirst-imu

            # Install default configuration (optional)
            sudo cp imu.default /etc/default/imu
            ```

            ## What's Changed

            ${{ needs.prepare-release.outputs.changelog }}

            ---

            **Full Documentation**: https://github.com/EdgeFirstAI/imu#readme
          files: |
            release-assets/*
          draft: false
          prerelease: ${{ contains(needs.prepare-release.outputs.version, '-') }}
          fail_on_unmatched_files: false

  publish-crates:
    name: Publish to crates.io
    runs-on: ubuntu-22.04
    needs:
      - prepare-release
      - create-github-release
    environment: crates-io

    steps:
      - name: Checkout code
        uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4

      - name: Install Rust
        uses: dtolnay/rust-toolchain@4be9e76fd7c4901c61fb841f559994984270fce7 # stable

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