Skip to content

Release

Release #7

Workflow file for this run

name: Release
on:
push:
tags:
- "v*.*.*"
workflow_dispatch:
inputs:
version:
description: "Version to release (e.g., v0.1.0)"
required: true
type: string
dry_run:
description: "Dry run (skip GitHub release and crates.io publish)"
required: false
type: boolean
default: true
publish_crate:
description: "Publish to crates.io (ignored if dry_run is true)"
required: false
type: boolean
default: false
permissions:
contents: write
env:
CARGO_TERM_COLOR: always
BINARY_NAME: tuigram
jobs:
prepare:
name: Prepare
runs-on: ubuntu-latest
outputs:
version: ${{ steps.config.outputs.version }}
dry_run: ${{ steps.config.outputs.dry_run }}
publish_crate: ${{ steps.config.outputs.publish_crate }}
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Install Rust stable
uses: dtolnay/rust-toolchain@stable
- name: Cache Cargo dependencies
uses: Swatinem/rust-cache@v2
- name: Determine version and mode
id: config
run: |
if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then
echo "version=${{ inputs.version }}" >> $GITHUB_OUTPUT
echo "dry_run=${{ inputs.dry_run }}" >> $GITHUB_OUTPUT
echo "publish_crate=${{ inputs.publish_crate }}" >> $GITHUB_OUTPUT
else
echo "version=${{ github.ref_name }}" >> $GITHUB_OUTPUT
echo "dry_run=false" >> $GITHUB_OUTPUT
echo "publish_crate=false" >> $GITHUB_OUTPUT
fi
- name: Print configuration
run: |
echo "🏷️ Version: ${{ steps.config.outputs.version }}"
echo "🧪 Dry run: ${{ steps.config.outputs.dry_run }}"
echo "📦 Publish to crates.io: ${{ steps.config.outputs.publish_crate }}"
- name: Verify crate version matches tag
run: |
TAG="${{ steps.config.outputs.version }}"
TAG_VERSION="${TAG#v}"
CARGO_VERSION=$(grep -m1 '^version' Cargo.toml | sed 's/.*"\(.*\)".*/\1/')
if [[ "$TAG_VERSION" != "$CARGO_VERSION" ]]; then
echo "❌ Error: Tag version ($TAG_VERSION) does not match Cargo.toml version ($CARGO_VERSION)"
exit 1
fi
echo "✅ Version verified: $CARGO_VERSION"
- name: Run tests
run: cargo test --all --verbose
- name: Run clippy
run: cargo clippy -- -D warnings
- name: Dry run cargo publish
run: cargo publish --dry-run
build:
name: Build ${{ matrix.target }}
needs: prepare
if: needs.prepare.outputs.dry_run == 'false'
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
include:
- target: x86_64-unknown-linux-gnu
os: ubuntu-latest
- target: x86_64-unknown-linux-musl
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
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Install Rust stable
uses: dtolnay/rust-toolchain@stable
with:
targets: ${{ matrix.target }}
- name: Install musl-tools (Linux musl)
if: matrix.target == 'x86_64-unknown-linux-musl'
run: sudo apt-get update && sudo apt-get install -y musl-tools
- name: Install cross-compilation tools (Linux ARM)
if: matrix.target == 'aarch64-unknown-linux-gnu'
run: |
sudo apt-get update
sudo apt-get install -y gcc-aarch64-linux-gnu
- name: Cache Cargo dependencies
uses: Swatinem/rust-cache@v2
with:
key: ${{ matrix.target }}
- name: Build binary
run: cargo build --release --target ${{ matrix.target }}
env:
CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER: aarch64-linux-gnu-gcc
- name: Package binary (Unix)
if: runner.os != 'Windows'
run: |
cd target/${{ matrix.target }}/release
tar czvf ../../../${{ env.BINARY_NAME }}-${{ needs.prepare.outputs.version }}-${{ matrix.target }}.tar.gz ${{ env.BINARY_NAME }}
- name: Package binary (Windows)
if: runner.os == 'Windows'
run: |
cd target/${{ matrix.target }}/release
7z a ../../../${{ env.BINARY_NAME }}-${{ needs.prepare.outputs.version }}-${{ matrix.target }}.zip ${{ env.BINARY_NAME }}.exe
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: ${{ env.BINARY_NAME }}-${{ matrix.target }}
path: ${{ env.BINARY_NAME }}-${{ needs.prepare.outputs.version }}-${{ matrix.target }}.*
release:
name: Release
needs: [prepare, build]
if: needs.prepare.outputs.dry_run == 'false'
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Download all artifacts
uses: actions/download-artifact@v4
with:
path: artifacts
merge-multiple: true
- name: List artifacts
run: ls -la artifacts/
- name: Install git-cliff
uses: taiki-e/install-action@v2
with:
tool: git-cliff
- name: Generate changelog
run: |
TAG="${{ needs.prepare.outputs.version }}"
git cliff --unreleased --tag "$TAG" --strip all -o RELEASE_CHANGELOG.md
git cliff --tag "$TAG" -o CHANGELOG.md
- name: Commit changelog
run: |
TAG="${{ needs.prepare.outputs.version }}"
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git add CHANGELOG.md
git commit -m "chore(release): update changelog for $TAG" || echo "No changes to commit"
git push origin HEAD:main
- name: Update tag
run: |
TAG="${{ needs.prepare.outputs.version }}"
git tag -f "$TAG" -m "Release $TAG"
git push origin "$TAG" --force
- name: Create GitHub release
uses: softprops/action-gh-release@v2
with:
tag_name: ${{ needs.prepare.outputs.version }}
name: ${{ needs.prepare.outputs.version }}
body_path: RELEASE_CHANGELOG.md
draft: false
prerelease: ${{ contains(needs.prepare.outputs.version, '-') }}
files: artifacts/*
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Summary
run: |
echo ""
echo "========== Release Summary =========="
echo "Version: ${{ needs.prepare.outputs.version }}"
echo "GitHub Release: ✅ Created with binaries"
echo "====================================="
publish:
name: Publish to crates.io
needs: [prepare, release]
if: needs.prepare.outputs.dry_run == 'false' && needs.prepare.outputs.publish_crate == 'true'
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Install Rust stable
uses: dtolnay/rust-toolchain@stable
- name: Cache Cargo dependencies
uses: Swatinem/rust-cache@v2
- name: Publish to crates.io
run: cargo publish --token ${{ secrets.CARGO_REGISTRY_TOKEN }}
env:
CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}
- name: Summary
run: |
echo ""
echo "========== Publish Summary =========="
echo "Version: ${{ needs.prepare.outputs.version }}"
echo "crates.io: ✅ Published"
echo "====================================="
dry-run-summary:
name: Dry Run Summary
needs: prepare
if: needs.prepare.outputs.dry_run == 'true'
runs-on: ubuntu-latest
steps:
- name: Summary
run: |
echo ""
echo "========== Dry Run Summary =========="
echo "Version: ${{ needs.prepare.outputs.version }}"
echo "Status: ✅ All checks passed"
echo ""
echo "To perform an actual release, run again with dry_run: false"
echo "====================================="