Compare commits

...

2 Commits

Author SHA1 Message Date
bherbruck 0f8aa72732 Release: Windows jobs start at once on 8 vCPU runners
The icons job only copied the committed .ico after a cold build of the CLI, and the Windows
jobs waited for it; package.ps1 falls back to the same file. The Windows builds were 35 minutes
on a 2 vCPU runner.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-20 20:43:43 -04:00
bherbruck 2c5f8c1776 Build the macOS release binaries per architecture in parallel
The universal macOS job built aarch64 and x86_64 one after the other on a
3-core runner and took 45-50 minutes, the longest job of a release. Each
architecture now builds on its own runner and a small job joins them with lipo
and packages the dmg and CLI zip exactly as before.
2026-10-20 17:43:07 -04:00
2 changed files with 72 additions and 38 deletions
+53 -37
View File
@@ -8,7 +8,7 @@
#
# Linux x86_64, aarch64 AppImage (+ .zsync), .deb, .rpm, .flatpak, .snap, .tar.gz packaging/linux
# FreeBSD x86_64 .tar.gz (built in a FreeBSD VM) packaging/freebsd
# macOS universal .dmg, and the CLI as a .zip packaging/macos
# macOS universal .dmg, and the CLI as a .zip (both archs built in parallel) packaging/macos
# Windows x64, x86, arm64 .msi and a portable .zip; x64 also the plain .exe packaging/windows
# Web a .zip of the static site packaging/web
#
@@ -83,28 +83,6 @@ jobs:
{ echo "version=$VERSION"; echo "date=$(date -u +%Y-%m-%d)"; echo "prerelease=$pre"; } >>"$GITHUB_OUTPUT"
echo "### SolidCraft v$VERSION (\`${GITHUB_SHA::9}\`)" >>"$GITHUB_STEP_SUMMARY"
# The app icon in every size, drawn by solidcraft-cli (no image files are committed), for the
# Windows jobs: the ARM64 build is cross-compiled and can't run there to draw its own.
icons:
needs: version
if: needs.version.outputs.build == 'true'
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- uses: dtolnay/rust-toolchain@stable
- uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2.9.2
with:
key: release-icons
- run: cargo build --release --locked -p solidcraft-cli
- run: |
. packaging/env.sh
make_icons target/release/solidcraft-cli icons
- uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
with:
name: icons
path: icons
if-no-files-found: error
linux:
name: Linux ${{ matrix.arch }}
needs: version
@@ -293,11 +271,19 @@ jobs:
path: dist/release/*
if-no-files-found: error
macos:
name: macOS universal
# The two halves of the universal binary build in parallel on their own runners (each alone
# took about half of the old single job's 45 minutes); `macos` below joins and packages them.
macos-build:
name: macOS build ${{ matrix.arch }}
needs: version
if: needs.version.outputs.build == 'true'
runs-on: macos-14
strategy:
fail-fast: false
matrix:
include:
- { arch: aarch64, target: aarch64-apple-darwin }
- { arch: x86_64, target: x86_64-apple-darwin }
env:
SOLIDCRAFT_VERSION: ${{ needs.version.outputs.version }}
SOLIDCRAFT_BUILD_DATE: ${{ needs.version.outputs.date }}
@@ -305,12 +291,45 @@ jobs:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- uses: dtolnay/rust-toolchain@stable
with:
targets: aarch64-apple-darwin, x86_64-apple-darwin
targets: ${{ matrix.target }}
- uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2.9.2
with:
key: release-macos-universal
- name: Build and package (dmg, CLI zip; the dmg is mounted and checked)
run: packaging/macos/package.sh --arch universal
key: release-macos-${{ matrix.arch }}
- name: Build
run: packaging/macos/package.sh --build-only ${{ matrix.target }}
# Not named release-*: the release job collects every release-* artifact as an asset.
- uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
with:
name: macos-bin-${{ matrix.arch }}
path: |
target/${{ matrix.target }}/release/solidcraft
target/${{ matrix.target }}/release/solidcraft-cli
target/${{ matrix.target }}/release/solvecraft-cli
if-no-files-found: error
macos:
name: macOS universal
needs: [version, macos-build]
if: needs.version.outputs.build == 'true'
runs-on: macos-14
env:
SOLIDCRAFT_VERSION: ${{ needs.version.outputs.version }}
SOLIDCRAFT_BUILD_DATE: ${{ needs.version.outputs.date }}
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
with:
name: macos-bin-aarch64
path: target/aarch64-apple-darwin/release
- uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
with:
name: macos-bin-x86_64
path: target/x86_64-apple-darwin/release
- name: Join, package and check (dmg, CLI zip; the dmg is mounted and checked)
run: |
# Artifacts don't keep the executable bit.
chmod +x target/*-apple-darwin/release/solidcraft target/*-apple-darwin/release/solidcraft-cli target/*-apple-darwin/release/solvecraft-cli
packaging/macos/package.sh --arch universal --skip-build
- uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
with:
name: release-macos
@@ -319,9 +338,12 @@ jobs:
windows:
name: Windows ${{ matrix.arch }}
needs: [version, icons]
needs: version
if: needs.version.outputs.build == 'true'
runs-on: windows-latest
# An 8 vCPU runner: the release build was 35 minutes on a 2 vCPU windows-latest and is the
# longest job of the release. The installer icon is the committed
# assets/icons/app/windows/exports/solidcraft.ico (package.ps1's default), so nothing waits.
runs-on: blacksmith-8vcpu-windows-2025
strategy:
fail-fast: false
matrix:
@@ -334,10 +356,6 @@ jobs:
SOLIDCRAFT_VERSION: ${{ needs.version.outputs.version }}
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
with:
name: icons
path: icons
- uses: dtolnay/rust-toolchain@stable
with:
targets: ${{ matrix.target }}
@@ -351,8 +369,6 @@ jobs:
wix extension add -g WixToolset.UI.wixext/5.0.2 WixToolset.Util.wixext/5.0.2
- name: Build and package (msi, portable zip)
shell: pwsh
env:
SOLIDCRAFT_ICONS: ${{ github.workspace }}/icons
run: ./packaging/windows/package.ps1 -Arch ${{ matrix.arch }}
- uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
with:
+19 -1
View File
@@ -7,6 +7,12 @@
# compatibility alias) with the licence files
#
# Usage: packaging/macos/package.sh [--arch universal|aarch64|x86_64] [--skip-build]
# packaging/macos/package.sh --build-only <rust-target>
#
# --build-only builds just that target (aarch64-apple-darwin or x86_64-apple-darwin) and stops,
# so the release workflow can build the two halves of the universal binary on separate runners;
# a later `--arch universal --skip-build` run joins the binaries it finds under
# $CARGO_TARGET_DIR/<target>/release/ and packages them.
#
# The app is ad-hoc signed (not notarized): the first launch needs right-click > Open.
# Adapted from PhotoCraft's packaging (storytold/photocraft, Apache-2.0; see ATTRIBUTION.md).
@@ -18,11 +24,13 @@ MACOS_BUNDLE_ID=ai.storyteller.solidcraft
ARCH=universal
SKIP_BUILD=0
BUILD_ONLY=
while [ $# -gt 0 ]; do
case "$1" in
--arch) ARCH="$2"; shift 2 ;;
--skip-build) SKIP_BUILD=1; shift ;;
-h | --help) sed -n '2,10p' "$0"; exit 0 ;;
--build-only) BUILD_ONLY="$2"; shift 2 ;;
-h | --help) sed -n '2,16p' "$0"; exit 0 ;;
*) echo "unknown argument: $1" >&2; exit 2 ;;
esac
done
@@ -41,6 +49,16 @@ APP="$WORK/SolidCraft.app"
DMG="$DIST/solidcraft-$VERSION-macos-$ARCH.dmg"
CLI_ZIP="$DIST/solidcraft-cli-$VERSION-macos-$ARCH.zip"
if [ -n "$BUILD_ONLY" ]; then
case "$BUILD_ONLY" in
aarch64-apple-darwin | x86_64-apple-darwin) ;;
*) echo "unknown --build-only target $BUILD_ONLY" >&2; exit 2 ;;
esac
echo "==> SolidCraft $VERSION for macOS ($BUILD_ONLY, build only)"
(cd "$ROOT" && cargo build --release --locked -p solidcraft -p solidcraft-cli --target "$BUILD_ONLY")
exit 0
fi
echo "==> SolidCraft $VERSION for macOS ($ARCH)"
if [ "$SKIP_BUILD" = 0 ]; then
args=()