holocron 0.1.7

Declarative schema & query compiler — one YAML as the source of truth for SQL schema and a type-checked query catalog.
name: Release

# Automated semantic release. On every push to main (i.e. when a PR merges),
# cocogitto reads the Conventional Commits since the last tag, computes the next
# version, bumps Cargo.toml, updates CHANGELOG.md, and creates the version commit
# and tag. The tag then drives the GitHub Release and (when configured) the
# crates.io publish. No release PR — the tag is created automatically.
on:
  push:
    branches: [main]
  workflow_dispatch:

# Needed to push the bump commit + tag and to create the GitHub Release.
permissions:
  contents: write

# Never run two releases at once, and never cancel one mid-publish.
concurrency:
  group: release
  cancel-in-progress: false

env:
  CARGO_TERM_COLOR: always

jobs:
  release:
    name: Semantic release
    runs-on: ubuntu-latest
    # Expose whether a release happened and its tag, so the binary-upload job
    # below can run only on a real release and target the right tag.
    outputs:
      released: ${{ steps.bump.outputs.released }}
      tag: ${{ steps.bump.outputs.tag }}
    steps:
      - uses: actions/checkout@v7
        with:
          fetch-depth: 0 # full history so cocogitto can analyse every commit

      - uses: dtolnay/rust-toolchain@stable

      - uses: Swatinem/rust-cache@v2

      # Prebuilt binaries — fast, no compilation.
      # --force: rust-cache restores ~/.cargo/.crates.toml (the "installed" registry)
      # but not the binaries themselves, so without --force binstall sees cocogitto as
      # "already installed" and skips it, leaving `cog` missing on PATH.
      - uses: cargo-bins/cargo-binstall@main
      - name: Install cocogitto and cargo-edit
        run: cargo binstall -y --force cocogitto cargo-edit

      - name: Configure git identity
        run: |
          git config user.name "github-actions[bot]"
          git config user.email "41898282+github-actions[bot]@users.noreply.github.com"

      - name: Bump version, update changelog, and tag
        id: bump
        run: |
          # Fail loudly if the tool is missing, rather than mistaking it for
          # "no releasable changes" below and exiting green without releasing.
          command -v cog >/dev/null || { echo "::error::cocogitto (cog) is not installed"; exit 1; }
          before=$(git describe --tags --abbrev=0 2>/dev/null || echo "none")
          # `cog bump --auto` exits non-zero when there are no releasable commits.
          if cog bump --auto; then
            tag=$(git describe --tags --abbrev=0)
            echo "released=true" >> "$GITHUB_OUTPUT"
            echo "tag=$tag" >> "$GITHUB_OUTPUT"
            echo "Released $tag (previous: $before)"
          else
            echo "released=false" >> "$GITHUB_OUTPUT"
            echo "No releasable changes since $before — skipping release."
          fi

      - name: Push commit and tag
        if: steps.bump.outputs.released == 'true'
        run: git push --follow-tags origin HEAD:main

      # Publishing only runs once a crates.io token is configured, so a pre-release
      # stub is never published by accident. Add the CARGO_REGISTRY_TOKEN secret to
      # enable it (Settings → Secrets and variables → Actions).
      - name: Check for crates.io token
        if: steps.bump.outputs.released == 'true'
        id: cratesio
        env:
          TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}
        run: |
          if [ -n "$TOKEN" ]; then
            echo "enabled=true" >> "$GITHUB_OUTPUT"
          else
            echo "enabled=false" >> "$GITHUB_OUTPUT"
            echo "CARGO_REGISTRY_TOKEN not set — skipping crates.io publish."
          fi

      # Publish before creating the GitHub Release, so the crates.io link added to
      # the release notes is already valid when the release goes live.
      - name: Publish to crates.io
        if: steps.bump.outputs.released == 'true' && steps.cratesio.outputs.enabled == 'true'
        env:
          CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}
        run: cargo publish

      - name: Extract release notes
        if: steps.bump.outputs.released == 'true'
        # Take the newest section of the changelog cocogitto just wrote (from the
        # first "## " heading up to the next one). Avoids re-parsing old, possibly
        # non-conventional history, which `cog changelog --at` would choke on.
        # Write outside the repo so the working tree stays clean for cargo publish.
        # When the crate was published, append a link to the crates.io release.
        run: |
          notes="$RUNNER_TEMP/RELEASE_NOTES.md"
          awk '/^## /{n++} n==1{print} n==2{exit}' CHANGELOG.md > "$notes"
          if [ "${{ steps.cratesio.outputs.enabled }}" = "true" ]; then
            version="${{ steps.bump.outputs.tag }}"
            version="${version#v}"
            printf '\n📦 **crates.io:** [holocron %s](https://crates.io/crates/holocron/%s)\n' "$version" "$version" >> "$notes"
          fi

      - name: Create GitHub Release
        if: steps.bump.outputs.released == 'true'
        uses: softprops/action-gh-release@v2
        with:
          tag_name: ${{ steps.bump.outputs.tag }}
          body_path: ${{ runner.temp }}/RELEASE_NOTES.md

  # Build the holocron binary for each platform and attach the archives to the
  # GitHub Release created above. Runs only when a release was actually cut.
  upload-binaries:
    name: Upload binary (${{ matrix.target }})
    needs: release
    if: needs.release.outputs.released == 'true'
    permissions:
      contents: write # to upload release assets
    strategy:
      fail-fast: false
      matrix:
        include:
          - target: x86_64-unknown-linux-gnu
            os: ubuntu-latest
          - target: aarch64-unknown-linux-gnu
            os: ubuntu-latest
          - target: x86_64-apple-darwin
            os: macos-latest
          - target: aarch64-apple-darwin
            os: macos-latest
          - target: x86_64-pc-windows-msvc
            os: windows-latest
    runs-on: ${{ matrix.os }}
    steps:
      # Check out the released tag so the binary matches the published version.
      - uses: actions/checkout@v7
        with:
          ref: refs/tags/${{ needs.release.outputs.tag }}

      - name: Build and upload binary
        uses: taiki-e/upload-rust-binary-action@v1
        with:
          bin: holocron
          target: ${{ matrix.target }}
          # Archive name, e.g. holocron-v0.1.3-x86_64-unknown-linux-gnu.tar.gz
          archive: $bin-$tag-$target
          # Attach to the release for the tag we just created.
          ref: refs/tags/${{ needs.release.outputs.tag }}
          # Also bundle these files and publish a SHA-256 checksum per archive.
          include: LICENSE,README.md
          checksum: sha256
          token: ${{ secrets.GITHUB_TOKEN }}