githubdw 0.2.4

Local SQLite data warehouse for GitHub repositories: sync PRs, reviews, and issues; query, metrics, fulltext search, and MCP server
Documentation
name: Release

on:
  push:
    tags:
      - "v[0-9]+.[0-9]+.[0-9]+*"
  # Manual dry-run: builds all binaries but skips release creation + publish.
  workflow_dispatch:

permissions:
  contents: write

env:
  CARGO_TERM_COLOR: always

jobs:
  build:
    name: Build ${{ matrix.target }}
    runs-on: ${{ matrix.runner }}
    strategy:
      # A release is all-or-nothing: if one platform fails, fix it and re-tag
      # rather than shipping a partial asset set.
      fail-fast: true
      matrix:
        include:
          # musl, statically linked: the gnu builds inherit the runner
          # image glibc (2.39 on ubuntu-24.04), which older hosts cannot
          # load. rusqlite bundles SQLite, so the result has no runtime
          # library requirements at all.
          - target: x86_64-unknown-linux-musl
            runner: ubuntu-latest
          - target: aarch64-unknown-linux-musl
            runner: ubuntu-24.04-arm
          - target: aarch64-apple-darwin
            runner: macos-latest
          - target: x86_64-apple-darwin
            # Cross-compiled from the arm64 runner; Apple's toolchain builds
            # both architectures natively, including rusqlite's bundled cc.
            runner: macos-latest
    steps:
      - uses: actions/checkout@v5

      - name: Install Rust
        uses: dtolnay/rust-toolchain@stable
        with:
          targets: ${{ matrix.target }}

      - name: Install musl toolchain
        if: contains(matrix.target, 'musl')
        run: sudo apt-get update -q && sudo apt-get install -y musl-tools

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

      - name: Smoke-test the binary
        # Only when the build architecture can execute on this runner.
        if: matrix.target != 'x86_64-apple-darwin'
        run: ./target/${{ matrix.target }}/release/githubdw --version

      - name: Package
        run: |
          version="${GITHUB_REF_NAME#v}"
          name="githubdw-${version}-${{ matrix.target }}"
          mkdir -p "dist/${name}"
          cp "target/${{ matrix.target }}/release/githubdw" "dist/${name}/"
          cp LICENSE README.md CHANGELOG.md "dist/${name}/"
          tar -czf "dist/${name}.tar.gz" -C dist "${name}"
          (cd dist && shasum -a 256 "${name}.tar.gz" > "${name}.tar.gz.sha256")

      - name: Upload artifact
        uses: actions/upload-artifact@v4
        with:
          name: tarball-${{ matrix.target }}
          path: |
            dist/*.tar.gz
            dist/*.tar.gz.sha256
          if-no-files-found: error

  release:
    name: Release
    # Dry-runs (workflow_dispatch) stop after the builds succeed.
    if: startsWith(github.ref, 'refs/tags/')
    needs: build
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v5

      - name: Extract version from tag
        id: version
        run: echo "version=${GITHUB_REF_NAME#v}" >> "$GITHUB_OUTPUT"

      - name: Verify tag matches Cargo.toml version
        run: |
          crate_version=$(grep -m1 '^version' Cargo.toml | cut -d'"' -f2)
          if [ "$crate_version" != "${{ steps.version.outputs.version }}" ]; then
            echo "Tag ${{ steps.version.outputs.version }} != Cargo.toml $crate_version" >&2
            exit 1
          fi

      - name: Extract changelog section
        id: changelog
        run: |
          # Extract the section for this version from CHANGELOG.md
          section=$(awk '/^## \['"${{ steps.version.outputs.version }}"'\]/{found=1; next} /^## \[/{if(found) exit} found{print}' CHANGELOG.md)
          {
            echo "notes<<EOF"
            echo "$section"
            echo "EOF"
          } >> "$GITHUB_OUTPUT"

      - name: Download build artifacts
        uses: actions/download-artifact@v4
        with:
          # OUTSIDE the checkout: cargo publish refuses to run from a dirty
          # working tree, and downloaded tarballs inside the repo dir are
          # exactly that (v0.2.0 release failed on this).
          path: ${{ runner.temp }}/dist
          pattern: tarball-*
          merge-multiple: true

      - name: Create GitHub Release with binaries
        run: |
          gh release create "$GITHUB_REF_NAME" \
            --title "$GITHUB_REF_NAME" \
            --notes "$RELEASE_NOTES" \
            "$RUNNER_TEMP"/dist/*.tar.gz "$RUNNER_TEMP"/dist/*.tar.gz.sha256
        env:
          GH_TOKEN: ${{ github.token }}
          RELEASE_NOTES: ${{ steps.changelog.outputs.notes }}

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

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