forked from 1b-agent/opencadstudio-upstream
The Windows executable carried no icon, so Explorer, the taskbar, the Start-menu tile and file-association entries showed a generic icon. Embed AppIcon.ico via winresource in build.rs, and generate the .ico from the logo before the build (it was produced after the build, too late to embed). Local and non-Windows builds skip the step when the .ico is absent. Fixes #107. Co-Authored-By: Claude Opus 4.8 <[email protected]>
296 lines
13 KiB
YAML
296 lines
13 KiB
YAML
name: Release
|
|
|
|
on:
|
|
release:
|
|
types: [published]
|
|
workflow_dispatch:
|
|
|
|
jobs:
|
|
build-appimage:
|
|
runs-on: ubuntu-22.04
|
|
permissions:
|
|
contents: write
|
|
|
|
steps:
|
|
- name: Checkout
|
|
uses: actions/checkout@v4
|
|
|
|
- name: Install Rust
|
|
uses: dtolnay/rust-toolchain@stable
|
|
|
|
- name: Install dependencies
|
|
run: |
|
|
sudo apt-get update -q
|
|
sudo apt-get install -y \
|
|
libgl1-mesa-dev libx11-dev libxcursor-dev libxi-dev libxrandr-dev \
|
|
libxkbcommon-dev libwayland-dev libfontconfig1-dev libfreetype6-dev \
|
|
librsvg2-bin fuse libfuse2
|
|
|
|
- name: Build
|
|
run: cargo build --release
|
|
|
|
- name: Prepare AppDir
|
|
run: |
|
|
mkdir -p AppDir/usr/bin
|
|
mkdir -p AppDir/usr/share/applications
|
|
mkdir -p AppDir/usr/share/icons/hicolor/256x256/apps
|
|
cp target/release/OpenCADStudio AppDir/usr/bin/OpenCADStudio
|
|
cp packaging/OpenCADStudio.desktop AppDir/usr/share/applications/io.github.HakanSeven12.OpenCadStudio.desktop
|
|
rsvg-convert -w 256 -h 256 assets/logo.svg \
|
|
-o AppDir/usr/share/icons/hicolor/256x256/apps/io.github.HakanSeven12.OpenCadStudio.png
|
|
|
|
- name: Download linuxdeploy
|
|
run: |
|
|
wget -q https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-x86_64.AppImage
|
|
chmod +x linuxdeploy-x86_64.AppImage
|
|
|
|
- name: Build AppImage
|
|
env:
|
|
APPIMAGE_EXTRACT_AND_RUN: 1
|
|
run: |
|
|
./linuxdeploy-x86_64.AppImage \
|
|
--appdir AppDir \
|
|
--desktop-file AppDir/usr/share/applications/io.github.HakanSeven12.OpenCadStudio.desktop \
|
|
--icon-file AppDir/usr/share/icons/hicolor/256x256/apps/io.github.HakanSeven12.OpenCadStudio.png \
|
|
--output appimage
|
|
mv Open*CAD*Studio*.AppImage OpenCADStudio.AppImage
|
|
|
|
- name: Upload AppImage to release
|
|
if: github.event_name == 'release'
|
|
env:
|
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
run: |
|
|
mv OpenCADStudio.AppImage OpenCADStudio-${{ github.ref_name }}-linux-x86_64.AppImage
|
|
gh release upload ${{ github.ref_name }} OpenCADStudio-${{ github.ref_name }}-linux-x86_64.AppImage --clobber --repo ${{ github.repository }}
|
|
|
|
build-windows:
|
|
runs-on: windows-latest
|
|
permissions:
|
|
contents: write
|
|
|
|
steps:
|
|
- name: Checkout
|
|
uses: actions/checkout@v4
|
|
|
|
- name: Install Rust
|
|
uses: dtolnay/rust-toolchain@stable
|
|
|
|
- name: Convert SVG icon to ICO
|
|
shell: pwsh
|
|
run: |
|
|
# ImageMagick is pre-installed on windows-latest. The
|
|
# auto-resize generates every size Explorer / Add-Remove
|
|
# Programs / the Start Menu shortcut may request from a
|
|
# single source SVG. Must run BEFORE the build so build.rs
|
|
# can embed the icon into the .exe (issue #107).
|
|
magick assets/logo.svg `
|
|
-define icon:auto-resize=16,24,32,48,64,128,256 `
|
|
packaging/windows/AppIcon.ico
|
|
|
|
- name: Build
|
|
run: cargo build --release
|
|
|
|
- name: Sign executable (Azure Trusted Signing)
|
|
# Sign the bare .exe *before* the MSI is built so the copy packed
|
|
# into the installer carries the signature too. AZURE_CLIENT_SECRET
|
|
# authenticates the App Registration; the remaining AZURE_* secrets
|
|
# select the Trusted Signing account / certificate profile.
|
|
uses: azure/artifact-signing-action@v2
|
|
with:
|
|
azure-tenant-id: ${{ secrets.AZURE_TENANT_ID }}
|
|
azure-client-id: ${{ secrets.AZURE_CLIENT_ID }}
|
|
azure-client-secret: ${{ secrets.AZURE_CLIENT_SECRET }}
|
|
endpoint: ${{ secrets.AZURE_ENDPOINT }}
|
|
signing-account-name: ${{ secrets.AZURE_TRUSTED_SIGNING_ACCOUNT_NAME }}
|
|
certificate-profile-name: ${{ secrets.AZURE_CERTIFICATE_PROFILE_NAME }}
|
|
files: ${{ github.workspace }}\target\release\OpenCADStudio.exe
|
|
file-digest: SHA256
|
|
timestamp-rfc3161: http://timestamp.acs.microsoft.com
|
|
timestamp-digest: SHA256
|
|
|
|
- name: Build MSI installer
|
|
shell: pwsh
|
|
run: |
|
|
$version = "${{ github.ref_name }}" -replace '^v', ''
|
|
# workflow_dispatch runs use the branch name as ref_name, which
|
|
# is not a valid MSI ProductVersion — fall back to 0.0.0 so test
|
|
# builds still produce an installer.
|
|
if ($version -notmatch '^\d+(\.\d+){0,3}$') { $version = "0.0.0" }
|
|
# WiX Toolset 3.x is pre-installed on windows-latest; $env:WIX
|
|
# points to the install root. candle compiles .wxs → .wixobj
|
|
# and light links it into the final .msi.
|
|
$candle = Join-Path $env:WIX "bin\candle.exe"
|
|
$light = Join-Path $env:WIX "bin\light.exe"
|
|
# Resolve to absolute paths and pass each `-d<name>=<value>`
|
|
# as one quoted argument. PowerShell's native-command argument
|
|
# passing strips unquoted `-d…=…` strings on the `=` sign,
|
|
# which would otherwise hand candle an empty Source variable
|
|
# and `target\release\OpenCADStudio.exe` as a stray input
|
|
# filename.
|
|
$exePath = (Resolve-Path target\release\OpenCADStudio.exe).Path
|
|
$iconPath = (Resolve-Path packaging\windows\AppIcon.ico).Path
|
|
# GPL-3 license RTF shown on the installer's EULA page.
|
|
$licensePath = (Resolve-Path packaging\windows\License.rtf).Path
|
|
# main.wxs holds the package/feature; ui.wxs holds the installer UI
|
|
# and finish-screen launch checkbox. Both compile together.
|
|
$mainWxs = (Resolve-Path packaging\windows\main.wxs).Path
|
|
$uiWxs = (Resolve-Path packaging\windows\ui.wxs).Path
|
|
# candle writes one .wixobj per source into this directory (the
|
|
# trailing slash tells it -out is a folder, not a single file).
|
|
$objDir = Join-Path $PWD "packaging\windows\"
|
|
$msiPath = Join-Path $PWD "OpenCADStudio.msi"
|
|
& $candle -arch x64 `
|
|
"-dVersion=$version" `
|
|
"-dSource=$exePath" `
|
|
"-dIcon=$iconPath" `
|
|
"-dLicense=$licensePath" `
|
|
$mainWxs $uiWxs `
|
|
-out $objDir
|
|
if ($LASTEXITCODE -ne 0) { throw "candle failed" }
|
|
$mainObj = Join-Path $objDir "main.wixobj"
|
|
$uiObj = Join-Path $objDir "ui.wixobj"
|
|
& $light $mainObj $uiObj -ext WixUIExtension -out $msiPath
|
|
if ($LASTEXITCODE -ne 0) { throw "light failed" }
|
|
|
|
- name: Sign MSI installer (Azure Trusted Signing)
|
|
# The installer itself must be signed separately — light produces a
|
|
# fresh, unsigned .msi even though the .exe inside is already signed.
|
|
uses: azure/artifact-signing-action@v2
|
|
with:
|
|
azure-tenant-id: ${{ secrets.AZURE_TENANT_ID }}
|
|
azure-client-id: ${{ secrets.AZURE_CLIENT_ID }}
|
|
azure-client-secret: ${{ secrets.AZURE_CLIENT_SECRET }}
|
|
endpoint: ${{ secrets.AZURE_ENDPOINT }}
|
|
signing-account-name: ${{ secrets.AZURE_TRUSTED_SIGNING_ACCOUNT_NAME }}
|
|
certificate-profile-name: ${{ secrets.AZURE_CERTIFICATE_PROFILE_NAME }}
|
|
files: ${{ github.workspace }}\OpenCADStudio.msi
|
|
file-digest: SHA256
|
|
timestamp-rfc3161: http://timestamp.acs.microsoft.com
|
|
timestamp-digest: SHA256
|
|
|
|
- name: Upload artifacts to release
|
|
if: github.event_name == 'release'
|
|
shell: pwsh
|
|
env:
|
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
run: |
|
|
$tag = "${{ github.ref_name }}"
|
|
# Ship both the bare .exe (portable, no install) and the
|
|
# .msi (installer with Start Menu shortcut + .dwg / .dxf
|
|
# file association). The `-portable` / `-installer` suffix
|
|
# makes the distinction obvious on the release page.
|
|
Move-Item target\release\OpenCADStudio.exe "OpenCADStudio-$tag-windows-x86_64-portable.exe"
|
|
Move-Item OpenCADStudio.msi "OpenCADStudio-$tag-windows-x86_64-installer.msi"
|
|
gh release upload $tag `
|
|
"OpenCADStudio-$tag-windows-x86_64-portable.exe" `
|
|
"OpenCADStudio-$tag-windows-x86_64-installer.msi" `
|
|
--clobber --repo ${{ github.repository }}
|
|
|
|
build-macos:
|
|
runs-on: macos-14 # Apple Silicon (arm64) only
|
|
permissions:
|
|
contents: write
|
|
|
|
steps:
|
|
- name: Checkout
|
|
uses: actions/checkout@v4
|
|
|
|
- name: Install Rust
|
|
uses: dtolnay/rust-toolchain@stable
|
|
with:
|
|
targets: aarch64-apple-darwin
|
|
|
|
- name: Install librsvg (for rsvg-convert)
|
|
env:
|
|
HOMEBREW_NO_AUTO_UPDATE: "1"
|
|
run: brew install librsvg
|
|
|
|
- name: Build
|
|
run: cargo build --release --target aarch64-apple-darwin
|
|
|
|
- name: Build .icns from SVG
|
|
run: |
|
|
mkdir -p OpenCADStudio.iconset
|
|
# Render all the sizes Apple expects in an .icns.
|
|
for SIZE in 16 32 64 128 256 512 1024; do
|
|
rsvg-convert -w $SIZE -h $SIZE assets/logo.svg -o OpenCADStudio.iconset/icon_${SIZE}x${SIZE}.png
|
|
done
|
|
# @2x retina variants (half-size base name)
|
|
for BASE in 16 32 128 256 512; do
|
|
DOUBLE=$((BASE * 2))
|
|
cp OpenCADStudio.iconset/icon_${DOUBLE}x${DOUBLE}.png OpenCADStudio.iconset/icon_${BASE}x${BASE}@2x.png
|
|
done
|
|
iconutil -c icns OpenCADStudio.iconset -o AppIcon.icns
|
|
|
|
- name: Assemble .app bundle
|
|
run: |
|
|
APP=OpenCADStudio.app
|
|
rm -rf "$APP"
|
|
mkdir -p "$APP/Contents/MacOS" "$APP/Contents/Resources"
|
|
cp target/aarch64-apple-darwin/release/OpenCADStudio "$APP/Contents/MacOS/OpenCADStudio"
|
|
chmod +x "$APP/Contents/MacOS/OpenCADStudio"
|
|
cp AppIcon.icns "$APP/Contents/Resources/AppIcon.icns"
|
|
# Substitute version into Info.plist.
|
|
VERSION="${{ github.ref_name }}"
|
|
VERSION="${VERSION#v}"
|
|
[ -z "$VERSION" ] && VERSION="0.0.0"
|
|
sed "s/__VERSION__/$VERSION/g" packaging/Info.plist > "$APP/Contents/Info.plist"
|
|
|
|
- name: Ad-hoc code-sign the bundle
|
|
run: |
|
|
# No paid Apple Developer ID is available, so the app cannot be
|
|
# notarised. An *ad-hoc* signature (identity "-") at least gives the
|
|
# bundle a valid self-signature: this avoids the harshest Gatekeeper
|
|
# verdict ("app is damaged, Move to Trash") on a quarantined download
|
|
# and is mandatory anyway for arm64 binaries to execute. Sign the
|
|
# whole bundle deeply, then verify.
|
|
codesign --force --deep --sign - --timestamp=none OpenCADStudio.app
|
|
codesign --verify --strict --verbose=2 OpenCADStudio.app
|
|
|
|
- name: Create .dmg
|
|
run: |
|
|
# hdiutil intermittently fails with "Resource busy" on the hosted
|
|
# runner (a stale mount or background indexer holding the image).
|
|
# Detach any leftover volume and retry a few times before giving up.
|
|
set +e
|
|
for attempt in 1 2 3 4 5; do
|
|
hdiutil detach "/Volumes/Open CAD Studio" >/dev/null 2>&1 || true
|
|
rm -f OpenCADStudio.dmg
|
|
hdiutil create \
|
|
-volname "Open CAD Studio" \
|
|
-srcfolder OpenCADStudio.app \
|
|
-ov -format UDZO \
|
|
OpenCADStudio.dmg && break
|
|
echo "hdiutil create failed (attempt $attempt) — retrying in 5s"
|
|
sleep 5
|
|
done
|
|
set -e
|
|
test -f OpenCADStudio.dmg
|
|
|
|
- name: Upload .dmg to release
|
|
if: github.event_name == 'release'
|
|
env:
|
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
run: |
|
|
mv OpenCADStudio.dmg OpenCADStudio-${{ github.ref_name }}-macos-arm64.dmg
|
|
gh release upload ${{ github.ref_name }} OpenCADStudio-${{ github.ref_name }}-macos-arm64.dmg --clobber --repo ${{ github.repository }}
|
|
|
|
- name: Emit Homebrew cask sha256
|
|
if: github.event_name == 'release'
|
|
run: |
|
|
# Print the values needed to bump the Homebrew cask
|
|
# (packaging/homebrew/open-cad-studio.rb) for this release, so the
|
|
# tap can be updated with a copy-paste instead of computing the
|
|
# digest by hand.
|
|
VERSION="${{ github.ref_name }}"
|
|
VERSION="${VERSION#v}"
|
|
SHA=$(shasum -a 256 OpenCADStudio-${{ github.ref_name }}-macos-arm64.dmg | awk '{print $1}')
|
|
{
|
|
echo "## Homebrew cask bump"
|
|
echo "Update \`packaging/homebrew/open-cad-studio.rb\`:"
|
|
echo '```ruby'
|
|
echo " version \"$VERSION\""
|
|
echo " sha256 \"$SHA\""
|
|
echo '```'
|
|
} >> "$GITHUB_STEP_SUMMARY"
|