name: Release
on:
push:
tags:
- "v*"
workflow_dispatch:
permissions:
contents: read
env:
CARGO_TERM_COLOR: always
jobs:
linux:
name: Linux (${{ matrix.target }})
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
target: [x86_64-unknown-linux-gnu, aarch64-unknown-linux-gnu]
steps:
- uses: actions/checkout@v7
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable
with:
targets: ${{ matrix.target }}
- name: Cache build artifacts
uses: Swatinem/rust-cache@v2
with:
key: ${{ matrix.target }}
- name: Install cargo-zigbuild
run: PIP_BREAK_SYSTEM_PACKAGES=1 pip3 install --quiet cargo-zigbuild
- name: Install fpm
env:
GEM_HOME: ${{ runner.temp }}/gem
GEM_PATH: ${{ runner.temp }}/gem
run: |
echo "GEM_HOME=${GEM_HOME}" >> "$GITHUB_ENV"
echo "GEM_PATH=${GEM_PATH}" >> "$GITHUB_ENV"
echo "${GEM_HOME}/bin" >> "$GITHUB_PATH"
gem install --no-document fpm
- name: Resolve release version
shell: bash
run: |
tag="${GITHUB_REF_NAME#v}"
version="$(cargo metadata --locked --no-deps --format-version 1 | jq -r '.packages[] | select(.name == "shuvarie") | .version')"
if [[ "$GITHUB_REF_TYPE" == "tag" ]]; then
if [[ "$tag" != "$version" ]]; then
echo "::error::Tag ${GITHUB_REF_NAME} does not match workspace version ${version}"
exit 1
fi
echo "VERSION=${tag}" >> "$GITHUB_ENV"
else
# Dry run (workflow_dispatch): fall back to the workspace version
echo "VERSION=${version}" >> "$GITHUB_ENV"
fi
- name: Build
run: cargo zigbuild --locked --release --target "${{ matrix.target }}.2.17" --bin shuvarie
- name: Stage files
run: |
mkdir -p "dist/shuvarie-${VERSION}"
cp "target/${{ matrix.target }}/release/shuvarie" "dist/shuvarie-${VERSION}/shuvarie"
cp LICENSE README.md "dist/shuvarie-${VERSION}/"
- name: Create tarball
run: tar -czf "shuvarie-${VERSION}-${{ matrix.target }}.tar.gz" -C dist "shuvarie-${VERSION}"
- name: Map package architectures
run: |
case "${{ matrix.target }}" in
x86_64-*) deb_arch=amd64; rpm_arch=x86_64 ;;
aarch64-*) deb_arch=arm64; rpm_arch=aarch64 ;;
*) echo "::error::Unsupported target: ${{ matrix.target }}"; exit 1 ;;
esac
{
echo "DEB_ARCH=${deb_arch}"
echo "RPM_ARCH=${rpm_arch}"
} >> "$GITHUB_ENV"
- name: Create .deb package
run: >
fpm -s dir -t deb -n shuvarie -v "${VERSION}" -a "$DEB_ARCH"
--license "MIT"
--maintainer "Charles Dong <chardon_cs@proton.me>"
--url "${{ github.server_url }}/${{ github.repository }}"
--description "Blazingly fast AI coding TUI for chivalrous people"
--depends "libc6" --depends "libgcc-s1"
"dist/shuvarie-${VERSION}/shuvarie=/usr/bin/shuvarie"
"dist/shuvarie-${VERSION}/LICENSE=/usr/share/licenses/shuvarie/LICENSE"
"dist/shuvarie-${VERSION}/LICENSE=/usr/share/doc/shuvarie/copyright"
"dist/shuvarie-${VERSION}/README.md=/usr/share/doc/shuvarie/README.md"
- name: Create .rpm package
run: >
fpm -s dir -t rpm --rpm-os linux -n shuvarie -v "${VERSION}" -a "$RPM_ARCH"
--license "MIT"
--maintainer "Charles Dong <chardon_cs@proton.me>"
--url "${{ github.server_url }}/${{ github.repository }}"
--description "Blazingly fast AI coding TUI for chivalrous people"
--depends "glibc"
"dist/shuvarie-${VERSION}/shuvarie=/usr/bin/shuvarie"
"dist/shuvarie-${VERSION}/LICENSE=/usr/share/licenses/shuvarie/LICENSE"
"dist/shuvarie-${VERSION}/README.md=/usr/share/doc/shuvarie/README.md"
- name: Upload artifacts
uses: actions/upload-artifact@v7
with:
name: release-linux-${{ matrix.target }}
path: |
shuvarie-*.tar.gz
shuvarie_*.deb
shuvarie-*.rpm
if-no-files-found: error
retention-days: 1
linux-musl:
name: Linux (${{ matrix.target }})
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
target: [x86_64-unknown-linux-musl, aarch64-unknown-linux-musl]
steps:
- uses: actions/checkout@v7
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable
with:
targets: ${{ matrix.target }}
- name: Cache build artifacts
uses: Swatinem/rust-cache@v2
with:
key: ${{ matrix.target }}
- name: Install cargo-zigbuild
run: PIP_BREAK_SYSTEM_PACKAGES=1 pip3 install --quiet cargo-zigbuild
- name: Resolve release version
shell: bash
run: |
tag="${GITHUB_REF_NAME#v}"
version="$(cargo metadata --locked --no-deps --format-version 1 | jq -r '.packages[] | select(.name == "shuvarie") | .version')"
if [[ "$GITHUB_REF_TYPE" == "tag" ]]; then
if [[ "$tag" != "$version" ]]; then
echo "::error::Tag ${GITHUB_REF_NAME} does not match workspace version ${version}"
exit 1
fi
echo "VERSION=${tag}" >> "$GITHUB_ENV"
else
# Dry run (workflow_dispatch): fall back to the workspace version
echo "VERSION=${version}" >> "$GITHUB_ENV"
fi
- name: Build
run: cargo zigbuild --locked --release --target ${{ matrix.target }} --bin shuvarie
- name: Stage files
run: |
mkdir -p "dist/shuvarie-${VERSION}"
cp "target/${{ matrix.target }}/release/shuvarie" "dist/shuvarie-${VERSION}/shuvarie"
cp LICENSE README.md "dist/shuvarie-${VERSION}/"
- name: Create tarball
run: tar -czf "shuvarie-${VERSION}-${{ matrix.target }}.tar.gz" -C dist "shuvarie-${VERSION}"
- name: Upload artifacts
uses: actions/upload-artifact@v7
with:
name: release-linux-musl-${{ matrix.target }}
path: |
shuvarie-*.tar.gz
if-no-files-found: error
retention-days: 1
macos:
name: macOS (${{ matrix.target }})
runs-on: macos-15
strategy:
fail-fast: false
matrix:
target: [aarch64-apple-darwin, x86_64-apple-darwin]
steps:
- uses: actions/checkout@v7
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable
with:
targets: ${{ matrix.target }}
- name: Cache build artifacts
uses: Swatinem/rust-cache@v2
with:
key: ${{ matrix.target }}
- name: Resolve release version
shell: bash
run: |
tag="${GITHUB_REF_NAME#v}"
version="$(cargo metadata --locked --no-deps --format-version 1 | jq -r '.packages[] | select(.name == "shuvarie") | .version')"
if [[ "$GITHUB_REF_TYPE" == "tag" ]]; then
if [[ "$tag" != "$version" ]]; then
echo "::error::Tag ${GITHUB_REF_NAME} does not match workspace version ${version}"
exit 1
fi
echo "VERSION=${tag}" >> "$GITHUB_ENV"
else
# Dry run (workflow_dispatch): fall back to the workspace version
echo "VERSION=${version}" >> "$GITHUB_ENV"
fi
- name: Build
run: cargo build --locked --release --target ${{ matrix.target }} --bin shuvarie
- name: Stage files
run: |
mkdir -p "dist/shuvarie-${VERSION}"
cp "target/${{ matrix.target }}/release/shuvarie" "dist/shuvarie-${VERSION}/shuvarie"
cp LICENSE README.md "dist/shuvarie-${VERSION}/"
- name: Create tarball
run: tar -czf "shuvarie-${VERSION}-${{ matrix.target }}.tar.gz" -C dist "shuvarie-${VERSION}"
- name: Create .dmg image
run: |
hdiutil create \
-volname "Shuvarie ${VERSION}" \
-srcfolder "dist/shuvarie-${VERSION}" \
-format UDZO -ov \
"shuvarie-${VERSION}-${{ matrix.target }}.dmg"
- name: Upload artifacts
uses: actions/upload-artifact@v7
with:
name: release-macos-${{ matrix.target }}
path: |
shuvarie-*.tar.gz
shuvarie-*.dmg
if-no-files-found: error
retention-days: 1
windows:
name: Windows (${{ matrix.target }})
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
target: [x86_64-pc-windows-gnullvm, aarch64-pc-windows-gnullvm]
steps:
- uses: actions/checkout@v7
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable
with:
targets: ${{ matrix.target }}
- name: Cache build artifacts
uses: Swatinem/rust-cache@v2
with:
key: ${{ matrix.target }}
- name: Install cargo-zigbuild
run: PIP_BREAK_SYSTEM_PACKAGES=1 pip3 install --quiet cargo-zigbuild
- name: Install NSIS
run: |
sudo apt-get update -q
sudo apt-get install -qy nsis zip
- name: Install windres shim
run: |
llvm_rc="$(command -v llvm-rc || true)"
if [ -z "$llvm_rc" ]; then
llvm_rc="$(ls /usr/lib/llvm-*/bin/llvm-rc 2>/dev/null | sort -V | tail -n 1)"
fi
if [ -z "$llvm_rc" ]; then
sudo apt-get install -qy llvm
llvm_rc="$(command -v llvm-rc)"
fi
mkdir -p "$HOME/.windres-shim"
ln -sf "$(readlink -f "$llvm_rc")" "$HOME/.windres-shim/llvm-rc"
cat > "$HOME/.windres-shim/windres" <<'EOF'
#!/bin/sh
# turso_sdk_kit's build script calls: windres <input.rc> -O coff -o <out>
src=
out=
while [ $# -gt 0 ]; do
case "$1" in
-o) out=$2; shift 2 ;;
-O) shift 2 ;;
*) src=$1; shift ;;
esac
done
exec llvm-rc /FO "$out" "$src"
EOF
chmod +x "$HOME/.windres-shim/windres"
echo "$HOME/.windres-shim" >> "$GITHUB_PATH"
- name: Resolve release version
shell: bash
run: |
tag="${GITHUB_REF_NAME#v}"
version="$(cargo metadata --locked --no-deps --format-version 1 | jq -r '.packages[] | select(.name == "shuvarie") | .version')"
if [[ "$GITHUB_REF_TYPE" == "tag" ]]; then
if [[ "$tag" != "$version" ]]; then
echo "::error::Tag ${GITHUB_REF_NAME} does not match workspace version ${version}"
exit 1
fi
echo "VERSION=${tag}" >> "$GITHUB_ENV"
else
# Dry run (workflow_dispatch): fall back to the workspace version
echo "VERSION=${version}" >> "$GITHUB_ENV"
fi
- name: Build
env:
CFLAGS_x86_64_pc_windows_gnullvm: "-Wno-error=date-time"
CFLAGS_aarch64_pc_windows_gnullvm: "-Wno-error=date-time"
run: cargo zigbuild --locked --release --target ${{ matrix.target }} --bin shuvarie
- name: Stage files
run: |
mkdir -p "dist/shuvarie-${VERSION}"
cp "target/${{ matrix.target }}/release/shuvarie.exe" "dist/shuvarie-${VERSION}/shuvarie.exe"
cp LICENSE README.md "dist/shuvarie-${VERSION}/"
- name: Create .zip archive
run: |
cd dist
zip -r "../shuvarie-${VERSION}-${{ matrix.target }}.zip" "shuvarie-${VERSION}"
- name: Create NSIS installer
working-directory: nsis
run: |
case "${{ matrix.target }}" in
x86_64-*) arch=amd64 ;;
aarch64-*) arch=arm64 ;;
*) echo "::error::Unsupported target: ${{ matrix.target }}"; exit 1 ;;
esac
makensis -DVERSION="${VERSION}" \
-DBINARY="../target/${{ matrix.target }}/release/shuvarie.exe" \
-DOUT_FILE="shuvarie-setup-${VERSION}-${arch}.exe" \
installer.nsi
# Move the installer to the workspace root so the artifact below
# stays flat (upload-artifact keeps paths relative to the least
# common ancestor of its globs, and a nested nsis/ dir breaks the
# release job's flat `sha256sum *` / `dist/*` handling).
mv "shuvarie-setup-${VERSION}-${arch}.exe" ..
- name: Upload artifacts
uses: actions/upload-artifact@v7
with:
name: release-windows-${{ matrix.target }}
path: |
shuvarie-*.zip
shuvarie-setup-*.exe
if-no-files-found: error
retention-days: 1
release:
name: Publish GitHub release
needs: [linux, linux-musl, macos, windows]
if: startsWith(github.ref, 'refs/tags/')
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- name: Checkout
uses: actions/checkout@v7
with:
fetch-depth: 0
- name: Download build artifacts
uses: actions/download-artifact@v8
with:
pattern: release-*
merge-multiple: true
path: dist
- name: Generate SHA-256 checksums
run: |
if [ -z "$(ls -A dist)" ]; then
echo "::error::No build artifacts were downloaded"
exit 1
fi
cd dist
sha256sum * > SHA256SUMS
- name: Generate changelog
uses: orhun/git-cliff-action@v4
id: git-cliff
with:
config: cliff.toml
args: --latest --strip header
env:
OUTPUT: CHANGES.md
GITHUB_REPO: ${{ github.repository }}
- name: Publish release
env:
GH_TOKEN: ${{ github.token }}
GH_REPO: ${{ github.repository }}
run: |
gh release create "${GITHUB_REF_NAME}" \
--verify-tag \
--title "${GITHUB_REF_NAME}" \
--notes-file "${{ steps.git-cliff.outputs.changelog }}" \
dist/*