name: Release
on:
push:
tags:
- 'v*'
release:
types: [published] workflow_dispatch:
permissions:
contents: write
jobs:
validate:
name: Validate Release
if: startsWith(github.ref, 'refs/tags/v')
uses: ./.github/workflows/validate-release.yml
secrets: inherit
publish-crate:
name: Publish to crates.io
runs-on: ubuntu-latest
if: github.event_name == 'release' && github.event.action == 'published'
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0
- name: Install Rust
uses: dtolnay/rust-toolchain@fa04a1451ff1842e2626ccb99004d0195b455a88 with:
toolchain: stable
- name: Check version matches tag
run: |
TAG_VERSION=${GITHUB_REF#refs/tags/v}
CARGO_VERSION=$(grep "^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
- name: Run tests
run: cargo test --all-features
- name: Publish to crates.io
run: cargo publish --token "${CARGO_REGISTRY_TOKEN}"
env:
CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}
build-deb:
name: Build Debian Package
runs-on: ubuntu-latest
needs: validate
if: startsWith(github.ref, 'refs/tags/v')
strategy:
matrix:
target:
- x86_64-unknown-linux-gnu
- aarch64-unknown-linux-gnu
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0
- name: Install Rust
uses: dtolnay/rust-toolchain@fa04a1451ff1842e2626ccb99004d0195b455a88 with:
toolchain: stable
targets: ${{ matrix.target }}
- name: Setup Rust cache
uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 with:
key: ${{ matrix.target }}
- name: Cache cargo-deb
id: cache-cargo-deb
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 with:
path: ~/.cargo/bin/cargo-deb
key: ${{ runner.os }}-cargo-deb-2.7.0
- name: Install cargo-deb
if: steps.cache-cargo-deb.outputs.cache-hit != 'true'
run: cargo install cargo-deb --version 2.7.0
- name: Install cross-compilation tools for ARM64
if: matrix.target == 'aarch64-unknown-linux-gnu'
run: |
sudo apt-get update
sudo apt-get install -y gcc-aarch64-linux-gnu pkg-config libssl-dev
- name: Build release binary
run: |
if [ "${{ matrix.target }}" = "aarch64-unknown-linux-gnu" ]; then
export CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER=aarch64-linux-gnu-gcc
export CC_aarch64_unknown_linux_gnu=aarch64-linux-gnu-gcc
export CXX_aarch64_unknown_linux_gnu=aarch64-linux-gnu-g++
fi
cargo build --release --target ${{ matrix.target }}
- name: Build .deb package
run: |
if [ "${{ matrix.target }}" = "aarch64-unknown-linux-gnu" ]; then
# For cross-compilation, disable stripping to avoid strip format errors
cargo deb --target ${{ matrix.target }} --no-build --no-strip
else
cargo deb --target ${{ matrix.target }} --no-build
fi
- name: Upload .deb artifact
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a with:
name: ftr-deb-${{ matrix.target }}
path: target/${{ matrix.target }}/debian/*.deb
build-windows:
name: Build Windows Binary
runs-on: windows-latest
needs: validate
if: startsWith(github.ref, 'refs/tags/v')
strategy:
matrix:
target:
- x86_64-pc-windows-msvc
- aarch64-pc-windows-msvc
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0
- name: Install Rust
uses: dtolnay/rust-toolchain@fa04a1451ff1842e2626ccb99004d0195b455a88 with:
toolchain: stable
targets: ${{ matrix.target }}
- name: Setup Rust cache
uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 with:
key: ${{ matrix.target }}
- name: Build release binary
run: cargo build --release --target ${{ matrix.target }}
- name: Create archive
shell: pwsh
run: |
$target = "${{ matrix.target }}"
$version = "${env:GITHUB_REF}" -replace "refs/tags/v", ""
$archiveName = "ftr-${version}-${target}.zip"
# Create a directory for the archive contents
New-Item -ItemType Directory -Force -Path "archive"
# Copy the binary
Copy-Item "target\${target}\release\ftr.exe" "archive\"
# Copy README and LICENSE
Copy-Item "README.md" "archive\"
Copy-Item "LICENSE" "archive\"
# Create the zip archive
Compress-Archive -Path "archive\*" -DestinationPath $archiveName
# Output the archive name for the upload step
echo "ARCHIVE_NAME=$archiveName" >> $env:GITHUB_ENV
- name: Upload Windows artifact
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a with:
name: ftr-windows-${{ matrix.target }}
path: ${{ env.ARCHIVE_NAME }}
create-release:
name: Create Release
needs: [build-deb, build-windows]
runs-on: ubuntu-latest
permissions:
contents: write
id-token: write attestations: write steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0
- name: Download all artifacts
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c with:
pattern: ftr-*
merge-multiple: true
- name: Generate SHA256SUMS
run: |
sha256sum -- *.deb *.zip > SHA256SUMS
cat SHA256SUMS
- name: Attest build provenance
uses: actions/attest-build-provenance@0f67c3f4856b2e3261c31976d6725780e5e4c373 with:
subject-path: |
*.deb
*.zip
- name: Create Release
uses: softprops/action-gh-release@718ea10b132b3b2eba29c1007bb80653f286566b with:
files: |
*.deb
*.zip
SHA256SUMS
draft: true prerelease: false
body: |
## Installation
### Windows
Download the appropriate .zip file below for your architecture:
- `ftr-*-x86_64-pc-windows-msvc.zip` for 64-bit Intel/AMD
- `ftr-*-aarch64-pc-windows-msvc.zip` for ARM64
Extract the archive and add the directory to your PATH, or run `ftr.exe` directly.
### Debian/Ubuntu packages
Download the appropriate .deb file below for your architecture:
- `ftr_*_amd64.deb` for 64-bit Intel/AMD
- `ftr_*_arm64.deb` for ARM64
### Other platforms
- macOS: `brew tap dweekly/ftr && brew install ftr`
- Cargo: `cargo install ftr` (available after this release is published)
## Verifying downloads
Checksums for all artifacts are in `SHA256SUMS` (`sha256sum -c SHA256SUMS --ignore-missing`).
Each artifact also has signed build provenance: `gh attestation verify <file> --repo ${{ github.repository }}`
## Release Notes
Please see [CHANGELOG.md](https://github.com/${{ github.repository }}/blob/${{ github.ref_name }}/CHANGELOG.md) for detailed changes.
---
*Note: This is a draft release. Please edit with proper release notes before publishing.*
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}