name: Release
on:
workflow_run:
workflows: ["CI"]
types: [completed]
workflow_dispatch:
inputs:
tag:
description: "Existing release tag to build (e.g. v0.1.2-beta)"
required: true
type: string
permissions:
contents: write
env:
CARGO_TERM_COLOR: always
jobs:
prepare:
name: Prepare release tag
runs-on: ubuntu-latest
if: >-
github.event_name == 'workflow_dispatch' ||
(
github.event_name == 'workflow_run' &&
github.event.workflow_run.conclusion == 'success' &&
github.event.workflow_run.event == 'push' &&
github.event.workflow_run.head_branch == 'main' &&
github.event.workflow_run.actor.login != 'github-actions[bot]'
)
outputs:
release_tag: ${{ steps.prepare.outputs.release_tag }}
should_release: ${{ steps.prepare.outputs.should_release }}
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
ref: ${{ github.event_name == 'workflow_run' && github.event.workflow_run.head_sha || github.sha }}
- name: Install Rust toolchain
if: github.event_name == 'workflow_run'
uses: dtolnay/rust-toolchain@stable
- name: Cache Cargo dependencies
if: github.event_name == 'workflow_run'
uses: Swatinem/rust-cache@v2
- name: Resolve tag (manual / auto-bump after CI on main)
id: prepare
env:
MANUAL_TAG: ${{ github.event.inputs.tag }}
shell: bash
run: |
set -euo pipefail
# 1) Manual dispatch path: use provided tag.
if [[ "${GITHUB_EVENT_NAME}" == "workflow_dispatch" ]]; then
if [[ ! "${MANUAL_TAG}" =~ ^v ]]; then
echo "Manual tag must start with 'v' (got: ${MANUAL_TAG})" >&2
exit 1
fi
echo "release_tag=${MANUAL_TAG}" >> "$GITHUB_OUTPUT"
echo "should_release=true" >> "$GITHUB_OUTPUT"
exit 0
fi
# 2) CI-success on main path: auto-bump beta patch, commit, tag, push.
./scripts/bump-beta.sh
VERSION="$(awk '
$0=="[package]" { in_pkg=1; next }
/^\[/ && $0!="[package]" { in_pkg=0 }
in_pkg && $1=="version" {
gsub(/"/, "", $3)
print $3
exit
}
' Cargo.toml)"
if [[ -z "${VERSION}" ]]; then
echo "Could not read version from Cargo.toml" >&2
exit 1
fi
TAG="v${VERSION}"
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
if ! git diff --quiet -- Cargo.toml Cargo.lock; then
git add Cargo.toml Cargo.lock
git commit -m "chore(release): bump version to ${VERSION}"
git push origin HEAD:main
fi
if git rev-parse "${TAG}" >/dev/null 2>&1; then
echo "Tag ${TAG} already exists; skipping tag creation."
else
git tag -a "${TAG}" -m "Release ${TAG}"
git push origin "${TAG}"
fi
echo "release_tag=${TAG}" >> "$GITHUB_OUTPUT"
echo "should_release=true" >> "$GITHUB_OUTPUT"
build:
name: Build — ${{ matrix.target }}
runs-on: ${{ matrix.os }}
needs: prepare
if: needs.prepare.outputs.should_release == 'true'
strategy:
fail-fast: false
matrix:
include:
- os: ubuntu-latest
target: x86_64-unknown-linux-gnu
binary_name: shql
asset_name: shql-linux-x86_64
- os: macos-14
target: aarch64-apple-darwin
binary_name: shql
asset_name: shql-macos-arm64
- os: windows-latest
target: x86_64-pc-windows-msvc
binary_name: shql.exe
asset_name: shql-windows-x86_64.exe
steps:
- name: Checkout code at release tag
uses: actions/checkout@v4
with:
ref: ${{ needs.prepare.outputs.release_tag }}
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable
with:
targets: ${{ matrix.target }}
- name: Cache Cargo dependencies
uses: Swatinem/rust-cache@v2
with:
key: ${{ matrix.target }}
- name: Build release binary
run: cargo build --release --locked --target ${{ matrix.target }}
- name: Rename binary (Unix)
if: matrix.os != 'windows-latest'
run: |
cp target/${{ matrix.target }}/release/${{ matrix.binary_name }} ${{ matrix.asset_name }}
- name: Rename binary (Windows)
if: matrix.os == 'windows-latest'
shell: pwsh
run: |
Copy-Item "target/${{ matrix.target }}/release/${{ matrix.binary_name }}" "${{ matrix.asset_name }}"
- name: Upload binary artifact
uses: actions/upload-artifact@v4
with:
name: ${{ matrix.asset_name }}
path: ${{ matrix.asset_name }}
release:
name: Create GitHub Release
runs-on: ubuntu-latest
needs: [prepare, build]
if: needs.prepare.outputs.should_release == 'true'
steps:
- name: Download all binaries
uses: actions/download-artifact@v4
with:
path: binaries/
merge-multiple: true
- name: Create release and upload binaries
uses: softprops/action-gh-release@v2
with:
tag_name: ${{ needs.prepare.outputs.release_tag }}
generate_release_notes: true
prerelease: ${{ contains(needs.prepare.outputs.release_tag, '-beta') }}
files: binaries/*