hotdata 0.20.0

Powerful data platform API for datasets, queries, and analytics.
Documentation
# Cut a release entirely from CI, using the same scripts/release.sh a human
# would run locally. Three steps:
#
#   1. `gh workflow run cut-release.yml -f bump=<patch|minor|major|X.Y.Z>`
#      runs `release.sh prepare`: bumps Cargo.toml, rolls [Unreleased] into a
#      versioned CHANGELOG section, pushes release/vX.Y.Z and opens the PR,
#      then enables auto-merge on it.
#   2. The PR merges on its own once CI and the review gate pass.
#   3. The merge of a release/v* branch triggers the `publish` job below, which
#      runs `release.sh publish`: tags main with vX.Y.Z and pushes the tag.
#      The tag push then triggers publish.yml (crates.io) and release.yml
#      (GitHub Release) as it always has.
#
# Every git/gh call uses a GitHub App token instead of GITHUB_TOKEN. PRs opened
# and tags pushed with GITHUB_TOKEN never trigger other workflows, so with it
# the release PR would get no CI checks and the tag would never publish.

name: Cut Release

on:
  workflow_dispatch:
    inputs:
      bump:
        description: 'patch | minor | major | explicit X.Y.Z'
        required: true
        default: patch
        type: string
  pull_request:
    types: [closed]
    branches: [main]

permissions: {}

concurrency:
  group: cut-release
  cancel-in-progress: false

jobs:
  prepare:
    name: Open release PR
    if: github.event_name == 'workflow_dispatch'
    runs-on: ubuntu-latest
    steps:
      - name: Generate GitHub App token
        id: app-token
        uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0
        with:
          client-id: Iv23liKBX2RYMoZIYuKa
          private-key: ${{ secrets.HOTDATA_AUTOMATION_PRIVATE_KEY }}
          owner: hotdata-dev

      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
        with:
          token: ${{ steps.app-token.outputs.token }}
          fetch-depth: 0
          fetch-tags: true

      - uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable
        with:
          toolchain: stable

      # release.sh bumps Cargo.toml with `cargo set-version` (cargo-edit).
      - name: Install cargo-edit
        uses: taiki-e/install-action@1168f6810a3cb30a3514bf5756a3b7f0422c6df8 # v2.87.28
        with:
          tool: cargo-edit

      - name: Configure git identity
        env:
          GH_TOKEN: ${{ steps.app-token.outputs.token }}
        run: |
          slug="${{ steps.app-token.outputs.app-slug }}[bot]"
          id="$(gh api "/users/${slug}" --jq .id)"
          git config user.name "$slug"
          git config user.email "${id}+${slug}@users.noreply.github.com"

      # release.sh resolves the default branch from origin/HEAD, which
      # actions/checkout never sets; without this the script sees an empty
      # branch name and git aborts on an empty pathspec.
      - name: Point origin/HEAD at the default branch
        run: git remote set-head origin --auto

      - name: Prepare release
        env:
          GH_TOKEN: ${{ steps.app-token.outputs.token }}
        run: ./scripts/release.sh prepare "${{ inputs.bump }}"

      # Branch protection on main gates the merge on CI plus the review gate,
      # so this only merges once everything is green.
      - name: Enable auto-merge on the release PR
        env:
          GH_TOKEN: ${{ steps.app-token.outputs.token }}
        run: |
          branch="$(git rev-parse --abbrev-ref HEAD)"
          number="$(gh pr list --head "$branch" --state open --json number --jq '.[0].number')"
          [[ -n "$number" ]] || { echo "::error::no open PR for $branch"; exit 1; }
          gh pr merge "$number" --squash --auto

  publish:
    name: Tag release
    if: >-
      github.event_name == 'pull_request' &&
      github.event.pull_request.merged == true &&
      startsWith(github.event.pull_request.head.ref, 'release/v')
    runs-on: ubuntu-latest
    steps:
      - name: Generate GitHub App token
        id: app-token
        uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0
        with:
          client-id: Iv23liKBX2RYMoZIYuKa
          private-key: ${{ secrets.HOTDATA_AUTOMATION_PRIVATE_KEY }}
          owner: hotdata-dev

      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
        with:
          ref: main
          token: ${{ steps.app-token.outputs.token }}
          fetch-depth: 0
          fetch-tags: true

      # release.sh reads the version with `cargo metadata`.
      - uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable
        with:
          toolchain: stable

      - name: Configure git identity
        env:
          GH_TOKEN: ${{ steps.app-token.outputs.token }}
        run: |
          slug="${{ steps.app-token.outputs.app-slug }}[bot]"
          id="$(gh api "/users/${slug}" --jq .id)"
          git config user.name "$slug"
          git config user.email "${id}+${slug}@users.noreply.github.com"

      # release.sh resolves the default branch from origin/HEAD, which
      # actions/checkout never sets; without this the script sees an empty
      # branch name and git aborts on an empty pathspec.
      - name: Point origin/HEAD at the default branch
        run: git remote set-head origin --auto

      - name: Tag and push
        env:
          GH_TOKEN: ${{ steps.app-token.outputs.token }}
        run: ./scripts/release.sh publish