Skip to content

Bump version to 1.4.1, document supported architectures and RAW input #48

Bump version to 1.4.1, document supported architectures and RAW input

Bump version to 1.4.1, document supported architectures and RAW input #48

Workflow file for this run

name: Release
on:
push:
tags:
- "v*"
workflow_dispatch:
env:
CARGO_TERM_COLOR: always
# Keep these checksums in sync with ci.yml.
YUNET_ORIGINAL_SHA256: 8f2383e4dd3cfbb4553ea8718107fc0423210dc964f9f4280604804ed2552fa4
YUNET_640_SHA256: d2c5a887db77802389261b13d2b9f5e1171b9d5787cb315d0add225812ff4d96
jobs:
shader-validation:
name: Validate WGSL shaders
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v4
- name: Install build dependencies
run: |
sudo apt-get update
sudo apt-get install -y pkg-config libdav1d-dev
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
with:
toolchain: 1.96.0
- name: Rust Cache
uses: swatinem/rust-cache@v2
- name: Validate WGSL shaders
run: cargo test -p fcs-utils validate_all_wgsl_files
prepare-models:
name: Prepare Release Models
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.11"
- name: Set up uv
uses: astral-sh/setup-uv@v5
- name: Download and process models
shell: bash
run: |
mkdir -p models
curl -L -o models/face_detection_yunet_2023mar.onnx https://github.com/opencv/opencv_zoo/raw/main/models/face_detection_yunet/face_detection_yunet_2023mar.onnx
uvx --python 3.11 --with onnxsim==0.4.36 --with onnxruntime onnxsim models/face_detection_yunet_2023mar.onnx models/face_detection_yunet_2023mar_640.onnx --overwrite-input-shape "1,3,640,640" \
|| uvx --python 3.11 --with onnxsim==0.4.36 --with onnxruntime onnxsim models/face_detection_yunet_2023mar.onnx models/face_detection_yunet_2023mar_640.onnx --input-shape "1,3,640,640"
- name: Verify model checksums
shell: bash
run: |
python - <<'PY'
import hashlib
import os
import pathlib
import sys
expected = {
"models/face_detection_yunet_2023mar.onnx": os.environ["YUNET_ORIGINAL_SHA256"],
"models/face_detection_yunet_2023mar_640.onnx": os.environ["YUNET_640_SHA256"],
}
def sha256(path: pathlib.Path) -> str:
h = hashlib.sha256()
with path.open("rb") as f:
for chunk in iter(lambda: f.read(1024 * 1024), b""):
h.update(chunk)
return h.hexdigest()
failed = False
for rel_path, expected_hash in expected.items():
path = pathlib.Path(rel_path)
if not path.exists():
print(f"Missing model file: {rel_path}", file=sys.stderr)
failed = True
continue
actual_hash = sha256(path)
if actual_hash != expected_hash:
print(
f"Checksum mismatch for {rel_path}: expected {expected_hash}, got {actual_hash}",
file=sys.stderr,
)
failed = True
else:
print(f"Verified {rel_path}: {actual_hash}")
if failed:
sys.exit(1)
PY
- name: Upload prepared models
uses: actions/upload-artifact@v4
with:
name: release-models
path: |
models/face_detection_yunet_2023mar.onnx
models/face_detection_yunet_2023mar_640.onnx
if-no-files-found: error
retention-days: 1
windows-release:
name: Windows Release Artifacts
needs: [shader-validation, prepare-models]
runs-on: windows-latest
permissions:
contents: write
env:
# Evaluated once at job start; used by signing steps to skip gracefully
# when the certificate secret is not configured.
HAS_CODE_SIGN: ${{ secrets.CODE_SIGN_PFX != '' }}
steps:
- uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.11"
- name: Download prepared models
uses: actions/download-artifact@v4
with:
name: release-models
path: models
- name: Verify model checksums
shell: bash
run: |
python - <<'PY'
import hashlib
import os
import pathlib
import sys
expected = {
"models/face_detection_yunet_2023mar.onnx": os.environ["YUNET_ORIGINAL_SHA256"],
"models/face_detection_yunet_2023mar_640.onnx": os.environ["YUNET_640_SHA256"],
}
def sha256(path: pathlib.Path) -> str:
h = hashlib.sha256()
with path.open("rb") as f:
for chunk in iter(lambda: f.read(1024 * 1024), b""):
h.update(chunk)
return h.hexdigest()
failed = False
for rel_path, expected_hash in expected.items():
path = pathlib.Path(rel_path)
if not path.exists():
print(f"Missing model file: {rel_path}", file=sys.stderr)
failed = True
continue
actual_hash = sha256(path)
if actual_hash != expected_hash:
print(
f"Checksum mismatch for {rel_path}: expected {expected_hash}, got {actual_hash}",
file=sys.stderr,
)
failed = True
else:
print(f"Verified {rel_path}: {actual_hash}")
if failed:
sys.exit(1)
PY
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
with:
toolchain: 1.96.0
- name: Rust Cache
uses: swatinem/rust-cache@v2
- name: Install NSIS
shell: pwsh
run: |
choco install nsis --no-progress -y
- name: Install WiX v7
shell: pwsh
run: |
dotnet tool install -g wix --version 7.0.0
wix -acceptEula wix7 extension add WixToolset.UI.wixext/7.0.0
- name: Install pkg-config
shell: pwsh
run: |
choco install pkgconfiglite --no-progress -y
- name: Cache vcpkg
uses: actions/cache@v4
with:
path: C:\vcpkg\installed
key: vcpkg-dav1d-libheif-x64-windows-static-${{ runner.os }}
- name: Install dav1d + libheif (vcpkg)
shell: pwsh
run: |
if (-not (Test-Path "C:\vcpkg\vcpkg.exe")) {
git clone https://github.com/microsoft/vcpkg C:\vcpkg
& C:\vcpkg\bootstrap-vcpkg.bat
}
& C:\vcpkg\vcpkg.exe install dav1d:x64-windows-static libheif:x64-windows-static
- name: Build release binaries
env:
RUSTFLAGS: -C target-feature=+crt-static
PKG_CONFIG_PATH: C:\vcpkg\installed\x64-windows-static\lib\pkgconfig
PKG_CONFIG_ALL_STATIC: "1"
# libheif-sys finds libheif through the `vcpkg` crate, not pkg-config.
VCPKG_ROOT: C:\vcpkg
run: cargo build --release -p fcs-cli -p fcs-gui
- name: Sign release binaries
# Requires CODE_SIGN_PFX (base64-encoded PFX) and CODE_SIGN_PASSWORD
# to be set as repository secrets. Skipped silently if absent.
if: env.HAS_CODE_SIGN == 'true'
shell: pwsh
env:
CODE_SIGN_PFX: ${{ secrets.CODE_SIGN_PFX }}
CODE_SIGN_PASSWORD: ${{ secrets.CODE_SIGN_PASSWORD }}
run: |
$CertPath = "$env:TEMP\codesign.pfx"
[IO.File]::WriteAllBytes($CertPath, [Convert]::FromBase64String($env:CODE_SIGN_PFX))
$SignTool = (Get-ChildItem "C:\Program Files (x86)\Windows Kits\10\bin" -Recurse -Filter signtool.exe |
Sort-Object FullName -Descending | Select-Object -First 1).FullName
if (-not $SignTool) { throw "signtool.exe not found" }
foreach ($bin in @("target\release\fcs-cli.exe", "target\release\fcs-gui.exe")) {
& $SignTool sign /fd SHA256 /f $CertPath /p $env:CODE_SIGN_PASSWORD `
/tr http://timestamp.digicert.com /td SHA256 `
/d "Face Crop Studio" $bin
if ($LASTEXITCODE -ne 0) { throw "signtool failed for $bin" }
}
Remove-Item $CertPath -Force
- name: Package artifacts
shell: pwsh
run: |
$DistName = "face-crop-studio-windows-x86_64"
$DistDir = "dist/$DistName"
New-Item -ItemType Directory -Force -Path $DistDir | Out-Null
New-Item -ItemType Directory -Force -Path "$DistDir/models" | Out-Null
Copy-Item target/release/fcs-cli.exe "$DistDir/fcs-cli.exe"
Copy-Item target/release/fcs-gui.exe "$DistDir/fcs-gui.exe"
Copy-Item fcs-gui/assets/app_icon.ico "$DistDir/app_icon.ico"
Copy-Item models/face_detection_yunet_2023mar_640.onnx "$DistDir/models/face_detection_yunet_2023mar_640.onnx"
if (Test-Path samples) {
Copy-Item -Recurse samples "$DistDir/samples"
}
if (Test-Path README.md) {
Copy-Item README.md "$DistDir/README.md"
}
if (Test-Path LICENSE) {
Copy-Item LICENSE "$DistDir/LICENSE"
}
if (Test-Path LICENSE-APACHE) {
Copy-Item LICENSE-APACHE "$DistDir/LICENSE-APACHE"
}
if (Test-Path LICENSE-MIT) {
Copy-Item LICENSE-MIT "$DistDir/LICENSE-MIT"
}
Compress-Archive -Path "$DistDir/*" -DestinationPath "dist/$DistName.zip" -Force
- name: Verify packaged model path
shell: pwsh
run: |
$DistName = "face-crop-studio-windows-x86_64"
$ModelPath = "dist/$DistName/models/face_detection_yunet_2023mar_640.onnx"
if (-not (Test-Path $ModelPath)) {
Write-Error "Expected packaged model missing at $ModelPath"
exit 1
}
- name: Build NSIS installer
shell: pwsh
run: |
$DistName = "face-crop-studio-windows-x86_64"
$Version = "${{ github.ref_name }}"
if ($Version.StartsWith("v")) { $Version = $Version.Substring(1) }
$DistDir = Join-Path $PWD "dist\$DistName"
$OutFile = Join-Path $PWD "dist\face-crop-studio-windows-x86_64-setup.exe"
$Script = Join-Path $PWD "installer\windows\face-crop-studio.nsi"
$env:Path = "C:\ProgramData\chocolatey\bin;$env:Path"
$Makensis = (Get-Command makensis.exe -ErrorAction SilentlyContinue).Source
if (-not $Makensis) {
$Candidates = @(
"$env:ProgramFiles(x86)\NSIS\makensis.exe",
"$env:ProgramFiles\NSIS\makensis.exe",
"C:\Program Files (x86)\NSIS\makensis.exe",
"C:\Program Files\NSIS\makensis.exe"
)
foreach ($Candidate in $Candidates) {
if (Test-Path $Candidate) {
$Makensis = $Candidate
break
}
}
}
if (-not $Makensis) {
throw "makensis.exe not found after NSIS installation"
}
& $Makensis /DAPP_VERSION=$Version /DDIST_DIR="$DistDir" /DOUT_FILE="$OutFile" "$Script"
if ($LASTEXITCODE -ne 0) {
throw "NSIS installer build failed with exit code $LASTEXITCODE"
}
if (-not (Test-Path $OutFile)) {
throw "Installer missing at $OutFile"
}
- name: Build MSI installer
shell: pwsh
run: |
$DistName = "face-crop-studio-windows-x86_64"
$RawVersion = "${{ github.ref_name }}"
if ($RawVersion.StartsWith("v")) { $RawVersion = $RawVersion.Substring(1) }
$MsiVersion = $RawVersion.Split("-")[0]
if ($MsiVersion -notmatch '^\d+\.\d+\.\d+$') {
throw "Invalid MSI version '$MsiVersion' derived from tag '${{ github.ref_name }}'"
}
$DistDir = Join-Path $PWD "dist\$DistName"
$MsiOut = Join-Path $PWD "dist\face-crop-studio-windows-x86_64.msi"
Write-Host "Using MSI version: $MsiVersion"
# WiX v7: single 'wix build' replaces heat + candle + light.
# -arch x64 marks all harvested components as 64-bit (no XML patching needed).
# <Files> in Product.wxs harvests SourceDir instead of the old heat.exe step.
wix build `
-acceptEula wix7 `
-arch x64 `
-d SourceDir="$DistDir" `
-d MsiVersion="$MsiVersion" `
-ext WixToolset.UI.wixext `
-o "$MsiOut" `
installer\windows\wix\Product.wxs
if ($LASTEXITCODE -ne 0) { throw "wix build failed with exit code $LASTEXITCODE" }
if (-not (Test-Path $MsiOut)) { throw "MSI missing at $MsiOut" }
- name: Generate checksums
shell: bash
run: |
cd dist
sha256sum face-crop-studio-windows-x86_64.zip > SHA256SUMS.txt
sha256sum face-crop-studio-windows-x86_64-setup.exe >> SHA256SUMS.txt
sha256sum face-crop-studio-windows-x86_64.msi >> SHA256SUMS.txt
- name: Upload build artifacts
uses: actions/upload-artifact@v4
with:
name: windows-release-artifacts
path: |
dist/face-crop-studio-windows-x86_64.zip
dist/face-crop-studio-windows-x86_64-setup.exe
dist/face-crop-studio-windows-x86_64.msi
dist/SHA256SUMS.txt
- name: Publish GitHub release assets
uses: softprops/action-gh-release@v2
with:
files: |
dist/face-crop-studio-windows-x86_64.zip
dist/face-crop-studio-windows-x86_64-setup.exe
dist/face-crop-studio-windows-x86_64.msi
dist/SHA256SUMS.txt
macos-release:
name: macOS Release Artifacts (Apple Silicon)
needs: [shader-validation, prepare-models]
runs-on: macos-latest
permissions:
contents: write
env:
# Evaluated once at job start so signing/notarization steps can skip
# gracefully when the Apple secrets aren't configured.
HAS_APPLE_SIGNING: ${{ secrets[format('{0}', 'APPLE_DEVELOPER_ID_CERT')] != '' }}
steps:
- uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.11"
- name: Download prepared models
uses: actions/download-artifact@v4
with:
name: release-models
path: models
- name: Verify model checksums
shell: bash
run: |
python - <<'PY'
import hashlib
import os
import pathlib
import sys
expected = {
"models/face_detection_yunet_2023mar.onnx": os.environ["YUNET_ORIGINAL_SHA256"],
"models/face_detection_yunet_2023mar_640.onnx": os.environ["YUNET_640_SHA256"],
}
def sha256(path: pathlib.Path) -> str:
h = hashlib.sha256()
with path.open("rb") as f:
for chunk in iter(lambda: f.read(1024 * 1024), b""):
h.update(chunk)
return h.hexdigest()
failed = False
for rel_path, expected_hash in expected.items():
path = pathlib.Path(rel_path)
if not path.exists():
print(f"Missing model file: {rel_path}", file=sys.stderr)
failed = True
continue
actual_hash = sha256(path)
if actual_hash != expected_hash:
print(
f"Checksum mismatch for {rel_path}: expected {expected_hash}, got {actual_hash}",
file=sys.stderr,
)
failed = True
else:
print(f"Verified {rel_path}: {actual_hash}")
if failed:
sys.exit(1)
PY
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
with:
toolchain: 1.96.0
targets: aarch64-apple-darwin
- name: Rust Cache
uses: swatinem/rust-cache@v2
- name: Install build dependencies (Homebrew)
run: |
brew update
# dav1d + pkg-config: AVIF decode support (mirrors the Windows vcpkg setup).
# libheif: HEIC/HEIF decode (brew ships a recent libheif for libheif-rs).
# librsvg: rsvg-convert for SVG → PNG iconset generation.
# create-dmg: drag-to-Applications DMG layout.
brew install dav1d libheif pkg-config librsvg create-dmg
- name: Build release binary (aarch64-apple-darwin)
run: cargo build --release -p fcs-gui --target aarch64-apple-darwin
- name: Import Developer ID certificate
# Mirrors the Windows signing pattern: only runs if the cert secret is
# configured. Imports the .p12 into a temporary keychain so codesign
# picks it up, then the build script uses APPLE_DEVELOPER_ID_NAME to
# select the identity.
if: env.HAS_APPLE_SIGNING == 'true'
env:
APPLE_DEVELOPER_ID_CERT: ${{ secrets[format('{0}', 'APPLE_DEVELOPER_ID_CERT')] }}
APPLE_DEVELOPER_ID_PASS: ${{ secrets[format('{0}', 'APPLE_DEVELOPER_ID_PASS')] }}
KEYCHAIN_PASS: ${{ github.run_id }}-keychain
run: |
CERT_PATH="$RUNNER_TEMP/certificate.p12"
KEYCHAIN_PATH="$RUNNER_TEMP/codesign.keychain-db"
echo -n "$APPLE_DEVELOPER_ID_CERT" | base64 --decode > "$CERT_PATH"
security create-keychain -p "$KEYCHAIN_PASS" "$KEYCHAIN_PATH"
security set-keychain-settings -lut 21600 "$KEYCHAIN_PATH"
security unlock-keychain -p "$KEYCHAIN_PASS" "$KEYCHAIN_PATH"
security import "$CERT_PATH" -P "$APPLE_DEVELOPER_ID_PASS" \
-A -t cert -f pkcs12 -k "$KEYCHAIN_PATH"
security set-key-partition-list -S apple-tool:,apple: -k "$KEYCHAIN_PASS" "$KEYCHAIN_PATH"
security list-keychains -d user -s "$KEYCHAIN_PATH" $(security list-keychains -d user | tr -d '"')
rm -f "$CERT_PATH"
- name: Build .app bundle and DMG
env:
APPLE_DEVELOPER_ID_NAME: ${{ secrets[format('{0}', 'APPLE_DEVELOPER_ID_NAME')] }}
APPLE_NOTARIZE_USER: ${{ secrets[format('{0}', 'APPLE_NOTARIZE_USER')] }}
APPLE_NOTARIZE_PASS: ${{ secrets[format('{0}', 'APPLE_NOTARIZE_PASS')] }}
APPLE_TEAM_ID: ${{ secrets[format('{0}', 'APPLE_TEAM_ID')] }}
run: |
RawVersion="${{ github.ref_name }}"
Version="${RawVersion#v}"
bash installer/macos/build_macos.sh "$Version"
- name: Generate checksums
shell: bash
run: |
cd dist/macos
shasum -a 256 *.dmg > SHA256SUMS.txt
cat SHA256SUMS.txt
- name: Upload build artifacts
uses: actions/upload-artifact@v4
with:
name: macos-release-artifacts
path: |
dist/macos/*.dmg
dist/macos/SHA256SUMS.txt
- name: Publish GitHub release assets
uses: softprops/action-gh-release@v2
with:
files: |
dist/macos/*.dmg
dist/macos/SHA256SUMS.txt
linux-release:
name: Linux Release Artifacts (x86_64)
needs: [shader-validation, prepare-models]
# Build on 22.04 for broad glibc compatibility (binaries link against
# glibc 2.35 and run on Ubuntu 22.04+ and other modern distros).
runs-on: ubuntu-22.04
permissions:
contents: write
steps:
- uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.11"
- name: Download prepared models
uses: actions/download-artifact@v4
with:
name: release-models
path: models
- name: Verify model checksums
shell: bash
run: |
python - <<'PY'
import hashlib
import os
import pathlib
import sys
expected = {
"models/face_detection_yunet_2023mar.onnx": os.environ["YUNET_ORIGINAL_SHA256"],
"models/face_detection_yunet_2023mar_640.onnx": os.environ["YUNET_640_SHA256"],
}
def sha256(path: pathlib.Path) -> str:
h = hashlib.sha256()
with path.open("rb") as f:
for chunk in iter(lambda: f.read(1024 * 1024), b""):
h.update(chunk)
return h.hexdigest()
failed = False
for rel_path, expected_hash in expected.items():
path = pathlib.Path(rel_path)
if not path.exists():
print(f"Missing model file: {rel_path}", file=sys.stderr)
failed = True
continue
actual_hash = sha256(path)
if actual_hash != expected_hash:
print(
f"Checksum mismatch for {rel_path}: expected {expected_hash}, got {actual_hash}",
file=sys.stderr,
)
failed = True
else:
print(f"Verified {rel_path}: {actual_hash}")
if failed:
sys.exit(1)
PY
- name: Install build dependencies (apt)
run: |
DAV1D_VERSION=1.5.1
sudo apt-get update
sudo apt-get install -y \
meson \
ninja-build \
nasm \
pkg-config \
libdav1d-dev \
librsvg2-bin \
libgtk-3-dev \
libxkbcommon-dev \
libwayland-dev \
libxcb1-dev libxcb-shape0-dev libxcb-xfixes0-dev libxcb-render0-dev \
libegl-dev \
libgl-dev
curl -fsSL -o /tmp/dav1d.tar.xz \
"https://download.videolan.org/pub/videolan/dav1d/${DAV1D_VERSION}/dav1d-${DAV1D_VERSION}.tar.xz"
tar -xf /tmp/dav1d.tar.xz -C /tmp
meson setup "/tmp/dav1d-${DAV1D_VERSION}/build" "/tmp/dav1d-${DAV1D_VERSION}" \
--prefix=/usr/local \
--libdir=lib \
--buildtype=release \
--default-library=static \
-Denable_tools=false \
-Denable_tests=false
ninja -C "/tmp/dav1d-${DAV1D_VERSION}/build"
sudo ninja -C "/tmp/dav1d-${DAV1D_VERSION}/build" install
export PKG_CONFIG_PATH="/usr/local/lib/pkgconfig:${PKG_CONFIG_PATH:-}"
echo "PKG_CONFIG_PATH=$PKG_CONFIG_PATH" >> "$GITHUB_ENV"
echo "PKG_CONFIG_ALL_STATIC=1" >> "$GITHUB_ENV"
pkg-config --modversion dav1d
# HEIC/HEIF decode: apt's libheif (1.12 on 22.04) is older than the 1.21
# libheif-rs needs, so build libde265 (HEVC decode) + libheif from source as
# static libs, mirroring the dav1d-from-source approach for clean static linking.
DE265_VERSION=1.0.15
LIBHEIF_VERSION=1.23.0
curl -fsSL -o /tmp/libde265.tar.gz \
"https://github.com/strukturag/libde265/releases/download/v${DE265_VERSION}/libde265-${DE265_VERSION}.tar.gz"
tar -xf /tmp/libde265.tar.gz -C /tmp
cmake -S "/tmp/libde265-${DE265_VERSION}" -B "/tmp/libde265-${DE265_VERSION}/build" \
-DCMAKE_INSTALL_PREFIX=/usr/local \
-DCMAKE_BUILD_TYPE=Release \
-DBUILD_SHARED_LIBS=OFF \
-DENABLE_DECODER=ON \
-DENABLE_ENCODER=OFF \
-DENABLE_SDL=OFF
cmake --build "/tmp/libde265-${DE265_VERSION}/build" --parallel
sudo cmake --install "/tmp/libde265-${DE265_VERSION}/build"
curl -fsSL -o /tmp/libheif.tar.gz \
"https://github.com/strukturag/libheif/releases/download/v${LIBHEIF_VERSION}/libheif-${LIBHEIF_VERSION}.tar.gz"
tar -xf /tmp/libheif.tar.gz -C /tmp
cmake -S "/tmp/libheif-${LIBHEIF_VERSION}" -B "/tmp/libheif-${LIBHEIF_VERSION}/build" \
-DCMAKE_INSTALL_PREFIX=/usr/local \
-DCMAKE_BUILD_TYPE=Release \
-DBUILD_SHARED_LIBS=OFF \
-DWITH_EXAMPLES=OFF \
-DWITH_LIBDE265=ON \
-DWITH_X265=OFF \
-DWITH_AOM_ENCODER=OFF \
-DWITH_AOM_DECODER=OFF \
-DENABLE_PLUGIN_LOADING=OFF
cmake --build "/tmp/libheif-${LIBHEIF_VERSION}/build" --parallel
sudo cmake --install "/tmp/libheif-${LIBHEIF_VERSION}/build"
pkg-config --modversion libheif
pkg-config --libs --static libheif
echo "SYSTEM_DEPS_LIBHEIF_LINK=static" >> "$GITHUB_ENV"
echo "SYSTEM_DEPS_LIBHEIF_SEARCH_NATIVE=/usr/local/lib" >> "$GITHUB_ENV"
echo "SYSTEM_DEPS_LIBHEIF_LIB=heif de265" >> "$GITHUB_ENV"
echo "SYSTEM_DEPS_LIBHEIF_INCLUDE=/usr/local/include" >> "$GITHUB_ENV"
echo "RUSTFLAGS=-l dylib=stdc++" >> "$GITHUB_ENV"
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
with:
toolchain: 1.96.0
- name: Rust Cache
uses: swatinem/rust-cache@v2
- name: Install cargo-deb
run: |
cargo install cargo-deb --locked --version 3.7.0
cargo deb --version
- name: Install appimagetool
# Extract instead of running directly so we don't need FUSE on the runner.
run: |
curl -fsSL -o /tmp/appimagetool.AppImage \
https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-x86_64.AppImage
chmod +x /tmp/appimagetool.AppImage
(cd /tmp && ./appimagetool.AppImage --appimage-extract >/dev/null)
sudo mv /tmp/squashfs-root /opt/appimagetool
sudo ln -sf /opt/appimagetool/AppRun /usr/local/bin/appimagetool
- name: Build release binary
run: cargo build --release -p fcs-gui
- name: Build AppImage and .deb
run: |
RawVersion="${{ github.ref_name }}"
Version="${RawVersion#v}"
bash installer/linux/build_linux.sh "$Version"
ls -lh dist/linux
- name: Generate checksums
shell: bash
run: |
cd dist/linux
sha256sum *.AppImage *.deb > SHA256SUMS.txt
cat SHA256SUMS.txt
- name: Upload build artifacts
uses: actions/upload-artifact@v4
with:
name: linux-release-artifacts
path: |
dist/linux/*.AppImage
dist/linux/*.deb
dist/linux/SHA256SUMS.txt
- name: Publish GitHub release assets
uses: softprops/action-gh-release@v2
with:
files: |
dist/linux/*.AppImage
dist/linux/*.deb
dist/linux/SHA256SUMS.txt