Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create DMGs for x64 and arm64 builds #135

Merged
merged 16 commits into from
Jul 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .buildkite/commands/prepare-environment.sh
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,4 @@ echo "--- :closed_lock_with_key: Installing Secrets"
bundle exec fastlane run configure_apply

echo "--- :testflight: Fetching Signing Certificates"
bundle exec fastlane set_up_signing
bundle exec fastlane set_up_signing
47 changes: 45 additions & 2 deletions .buildkite/pipeline.yml
Original file line number Diff line number Diff line change
Expand Up @@ -71,17 +71,39 @@ steps:
command: |
.buildkite/commands/prepare-environment.sh

echo "--- :node: Building Binary"
.buildkite/commands/install-node-dependencies.sh

node ./scripts/prepare-dev-build-version.mjs

echo "--- :node: Building Binary"
npm run make:macos-{{matrix}}

# Local trial and error show this needs to run before the DMG generation (obviously) but after the binary has been built
echo "--- :hammer: Rebuild fs-attr if necessary before generating DMG"
case {{matrix}} in
universal | x64)
echo "Rebuilding fs-xattr for {{matrix}} architecture"
npm rebuild fs-xattr --cpu universal
;;
arm64)
echo "No need to rebuild fs-xattr because it works out of the box on Apple Silicon"
;;
*)
echo "^^^ +++ Unexpected architecture {{matrix}}"
exit 1
;;
esac

echo "--- :node: Packaging in DMG"
npm run make:dmg-{{matrix}}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should it happen after we notarize the binary?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here's what the docs say:

Alternatively, you can put apps, kernel extensions, and other software in a container, like a disk image, and notarize the container. The notary service accepts disk images (UDIF format), signed flat installer packages, and ZIP archives. It processes nested containers as well, like packages inside a disk image.

Important: If you distribute your software via a custom third-party installer, you need two rounds of notarization. First you notarize the installer’s payload (everything the installer will install). You then package the notarized (and stapled, as described in Staple the ticket to your distribution) items into the installer and notarize it as you would any other executable. If you use a network installer, separately notarize both the installer and the items it downloads.

So, I think in our case, given we distribute both .app and .dmg, we'll want to notarize both. If we were only distributing the DMG, we could notarize just that and trust Apple's tooling will handle it.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried a local notarization of a DMG built from this branch, as of d538a17, and this diff worked:

--- a/fastlane/Fastfile
+++ b/fastlane/Fastfile
@@ -45,13 +45,20 @@ lane :set_up_signing do |_options|
 end

 desc 'Notarize the compiled binary'
-lane :notarize_binary do |_options|
+lane :notarize_binary do
   Dir[File.join(BUILDS_FOLDER, '**', 'Studio.app')].each do |path|
     notarize(
       package: path,
       api_key_path: APPLE_API_KEY_PATH
     )
   end
+  Dir[File.join(BUILDS_FOLDER, '**', 'Studio-*.dmg')].each do |path|
+    notarize(
+      bundle_id: APPLE_BUNDLE_IDENTIFIER,
+      package: path,
+      api_key_path: APPLE_API_KEY_PATH
+    )
+  end
 end

 desc 'Ship the binary to internal testers'


echo "--- 📃 Notarizing Binary"
bundle exec fastlane notarize_binary

plugins: *common_plugins
artifact_paths:
- 'out/**/*.app.zip'
- 'out/*.dmg'
matrix:
- "universal"
- "x64"
Expand Down Expand Up @@ -139,17 +161,38 @@ steps:
command: |
.buildkite/commands/prepare-environment.sh

echo "--- :node: Building Binary"
.buildkite/commands/install-node-dependencies.sh
node ./scripts/confirm-tag-matches-version.mjs

echo "--- :node: Building Binary"
npm run make:macos-{{matrix}}

# Local trial and error show this needs to run before the DMG generation (obviously) but after the binary has been built
echo "--- :hammer: Rebuild fs-attr if necessary before generating DMG"
case {{matrix}} in
universal | x64)
echo "Rebuilding fs-xattr for {{matrix}} architecture"
npm rebuild fs-xattr --cpu universal
;;
arm64)
echo "No need to rebuild fs-xattr because it works out of the box on Apple Silicon"
;;
*)
echo "^^^ +++ Unexpected architecture {{matrix}}"
exit 1
;;
esac

echo "--- :node: Packaging in DMG"
npm run make:dmg-{{matrix}}

echo "--- 📃 Notarizing Binary"
bundle exec fastlane notarize_binary

plugins: *common_plugins
artifact_paths:
- 'out/**/*.app.zip'
- 'out/*.dmg'
matrix:
- "universal"
- "x64"
Expand Down
27 changes: 26 additions & 1 deletion fastlane/Fastfile
Original file line number Diff line number Diff line change
Expand Up @@ -45,13 +45,20 @@ lane :set_up_signing do |_options|
end

desc 'Notarize the compiled binary'
lane :notarize_binary do |_options|
lane :notarize_binary do
Dir[File.join(BUILDS_FOLDER, '**', 'Studio.app')].each do |path|
notarize(
package: path,
api_key_path: APPLE_API_KEY_PATH
)
end
Dir[File.join(BUILDS_FOLDER, '**', 'Studio-*.dmg')].each do |path|
notarize(
bundle_id: APPLE_BUNDLE_IDENTIFIER,
package: path,
api_key_path: APPLE_API_KEY_PATH
)
end
end

desc 'Ship the binary to internal testers'
Expand Down Expand Up @@ -96,18 +103,36 @@ def distribute_builds(
extension: 'app.zip',
name: 'Mac Universal'
},
mac_universal_dmg: {
binary_path: File.join(BUILDS_FOLDER, 'Studio-darwin-universal', 'Studio.dmg'),
filename_core: 'darwin-universal',
extension: 'dmg',
name: 'Mac Universal (DMG)'
},
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Glad the DRY from #117 turned out to be useful. I wasn't expecting us to add new files to upload, but there you go. Happy it was here.

x64: {
binary_path: File.join(BUILDS_FOLDER, 'Studio-darwin-x64', 'Studio.app.zip'),
filename_core: 'darwin-x64',
extension: 'app.zip',
name: 'Mac Intel'
},
x64_dmg: {
binary_path: File.join(BUILDS_FOLDER, 'Studio-darwin-x64', 'Studio.dmg'),
filename_core: 'darwin-x64',
extension: 'dmg',
name: 'Mac Intel (DMG)'
},
arm64: {
binary_path: File.join(BUILDS_FOLDER, 'Studio-darwin-arm64', 'Studio.app.zip'),
filename_core: 'darwin-arm64',
extension: 'app.zip',
name: 'Mac Apple Silicon'
},
arm64_dmg: {
binary_path: File.join(BUILDS_FOLDER, 'Studio-darwin-arm64', 'Studio.dmg'),
filename_core: 'darwin-arm64',
extension: 'dmg',
name: 'Mac Apple Silicon (DMG)'
},
windows: {
binary_path: File.join(BUILDS_FOLDER, 'make', 'squirrel.windows', 'x64', 'studio-setup.exe'),
filename_core: 'win32',
Expand Down
3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@
"make:macos-universal": "SKIP_DMG=true electron-forge make --arch=universal",
"make:macos-x64": "SKIP_DMG=true FILE_ARCHITECTURE=x64 electron-forge make --arch=x64 --platform=darwin",
"make:macos-arm64": "SKIP_DMG=true FILE_ARCHITECTURE=arm64 electron-forge make --arch=arm64 --platform=darwin",
"make:dmg-universal": "FILE_ARCHITECTURE=universal node ./scripts/make-dmg.mjs",
"make:dmg-x64": "FILE_ARCHITECTURE=x64 node ./scripts/make-dmg.mjs",
"make:dmg-arm64": "FILE_ARCHITECTURE=arm64 node ./scripts/make-dmg.mjs",
"publish": "electron-forge publish",
"lint": "eslint --ext .ts,.tsx,.js,.jsx,.mjs .",
"format": "prettier . --write",
Expand Down
46 changes: 46 additions & 0 deletions scripts/make-dmg.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import child_process from 'child_process';
import * as fs from 'fs';
import * as path from 'path';
import { fileURLToPath } from 'url';
import packageJson from '../package.json' assert { type: 'json' };

const __dirname = path.dirname( fileURLToPath( import.meta.url ) );

const appPath = path.resolve(
__dirname,
'../out',
`${ packageJson.productName }-darwin-${ process.env.FILE_ARCHITECTURE }`,
`${ packageJson.productName }.app`
);

const dmgPath = path.resolve(
__dirname,
'../out',
`${ packageJson.productName }-darwin-${ process.env.FILE_ARCHITECTURE }.dmg`
);

const volumeIconPath = path.resolve( __dirname, '../assets/studio-app-icon.icns' );
const backgroundPath = path.resolve( __dirname, '../assets/dmg-background.png' );

const dmgSpecs = {
title: packageJson.productName,
icon: volumeIconPath,
'icon-size': 80,
background: backgroundPath,
window: { size: { width: 710, height: 502 } },
contents: [
{ type: 'file', path: appPath, x: 533, y: 122 },
{ type: 'link', path: '/Applications', x: 533, y: 354 },
],
};

if ( fs.existsSync( dmgPath ) ) {
fs.unlinkSync( dmgPath );
}

const specsFile = path.resolve( __dirname, '..', 'appdmg-specs.json' );
fs.writeFileSync( specsFile, JSON.stringify( dmgSpecs ) );
child_process.execSync(
[ path.join( __dirname, '..', 'node_modules', '.bin', `appdmg` ), specsFile, dmgPath ].join( ' ' )
);
fs.unlinkSync( specsFile );
Loading