name: Build and Release on: push: tags: - "v*" permissions: contents: read env: CARGO_TERM_COLOR: always CARGO_NET_RETRY: 10 jobs: build: name: Build ${{ matrix.asset_name }} runs-on: ${{ matrix.os }} strategy: fail-fast: false matrix: include: # AppImages must be built on the oldest supported distribution so # that their glibc requirement remains compatible with newer ones. - os: ubuntu-22.04 target: x86_64-unknown-linux-gnu asset_name: furumi-desktop-linux-x86_64 archive_ext: AppImage binary_name: furumi-desktop - os: macos-latest target: aarch64-apple-darwin asset_name: furumi-desktop-macos-aarch64 archive_ext: tar.gz binary_name: furumi-desktop - os: windows-latest target: x86_64-pc-windows-msvc asset_name: furumi-desktop-windows-x86_64 archive_ext: zip binary_name: furumi-desktop.exe steps: - name: Checkout uses: actions/checkout@v4 - name: Install Linux build dependencies if: runner.os == 'Linux' run: | sudo apt-get update sudo apt-get install -y --no-install-recommends \ libasound2-dev \ libegl1-mesa-dev \ libfontconfig1-dev \ libfreetype-dev \ libgl1-mesa-dev \ libudev-dev \ libwayland-dev \ libx11-dev \ libx11-xcb-dev \ libxkbcommon-dev \ libxkbcommon-x11-dev \ libxcursor-dev \ libxi-dev \ libxrandr-dev \ pkg-config - name: Install Rust target shell: bash run: rustup target add "${{ matrix.target }}" - name: Show Rust version shell: bash run: | rustc --version --verbose cargo --version - name: Fetch locked dependencies shell: bash run: cargo fetch --locked --target "${{ matrix.target }}" - name: Build desktop application shell: bash run: | cargo build \ --release \ --locked \ --offline \ --package furumi-desktop \ --target "${{ matrix.target }}" - name: Package shell: bash run: | set -euo pipefail version="${GITHUB_REF_NAME#v}" archive_name="${{ matrix.asset_name }}-${version}.${{ matrix.archive_ext }}" package_dir="dist/${{ matrix.asset_name }}" binary="target/${{ matrix.target }}/release/${{ matrix.binary_name }}" if [[ "${{ runner.os }}" == "Linux" ]]; then app_dir="dist/FurumiDesktop.AppDir" appimage_runtime="$RUNNER_TEMP/appimage-runtime-x86_64" linuxdeploy="$RUNNER_TEMP/linuxdeploy-x86_64.AppImage" linuxdeploy_dir="$RUNNER_TEMP/linuxdeploy" linuxdeploy_version="1-alpha-20251107-1" linuxdeploy_sha256="c20cd71e3a4e3b80c3483cef793cda3f4e990aca14014d23c544ca3ce1270b4d" runtime_version="20251108" runtime_sha256="2fca8b443c92510f1483a883f60061ad09b46b978b2631c807cd873a47ec260d" mkdir -p "$app_dir/usr/share/doc/furumi-desktop" cp README.md LICENSE "$app_dir/usr/share/doc/furumi-desktop/" curl --fail --location --retry 3 --silent --show-error \ "https://github.com/linuxdeploy/linuxdeploy/releases/download/${linuxdeploy_version}/linuxdeploy-x86_64.AppImage" \ --output "$linuxdeploy" echo "${linuxdeploy_sha256} ${linuxdeploy}" | sha256sum --check chmod +x "$linuxdeploy" curl --fail --location --retry 3 --silent --show-error \ "https://github.com/AppImage/type2-runtime/releases/download/${runtime_version}/runtime-x86_64" \ --output "$appimage_runtime" echo "${runtime_sha256} ${appimage_runtime}" | sha256sum --check APPIMAGE_EXTRACT_AND_RUN=1 "$linuxdeploy" \ --appdir "$app_dir" \ --executable "$binary" \ --desktop-file packaging/linux/furumi-desktop.desktop \ --icon-file crates/ui/assets/federation.svg \ --icon-filename furumi-desktop mkdir -p "$linuxdeploy_dir" ( cd "$linuxdeploy_dir" "$linuxdeploy" --appimage-extract >/dev/null ) appimagetool="$linuxdeploy_dir/squashfs-root/plugins/linuxdeploy-plugin-appimage/appimagetool-prefix/AppRun" ARCH=x86_64 VERSION="$version" "$appimagetool" \ --no-appstream \ --runtime-file "$appimage_runtime" \ "$app_dir" \ "$archive_name" chmod +x "$archive_name" "./$archive_name" --appimage-extract >/dev/null test -x squashfs-root/AppRun test -x squashfs-root/usr/bin/furumi-desktop test -f squashfs-root/usr/share/applications/furumi-desktop.desktop test -f squashfs-root/usr/share/icons/hicolor/scalable/apps/furumi-desktop.svg rm -rf squashfs-root elif [[ "${{ runner.os }}" == "macOS" ]]; then mkdir -p "$package_dir" app_dir="$package_dir/Furumi Desktop.app" mkdir -p "$app_dir/Contents/MacOS" "$app_dir/Contents/Resources" cp "$binary" "$app_dir/Contents/MacOS/furumi-desktop" iconset="$RUNNER_TEMP/furumi.iconset" mkdir -p "$iconset" sips -s format png -z 16 16 crates/ui/assets/federation.svg --out "$iconset/icon_16x16.png" >/dev/null sips -s format png -z 32 32 crates/ui/assets/federation.svg --out "$iconset/icon_16x16@2x.png" >/dev/null sips -s format png -z 32 32 crates/ui/assets/federation.svg --out "$iconset/icon_32x32.png" >/dev/null sips -s format png -z 64 64 crates/ui/assets/federation.svg --out "$iconset/icon_32x32@2x.png" >/dev/null sips -s format png -z 128 128 crates/ui/assets/federation.svg --out "$iconset/icon_128x128.png" >/dev/null sips -s format png -z 256 256 crates/ui/assets/federation.svg --out "$iconset/icon_128x128@2x.png" >/dev/null sips -s format png -z 256 256 crates/ui/assets/federation.svg --out "$iconset/icon_256x256.png" >/dev/null sips -s format png -z 512 512 crates/ui/assets/federation.svg --out "$iconset/icon_256x256@2x.png" >/dev/null sips -s format png -z 512 512 crates/ui/assets/federation.svg --out "$iconset/icon_512x512.png" >/dev/null sips -s format png -z 1024 1024 crates/ui/assets/federation.svg --out "$iconset/icon_512x512@2x.png" >/dev/null iconutil -c icns "$iconset" -o "$app_dir/Contents/Resources/furumi.icns" cat > "$app_dir/Contents/Info.plist" < CFBundleDevelopmentRegion en CFBundleDisplayName Furumi Desktop CFBundleExecutable furumi-desktop CFBundleIdentifier cy.hexor.furumi-desktop CFBundleIconFile furumi.icns CFBundleInfoDictionaryVersion 6.0 CFBundleName Furumi Desktop CFBundlePackageType APPL CFBundleShortVersionString ${version} CFBundleVersion ${GITHUB_RUN_NUMBER} LSApplicationCategoryType public.app-category.music LSMinimumSystemVersion 11.0 NSHighResolutionCapable PLIST plutil -lint "$app_dir/Contents/Info.plist" codesign --force --deep --sign - "$app_dir" codesign --verify --deep --strict "$app_dir" else mkdir -p "$package_dir" cp "$binary" "$package_dir/" fi if [[ "${{ runner.os }}" == "Windows" ]]; then cp README.md LICENSE "$package_dir/" (cd dist && 7z a "../${archive_name}" "${{ matrix.asset_name }}") elif [[ "${{ runner.os }}" == "macOS" ]]; then cp README.md LICENSE "$package_dir/" tar -C dist -czf "$archive_name" "${{ matrix.asset_name }}" fi - name: Upload build artifact uses: actions/upload-artifact@v4 with: name: ${{ matrix.asset_name }} path: ${{ matrix.asset_name }}-* if-no-files-found: error publish: name: Publish release assets needs: build runs-on: ubuntu-latest permissions: contents: write steps: - name: Checkout uses: actions/checkout@v4 - name: Download build artifacts uses: actions/download-artifact@v4 with: path: artifacts - name: Create release and upload assets env: GH_TOKEN: ${{ github.token }} RELEASE_TAG: ${{ github.ref_name }} run: | set -euo pipefail gh release create "$RELEASE_TAG" artifacts/*/* \ --title "furumi-desktop ${RELEASE_TAG}" \ --generate-notes \ --verify-tag