Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
157 changes: 157 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
name: Release

on:
workflow_dispatch:
inputs:
version:
description: "Version to release (e.g. 0.2.2)"
required: true
type: string
skip_crates:
description: "Skip crates.io publish"
required: false
type: boolean
default: false
skip_docker:
description: "Skip Docker image push"
required: false
type: boolean
default: false

env:
CARGO_TERM_COLOR: always
DOCKER_IMAGE: ghcr.io/totte-dev/qhook

jobs:
validate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6

- name: Validate version matches Cargo.toml
run: |
cargo_version=$(grep '^version' Cargo.toml | head -1 | sed 's/.*"\(.*\)"/\1/')
if [ "$cargo_version" != "${{ inputs.version }}" ]; then
echo "::error::Version mismatch: Cargo.toml has $cargo_version, input is ${{ inputs.version }}"
exit 1
fi

- name: Validate version matches CHANGELOG.md
run: |
if ! grep -q "## \[${{ inputs.version }}\]" CHANGELOG.md; then
echo "::error::Version ${{ inputs.version }} not found in CHANGELOG.md"
exit 1
fi

- name: Check tag does not exist
run: |
if git rev-parse "v${{ inputs.version }}" >/dev/null 2>&1; then
echo "::error::Tag v${{ inputs.version }} already exists"
exit 1
fi

test:
needs: validate
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6

- uses: dtolnay/rust-toolchain@stable
with:
components: clippy, rustfmt

- uses: Swatinem/rust-cache@v2

- name: Format
run: cargo fmt --check

- name: Clippy
run: cargo clippy --all-targets

- name: Unit tests
run: cargo test

- name: Build release
run: cargo build --release

- name: E2E tests
run: bash tests/e2e.sh

github-release:
needs: test
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- uses: actions/checkout@v6

- name: Extract changelog for this version
id: changelog
run: |
# Extract the section for this version from CHANGELOG.md
awk '/^## \[${{ inputs.version }}\]/{found=1; next} /^## \[/{if(found) exit} found{print}' CHANGELOG.md > release_notes.md
cat release_notes.md

- name: Create tag and release
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
git tag "v${{ inputs.version }}"
git push origin "v${{ inputs.version }}"
gh release create "v${{ inputs.version }}" \
--title "v${{ inputs.version }}" \
--notes-file release_notes.md

crates-io:
needs: test
if: ${{ !inputs.skip_crates }}
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6

- uses: dtolnay/rust-toolchain@stable

- uses: Swatinem/rust-cache@v2

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

docker:
needs: test
if: ${{ !inputs.skip_docker }}
runs-on: ubuntu-latest
permissions:
packages: write
steps:
- uses: actions/checkout@v6

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

- name: Log in to GHCR
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Log in to Docker Hub
if: ${{ secrets.DOCKERHUB_TOKEN != '' }}
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}

- name: Build and push
uses: docker/build-push-action@v6
with:
context: .
push: true
platforms: linux/amd64,linux/arm64
tags: |
${{ env.DOCKER_IMAGE }}:${{ inputs.version }}
${{ env.DOCKER_IMAGE }}:latest
cache-from: type=gha
cache-to: type=gha,mode=max