Skip to content

Release

Release #156

Workflow file for this run

# This action enables building release executables/installers and can be triggered manually or by release creation.
#
# Executables are built both for releases and for manually triggered runs, uploaded to artifacts and assets.
name: Release
on:
workflow_dispatch:
push:
tags:
- "*"
# Incremental compilation here isn't helpful
env:
CARGO_INCREMENTAL: 0
jobs:
release:
strategy:
matrix:
build:
- os: ubuntu-24.04
target: x86_64-unknown-linux-gnu
suffix: ubuntu-x86_64-skylake-${{ github.ref_name }}
modern-rustflags: "-C target-cpu=skylake"
rustflags: "-C target-cpu=x86-64-v2"
# TODO: Package for more Linux distributions/packaging formats/architectures and macOS
#- os: ubuntu-24.04
# target: aarch64-unknown-linux-gnu
# suffix: ubuntu-aarch64-${{ github.ref_name }}
# rustflags: "-C linker=aarch64-linux-gnu-gcc"
- os: macos-14
target: aarch64-apple-darwin
suffix: macos-aarch64-${{ github.ref_name }}
- os: windows-2022
target: x86_64-pc-windows-msvc
suffix: windows-x86_64-skylake-${{ github.ref_name }}
modern-rustflags: "-C target-cpu=skylake"
rustflags: "-C target-cpu=x86-64-v2"
fail-fast: false
runs-on: ${{ matrix.build.os }}
steps:
- name: Checkout
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
- name: Install GTK4 and libfuse2 (Linux)
# libfuse2 is needed for AppImage to run
run: sudo apt-get update && sudo apt-get install --no-install-recommends -y libgtk-4-dev libdbus-1-dev libfuse2
if: runner.os == 'Linux'
- name: Configure GTK4 cache (Windows)
uses: actions/cache@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2
id: cache
with:
path: C:\gtk-build\gtk\x64\release
key: ${{ runner.os }}-gtk4
if: runner.os == 'Windows'
- name: Install GTK4 (macOS)
run: |
brew install gtk4 librsvg
if: runner.os == 'macOS'
- name: Install GTK4 (Windows)
run: |
# TODO: Next 3 lines should have been `pipx install gvsbuild`, but https://github.com/wingtk/gvsbuild/issues/1436
py -m venv .venv
.\.venv\Scripts\activate.ps1
py -m pip install gvsbuild
gvsbuild build gtk4 librsvg
if: runner.os == 'Windows' && steps.cache.outputs.cache-hit != 'true'
- name: Configure GTK4 (Windows)
run: |
Add-Content $env:GITHUB_ENV "PKG_CONFIG_PATH=C:\gtk-build\gtk\x64\release\lib\pkgconfig"
Add-Content $env:GITHUB_ENV ("LIB=" + $env:LIB + ";" + "C:\gtk-build\gtk\x64\release\lib")
Add-Content $env:GITHUB_PATH "C:\gtk-build\gtk\x64\release\bin"
# We have hardcoded list of libraries in space-acres.wxs, make sure it didn't change unexpectedly
Get-ChildItem C:\gtk-build\gtk\x64\release\bin\*.dll | ForEach-Object { $_.Name } > actual-dlls.log
if (Compare-Object -ReferenceObject (Get-Content -Path res\windows\wix\expected-dlls.log) -DifferenceObject (Get-Content -Path actual-dlls.log)) {
Write-Output "Expected DLLs:"
Get-Content res\windows\wix\expected-dlls.log
Write-Output "Actual DLLs:"
Get-Content actual-dlls.log
Throw "Actual DLLs do not match expected"
}
if: runner.os == 'Windows'
# On macOS, we need a proper Clang version, not Apple's custom version without wasm32 support
- name: Install LLVM and Clang for macOS
uses: KyleMayes/install-llvm-action@dec985c8d7b46a2f363ea1a78f660c946a3349ea # v2.0.1
with:
env: true
version: 17
if: runner.os == 'macOS'
# Because macOS, see https://andreasfertig.blog/2021/02/clang-and-gcc-on-macos-catalina-finding-the-include-paths/
- name: Configure C compiler macOS
run: |
echo "SDKROOT=$(xcrun --show-sdk-path)" >> $GITHUB_ENV
if: runner.os == 'macOS'
- name: Install glibtoolize (macOS)
run: brew install libtool
if: runner.os == 'macOS'
- name: CUDA toolchain (Windows)
uses: Jimver/cuda-toolkit@dc581bec6470cf161025608f13d71b3c00c2c0b7 # v0.2.17
with:
cuda: '12.4.1'
method: network
sub-packages: '["nvcc", "cudart"]'
if: runner.os == 'Windows'
- name: CUDA toolchain (Ubuntu)
run: sudo apt-get install -y --no-install-recommends nvidia-cuda-toolkit
if: runner.os == 'Linux'
- name: Install Protoc
uses: arduino/setup-protoc@c65c819552d16ad3c9b72d9dfd5ba5237b9c906b # v3.0.0
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
# Needed for hwloc
- name: Install automake (macOS)
run: brew install automake
if: runner.os == 'macOS'
- name: AArch64 cross-compile packages
run: sudo apt-get update && sudo apt-get install -y --no-install-recommends g++-aarch64-linux-gnu gcc-aarch64-linux-gnu libc6-dev-arm64-cross
if: matrix.build.target == 'aarch64-unknown-linux-gnu'
- name: Configure cache
uses: actions/cache@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2
with:
path: |
~/.cargo/registry
~/.cargo/git
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.toml') }}
restore-keys: |
${{ runner.os }}-cargo-
- name: Build app (Linux, modern, CUDA)
# CXX for CUDA
env:
CXX: g++-12
RUSTFLAGS: ${{ matrix.build.modern-rustflags }}
run: |
cargo -Zgitoxide -Zgit build --locked -Z build-std --target ${{ matrix.build.target }} --profile production --features cuda
mv target/${{ matrix.build.target }}/production/space-acres target/${{ matrix.build.target }}/production/space-acres-modern
if: runner.os == 'Linux' && matrix.build.modern-rustflags
- name: Build app (Windows, modern, CUDA)
env:
RUSTFLAGS: ${{ matrix.build.modern-rustflags }}
run: |
cargo -Zgitoxide -Zgit build --locked -Z build-std --target ${{ matrix.build.target }} --profile production --features cuda
Move-Item -Path target\${{ matrix.build.target }}\production\space-acres.exe -Destination target\${{ matrix.build.target }}\production\space-acres-modern.exe
if: runner.os == 'Windows' && matrix.build.modern-rustflags
- name: Build app (macOS, normal)
env:
RUSTFLAGS: ${{ matrix.build.rustflags }}
run: cargo -Zgitoxide -Zgit build --locked -Z build-std --target ${{ matrix.build.target }} --profile production
if: runner.os == 'macOS'
- name: Build app (Linux, normal, CUDA)
# CXX for CUDA
env:
CXX: g++-12
RUSTFLAGS: ${{ matrix.build.rustflags }}
run: cargo -Zgitoxide -Zgit build --locked -Z build-std --target ${{ matrix.build.target }} --profile production --features cuda
if: runner.os == 'Linux'
- name: Build app (Windows, normal, CUDA)
env:
RUSTFLAGS: ${{ matrix.build.rustflags }}
run: cargo -Zgitoxide -Zgit build --locked -Z build-std --target ${{ matrix.build.target }} --profile production --features cuda
if: runner.os == 'Windows'
- name: Create bundle (macOS)
run: |
target=${{ matrix.build.target }}
BUNDLE_VERSION=$(cargo pkgid | cut -d "#" -f2)
BUNDLE_BUILD=$(date +"%Y%m%d%H%M")
APP_PREFIX=target/bundle
function process_dependencies()
{
local target=$1
local destdir=$2
local file=$3
local rpath=$4
echo "Processing $file"
local inst_prefix="$(brew --prefix)/*"
local DEPS=$(dyld_info -dependents $file | tail -n +4)
local process_list=""
for dep in $DEPS; do
if [[ $dep == $inst_prefix ]]; then
dep_file=$(basename $dep)
new_dep_file=$destdir/$dep_file
if [ ! -f $new_dep_file ]; then
# Not exist, do copy
echo " Copying $dep"
cp -n $dep $destdir
fi
# Fix the dependency
echo " Patching $dep"
install_name_tool -change $dep $rpath/$dep_file $file
# Collect list of dependencies
process_list="$new_dep_file $process_list"
fi
done
# Recursively process dependencies
for dep in $process_list; do
process_dependencies $target $destdir $dep $rpath
done
}
# 1. Create the bundle
mkdir -p $APP_PREFIX/$target/SpaceAcres.app/Contents/{MacOS,Resources}
mkdir -p $APP_PREFIX/$target/SpaceAcres.app/Contents/Resources/{lib,share}
cp target/$target/production/space-acres $APP_PREFIX/$target/SpaceAcres.app/Contents/MacOS
cp res/macos/space-acres.icns $APP_PREFIX/$target/SpaceAcres.app/Contents/Resources
cp res/macos/space-acres.sh $APP_PREFIX/$target/SpaceAcres.app/Contents/MacOS
cp res/macos/Info.plist $APP_PREFIX/$target/SpaceAcres.app/Contents/
sed -i '' "s/%BUNDLE_VERSION%/$BUNDLE_VERSION/g" $APP_PREFIX/$target/SpaceAcres.app/Contents/Info.plist
sed -i '' "s/%BUNDLE_BUILD%/$BUNDLE_BUILD/g" $APP_PREFIX/$target/SpaceAcres.app/Contents/Info.plist
mkdir -p $APP_PREFIX/$target/SpaceAcres.app/Contents/Resources/share/glib-2.0
cp -r /opt/homebrew/share/glib-2.0/schemas $APP_PREFIX/$target/SpaceAcres.app/Contents/Resources/share/glib-2.0
# 2. Copy and fix dependencies
destDir=$APP_PREFIX/$target/SpaceAcres.app/Contents/Resources/lib
process_dependencies $target $destDir $APP_PREFIX/$target/SpaceAcres.app/Contents/MacOS/space-acres "@executable_path/../Resources/lib"
# 3. Copy loaders
mkdir -p $APP_PREFIX/$target/SpaceAcres.app/Contents/Resources/lib/gdk-pixbuf-2.0/2.10.0/loaders
cp -r /opt/homebrew/lib/gdk-pixbuf-2.0/2.10.0/loaders/*.so $APP_PREFIX/$target/SpaceAcres.app/Contents/Resources/lib/gdk-pixbuf-2.0/2.10.0/loaders
# 4. Fix loaders
for loader in $APP_PREFIX/$target/SpaceAcres.app/Contents/Resources/lib/gdk-pixbuf-2.0/2.10.0/loaders/*.so; do
process_dependencies $target $destDir $loader "@executable_path/../Resources/lib"
done
cp -r /opt/homebrew/lib/gdk-pixbuf-2.0/2.10.0/loaders.cache $APP_PREFIX/$target/SpaceAcres.app/Contents/Resources/lib/gdk-pixbuf-2.0/2.10.0
sed -i '' "s|$(brew --prefix)|/Applications/SpaceAcres.app/Contents/Resources|g" $APP_PREFIX/$target/SpaceAcres.app/Contents/Resources/lib/gdk-pixbuf-2.0/2.10.0/loaders.cache
if: runner.os == 'macOS'
- name: Sign Application (macOS)
run: |
echo "Importing certificate"
echo "${{ secrets.MACOS_CERTIFICATE }}" | base64 --decode > certificate.p12
security create-keychain -p "${{ secrets.MACOS_CERTIFICATE_PW }}" build.keychain
security default-keychain -s build.keychain
security unlock-keychain -p "${{ secrets.MACOS_CERTIFICATE_PW }}" build.keychain
security import certificate.p12 -k build.keychain -P "${{ secrets.MACOS_CERTIFICATE_PW }}" -T /usr/bin/codesign
security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "${{ secrets.MACOS_CERTIFICATE_PW }}" build.keychain
echo "Signing app"
# Sign all libs under Resources/lib
find target/bundle/${{ matrix.build.target }}/SpaceAcres.app/Contents/Resources/lib '(' -name '*.dylib' -o -name '*.so' ')' -type f -exec codesign --verbose=999 --deep --force --options=runtime --entitlements res/macos/Entitlements.plist -s "${{ secrets.MACOS_IDENTITY }}" --timestamp {} \;
# Sign the app
codesign --deep --force --options=runtime --entitlements res/macos/Entitlements.plist -s "${{ secrets.MACOS_IDENTITY }}" --timestamp target/bundle/${{ matrix.build.target }}/SpaceAcres.app
# Allow code signing to fail on non-release builds and in non-autonomys repos (forks)
continue-on-error: ${{ github.repository_owner != 'autonomys' || github.event_name != 'push' || github.ref_type != 'tag' }}
if: runner.os == 'macOS'
- name: Create dmg (macOS)
run: |
version=$(cargo pkgid | cut -d "#" -f2)
npx [email protected] res/macos/spec-${{ matrix.build.target }}.json target/bundle/space-acres-$version.dmg
if: runner.os == 'macOS'
- name: Sign and notarize dmg (macOS)
run: |
echo "Signing"
version=$(cargo pkgid | cut -d "#" -f2)
codesign --deep --force --options=runtime -s "${{ secrets.MACOS_IDENTITY }}" --timestamp target/bundle/space-acres-$version.dmg
echo "Notarizing"
# Notarize the Dmg using notarytool
xcrun notarytool submit target/bundle/space-acres-$version.dmg --apple-id "${{ secrets.MACOS_APPLE_ID }}" --password "${{ secrets.MACOS_APP_PW }}" --team-id "${{ secrets.MACOS_TEAM_ID }}" --wait
xcrun stapler staple target/bundle/space-acres-$version.dmg
# Allow code signing to fail on non-release builds and in non-autonomys repos (forks)
continue-on-error: ${{ github.repository_owner != 'autonomys' || github.event_name != 'push' || github.ref_type != 'tag' }}
if: runner.os == 'macOS'
- name: Install cargo-wix (Windows)
uses: taiki-e/cache-cargo-install-action@1b76958d032c4d048c599f9fdfa48abe804d6319 # v1.2.2
with:
tool: cargo-wix
if: runner.os == 'Windows'
- name: Package (Windows)
run: |
Remove-Item target\wix\gtk4 -Recurse -Confirm:$false -ErrorAction SilentlyContinue
New-Item target\wix\gtk4\bin -ItemType Directory
New-Item target\wix\gtk4\lib\gdk-pixbuf-2.0\2.10.0\loaders -ItemType Directory
New-Item target\wix\gtk4\share\glib-2.0\schemas -ItemType Directory
Copy-Item -Path C:\gtk-build\gtk\x64\release\bin\*.dll -Destination target\wix\gtk4\bin
Copy-Item -Path C:\gtk-build\gtk\x64\release\bin\gdbus.exe -Destination target\wix\gtk4\bin
Copy-Item -Path C:\gtk-build\gtk\x64\release\bin\gspawn-win64-helper.exe -Destination target\wix\gtk4\bin
Copy-Item -Path C:\gtk-build\gtk\x64\release\bin\gspawn-win64-helper-console.exe -Destination target\wix\gtk4\bin
Copy-Item -Path C:\gtk-build\gtk\x64\release\lib\gdk-pixbuf-2.0\2.10.0\loaders\*.dll -Destination target\wix\gtk4\lib\gdk-pixbuf-2.0\2.10.0\loaders
Copy-Item -Path C:\gtk-build\gtk\x64\release\lib\gdk-pixbuf-2.0\2.10.0\loaders.cache -Destination target\wix\gtk4\lib\gdk-pixbuf-2.0\2.10.0
Copy-Item -Path C:\gtk-build\gtk\x64\release\share\glib-2.0\schemas\gschemas.compiled -Destination target\wix\gtk4\share\glib-2.0\schemas\gschemas.compiled
# TODO: Ideally something like this would have worked and we wouldn't need to hardcode stuff in `space-acres.wxs`: https://github.com/volks73/cargo-wix/issues/271
# & "C:\Program Files (x86)\WiX Toolset v3.11\bin\heat.exe" dir target\wix\gtk4 -gg -sfrag -template:fragment -out target\wix\gtk4.wxs -cg GTK -dr GTK
cargo wix --target ${{ matrix.build.target }} --profile production --no-build --nocapture
# Create bundle with Microsoft Visual C++ Redistributable in it
Remove-Item target\wix\space-acres.wixobj -Confirm:$false
cargo wix --profile release --no-build --nocapture --include res\windows\wix\bundle.wxs -C -ext -C WixBalExtension
Remove-Item target\wix\gtk4 -Recurse -Confirm:$false -ErrorAction SilentlyContinue
if: runner.os == 'Windows'
- name: Sign Application (Windows)
run: |
$ErrorActionPreference = "Stop"
dotnet tool install --global AzureSignTool
(Get-ChildItem -Path target\wix -Include space-acres-*.exe -Recurse) | ForEach-Object {
Write("Signing $($_)");
AzureSignTool sign --azure-key-vault-url "${{ secrets.AZURE_KEY_VAULT_URI }}" --azure-key-vault-client-id "${{ secrets.AZURE_CLIENT_ID }}" --azure-key-vault-client-secret "${{ secrets.AZURE_CLIENT_SECRET }}" --azure-key-vault-tenant-id "${{ secrets.AZURE_TENANT_ID }}" --azure-key-vault-certificate "${{ secrets.AZURE_CERT_NAME }}" --file-digest sha512 --timestamp-rfc3161 http://timestamp.digicert.com -v $($_);
}
# Allow code signing to fail on non-release builds and in non-autonomys repos (forks)
continue-on-error: ${{ github.repository_owner != 'autonomys' || github.event_name != 'push' || github.ref_type != 'tag' }}
if: runner.os == 'Windows'
- name: Install cargo-deb (Linux)
uses: taiki-e/cache-cargo-install-action@1b76958d032c4d048c599f9fdfa48abe804d6319 # v1.2.2
with:
tool: cargo-deb
if: runner.os == 'Linux'
- name: Package (Linux, with modern)
run: |
# Build Debian package
cargo deb --target ${{ matrix.build.target }} --profile production --no-build --no-strip --variant=modern
# And build AppImage as well
wget https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-x86_64.AppImage
wget https://raw.githubusercontent.com/linuxdeploy/linuxdeploy-plugin-gtk/3b67a1d1c1b0c8268f57f2bce40fe2d33d409cea/linuxdeploy-plugin-gtk.sh
chmod +x linuxdeploy*.AppImage linuxdeploy-plugin-gtk.sh
NO_STRIP=1 ./linuxdeploy-x86_64.AppImage \
--appdir AppDir \
--plugin gtk \
--executable target/${{ matrix.build.target }}/production/space-acres \
--executable target/${{ matrix.build.target }}/production/space-acres-modern \
--desktop-file res/linux/space-acres.desktop \
--icon-file res/linux/space-acres.png \
--output appimage
# Rename AppImage to be consistent with other files
version=$(grep -Po 'version = "\K.*?(?=")' -m 1 Cargo.toml)
mv Space_Acres-x86_64.AppImage space-acres-$version-x86_64.AppImage
if: runner.os == 'Linux' && matrix.build.modern-rustflags
- name: Package (Linux, without modern)
run: |
# Build Debian package
cargo deb --target ${{ matrix.build.target }} --profile production --no-build --no-strip
# And build AppImage as well
wget https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-x86_64.AppImage
wget https://raw.githubusercontent.com/linuxdeploy/linuxdeploy-plugin-gtk/3b67a1d1c1b0c8268f57f2bce40fe2d33d409cea/linuxdeploy-plugin-gtk.sh
chmod +x linuxdeploy*.AppImage linuxdeploy-plugin-gtk.sh
NO_STRIP=1 ./linuxdeploy-x86_64.AppImage \
--appdir AppDir \
--plugin gtk \
--executable target/${{ matrix.build.target }}/production/space-acres \
--desktop-file res/linux/space-acres.desktop \
--icon-file res/linux/space-acres.png \
--output appimage
# Rename AppImage to be consistent with other files
version=$(grep -Po 'version = "\K.*?(?=")' -m 1 Cargo.toml)
mv Space_Acres-x86_64.AppImage space-acres-$version-x86_64.AppImage
if: runner.os == 'Linux' && !matrix.build.modern-rustflags
- name: Upload installer to artifacts (Linux)
uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.1.3
with:
name: installer-${{ matrix.build.suffix }}
path: |
space-acres-*.AppImage
target/${{ matrix.build.target }}/debian/*.deb
if-no-files-found: error
if: runner.os == 'Linux'
- name: Upload installer to assets (Linux)
uses: alexellis/upload-assets@13926a61cdb2cb35f5fdef1c06b8b591523236d3 # 0.4.1
env:
GITHUB_TOKEN: ${{ github.token }}
with:
asset_paths: '["space-acres-*.AppImage", "target/${{ matrix.build.target }}/debian/*.deb"]'
if: runner.os == 'Linux' && github.event_name == 'push' && github.ref_type == 'tag'
- name: Upload dmg to artifacts (macOS)
uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.1.3
with:
name: space-acres-${{ matrix.build.suffix }}
path: |
target/bundle/*.dmg
if-no-files-found: error
if: runner.os == 'macOS'
- name: Upload dmg to assets (macOS)
uses: alexellis/upload-assets@13926a61cdb2cb35f5fdef1c06b8b591523236d3 # 0.4.1
env:
GITHUB_TOKEN: ${{ github.token }}
with:
asset_paths: '["target/bundle/*.dmg"]'
if: runner.os == 'macOS' && github.event_name == 'push' && github.ref_type == 'tag'
- name: Upload installer to artifacts (Windows)
uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.1.3
with:
name: installer-${{ matrix.build.suffix }}
path: |
target/wix/*.exe
if-no-files-found: error
if: runner.os == 'Windows'
- name: Upload installer to assets (Windows)
uses: alexellis/upload-assets@13926a61cdb2cb35f5fdef1c06b8b591523236d3 # 0.4.1
env:
GITHUB_TOKEN: ${{ github.token }}
with:
asset_paths: '["target/wix/*.exe"]'
if: runner.os == 'Windows' && github.event_name == 'push' && github.ref_type == 'tag'