Publish to Crates.io #16
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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 |