acpx 0.1.0

Simple Rust library and tooling for building on ACP.
Documentation
name: Release

on:
  push:
    tags:
      - "v*.*.*"
  workflow_dispatch:
    inputs:
      tag:
        description: "Release tag to publish, for example v0.1.0"
        required: true
        type: string
      dry_run:
        description: "Only run validation and dry-run publish checks"
        required: true
        default: true
        type: boolean

permissions:
  contents: write
  id-token: write

jobs:
  publish:
    runs-on: ubuntu-latest
    env:
      INPUT_TAG: ${{ inputs.tag }}
      DRY_RUN: ${{ github.event_name == 'workflow_dispatch' && inputs.dry_run || 'false' }}
    steps:
      - uses: actions/checkout@v6
        with:
          fetch-depth: 0

      - name: Select release ref
        if: github.event_name == 'workflow_dispatch'
        run: git checkout "$INPUT_TAG"

      - uses: ./.github/actions/setup-rust
        with:
          tools: git-cliff@2.12.0
          cache-key: publish

      - name: Resolve release tag
        run: |
          TAG="${GITHUB_REF_NAME}"
          if [ "${GITHUB_EVENT_NAME}" = "workflow_dispatch" ]; then
            TAG="${INPUT_TAG}"
          fi
          RELEASE_NOTES_PATH="${RUNNER_TEMP}/release-notes.md"
          echo "TAG=${TAG}" >> "$GITHUB_ENV"
          echo "RELEASE_NOTES_PATH=${RELEASE_NOTES_PATH}" >> "$GITHUB_ENV"

      - name: Verify tag matches Cargo.toml version
        run: ./scripts/verify-release-tag.sh "$TAG"

      - name: Verify CHANGELOG.md is current
        run: |
          tmpfile=$(mktemp)
          git cliff --config cliff.toml --output "$tmpfile"
          diff -u CHANGELOG.md "$tmpfile"

      - name: Dry run publish validation
        run: cargo publish --locked --dry-run

      - name: Render release notes
        run: git cliff --config cliff.toml --current --strip header --output "$RELEASE_NOTES_PATH"

      - name: Upload release notes artifact
        uses: actions/upload-artifact@v7
        with:
          name: release-notes-${{ github.event_name == 'workflow_dispatch' && inputs.tag || github.ref_name }}
          path: ${{ env.RELEASE_NOTES_PATH }}

      - name: Authenticate to crates.io with trusted publishing
        if: github.event_name == 'push' || env.DRY_RUN != 'true'
        uses: rust-lang/crates-io-auth-action@v1
        id: crates-io-auth

      - name: Publish to crates.io
        if: github.event_name == 'push' || env.DRY_RUN != 'true'
        run: cargo publish --locked
        env:
          CARGO_REGISTRY_TOKEN: ${{ steps.crates-io-auth.outputs.token }}

      - name: Publish GitHub release
        if: github.event_name == 'push' || env.DRY_RUN != 'true'
        env:
          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        run: |
          if gh release view "$TAG" >/dev/null 2>&1; then
            gh release edit "$TAG" --title "$TAG" --notes-file "$RELEASE_NOTES_PATH"
          else
            gh release create "$TAG" --verify-tag --title "$TAG" --notes-file "$RELEASE_NOTES_PATH"
          fi

      - name: Report dry-run mode
        if: github.event_name == 'workflow_dispatch' && env.DRY_RUN == 'true'
        run: |
          echo "Dry-run only: crates.io publish and GitHub release update were skipped."
          echo "Push the release tag to run the real CI publish with trusted publishing."