diff --git a/codemagic.yaml b/codemagic.yaml index f61e60522f4..0c58db6518c 100644 --- a/codemagic.yaml +++ b/codemagic.yaml @@ -1471,35 +1471,23 @@ workflows: xcrun stapler staple "$APP_PATH" - - name: Install create-dmg - script: | - brew install create-dmg - - name: Create DMG installer script: | set -e + pip3 install --break-system-packages dmgbuild APP_PATH=$(find $(pwd)/build/macos -name "Omi.app" -type d | head -1) mkdir -p build/macos/dmg - DMG_NAME="Omi.dmg" - DMG_PATH="build/macos/dmg/${DMG_NAME}" - - # Create professional DMG with Applications folder shortcut - # Use --skip-jenkins to avoid AppleScript timeout issues in CI - create-dmg \ - --volname "Omi ${VERSION}" \ - --volicon "$APP_PATH/Contents/Resources/prodAppIcon.icns" \ - --window-pos 200 120 \ - --window-size 660 400 \ - --icon-size 130 \ - --text-size 16 \ - --icon "Omi.app" 180 180 \ - --hide-extension "Omi.app" \ - --app-drop-link 480 180 \ - --no-internet-enable \ - --skip-jenkins \ - "$DMG_PATH" \ - "$APP_PATH" + DMG_PATH="build/macos/dmg/Omi.dmg" + + # Use dmgbuild instead of create-dmg — writes .DS_Store directly + # without Finder/AppleScript (which hangs in CI with --skip-jenkins) + dmgbuild -s ../desktop/dmg-assets/dmgbuild_settings.py \ + -D app_path="$APP_PATH" \ + -D app_name=Omi \ + -D assets_dir="$(pwd)/../desktop/dmg-assets" \ + "Omi ${VERSION}" \ + "$DMG_PATH" # Sign DMG codesign --force --sign "$DEVELOPER_ID_CERT" "$DMG_PATH" @@ -2295,13 +2283,11 @@ workflows: xcrun stapler staple "$APP_BUNDLE" echo "App stapled" - - name: Install create-dmg - script: | - brew install create-dmg || true - - name: Create DMG installer script: | set -e + pip3 install --break-system-packages dmgbuild + STAGING_DIR="/tmp/omi-dmg-staging-$$" mkdir -p "$STAGING_DIR" # Use ditto to preserve the notarization staple ticket (cp -R drops it) @@ -2310,23 +2296,14 @@ workflows: xcrun stapler validate "$STAGING_DIR/$APP_NAME.app" 2>/dev/null || \ xcrun stapler staple "$STAGING_DIR/$APP_NAME.app" - BG_ARGS="" - [ -f "dmg-assets/background.png" ] && BG_ARGS="--background dmg-assets/background.png" - - create-dmg \ - --volname "$APP_NAME" \ - --volicon "$STAGING_DIR/$APP_NAME.app/Contents/Resources/OmiIcon.icns" \ - --window-pos 200 120 \ - --window-size 610 365 \ - --icon-size 80 \ - --icon "$APP_NAME.app" 155 175 \ - --hide-extension "$APP_NAME.app" \ - --app-drop-link 455 175 \ - --no-internet-enable \ - --skip-jenkins \ - $BG_ARGS \ - "$DMG_PATH" \ - "$STAGING_DIR/$APP_NAME.app" + # Use dmgbuild instead of create-dmg — writes .DS_Store directly + # without Finder/AppleScript (which hangs in CI with --skip-jenkins) + dmgbuild -s dmg-assets/dmgbuild_settings.py \ + -D app_path="$STAGING_DIR/$APP_NAME.app" \ + -D app_name="$APP_NAME" \ + -D assets_dir="$(pwd)/dmg-assets" \ + "$APP_NAME" \ + "$DMG_PATH" rm -rf "$STAGING_DIR" echo "DMG created" diff --git a/desktop/dmg-assets/background.png b/desktop/dmg-assets/background.png index 9022ad0a7a5..97d81832dda 100644 Binary files a/desktop/dmg-assets/background.png and b/desktop/dmg-assets/background.png differ diff --git a/desktop/dmg-assets/dmgbuild_settings.py b/desktop/dmg-assets/dmgbuild_settings.py new file mode 100644 index 00000000000..f120f4f6b09 --- /dev/null +++ b/desktop/dmg-assets/dmgbuild_settings.py @@ -0,0 +1,51 @@ +# dmgbuild settings for OMI Desktop installer +# Usage: dmgbuild -s dmgbuild_settings.py -D app_path=/path/to/Omi.app -D app_name=omi "Omi" output.dmg +# +# This replaces create-dmg + AppleScript (which fails in CI due to --skip-jenkins). +# dmgbuild writes .DS_Store directly — no Finder/AppleScript needed. + +import os + +app_path = defines.get("app_path", "Omi.app") +app_name = defines.get("app_name", "omi") +# __file__ is not set when executed by dmgbuild; use defines or fall back to cwd +_script_dir = defines.get("assets_dir", os.path.join(os.getcwd(), "dmg-assets")) +bg_path = defines.get("background", os.path.join(_script_dir, "background.png")) +icon_path = defines.get("volume_icon", None) + +# Volume settings +format = "UDBZ" # bzip2 compressed +size = None # auto-calculate +filesystem = "HFS+" + +# Files to include +files = [app_path] +symlinks = {"Applications": "/Applications"} + +# Window settings +background = bg_path +show_status_bar = False +show_tab_view = False +show_toolbar = False +show_pathbar = False +show_sidebar = False +sidebar_width = 0 + +window_rect = ((200, 120), (610, 365)) +default_view = "icon-view" + +icon_size = 80 +text_size = 12 + +# Icon positions — must match background.png arrow (left=app, right=Applications) +icon_locations = { + app_name + ".app": (155, 175), + "Applications": (455, 175), +} + +# Hide extension for the app +hide_extensions = [app_name + ".app"] + +# Volume icon +if icon_path: + badge_icon = icon_path