Skip to content

Build & Bundle

Build & Bundle #117

Workflow file for this run

name: "Build & Bundle"
on:
push:
branches:
- main
paths:
- 'crates/**'
- 'Cargo.toml'
- 'Cargo.lock'
- 'apps/**'
- 'package/**'
- '.github/workflows/build.yml'
workflow_dispatch:
env:
BINARY_NAME: plumeimpactor
BUNDLE_NAME: Impactor
jobs:
build-linux:
runs-on: ${{ matrix.os }}
strategy:
fail-fast: true
matrix:
include:
- os: ubuntu-22.04
arch: x86_64
- os: ubuntu-22.04-arm
arch: aarch64
steps:
- uses: actions/checkout@v4
- name: Cache Rust dependencies
uses: actions/cache@v4
with:
path: |
~/.cargo/registry
~/.cargo/git
target
key: linux-${{ matrix.arch }}-cargo-${{ hashFiles('**/Cargo.lock') }}
restore-keys: linux-${{ matrix.arch }}-cargo-
- name: Install Rust stable
uses: dtolnay/rust-toolchain@stable
- name: Install Linux dependencies
run: |
sudo apt-get update
sudo apt-get install -y libglib2.0-dev libsecret-1-dev libgtk-3-dev libpng-dev libjpeg-dev libgl1-mesa-dev libglu1-mesa-dev libxkbcommon-dev libexpat1-dev libtiff-dev
- name: Build Dependencies
run: |
cargo install patch-crate
cargo fetch --locked || true
cargo patch-crate --force
mkdir -p build/out
- name: Build Binary
run: cargo build --bin ${{ env.BINARY_NAME }} --release
- name: Generate Runtime Metadata
run: |
cat > build/${{ env.BUNDLE_NAME }}.desktop <<EOF
[Desktop Entry]
Type=Application
Name=${{ env.BUNDLE_NAME }}
Exec=${{ env.BINARY_NAME }}
Icon=${{ env.BUNDLE_NAME }}
Categories=Utility;
Terminal=false
EOF
cp "package/linux/icon.png" "build/${{ env.BUNDLE_NAME }}.png"
- name: Bundle with LinuxDeploy
run: |
cd build
wget https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-${{ matrix.arch }}.AppImage
chmod +x linuxdeploy-${{ matrix.arch }}.AppImage
./linuxdeploy-${{ matrix.arch }}.AppImage --appimage-extract-and-run \
--appdir AppDir \
--executable ../target/release/${{ env.BINARY_NAME }} \
--desktop-file ${{ env.BUNDLE_NAME }}.desktop \
--icon-file ${{ env.BUNDLE_NAME }}.png \
--output appimage
rm linuxdeploy-${{ matrix.arch }}.AppImage
mv *.AppImage out/
cd ..
- name: Upload Bundles
uses: actions/upload-artifact@v4
with:
name: ${{ env.BINARY_NAME }}-linux-${{ matrix.arch }}
path: build/out/*
build-windows:
runs-on: windows-latest
steps:
- uses: actions/checkout@v4
- name: Install Rust stable
uses: dtolnay/rust-toolchain@stable
- name: Setup Windows MSVC environment
uses: ilammy/msvc-dev-cmd@v1
- name: Build Dependencies
run: |
cargo install patch-crate
cargo fetch --locked || true
cargo patch-crate --force
mkdir -p build/out
mkdir -p build/nsis
- name: Build & Bundle (Windows)
run: |
cargo build --bin ${{ env.BINARY_NAME }} --release
cp target/release/${{ env.BINARY_NAME }}.exe build/nsis
- name: Create NSIS Installer
run: |
mv package/windows/* build/nsis/
choco install nsis.portable
makensis build/nsis/installer.nsi
mv build/nsis/PlumeInstaller.exe build/out/${{ env.BINARY_NAME }}-setup.exe
- name: Create AppCast
shell: pwsh
run: |
curl -L -o WinSparkle-0.8.1.zip https://github.com/vslavik/winsparkle/releases/download/v0.8.1/WinSparkle-0.8.1.zip
unzip WinSparkle-0.8.1.zip -d WinSparkle
"${{ secrets.SPARKLE_PRIV_KEY_WIN }}" | Out-File -Encoding ascii dsa_priv.pem
$SIGNATURE = ./WinSparkle/WinSparkle-0.8.1/bin/sign_update.bat build/out/${{ env.BINARY_NAME }}-setup.exe dsa_priv.pem
$VERSION = (Select-String '^version *= *' Cargo.toml | Select-Object -First 1).Line -replace 'version *= *"(.+)"','$1'
$DATE = Get-Date -Format "ddd, dd MMM yyyy HH:mm:ss K"
$xml = @"
<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:sparkle="http://www.andymatuschak.org/xml-namespaces/sparkle">
<channel>
<title>PlumeImpactor</title>
<description>Most recent updates to PlumeImpactor</description>
<language>en</language>
<item>
<title>Version $VERSION</title>
<sparkle:version>$VERSION</sparkle:version>
<pubDate>$DATE</pubDate>
<enclosure url="https://github.com/khcrysalis/PlumeImpactor/releases/latest/download/${{ env.BINARY_NAME }}-setup.exe"
sparkle:dsaSignature="$SIGNATURE"
length="0"
type="application/octet-stream" />
</item>
</channel>
</rss>
"@
$xml | Out-File -Encoding utf8 build/out/appcast.xml
- name: Upload Bundles
uses: actions/upload-artifact@v4
with:
name: ${{ env.BINARY_NAME }}-windows
path: build/out/*
build-macos-slices:
runs-on: ${{ matrix.os }}
strategy:
matrix:
include:
- os: macos-latest
target: aarch64-apple-darwin
arch: arm
- os: macos-15-intel
target: x86_64-apple-darwin
arch: intel
steps:
- uses: actions/checkout@v4
- name: Install Rust stable
uses: dtolnay/rust-toolchain@stable
with:
targets: ${{ matrix.target }}
- name: Build Dependencies
run: |
cargo install patch-crate
cargo fetch --locked || true
cargo patch-crate --force
mkdir -p build/out
- name: Build (macOS ${{ matrix.arch }})
run: |
cargo build --bin ${{ env.BINARY_NAME }} --release --target ${{ matrix.target }}
strip target/${{ matrix.target }}/release/${{ env.BINARY_NAME }}
cp target/${{ matrix.target }}/release/${{ env.BINARY_NAME }} build/out/${{ env.BINARY_NAME }}-${{ matrix.arch }}
- name: Upload ${{ matrix.arch }} Slice
uses: actions/upload-artifact@v4
with:
name: ${{ env.BINARY_NAME }}-macos-slice-${{ matrix.arch }}
path: build/out/${{ env.BINARY_NAME }}-${{ matrix.arch }}
build-macos-universal:
runs-on: macos-latest
needs: [build-macos-slices]
steps:
- uses: actions/checkout@v4
- name: Get ARM Slice
uses: actions/download-artifact@v4
with:
name: ${{ env.BINARY_NAME }}-macos-slice-arm
path: build/slices
- name: Get Intel Slice
uses: actions/download-artifact@v4
with:
name: ${{ env.BINARY_NAME }}-macos-slice-intel
path: build/slices
- name: Setup Certificates
uses: apple-actions/import-codesign-certs@v5
with:
p12-file-base64: ${{ secrets.DEV_ID_P12_BASE64 }}
p12-password: ${{ secrets.DEV_ID_P12_PASSWORD }}
- name: Download CreateDMG
run: |
brew install create-dmg
- name: Create Universal Binary
run: |
mkdir -p build/universal
lipo -create -output build/universal/${{ env.BINARY_NAME }} build/slices/${{ env.BINARY_NAME }}-arm build/slices/${{ env.BINARY_NAME }}-intel
chmod +x build/universal/${{ env.BINARY_NAME }}
# for udid
make
- name: Bundle
run: |
mkdir -p build/dmg
# Ensure Info.plist is valid before copying
plutil -lint package/macos/${{ env.BUNDLE_NAME }}.app/Contents/Info.plist
VERSION=$(grep '^version *= *' Cargo.toml | head -n1 | sed 's/version *= *"\(.*\)"/\1/')
/usr/libexec/PlistBuddy -c "Set :CFBundleShortVersionString $VERSION" package/macos/${{ env.BUNDLE_NAME }}.app/Contents/Info.plist
/usr/libexec/PlistBuddy -c "Set :CFBundleVersion ${{ github.run_number }}" package/macos/${{ env.BUNDLE_NAME }}.app/Contents/Info.plist
cp -R package/macos/${{ env.BUNDLE_NAME }}.app build/dmg/${{ env.BUNDLE_NAME }}.app
mkdir -p build/dmg/${{ env.BUNDLE_NAME }}.app/Contents/MacOS
mv build/universal/${{ env.BINARY_NAME }} build/dmg/${{ env.BUNDLE_NAME }}.app/Contents/MacOS/${{ env.BINARY_NAME }}
# for udid
mv build/udid build/dmg/${{ env.BUNDLE_NAME }}.app/Contents/MacOS/udid
- name: Codesign
run: |
codesign --deep --force --options runtime \
--sign "${{ secrets.DEV_ID_IDENTITY_NAME }}" build/dmg/${{ env.BUNDLE_NAME }}.app/Contents/Frameworks/Sparkle.framework/Resources/Autoupdate.app
codesign --deep --force --options runtime \
--sign "${{ secrets.DEV_ID_IDENTITY_NAME }}" build/dmg/${{ env.BUNDLE_NAME }}.app/Contents/Frameworks/Sparkle.framework
codesign --deep --force --options runtime \
--sign "${{ secrets.DEV_ID_IDENTITY_NAME }}" build/dmg/${{ env.BUNDLE_NAME }}.app/Contents/MacOS/${{ env.BINARY_NAME }}
codesign --deep --force --options runtime \
--sign "${{ secrets.DEV_ID_IDENTITY_NAME }}" build/dmg/${{ env.BUNDLE_NAME }}.app
- name: Create DMG
run: |
mkdir -p build/out
create-dmg \
--volname ${{ env.BUNDLE_NAME }} \
--background "package/macos/background.png" \
--window-pos 200 120 \
--window-size 510 350 \
--icon-size 100 \
--icon ${{ env.BUNDLE_NAME }}.app 160 155 \
--hide-extension "${{ env.BUNDLE_NAME }}.app" \
--app-drop-link 350 155 \
build/out/${{ env.BUNDLE_NAME }}.dmg build/dmg
- name: Notarize DMG
run: |
xcrun notarytool submit build/out/${{ env.BUNDLE_NAME }}.dmg --apple-id "${{ secrets.APPLE_ID_EMAIL }}" --password "${{ secrets.APPLE_ID_PASSWORD }}" --team-id "${{ secrets.APPLE_ID_TEAM }}" --wait
xcrun stapler staple build/out/${{ env.BUNDLE_NAME }}.dmg
- name: Setup Sparkle
id: get_version
run: |
curl -L -o Sparkle-2.5.2.tar.xz https://github.com/sparkle-project/Sparkle/releases/download/2.5.2/Sparkle-2.5.2.tar.xz
tar -xJf Sparkle-2.5.2.tar.xz
chmod +x ./bin/generate_appcast
- name: Make Appcast
run: |
echo "$SPARKLE_PRIVATE_KEY" | ./bin/generate_appcast --ed-key-file - --download-url-prefix https://github.com/khcrysalis/PlumeImpactor/releases/latest/download/ update/out/
env:
SPARKLE_PRIVATE_KEY: ${{ secrets.SPARKLE_PRIV_KEY_MAC }}
- name: Upload Universal DMG
uses: actions/upload-artifact@v4
with:
name: ${{ env.BINARY_NAME }}-macos-universal
path: |
build/out/${{ env.BUNDLE_NAME }}.dmg
build/out/appcast.xml