Files
OneCAD-Draft/.github/workflows/release.yml
T
Mojtaba KarimiandClaude Opus 4.8 3163a5ee75 ci(windows): sign exe and installer with Azure Trusted Signing
Sign the bare .exe before the MSI is built (so the packed copy carries
the signature) and the linked .msi afterwards, via
azure/artifact-signing-action with SHA256 digests and Microsoft's
RFC3161 timestamp server. Credentials come from the AZURE_* repository
secrets.

Also fix the MSI version fallback: workflow_dispatch runs use the
branch name as ref_name, which is not a valid numeric ProductVersion,
so candle failed on any non-tag run.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-04 12:54:40 +02:00

273 lines
11 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: 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: 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.
magick assets/logo.svg `
-define icon:auto-resize=16,24,32,48,64,128,256 `
packaging/windows/AppIcon.ico
- 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
$wxsPath = (Resolve-Path packaging\windows\main.wxs).Path
$wixObj = Join-Path $PWD "packaging\windows\main.wixobj"
$msiPath = Join-Path $PWD "OpenCADStudio.msi"
& $candle -arch x64 `
"-dVersion=$version" `
"-dSource=$exePath" `
"-dIcon=$iconPath" `
$wxsPath `
-out $wixObj
if ($LASTEXITCODE -ne 0) { throw "candle failed" }
& $light $wixObj -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 create \
-volname "Open CAD Studio" \
-srcfolder OpenCADStudio.app \
-ov -format UDZO \
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"