Skip to content

Publish to Crates.io #16

Publish to Crates.io

Publish to Crates.io #16

Workflow file for this run

name: Publish to Crates.io
on:
push:
tags:
- 'v*.*.*'
branches:
- main
workflow_dispatch:
inputs:
tag:
description: 'Version tag to publish (e.g., v1.0.0)'
required: true
type: string
publish:
description: 'Publish to crates.io after tests pass'
required: true
type: boolean
default: false
env:
CARGO_TERM_COLOR: always
jobs:
# Cross-platform testing job
test:
name: Test on ${{ matrix.os }} (${{ matrix.arch }})
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
include:
# Windows
- os: windows-latest
arch: x86_64
target: x86_64-pc-windows-msvc
- os: windows-latest
arch: aarch64
target: aarch64-pc-windows-msvc
# Ubuntu
- os: ubuntu-latest
arch: x86_64
target: x86_64-unknown-linux-gnu
- os: ubuntu-latest
arch: aarch64
target: aarch64-unknown-linux-gnu
# macOS (both architectures natively supported)
- os: macos-latest
arch: x86_64
target: x86_64-apple-darwin
- os: macos-latest
arch: aarch64
target: aarch64-apple-darwin
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Rust toolchain
uses: dtolnay/rust-toolchain@stable
with:
targets: ${{ matrix.target }}
- name: Cache cargo registry
uses: actions/cache@v4
with:
path: |
~/.cargo/registry
~/.cargo/git
target
key: ${{ runner.os }}-${{ matrix.arch }}-cargo-${{ hashFiles('**/Cargo.lock') }}
restore-keys: |
${{ runner.os }}-${{ matrix.arch }}-cargo-
- name: Install cross for cross-compilation
if: ${{ matrix.os == 'ubuntu-latest' && matrix.arch == 'aarch64' }}
run: cargo install cross --git https://github.com/cross-rs/cross
- name: Run cargo check (cross-compilation)
if: ${{ matrix.os == 'ubuntu-latest' && matrix.arch == 'aarch64' }}
run: cross check --target ${{ matrix.target }} --verbose
- name: Run cargo check (native)
if: ${{ !(matrix.os == 'ubuntu-latest' && matrix.arch == 'aarch64') }}
run: cargo check --target ${{ matrix.target }} --verbose
- name: Run cargo clippy (cross-compilation)
if: ${{ matrix.os == 'ubuntu-latest' && matrix.arch == 'aarch64' }}
run: cross clippy --target ${{ matrix.target }} --all-targets --all-features -- -D warnings
- name: Run cargo clippy (native)
if: ${{ !(matrix.os == 'ubuntu-latest' && matrix.arch == 'aarch64') }}
run: cargo clippy --target ${{ matrix.target }} --all-targets --all-features -- -D warnings
- name: Run cargo fmt check
run: cargo fmt --all -- --check
# Publishing job (only runs if all tests pass)
publish:
name: Publish to Crates.io
runs-on: ubuntu-latest
needs: test
permissions:
contents: write
packages: write
if: (startsWith(github.ref, 'refs/tags/v')) || (github.event_name == 'workflow_dispatch' && inputs.publish)
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Create tag for manual dispatch
if: ${{ github.event_name == 'workflow_dispatch' }}
run: |
git config user.name github-actions
git config user.email github-actions@github.com
git tag ${{ inputs.tag }}
git push origin ${{ inputs.tag }}
- name: Setup Rust toolchain
uses: dtolnay/rust-toolchain@stable
- name: Cache cargo registry
uses: actions/cache@v4
with:
path: |
~/.cargo/registry
~/.cargo/git
target
key: ubuntu-latest-cargo-publish-${{ hashFiles('**/Cargo.lock') }}
- name: Verify version matches tag
run: |
if [ "${{ github.event_name }}" == "workflow_dispatch" ]; then
TAG_VERSION="${{ inputs.tag }}"
TAG_VERSION=${TAG_VERSION#v}
else
TAG_VERSION=${GITHUB_REF#refs/tags/v}
fi
CARGO_VERSION=$(cargo metadata --no-deps --format-version 1 | jq -r '.packages[0].version')
echo "Tag version: $TAG_VERSION"
echo "Cargo.toml version: $CARGO_VERSION"
if [ "$TAG_VERSION" != "$CARGO_VERSION" ]; then
echo "Error: Tag version ($TAG_VERSION) does not match Cargo.toml version ($CARGO_VERSION)"
exit 1
fi
- name: Final cargo check
run: cargo check --verbose
- name: Final cargo clippy
run: cargo clippy --all-targets --all-features -- -D warnings
- name: Run tests
run: cargo test --verbose
- name: Publish to crates.io
run: cargo publish --locked
env:
CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}
- name: Extract changelog for current version
id: changelog
run: |
if [ "${{ github.event_name }}" == "workflow_dispatch" ]; then
VERSION="${{ inputs.tag }}"
VERSION=${VERSION#v}
else
VERSION=${GITHUB_REF#refs/tags/v}
fi
# Extract changelog content for the current version
# Find the start and end of the version section
START_LINE=$(grep -n "^## \[$VERSION\]" docs/CHANGELOG.md | head -1 | cut -d: -f1)
if [ -z "$START_LINE" ]; then
echo "Warning: Version $VERSION not found in CHANGELOG.md"
echo "CHANGELOG_CONTENT=Version $VERSION changelog not found. See [CHANGELOG.md](https://github.com/KodeBarinn/mihomo-speedtest-rs/blob/main/docs/CHANGELOG.md) for details." >> $GITHUB_OUTPUT
else
# Find the next version section or end of file
NEXT_LINE=$(tail -n +$((START_LINE + 1)) docs/CHANGELOG.md | grep -n "^## \[" | head -1 | cut -d: -f1)
if [ -z "$NEXT_LINE" ]; then
# No next version found, take to end of file
CONTENT=$(tail -n +$START_LINE docs/CHANGELOG.md)
else
# Take until next version section
END_LINE=$((START_LINE + NEXT_LINE - 1))
CONTENT=$(sed -n "${START_LINE},${END_LINE}p" docs/CHANGELOG.md)
fi
# Remove the version header line since we'll add our own
CONTENT=$(echo "$CONTENT" | tail -n +2)
# Handle multiline content for GitHub Actions output
{
echo "CHANGELOG_CONTENT<<EOF"
echo "$CONTENT"
echo "EOF"
} >> $GITHUB_OUTPUT
fi
- name: Create GitHub Release
uses: softprops/action-gh-release@v2
with:
tag_name: ${{ github.event_name == 'workflow_dispatch' && inputs.tag || github.ref }}
name: Release ${{ github.event_name == 'workflow_dispatch' && inputs.tag || github.ref }}
body: |
## Release ${{ github.event_name == 'workflow_dispatch' && inputs.tag || github.ref }}
Published to [crates.io](https://crates.io/crates/mihomo-speedtest-rs).
### Installation
```bash
cargo install mihomo-speedtest-rs
```
${{ steps.changelog.outputs.CHANGELOG_CONTENT }}
---
For complete changelog, see [CHANGELOG.md](https://github.com/KodeBarinn/mihomo-speedtest-rs/blob/main/docs/CHANGELOG.md).
draft: false
prerelease: false