name: Release
on:
push:
tags:
- 'v*.*.*'
workflow_dispatch:
permissions:
contents: write
id-token: write
env:
PACKAGE_NAME: linthis
jobs:
linux:
name: Build Linux ${{ matrix.target }}
runs-on: ${{ matrix.runner }}
strategy:
fail-fast: false
matrix:
include:
- runner: ubuntu-latest
target: x86_64
- runner: ubuntu-24.04-arm
target: aarch64
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: '3.11'
- name: Build wheels
uses: PyO3/maturin-action@v1
with:
target: ${{ matrix.target }}
args: --release --locked --out dist
manylinux: '2_28'
- name: Upload wheels
uses: actions/upload-artifact@v4
with:
name: wheels-linux-${{ matrix.target }}
path: dist
- name: Archive binary
run: |
ARCH=${{ matrix.target }}
if [ "$ARCH" = "x86_64" ]; then
TARGET=x86_64-unknown-linux-gnu
else
TARGET=aarch64-unknown-linux-gnu
fi
ARCHIVE_NAME=${{ env.PACKAGE_NAME }}-$TARGET
ARCHIVE_FILE=$ARCHIVE_NAME.tar.gz
mkdir -p $ARCHIVE_NAME
cp target/$TARGET/release/${{ env.PACKAGE_NAME }} $ARCHIVE_NAME/
tar czvf $ARCHIVE_FILE $ARCHIVE_NAME
shasum -a 256 $ARCHIVE_FILE > $ARCHIVE_FILE.sha256
- name: Upload binary
uses: actions/upload-artifact@v4
with:
name: binaries-linux-${{ matrix.target }}
path: |
*.tar.gz
*.sha256
windows:
name: Build Windows x86_64
runs-on: windows-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: '3.11'
- name: Build wheels
uses: PyO3/maturin-action@v1
with:
target: x86_64
args: --release --locked --out dist
- name: Upload wheels
uses: actions/upload-artifact@v4
with:
name: wheels-windows-x86_64
path: dist
- name: Archive binary
shell: bash
run: |
TARGET=x86_64-pc-windows-msvc
ARCHIVE_NAME=${{ env.PACKAGE_NAME }}-$TARGET
ARCHIVE_FILE=$ARCHIVE_NAME.zip
mkdir -p $ARCHIVE_NAME
cp target/$TARGET/release/${{ env.PACKAGE_NAME }}.exe $ARCHIVE_NAME/
7z a $ARCHIVE_FILE $ARCHIVE_NAME
sha256sum $ARCHIVE_FILE > $ARCHIVE_FILE.sha256
- name: Upload binary
uses: actions/upload-artifact@v4
with:
name: binaries-windows-x86_64
path: |
*.zip
*.sha256
macos:
name: Build macOS ${{ matrix.target }}
runs-on: ${{ matrix.runner }}
strategy:
fail-fast: false
matrix:
include:
- runner: macos-15-intel
target: x86_64
- runner: macos-14
target: aarch64
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: '3.11'
- name: Build wheels
uses: PyO3/maturin-action@v1
with:
target: ${{ matrix.target }}
args: --release --locked --out dist
- name: Upload wheels
uses: actions/upload-artifact@v4
with:
name: wheels-macos-${{ matrix.target }}
path: dist
- name: Archive binary
run: |
ARCH=${{ matrix.target }}
if [ "$ARCH" = "x86_64" ]; then
TARGET=x86_64-apple-darwin
else
TARGET=aarch64-apple-darwin
fi
ARCHIVE_NAME=${{ env.PACKAGE_NAME }}-$TARGET
ARCHIVE_FILE=$ARCHIVE_NAME.tar.gz
mkdir -p $ARCHIVE_NAME
cp target/$TARGET/release/${{ env.PACKAGE_NAME }} $ARCHIVE_NAME/
tar czvf $ARCHIVE_FILE $ARCHIVE_NAME
shasum -a 256 $ARCHIVE_FILE > $ARCHIVE_FILE.sha256
- name: Upload binary
uses: actions/upload-artifact@v4
with:
name: binaries-macos-${{ matrix.target }}
path: |
*.tar.gz
*.sha256
sdist:
name: Build sdist
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Build sdist
uses: PyO3/maturin-action@v1
with:
command: sdist
args: --out dist
- name: Upload sdist
uses: actions/upload-artifact@v4
with:
name: wheels-sdist
path: dist
github-release:
name: Create GitHub Release
runs-on: ubuntu-latest
if: startsWith(github.ref, 'refs/tags/')
needs: [linux, windows, macos, sdist]
steps:
- uses: actions/checkout@v4
- name: Download all binaries
uses: actions/download-artifact@v4
with:
pattern: binaries-*
path: binaries
merge-multiple: true
- name: Prepare release body
id: release_body
run: |
VERSION=${GITHUB_REF_NAME#v}
cat << EOF > release_body.md
## Installation
\`\`\`bash
pip install linthis==$VERSION
# or
pip install --upgrade linthis
\`\`\`
## Quick Start
\`\`\`bash
# Run linthis
linthis [-i <path>]
\`\`\`
See [CHANGELOG.md](CHANGELOG.md) for details.
EOF
- name: Create Release
uses: softprops/action-gh-release@v2
with:
files: binaries/*
generate_release_notes: true
body_path: release_body.md
draft: false
prerelease: ${{ contains(github.ref, 'alpha') || contains(github.ref, 'beta') || contains(github.ref, 'rc') }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
publish-pypi:
name: Publish to PyPI
runs-on: ubuntu-latest
if: startsWith(github.ref, 'refs/tags/')
needs: [linux, windows, macos, sdist]
permissions:
id-token: write
steps:
- uses: actions/download-artifact@v4
with:
pattern: wheels-*
merge-multiple: true
path: dist
- name: Publish to PyPI
uses: pypa/gh-action-pypi-publish@release/v1
publish-crates:
name: Publish to crates.io
runs-on: ubuntu-latest
if: startsWith(github.ref, 'refs/tags/')
needs: [linux, windows, macos, sdist]
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
- name: Run tests
run: cargo test --locked
- name: Publish to crates.io
env:
CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}
run: cargo publish --locked
publish-homebrew:
name: Update Homebrew tap
runs-on: ubuntu-latest
if: startsWith(github.ref, 'refs/tags/') && !contains(github.ref, 'alpha') && !contains(github.ref, 'beta') && !contains(github.ref, 'rc')
needs: [github-release]
steps:
- name: Download binary artifacts
uses: actions/download-artifact@v4
with:
pattern: binaries-*
path: binaries
merge-multiple: true
- name: Extract SHA256 checksums
id: sha
run: |
extract_sha() {
local file="binaries/$1.sha256"
if [ ! -f "$file" ]; then
echo "Error: missing checksum file $file" >&2
exit 1
fi
awk '{print $1}' "$file"
}
{
echo "darwin_arm64=$(extract_sha linthis-aarch64-apple-darwin.tar.gz)"
echo "darwin_x86_64=$(extract_sha linthis-x86_64-apple-darwin.tar.gz)"
echo "linux_arm64=$(extract_sha linthis-aarch64-unknown-linux-gnu.tar.gz)"
echo "linux_x86_64=$(extract_sha linthis-x86_64-unknown-linux-gnu.tar.gz)"
} >> "$GITHUB_OUTPUT"
- name: Clone Homebrew tap
env:
HOMEBREW_TAP_TOKEN: ${{ secrets.HOMEBREW_TAP_TOKEN }}
run: |
git clone "https://x-access-token:${HOMEBREW_TAP_TOKEN}@github.com/zhlinh/homebrew-linthis.git" tap
- name: Update Formula
env:
VERSION: ${{ github.ref_name }}
SHA_DARWIN_ARM64: ${{ steps.sha.outputs.darwin_arm64 }}
SHA_DARWIN_X86_64: ${{ steps.sha.outputs.darwin_x86_64 }}
SHA_LINUX_ARM64: ${{ steps.sha.outputs.linux_arm64 }}
SHA_LINUX_X86_64: ${{ steps.sha.outputs.linux_x86_64 }}
run: |
VERSION_NO_V=${VERSION#v}
FORMULA=tap/Formula/linthis.rb
# Bump version
sed -i -E "s/^ version \"[^\"]+\"/ version \"${VERSION_NO_V}\"/" "$FORMULA"
# Patch each sha256 by its marker comment
sed -i -E "s|sha256 \"[0-9a-f]+\" # darwin-arm64|sha256 \"${SHA_DARWIN_ARM64}\" # darwin-arm64|" "$FORMULA"
sed -i -E "s|sha256 \"[0-9a-f]+\" # darwin-x86_64|sha256 \"${SHA_DARWIN_X86_64}\" # darwin-x86_64|" "$FORMULA"
sed -i -E "s|sha256 \"[0-9a-f]+\" # linux-arm64|sha256 \"${SHA_LINUX_ARM64}\" # linux-arm64|" "$FORMULA"
sed -i -E "s|sha256 \"[0-9a-f]+\" # linux-x86_64|sha256 \"${SHA_LINUX_X86_64}\" # linux-x86_64|" "$FORMULA"
echo "--- Updated Formula ---"
cat "$FORMULA"
- name: Commit and push
working-directory: tap
run: |
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
if git diff --quiet Formula/linthis.rb; then
echo "No changes to Formula — skipping commit"
exit 0
fi
git add Formula/linthis.rb
git commit -m "linthis ${GITHUB_REF_NAME#v}"
git push