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

Support deploying arm64 builds #11683

Merged
merged 11 commits into from
Apr 8, 2021
1 change: 1 addition & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ jobs:
- name: Publish production app
run: yarn run publish
env:
npm_config_arch: ${{ matrix.arch }}
Copy link
Member Author

Choose a reason for hiding this comment

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

This is what's used to tell our scripts about the target architecture.

DESKTOPBOT_TOKEN: ${{ secrets.DESKTOPBOT_TOKEN }}
WINDOWS_CERT_PASSWORD: ${{ secrets.WINDOWS_CERT_PASSWORD }}
KEY_PASSWORD: ${{ secrets.KEY_PASSWORD }}
Expand Down
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ uses [React](https://reactjs.org/).
Download the official installer for your operating system:

- [macOS](https://central.github.com/deployments/desktop/desktop/latest/darwin)
- [macOS (Apple Silicon)](https://central.github.com/deployments/desktop/desktop/latest/darwin-arm64)
- [Windows](https://central.github.com/deployments/desktop/desktop/latest/win32)
- [Windows machine-wide install](https://central.github.com/deployments/desktop/desktop/latest/win32?format=msi)

Expand All @@ -27,6 +28,7 @@ Want to test out new features and get fixes before everyone else? Install the
beta channel to get access to early builds of Desktop:

- [macOS](https://central.github.com/deployments/desktop/desktop/latest/darwin?env=beta)
- [macOS (Apple Silicon)](https://central.github.com/deployments/desktop/desktop/latest/darwin-arm64?env=beta)
- [Windows](https://central.github.com/deployments/desktop/desktop/latest/win32?env=beta)

The release notes for the latest beta versions are available [here](https://desktop.github.com/release-notes/?env=beta).
Expand Down
5 changes: 5 additions & 0 deletions app/src/lib/feature-flag.ts
Original file line number Diff line number Diff line change
Expand Up @@ -165,3 +165,8 @@ export function enableCherryPicking(): boolean {
export function enableTextDiffExpansion(): boolean {
return enableDevelopmentFeatures()
}

/** Should we allow apps running from Rosetta to auto-update to ARM64 builds? */
export function enableUpdateFromRosettaToARM64(): boolean {
return false
}
17 changes: 16 additions & 1 deletion app/src/ui/lib/update-store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { parseError } from '../../lib/squirrel-error-parser'
import { ReleaseSummary } from '../../models/release-notes'
import { generateReleaseSummary } from '../../lib/release-notes'
import { setNumber, getNumber } from '../../lib/local-storage'
import { enableUpdateFromRosettaToARM64 } from '../../lib/feature-flag'

/** The states the auto updater can be in. */
export enum UpdateStatus {
Expand Down Expand Up @@ -160,10 +161,24 @@ class UpdateStore {
return
}

let updatesURL = __UPDATES_URL__

// If the app is running under Rosetta (i.e. it's a macOS x64 binary running
// on an arm64 machine), we need to tweak the update URL here to point at
// the arm64 binary.
if (
enableUpdateFromRosettaToARM64() &&
remote.app.runningUnderRosettaTranslation === true
) {
const url = new URL(updatesURL)
url.searchParams.set('architecture', 'arm64')
updatesURL = url.toString()
}
Comment on lines +169 to +176
Copy link
Member Author

Choose a reason for hiding this comment

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

This is needed because __UPDATES_URL__ is set at compile time, so we can't set it to look for arm64 for users who downloaded the x64 build to then run it on an Apple Silicon machine.


this.userInitiatedUpdate = !inBackground

try {
autoUpdater.setFeedURL({ url: __UPDATES_URL__ })
autoUpdater.setFeedURL({ url: updatesURL })
autoUpdater.checkForUpdates()
} catch (e) {
this.emitError(e)
Expand Down
55 changes: 37 additions & 18 deletions script/dist-info.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import * as Path from 'path'
import * as Fs from 'fs'
import * as os from 'os'

import { getProductName, getVersion } from '../app/package-info'
import { getReleaseBranchName } from './build-platforms'
Expand All @@ -17,17 +16,9 @@ export function getDistRoot() {
}

export function getDistPath() {
let arch = os.arch()

if (process.env.npm_config_arch) {
// If a specific npm_config_arch is set, we use that one instead of the OS arch (to support cross compilation)
console.log('npm_config_arch detected: ' + process.env.npm_config_arch)
arch = process.env.npm_config_arch
}

return Path.join(
getDistRoot(),
`${getExecutableName()}-${process.platform}-${arch}`
`${getExecutableName()}-${process.platform}-${getArchitecture()}`
)
}

Expand All @@ -44,7 +35,7 @@ export function getExecutableName() {
}

export function getOSXZipName() {
return `${productName}.zip`
return `${productName}-${getArchitecture()}.zip`
}

export function getOSXZipPath() {
Expand All @@ -53,7 +44,7 @@ export function getOSXZipPath() {

export function getWindowsInstallerName() {
const productName = getExecutableName()
return `${productName}Setup.msi`
return `${productName}Setup-${getArchitecture()}.msi`
}

export function getWindowsInstallerPath() {
Expand All @@ -62,15 +53,18 @@ export function getWindowsInstallerPath() {

export function getWindowsStandaloneName() {
const productName = getExecutableName()
return `${productName}Setup.exe`
return `${productName}Setup-${getArchitecture()}.exe`
}

export function getWindowsStandalonePath() {
return Path.join(getDistPath(), '..', 'installer', getWindowsStandaloneName())
}

export function getWindowsFullNugetPackageName() {
return `${getWindowsIdentifierName()}-${version}-full.nupkg`
export function getWindowsFullNugetPackageName(
includeArchitecture: boolean = false
) {
const architectureInfix = includeArchitecture ? `-${getArchitecture()}` : ''
return `${getWindowsIdentifierName()}-${version}${architectureInfix}-full.nupkg`
}

export function getWindowsFullNugetPackagePath() {
Expand All @@ -82,8 +76,11 @@ export function getWindowsFullNugetPackagePath() {
)
}

export function getWindowsDeltaNugetPackageName() {
return `${getWindowsIdentifierName()}-${version}-delta.nupkg`
export function getWindowsDeltaNugetPackageName(
includeArchitecture: boolean = false
) {
const architectureInfix = includeArchitecture ? `-${getArchitecture()}` : ''
return `${getWindowsIdentifierName()}-${version}${architectureInfix}-delta.nupkg`
}

export function getWindowsDeltaNugetPackagePath() {
Expand Down Expand Up @@ -142,8 +139,30 @@ export function getReleaseSHA() {
return pieces[2]
}

export function getArchitecture(): 'arm64' | 'x64' {
// If a specific npm_config_arch is set, we use that one instead of the OS arch (to support cross compilation)
if (
process.env.npm_config_arch === 'arm64' ||
process.env.npm_config_arch === 'x64'
) {
return process.env.npm_config_arch
}

if (process.arch === 'arm64') {
return 'arm64'
}

// TODO: Check if it's x64 running on an arm64 Windows with IsWow64Process2
// More info: https://www.rudyhuyn.com/blog/2017/12/13/how-to-detect-that-your-x86-application-runs-on-windows-on-arm/
// Right now (March 3, 2021) is not very important because support for x64
// apps on an arm64 Windows is experimental. See:
// https://blogs.windows.com/windows-insider/2020/12/10/introducing-x64-emulation-in-preview-for-windows-10-on-arm-pcs-to-the-windows-insider-program/

return 'x64'
}

export function getUpdatesURL() {
return `https://central.github.com/api/deployments/desktop/desktop/latest?version=${version}&env=${getChannel()}`
return `https://central.github.com/api/deployments/desktop/desktop/latest?version=${version}&env=${getChannel()}&architecture=${getArchitecture()}`
}

export function shouldMakeDelta() {
Expand Down
19 changes: 15 additions & 4 deletions script/publish.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@ function uploadOSXAssets() {
}

function uploadWindowsAssets() {
// For the nuget packages, include the architecture infix in the asset name
// when they're uploaded.
const uploads = [
upload(
distInfo.getWindowsInstallerName(),
Expand All @@ -84,15 +86,15 @@ function uploadWindowsAssets() {
distInfo.getWindowsStandalonePath()
),
upload(
distInfo.getWindowsFullNugetPackageName(),
distInfo.getWindowsFullNugetPackageName(true),
distInfo.getWindowsFullNugetPackagePath()
),
]

if (distInfo.shouldMakeDelta()) {
uploads.push(
upload(
distInfo.getWindowsDeltaNugetPackageName(),
distInfo.getWindowsDeltaNugetPackageName(true),
distInfo.getWindowsDeltaNugetPackagePath()
)
)
Expand Down Expand Up @@ -160,10 +162,19 @@ function createSignature(body: any, secret: string) {
return `sha1=${hmac.digest('hex')}`
}

function updateDeploy(artifacts: ReadonlyArray<IUploadResult>, secret: string) {
function getContext() {
return (
process.platform + (distInfo.getArchitecture() === 'arm64' ? '-arm64' : '')
)
}

function updateDeploy(
artifacts: ReadonlyArray<IUploadResult>,
secret: string
): Promise<void> {
const { rendererSize, mainSize } = distInfo.getBundleSizes()
const body = {
context: process.platform,
context: getContext(),
branch_name: platforms.getReleaseBranchName(),
artifacts,
stats: {
Expand Down