diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0691cba81df5114efad3b0445fe2b855a04a6a13..5edd0918ab417028835a052ff99d6db64bd9b16a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -209,12 +209,25 @@ jobs: - name: Create macOS app bundle run: script/bundle-mac - - name: Upload app bundle to workflow run if main branch or specific label + - name: Upload app bundle (universal) to workflow run if main branch or specific label uses: actions/upload-artifact@v4 if: ${{ github.ref == 'refs/heads/main' }} || contains(github.event.pull_request.labels.*.name, 'run-bundling') }} with: name: Zed_${{ github.event.pull_request.head.sha || github.sha }}.dmg path: target/release/Zed.dmg + - name: Upload app bundle (aarch64) to workflow run if main branch or specific label + uses: actions/upload-artifact@v4 + if: ${{ github.ref == 'refs/heads/main' }} || contains(github.event.pull_request.labels.*.name, 'run-bundling') }} + with: + name: Zed_${{ github.event.pull_request.head.sha || github.sha }}_aarch64.dmg + path: target/aarch64-apple-darwin/release/Zed.dmg + + - name: Upload app bundle (x86_64) to workflow run if main branch or specific label + uses: actions/upload-artifact@v4 + if: ${{ github.ref == 'refs/heads/main' }} || contains(github.event.pull_request.labels.*.name, 'run-bundling') }} + with: + name: Zed_${{ github.event.pull_request.head.sha || github.sha }}_x86_64.dmg + path: target/x86_64-apple-darwin/release/Zed.dmg - uses: softprops/action-gh-release@v1 name: Upload app bundle to release @@ -222,7 +235,9 @@ jobs: with: draft: true prerelease: ${{ env.RELEASE_CHANNEL == 'preview' }} - files: target/release/Zed.dmg + files: | + target/aarch64-apple-darwin/release/Zed.dmg + target/x86_64-apple-darwin/release/Zed.dmg body: "" env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/script/bundle-mac b/script/bundle-mac index a333c67be3431e1a86d5d301a0554e47f0cb3777..d9a8549e82b5b43fe05bfe8048cd0c105474598f 100755 --- a/script/bundle-mac +++ b/script/bundle-mac @@ -104,8 +104,7 @@ local_target_triple=${host_line#*: } if [ "$local_arch" = true ]; then echo "Building for local target only." - cargo build ${build_flag} --package ${zed_crate} - cargo build ${build_flag} --package cli + cargo build ${build_flag} --package ${zed_crate} --package cli else echo "Compiling zed binaries" cargo build ${build_flag} --package ${zed_crate} --package cli --target aarch64-apple-darwin --target x86_64-apple-darwin @@ -126,175 +125,217 @@ sed \ if [ "$local_arch" = true ]; then app_path=$(cargo bundle ${build_flag} --select-workspace-root | xargs) else - app_path=$(cargo bundle ${build_flag} --target x86_64-apple-darwin --select-workspace-root | xargs) + app_path_x64=$(cargo bundle ${build_flag} --target x86_64-apple-darwin --select-workspace-root | xargs) + app_path_aarch64=$(cargo bundle ${build_flag} --target aarch64-apple-darwin --select-workspace-root | xargs) + app_path=$app_path_x64 fi mv Cargo.toml.backup Cargo.toml popd echo "Bundled ${app_path}" -if [ "$local_arch" = false ]; then - echo "Uploading dSYMs" - dsymutil --flat target/aarch64-apple-darwin/${target_dir}/Zed - dsymutil --flat target/x86_64-apple-darwin/${target_dir}/Zed +function prepare_binaries() { + local architecture=$1 + local app_path=$2 + + echo "Uploading dSYMs for $architecture" + dsymutil --flat target/${architecture}/${target_dir}/Zed version="$(cargo metadata --no-deps --manifest-path crates/zed/Cargo.toml --offline --format-version=1 | jq -r '.packages | map(select(.name == "zed"))[0].version')" if [ "$channel" == "nightly" ]; then version="$version-$(git rev-parse --short HEAD)" fi - echo "Removing existing gzipped dSYMs" - rm -f target/aarch64-apple-darwin/${target_dir}/Zed.dwarf.gz - rm -f target/x86_64-apple-darwin/${target_dir}/Zed.dwarf.gz + echo "Removing existing gzipped dSYMs for $architecture" + rm -f target/${architecture}/${target_dir}/Zed.dwarf.gz - echo "Gzipping dSYMs" - gzip target/aarch64-apple-darwin/${target_dir}/Zed.dwarf - gzip target/x86_64-apple-darwin/${target_dir}/Zed.dwarf + echo "Gzipping dSYMs for $architecture" + gzip target/${architecture}/${target_dir}/Zed.dwarf - echo "Uploading dSYMs" - uploadDsym target/aarch64-apple-darwin/${target_dir}/Zed.dwarf.gz "$channel/Zed-$version-aarch64-apple-darwin.dwarf.gz" - uploadDsym target/x86_64-apple-darwin/${target_dir}/Zed.dwarf.gz "$channel/Zed-$version-x86_64-apple-darwin.dwarf.gz" + echo "Uploading dSYMs for $architecture" + uploadDsym target/${architecture}/${target_dir}/Zed.dwarf.gz "$channel/Zed-$version-${architecture}.dwarf.gz" - echo "Creating fat binaries" - lipo \ - -create \ - target/{x86_64-apple-darwin,aarch64-apple-darwin}/${target_dir}/${binary_name} \ - -output \ - "${app_path}/Contents/MacOS/${zed_crate}" - lipo \ - -create \ - target/{x86_64-apple-darwin,aarch64-apple-darwin}/${target_dir}/cli \ - -output \ - "${app_path}/Contents/MacOS/cli" -fi + cp target/${architecture}/${target_dir}/${binary_name} "${app_path}/Contents/MacOS/${zed_crate}" + cp target/${architecture}/${target_dir}/cli "${app_path}/Contents/MacOS/cli" +} -echo "Copying WebRTC.framework into the frameworks folder" -mkdir "${app_path}/Contents/Frameworks" if [ "$local_arch" = false ]; then - cp -R target/${local_target_triple}/${target_dir}/WebRTC.framework "${app_path}/Contents/Frameworks/" -else - cp -R target/${target_dir}/WebRTC.framework "${app_path}/Contents/Frameworks/" - cp -R target/${target_dir}/cli "${app_path}/Contents/MacOS/" -fi - -# Note: The app identifier for our development builds is the same as the app identifier for nightly. -cp crates/${zed_crate}/contents/$channel/embedded.provisionprofile "${app_path}/Contents/" - -if [[ -n "${MACOS_CERTIFICATE:-}" && -n "${MACOS_CERTIFICATE_PASSWORD:-}" && -n "${APPLE_NOTARIZATION_USERNAME:-}" && -n "${APPLE_NOTARIZATION_PASSWORD:-}" ]]; then - echo "Signing bundle with Apple-issued certificate" - security create-keychain -p "$MACOS_CERTIFICATE_PASSWORD" zed.keychain || echo "" - security default-keychain -s zed.keychain - security unlock-keychain -p "$MACOS_CERTIFICATE_PASSWORD" zed.keychain - echo "$MACOS_CERTIFICATE" | base64 --decode > /tmp/zed-certificate.p12 - security import /tmp/zed-certificate.p12 -k zed.keychain -P "$MACOS_CERTIFICATE_PASSWORD" -T /usr/bin/codesign - rm /tmp/zed-certificate.p12 - security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "$MACOS_CERTIFICATE_PASSWORD" zed.keychain - - # sequence of codesign commands modeled after this example: https://developer.apple.com/forums/thread/701514 - /usr/bin/codesign --deep --force --timestamp --sign "Zed Industries, Inc." "${app_path}/Contents/Frameworks/WebRTC.framework" -v - /usr/bin/codesign --deep --force --timestamp --options runtime --sign "Zed Industries, Inc." "${app_path}/Contents/MacOS/cli" -v - /usr/bin/codesign --deep --force --timestamp --options runtime --entitlements crates/${zed_crate}/resources/zed.entitlements --sign "Zed Industries, Inc." "${app_path}/Contents/MacOS/${zed_crate}" -v - /usr/bin/codesign --force --timestamp --options runtime --entitlements crates/${zed_crate}/resources/zed.entitlements --sign "Zed Industries, Inc." "${app_path}" -v - - security default-keychain -s login.keychain -else - echo "One or more of the following variables are missing: MACOS_CERTIFICATE, MACOS_CERTIFICATE_PASSWORD, APPLE_NOTARIZATION_USERNAME, APPLE_NOTARIZATION_PASSWORD" - if [[ "$local_only" = false ]]; then - echo "To create a self-signed local build use ./scripts/build.sh -ldf" - exit 1 - fi - - echo "====== WARNING ======" - echo "This bundle is being signed without all entitlements, some features (e.g. universal links) will not work" - echo "====== WARNING ======" - - # NOTE: if you need to test universal links you have a few paths forward: - # - create a PR and tag it with the `run-bundling` label, and download the .dmg file from there. - # - get a signing key for the MQ55VZLNZQ team from Nathan. - # - create your own signing key, and update references to MQ55VZLNZQ to your own team ID - # then comment out this line. - cat crates/${zed_crate}/resources/zed.entitlements | sed '/com.apple.developer.associated-domains/,+1d' > "${app_path}/Contents/Resources/zed.entitlements" - - codesign --force --deep --entitlements "${app_path}/Contents/Resources/zed.entitlements" --sign ${MACOS_SIGNING_KEY:- -} "${app_path}" -v + prepare_binaries "aarch64-apple-darwin" "$app_path_aarch64" + prepare_binaries "x86_64-apple-darwin" "$app_path_x64" fi -if [[ "$target_dir" = "debug" && "$local_only" = false ]]; then - if [ "$open_result" = true ]; then - open "$app_path" +function sign_binaries() { + local app_path=$1 + local architecture_dir=$2 + echo "Copying WebRTC.framework into the frameworks folder" + mkdir "${app_path}/Contents/Frameworks" + if [ "$local_arch" = false ]; then + cp -R target/${local_target_triple}/${target_dir}/WebRTC.framework "${app_path}/Contents/Frameworks/" else - echo "Created application bundle:" - echo "$app_path" + cp -R target/${architecture_dir}/${target_dir}/WebRTC.framework "${app_path}/Contents/Frameworks/" + cp -R target/${architecture_dir}/${target_dir}/cli "${app_path}/Contents/MacOS/" fi - exit 0 -fi -# If bundle_name is not set or empty, use the basename of $app_path -if [ -z "$bundle_name" ]; then - bundle_name=$(basename "$app_path") -else - # If bundle_name doesn't end in .app, append it - if [[ "$bundle_name" != *.app ]]; then - bundle_name="$bundle_name.app" + # Note: The app identifier for our development builds is the same as the app identifier for nightly. + cp crates/${zed_crate}/contents/$channel/embedded.provisionprofile "${app_path}/Contents/" + + if [[ -n "${MACOS_CERTIFICATE:-}" && -n "${MACOS_CERTIFICATE_PASSWORD:-}" && -n "${APPLE_NOTARIZATION_USERNAME:-}" && -n "${APPLE_NOTARIZATION_PASSWORD:-}" ]]; then + echo "Signing bundle with Apple-issued certificate" + security create-keychain -p "$MACOS_CERTIFICATE_PASSWORD" zed.keychain || echo "" + security default-keychain -s zed.keychain + security unlock-keychain -p "$MACOS_CERTIFICATE_PASSWORD" zed.keychain + echo "$MACOS_CERTIFICATE" | base64 --decode > /tmp/zed-certificate.p12 + security import /tmp/zed-certificate.p12 -k zed.keychain -P "$MACOS_CERTIFICATE_PASSWORD" -T /usr/bin/codesign + rm /tmp/zed-certificate.p12 + security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "$MACOS_CERTIFICATE_PASSWORD" zed.keychain + + # sequence of codesign commands modeled after this example: https://developer.apple.com/forums/thread/701514 + /usr/bin/codesign --deep --force --timestamp --sign "Zed Industries, Inc." "${app_path}/Contents/Frameworks/WebRTC.framework" -v + /usr/bin/codesign --deep --force --timestamp --options runtime --sign "Zed Industries, Inc." "${app_path}/Contents/MacOS/cli" -v + /usr/bin/codesign --deep --force --timestamp --options runtime --entitlements crates/${zed_crate}/resources/zed.entitlements --sign "Zed Industries, Inc." "${app_path}/Contents/MacOS/${zed_crate}" -v + /usr/bin/codesign --force --timestamp --options runtime --entitlements crates/${zed_crate}/resources/zed.entitlements --sign "Zed Industries, Inc." "${app_path}" -v + + security default-keychain -s login.keychain + else + echo "One or more of the following variables are missing: MACOS_CERTIFICATE, MACOS_CERTIFICATE_PASSWORD, APPLE_NOTARIZATION_USERNAME, APPLE_NOTARIZATION_PASSWORD" + if [[ "$local_only" = false ]]; then + echo "To create a self-signed local build use ./scripts/build.sh -ldf" + exit 1 + fi + + echo "====== WARNING ======" + echo "This bundle is being signed without all entitlements, some features (e.g. universal links) will not work" + echo "====== WARNING ======" + + # NOTE: if you need to test universal links you have a few paths forward: + # - create a PR and tag it with the `run-bundling` label, and download the .dmg file from there. + # - get a signing key for the MQ55VZLNZQ team from Nathan. + # - create your own signing key, and update references to MQ55VZLNZQ to your own team ID + # then comment out this line. + cat crates/${zed_crate}/resources/zed.entitlements | sed '/com.apple.developer.associated-domains/,+1d' > "${app_path}/Contents/Resources/zed.entitlements" + + codesign --force --deep --entitlements "${app_path}/Contents/Resources/zed.entitlements" --sign ${MACOS_SIGNING_KEY:- -} "${app_path}" -v fi -fi -if [ "$local_only" = true ]; then - if [ "$overwrite_local_app" = true ]; then - rm -rf "/Applications/$bundle_name" + if [[ "$target_dir" = "debug" && "$local_only" = false ]]; then + if [ "$open_result" = true ]; then + open "$app_path" + else + echo "Created application bundle:" + echo "$app_path" + fi + exit 0 fi - mv "$app_path" "/Applications/$bundle_name" - if [ "$open_result" = true ]; then - open "/Applications/$bundle_name" + # If bundle_name is not set or empty, use the basename of $app_path + if [ -z "$bundle_name" ]; then + bundle_name=$(basename "$app_path") else - echo "Installed application bundle:" - echo "/Applications/$bundle_name" + # If bundle_name doesn't end in .app, append it + if [[ "$bundle_name" != *.app ]]; then + bundle_name="$bundle_name.app" + fi fi -else - dmg_target_directory="target/${target_dir}" - dmg_source_directory="${dmg_target_directory}/dmg" - dmg_file_path="${dmg_target_directory}/Zed.dmg" - xcode_bin_dir_path="$(xcode-select -p)/usr/bin" - rm -rf ${dmg_source_directory} - mkdir -p ${dmg_source_directory} - mv "${app_path}" "${dmg_source_directory}" - - if [[ -n $MACOS_CERTIFICATE && -n $MACOS_CERTIFICATE_PASSWORD && -n $APPLE_NOTARIZATION_USERNAME && -n $APPLE_NOTARIZATION_PASSWORD ]]; then - echo "Creating temporary DMG at ${dmg_file_path} using ${dmg_source_directory} to notarize app bundle" + if [ "$local_only" = true ]; then + if [ "$overwrite_local_app" = true ]; then + rm -rf "/Applications/$bundle_name" + fi + mv "$app_path" "/Applications/$bundle_name" + + if [ "$open_result" = true ]; then + open "/Applications/$bundle_name" + else + echo "Installed application bundle:" + echo "/Applications/$bundle_name" + fi + else + dmg_target_directory="target/${architecture_dir}/${target_dir}" + dmg_source_directory="${dmg_target_directory}/dmg" + dmg_file_path="${dmg_target_directory}/Zed.dmg" + xcode_bin_dir_path="$(xcode-select -p)/usr/bin" + + rm -rf ${dmg_source_directory} + mkdir -p ${dmg_source_directory} + mv "${app_path}" "${dmg_source_directory}" + + if [[ -n $MACOS_CERTIFICATE && -n $MACOS_CERTIFICATE_PASSWORD && -n $APPLE_NOTARIZATION_USERNAME && -n $APPLE_NOTARIZATION_PASSWORD ]]; then + echo "Creating temporary DMG at ${dmg_file_path} using ${dmg_source_directory} to notarize app bundle" + hdiutil create -volname Zed -srcfolder "${dmg_source_directory}" -ov -format UDZO "${dmg_file_path}" + + security create-keychain -p "$MACOS_CERTIFICATE_PASSWORD" zed.keychain || echo "" + security default-keychain -s zed.keychain + security unlock-keychain -p "$MACOS_CERTIFICATE_PASSWORD" zed.keychain + echo "$MACOS_CERTIFICATE" | base64 --decode > /tmp/zed-certificate.p12 + security import /tmp/zed-certificate.p12 -k zed.keychain -P "$MACOS_CERTIFICATE_PASSWORD" -T /usr/bin/codesign + rm /tmp/zed-certificate.p12 + security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "$MACOS_CERTIFICATE_PASSWORD" zed.keychain + + /usr/bin/codesign --deep --force --timestamp --options runtime --sign "Zed Industries, Inc." "$(pwd)/${dmg_file_path}" -v + security default-keychain -s login.keychain + echo "Notarizing DMG with Apple" + "${xcode_bin_dir_path}/notarytool" submit --wait --apple-id "$APPLE_NOTARIZATION_USERNAME" --password "$APPLE_NOTARIZATION_PASSWORD" --team-id "$APPLE_NOTORIZATION_TEAM" "${dmg_file_path}" + + echo "Removing temporary DMG (used only for notarization)" + rm "${dmg_file_path}" + + echo "Stapling notarization ticket to ${dmg_source_directory}/${bundle_name}" + "${xcode_bin_dir_path}/stapler" staple "${dmg_source_directory}/${bundle_name}" + fi + + echo "Adding symlink to /Applications to ${dmg_source_directory}" + ln -s /Applications ${dmg_source_directory} + + echo "Creating final DMG at ${dmg_file_path} using ${dmg_source_directory}" hdiutil create -volname Zed -srcfolder "${dmg_source_directory}" -ov -format UDZO "${dmg_file_path}" - echo "Notarizing DMG with Apple" - "${xcode_bin_dir_path}/notarytool" submit --wait --apple-id "$APPLE_NOTARIZATION_USERNAME" --password "$APPLE_NOTARIZATION_PASSWORD" --team-id "$APPLE_NOTORIZATION_TEAM" "${dmg_file_path}" - - echo "Removing temporary DMG (used only for notarization)" - rm "${dmg_file_path}" - - echo "Stapling notarization ticket to ${dmg_source_directory}/${bundle_name}" - "${xcode_bin_dir_path}/stapler" staple "${dmg_source_directory}/${bundle_name}" + # If someone runs this bundle script locally, a symlink will be placed in `dmg_source_directory`. + # This symlink causes CPU issues with Zed if the Zed codebase is the project being worked on, so we simply remove it for now. + echo "Removing symlink to /Applications from ${dmg_source_directory}" + rm ${dmg_source_directory}/Applications + + echo "Adding license agreement to DMG" + npm install --global dmg-license minimist + dmg-license script/eula/eula.json "${dmg_file_path}" + + if [[ -n $MACOS_CERTIFICATE && -n $MACOS_CERTIFICATE_PASSWORD && -n $APPLE_NOTARIZATION_USERNAME && -n $APPLE_NOTARIZATION_PASSWORD ]]; then + echo "Notarizing DMG with Apple" + security create-keychain -p "$MACOS_CERTIFICATE_PASSWORD" zed.keychain || echo "" + security default-keychain -s zed.keychain + security unlock-keychain -p "$MACOS_CERTIFICATE_PASSWORD" zed.keychain + echo "$MACOS_CERTIFICATE" | base64 --decode > /tmp/zed-certificate.p12 + security import /tmp/zed-certificate.p12 -k zed.keychain -P "$MACOS_CERTIFICATE_PASSWORD" -T /usr/bin/codesign + rm /tmp/zed-certificate.p12 + security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "$MACOS_CERTIFICATE_PASSWORD" zed.keychain + /usr/bin/codesign --deep --force --timestamp --options runtime --sign "Zed Industries, Inc." "$(pwd)/${dmg_file_path}" -v + security default-keychain -s login.keychain + "${xcode_bin_dir_path}/notarytool" submit --wait --apple-id "$APPLE_NOTARIZATION_USERNAME" --password "$APPLE_NOTARIZATION_PASSWORD" --team-id "$APPLE_NOTORIZATION_TEAM" "${dmg_file_path}" + "${xcode_bin_dir_path}/stapler" staple "${dmg_file_path}" + fi + + if [ "$open_result" = true ]; then + open $dmg_target_directory + fi fi +} - echo "Adding symlink to /Applications to ${dmg_source_directory}" - ln -s /Applications ${dmg_source_directory} - - echo "Creating final DMG at ${dmg_file_path} using ${dmg_source_directory}" - hdiutil create -volname Zed -srcfolder "${dmg_source_directory}" -ov -format UDZO "${dmg_file_path}" - - # If someone runs this bundle script locally, a symlink will be placed in `dmg_source_directory`. - # This symlink causes CPU issues with Zed if the Zed codebase is the project being worked on, so we simply remove it for now. - echo "Removing symlink to /Applications from ${dmg_source_directory}" - rm ${dmg_source_directory}/Applications - - echo "Adding license agreement to DMG" - npm install --global dmg-license minimist - dmg-license script/eula/eula.json "${dmg_file_path}" - - if [[ -n $MACOS_CERTIFICATE && -n $MACOS_CERTIFICATE_PASSWORD && -n $APPLE_NOTARIZATION_USERNAME && -n $APPLE_NOTARIZATION_PASSWORD ]]; then - echo "Notarizing DMG with Apple" - "${xcode_bin_dir_path}/notarytool" submit --wait --apple-id "$APPLE_NOTARIZATION_USERNAME" --password "$APPLE_NOTARIZATION_PASSWORD" --team-id "$APPLE_NOTORIZATION_TEAM" "${dmg_file_path}" - "${xcode_bin_dir_path}/stapler" staple "${dmg_file_path}" - fi +if [ "$local_arch" = true ]; then + sign_binaries "$app_path" "$local_target_triple" +else + # Create universal binary + cp -R "$app_path_x64" target/release/ + app_path=target/release/$(basename "$app_path_x64") + lipo \ + -create \ + target/{x86_64-apple-darwin,aarch64-apple-darwin}/${target_dir}/${binary_name} \ + -output \ + "${app_path}/Contents/MacOS/${zed_crate}" + lipo \ + -create \ + target/{x86_64-apple-darwin,aarch64-apple-darwin}/${target_dir}/cli \ + -output \ + "${app_path}/Contents/MacOS/cli" + sign_binaries "$app_path" "." - if [ "$open_result" = true ]; then - open $dmg_target_directory - fi + sign_binaries "$app_path_x64" "x86_64-apple-darwin" + sign_binaries "$app_path_aarch64" "aarch64-apple-darwin" fi diff --git a/script/upload-nightly b/script/upload-nightly index ba36961994a8c788c6820f4d731b4224903232aa..90dc133d168c54811282eb37c99a7766a060aa5c 100755 --- a/script/upload-nightly +++ b/script/upload-nightly @@ -59,6 +59,8 @@ sha=$(git rev-parse HEAD) echo ${sha} > target/latest-sha case "$target" in macos) + uploadToSpaces "target/aarch64-apple-darwin/Zed.dmg" "Zed-aarch64.dmg" + uploadToSpaces "target/x86_64-apple-darwin/release/Zed.dmg" "Zed-x86_64.dmg" uploadToSpaces "target/release/Zed.dmg" "Zed.dmg" uploadToSpaces "target/latest-sha" "latest-sha" ;;