feat: build Cypress for linux-arm64 (#22252)

This commit is contained in:
Zach Bloomquist
2022-06-15 12:22:10 -04:00
committed by GitHub
parent e18b0d567e
commit 61f19c0450
14 changed files with 195 additions and 68 deletions
+3
View File
@@ -23,6 +23,9 @@ exports['test runner manifest'] = {
"linux-x64": {
"url": "https://cdn.cypress.io/desktop/3.3.0/linux-x64/cypress.zip"
},
"linux-arm64": {
"url": "https://cdn.cypress.io/desktop/3.3.0/linux-arm64/cypress.zip"
},
"win32-x64": {
"url": "https://cdn.cypress.io/desktop/3.3.0/win32-x64/cypress.zip"
}
+4
View File
@@ -13,6 +13,10 @@ exports['upload util isValidPlatformArch checks given strings second 1'] = {
"given": "linux-x64",
"expect": true
},
{
"given": "linux-arm64",
"expect": true
},
{
"given": "win32-x64",
"expect": true
+66 -11
View File
@@ -22,14 +22,13 @@ defaults: &defaults
COLUMNS: 100
LINES: 24
# filters and requires for testing binary with Firefox
mainBuildFilters: &mainBuildFilters
filters:
branches:
only:
- develop
- 10.0-release
- use-m1-runners
- linux-arm64
# usually we don't build Mac app - it takes a long time
# but sometimes we want to really confirm we are doing the right thing
@@ -38,14 +37,23 @@ macWorkflowFilters: &darwin-workflow-filters
when:
or:
- equal: [ develop, << pipeline.git.branch >> ]
- equal: [ use-m1-runners, << pipeline.git.branch >> ]
- equal: [ linux-arm64, << pipeline.git.branch >> ]
- matches:
pattern: "-release$"
value: << pipeline.git.branch >>
linuxArm64WorkflowFilters: &linux-arm64-workflow-filters
when:
or:
- equal: [ develop, << pipeline.git.branch >> ]
- equal: [ linux-arm64, << pipeline.git.branch >> ]
- matches:
pattern: "-release$"
value: << pipeline.git.branch >>
# uncomment & add to the branch conditions below to disable the main linux
# flow if we don't want to test it for a certain branch
linuxWorkflowExcludeFilters: &linux-workflow-exclude-filters
linuxWorkflowExcludeFilters: &linux-x64-workflow-exclude-filters
unless:
or:
- false
@@ -58,7 +66,7 @@ fullWindowsWorkflowFilters: &full-windows-workflow-filters
branches:
only:
- develop
- 'use-m1-runners'
- 'linux-arm64'
- '*-release'
- 'win*'
@@ -108,13 +116,20 @@ executors:
environment:
PLATFORM: darwin
linux-arm64:
machine:
image: ubuntu-2004:2022.04.1
resource_class: arm.medium
environment:
PLATFORM: linux
commands:
verify_should_persist_artifacts:
steps:
- run:
name: Check current branch to persist artifacts
command: |
if [[ "$CIRCLE_BRANCH" != "develop" && "$CIRCLE_BRANCH" != "use-m1-runners" ]]; then
if [[ "$CIRCLE_BRANCH" != "develop" && "$CIRCLE_BRANCH" != "linux-arm64" ]]; then
echo "Not uploading artifacts or posting install comment for this branch."
circleci-agent step halt
fi
@@ -955,12 +970,24 @@ commands:
# notarization on Mac can take a while
no_output_timeout: "45m"
command: |
if [[ `node ./scripts/get-platform-key.js` == 'linux-arm64' ]]; then
# these are missing on Circle and there is no way to pre-install them on Arm
sudo apt-get update
sudo apt-get install -y libgtk2.0-0 libgtk-3-0 libgbm-dev libnotify-dev libgconf-2-4 libnss3 libxss1 libasound2 libxtst6 xauth xvfb
fi
node --version
yarn binary-build --version $(node ./scripts/get-next-version.js)
- run:
name: Zip the binary
command: |
[[ $PLATFORM == 'linux' ]] && apt-get update && apt-get install -y zip || [[ $PLATFORM != 'linux' ]]
if [[ $PLATFORM == 'linux' ]]; then
# on Arm, CI runs as non-root, on x64 CI runs as root but there is no sudo binary
if [[ `whoami` == 'root' ]]; then
apt-get update && apt-get install -y zip
else
sudo apt-get update && sudo apt-get install -y zip
fi
fi
yarn binary-zip
- store-npm-logs
- persist_to_workspace:
@@ -2236,7 +2263,7 @@ jobs:
command: DEBUG=cypress:cli $(yarn bin cypress) run
- store-npm-logs
linux-workflow: &linux-workflow
linux-x64-workflow: &linux-x64-workflow
jobs:
- node_modules_install
- build:
@@ -2545,6 +2572,31 @@ linux-workflow: &linux-workflow
- create-build-artifacts
- system-tests-node-modules-install
linux-arm64-workflow: &linux-arm64-workflow
jobs:
- node_modules_install:
name: linux-arm64-node-modules-install
executor: linux-arm64
resource_class: arm.medium
only-cache-for-root-user: true
- build:
name: linux-arm64-build
executor: linux-arm64
resource_class: arm.medium
requires:
- linux-arm64-node-modules-install
- create-build-artifacts:
name: linux-arm64-create-build-artifacts
context:
- test-runner:upload
- test-runner:commit-status-checks
executor: linux-arm64
resource_class: arm.medium
requires:
- linux-arm64-build
darwin-x64-workflow: &darwin-x64-workflow
jobs:
- node_modules_install:
@@ -2675,9 +2727,12 @@ windows-workflow: &windows-workflow
- windows-create-build-artifacts
workflows:
linux:
<<: *linux-workflow
<<: *linux-workflow-exclude-filters
linux-x64:
<<: *linux-x64-workflow
<<: *linux-x64-workflow-exclude-filters
linux-arm64:
<<: *linux-arm64-workflow
<<: *linux-arm64-workflow-filters
darwin-x64:
<<: *darwin-x64-workflow
<<: *darwin-workflow-filters
+20
View File
@@ -0,0 +1,20 @@
{
"extends": "../.eslintrc.js",
"rules": {
"no-restricted-syntax": [
"error",
{
"selector": "CallExpression[callee.name='arch']",
"message": "Do not use `arch()` to detect the user's machine architecture. Use util.getRealArch() instead."
},
{
"selector": "CallExpression[callee.object.name='os'][callee.property.name='arch']",
"message": "Do not use `os.arch()` to detect the user's machine architecture. Use util.getRealArch() instead."
},
{
"selector": "MemberExpression[object.name='process'][property.name='arch']",
"message": "Do not use `process.arch` to detect the user's machine architecture. Use util.getRealArch() instead."
}
]
}
}
+1 -1
View File
@@ -134,7 +134,7 @@ const downloadAndUnzip = ({ version, installDir, downloadDir }) => {
const validateOS = () => {
return util.getPlatformInfo().then((platformInfo) => {
return platformInfo.match(/(win32-x64|linux-x64|darwin-x64|darwin-arm64)/)
return platformInfo.match(/(win32-x64|linux-x64|linux-arm64|darwin-x64|darwin-arm64)/)
})
}
+13 -3
View File
@@ -481,22 +481,32 @@ const util = {
async function _getRealArch () {
const osPlatform = os.platform()
// eslint-disable-next-line no-restricted-syntax
const osArch = os.arch()
debug('detecting arch %o', { osPlatform, osArch })
if (osPlatform === 'darwin') {
if (osArch === 'arm64') return 'arm64'
if (osArch === 'arm64') return 'arm64'
if (osPlatform === 'darwin') {
// could possibly be x64 node on arm64 darwin, check if we are being translated by Rosetta
// https://stackoverflow.com/a/65347893/3474615
const { stdout } = await execa('sysctl', ['-n', 'sysctl.proc_translated']).catch(() => '')
debug('rosetta check result: %o', { stdout })
if (stdout === '1') return 'arm64'
}
if (osPlatform === 'linux') {
// could possibly be x64 node on arm64 linux, check the "machine hardware name"
// list of names for reference: https://stackoverflow.com/a/45125525/3474615
const { stdout } = await execa('uname', ['-m']).catch(() => '')
debug('arm uname -m result: %o ', { stdout })
if (['aarch64_be', 'aarch64', 'armv8b', 'armv8l'].includes(stdout)) return 'arm64'
}
// eslint-disable-next-line no-restricted-syntax
const pkgArch = arch()
if (pkgArch === 'x86') return 'ia32'
+74 -27
View File
@@ -478,44 +478,91 @@ describe('lib/tasks/download', function () {
sinon.stub(os, 'arch')
})
function nockDarwinArm64 () {
return nock('https://download.cypress.io')
.get('/desktop/1.2.3')
.query({ arch: 'arm64', platform: 'darwin' })
.reply(200, undefined, {
'x-version': '1.2.3',
context('Apple Silicon/M1', () => {
function nockDarwinArm64 () {
return nock('https://download.cypress.io')
.get('/desktop/1.2.3')
.query({ arch: 'arm64', platform: 'darwin' })
.reply(200, undefined, {
'x-version': '1.2.3',
})
}
it('downloads darwin-arm64 on M1', async function () {
os.platform.returns('darwin')
os.arch.returns('arm64')
nockDarwinArm64()
const responseVersion = await download.start(this.options)
expect(responseVersion).to.eq('1.2.3')
await fs.statAsync(downloadDestination)
})
}
it('downloads darwin-arm64 on M1', async function () {
os.platform.returns('darwin')
os.arch.returns('arm64')
nockDarwinArm64()
it('downloads darwin-arm64 on M1 translated by Rosetta', async function () {
os.platform.returns('darwin')
os.arch.returns('x64')
nockDarwinArm64()
const responseVersion = await download.start(this.options)
sinon.stub(cp, 'spawn').withArgs('sysctl', ['-n', 'sysctl.proc_translated'])
.callsFake(mockSpawn(((cp) => {
cp.stdout.write('1')
cp.emit('exit', 0, null)
cp.end()
})))
expect(responseVersion).to.eq('1.2.3')
const responseVersion = await download.start(this.options)
await fs.statAsync(downloadDestination)
expect(responseVersion).to.eq('1.2.3')
await fs.statAsync(downloadDestination)
})
})
it('downloads darwin-arm64 on M1 translated by Rosetta', async function () {
os.platform.returns('darwin')
os.arch.returns('x64')
nockDarwinArm64()
context('Linux arm64/aarch64', () => {
function nockLinuxArm64 () {
return nock('https://download.cypress.io')
.get('/desktop/1.2.3')
.query({ arch: 'arm64', platform: 'linux' })
.reply(200, undefined, {
'x-version': '1.2.3',
})
}
sinon.stub(cp, 'spawn').withArgs('sysctl', ['-n', 'sysctl.proc_translated'])
.callsFake(mockSpawn(((cp) => {
cp.stdout.write('1')
cp.emit('exit', 0, null)
cp.end()
})))
it('downloads linux-arm64 on arm64 processor', async function () {
os.platform.returns('linux')
os.arch.returns('arm64')
nockLinuxArm64()
const responseVersion = await download.start(this.options)
const responseVersion = await download.start(this.options)
expect(responseVersion).to.eq('1.2.3')
expect(responseVersion).to.eq('1.2.3')
await fs.statAsync(downloadDestination)
await fs.statAsync(downloadDestination)
})
it('downloads linux-arm64 on non-arm64 node running on arm machine', async function () {
os.platform.returns('linux')
os.arch.returns('x64')
sinon.stub(cp, 'spawn')
for (const arch of ['aarch64_be', 'aarch64', 'armv8b', 'armv8l']) {
nockLinuxArm64()
cp.spawn.withArgs('uname', ['-m'])
.callsFake(mockSpawn(((cp) => {
cp.stdout.write(arch)
cp.emit('exit', 0, null)
cp.end()
})))
const responseVersion = await download.start(this.options)
expect(responseVersion).to.eq('1.2.3')
await fs.statAsync(downloadDestination)
}
})
})
})
+1 -1
View File
@@ -141,7 +141,7 @@
"dedent": "^0.7.0",
"del": "3.0.0",
"detect-port": "^1.3.0",
"electron": "18.0.4",
"electron": "18.3.0",
"electron-builder": "^22.13.1",
"electron-notarize": "^1.1.1",
"enzyme-adapter-react-16": "1.12.1",
+1
View File
@@ -113,6 +113,7 @@ const deploy = {
checkDownloads ({ version }) {
const systems = [
{ platform: 'linux', arch: 'x64' },
{ platform: 'linux', arch: 'arm64' },
{ platform: 'darwin', arch: 'x64' },
{ platform: 'darwin', arch: 'arm64' },
{ platform: 'win32', arch: 'x64' },
+1 -1
View File
@@ -34,7 +34,7 @@ type semver = string
/**
* Platform plus architecture string like "darwin-x64"
*/
type platformArch = 'darwin-x64' | 'darwin-arm64' | 'linux-x64' | 'win32-x64'
type platformArch = 'darwin-x64' | 'darwin-arm64' | 'linux-x64' | 'linux-arm64' | 'win32-x64'
interface ReleaseInformation {
commit: commit
+1
View File
@@ -87,6 +87,7 @@ module.exports = {
'darwin-x64': getUrl('darwin-x64'),
'darwin-arm64': getUrl('darwin-arm64'),
'linux-x64': getUrl('linux-x64'),
'linux-arm64': getUrl('linux-arm64'),
'win32-x64': getUrl('win32-x64'),
},
}
+4 -18
View File
@@ -1,4 +1,3 @@
const _ = require('lodash')
const awspublish = require('gulp-awspublish')
const human = require('human-interval')
const la = require('lazy-ass')
@@ -112,7 +111,7 @@ const purgeDesktopAppAllPlatforms = function (version, zipName) {
}
// all architectures we are building the test runner for
const validPlatformArchs = ['darwin-arm64', 'darwin-x64', 'linux-x64', 'win32-x64']
const validPlatformArchs = ['darwin-arm64', 'darwin-x64', 'linux-x64', 'linux-arm64', 'win32-x64']
// simple check for platform-arch string
// example: isValidPlatformArch("darwin") // FALSE
const isValidPlatformArch = check.oneOf(validPlatformArchs)
@@ -122,25 +121,12 @@ const getValidPlatformArchs = () => {
}
const getUploadNameByOsAndArch = function (platform) {
// just hard code for now...
const arch = os.arch()
const uploadNames = {
darwin: {
'arm64': 'darwin-arm64',
'x64': 'darwin-x64',
},
linux: {
'x64': 'linux-x64',
},
win32: {
'x64': 'win32-x64',
},
}
const name = _.get(uploadNames[platform], arch)
const name = [platform, arch].join('-')
if (!name) {
throw new Error(`Cannot find upload name for OS: '${platform}' with arch: '${arch}'`)
if (!isValidPlatformArch(name)) {
throw new Error(`${name} is not a valid upload destination. Does validPlatformArchs need updating?`)
}
la(isValidPlatformArch(name), 'formed invalid platform', name, 'from', platform, arch)
+2 -2
View File
@@ -1,9 +1,9 @@
// checks if the terminal has all the variables set (especially on Linux Docker)
const assert = require('assert')
const isLinux = process.platform === 'linux'
const isMainLinux = process.platform === 'linux' && process.arch === 'x64'
if (isLinux) {
if (isMainLinux) {
assert.ok(process.env.TERM === 'xterm', `process.env.TERM=${process.env.TERM} and must be set to "xterm" for Docker to work`)
}
+4 -4
View File
@@ -16233,10 +16233,10 @@ electron-to-chromium@^1.3.247, electron-to-chromium@^1.4.84:
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.111.tgz#897613f6504f3f17c9381c7499a635b413e4df4e"
integrity sha512-/s3+fwhKf1YK4k7btOImOzCQLpUjS6MaPf0ODTNuT4eTM1Bg4itBpLkydhOzJmpmH6Z9eXFyuuK5czsmzRzwtw==
electron@18.0.4:
version "18.0.4"
resolved "https://registry.yarnpkg.com/electron/-/electron-18.0.4.tgz#7b9b094db32805d4a7826d9f7a1b376d9d7b9f86"
integrity sha512-xfsozNpFr3WzeM1EFlw2qqiqXbCrgQNBJJMlcC4/DUYVpkF8364SZenX7FFFA42NmwXiOEahkvvho/u7UrAcGg==
electron@18.3.0:
version "18.3.0"
resolved "https://registry.npmjs.org/electron/-/electron-18.3.0.tgz#43de95979341e63f1b209c569a0ad148d98ae5b7"
integrity sha512-2+pAUIViVvFOGE5mJKKi8F6ruyvQrcqdfsm/AUfz+6P05vbvR5ZsR6WBkr90mlyojHW5w/nAVX9ZSOtz3aHs4A==
dependencies:
"@electron/get" "^1.13.0"
"@types/node" "^16.11.26"