ci: Trigger an arm test on VSTS after CircleCI build (#14898)

* ci: Trigger an arm test on VSTS after CircleCI build
This commit is contained in:
John Kleinschmidt 2018-10-04 12:01:16 -04:00 committed by GitHub
parent 1acd840c38
commit 038b56e31e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 289 additions and 94 deletions

View file

@ -182,6 +182,11 @@ step-nodejs-headers-build: &step-nodejs-headers-build
cd src cd src
ninja -C out/Default third_party/electron_node:headers ninja -C out/Default third_party/electron_node:headers
step-nodejs-headers-store: &step-nodejs-headers-store
store_artifacts:
path: src/out/Default/gen/node_headers.tar.gz
destination: node_headers.tar.gz
step-electron-publish: &step-electron-publish step-electron-publish: &step-electron-publish
run: run:
name: Publish Electron Dist name: Publish Electron Dist
@ -314,6 +319,17 @@ step-maybe-native-mksnapshot-store: &step-maybe-native-mksnapshot-store
path: src/out/native_mksnapshot/mksnapshot.zip path: src/out/native_mksnapshot/mksnapshot.zip
destination: native_mksnapshot.zip destination: native_mksnapshot.zip
step-maybe-trigger-arm-test: &step-maybe-trigger-arm-test
run:
name: Trigger an arm test on VSTS if applicable
command: |
cd src
# Only run for non-fork prs
if [ "$TRIGGER_ARM_TEST" == "true" ] && [ -z "$CIRCLE_PR_NUMBER" ]; then
#Trigger VSTS job, passing along CircleCI job number and branch to build
echo "Triggering electron-$TARGET_ARCH-testing build on VSTS"
node electron/script/ci-release-build.js --job=electron-$TARGET_ARCH-testing --ci=VSTS --armTest --circleBuildNum=$CIRCLE_BUILD_NUM $CIRCLE_BRANCH
fi
# Lists of steps. # Lists of steps.
steps-checkout: &steps-checkout steps-checkout: &steps-checkout
steps: steps:
@ -377,12 +393,16 @@ steps-electron-build-for-tests: &steps-electron-build-for-tests
# Node.js headers # Node.js headers
- *step-nodejs-headers-build - *step-nodejs-headers-build
- *step-nodejs-headers-store
- *step-show-sccache-stats - *step-show-sccache-stats
# Save all data needed for a further tests run. # Save all data needed for a further tests run.
- *step-persist-data-for-tests - *step-persist-data-for-tests
# Trigger tests on arm hardware if needed
- *step-maybe-trigger-arm-test
- *step-maybe-notify-slack-failure - *step-maybe-notify-slack-failure
- *step-maybe-notify-slack-success - *step-maybe-notify-slack-success
@ -416,6 +436,7 @@ steps-electron-build-for-publish: &steps-electron-build-for-publish
# Node.js headers # Node.js headers
- *step-nodejs-headers-build - *step-nodejs-headers-build
- *step-nodejs-headers-store
# ffmpeg # ffmpeg
- *step-ffmpeg-gn-gen - *step-ffmpeg-gn-gen
@ -713,6 +734,7 @@ jobs:
<<: *env-arm <<: *env-arm
<<: *env-testing-build <<: *env-testing-build
<<: *env-enable-sccache <<: *env-enable-sccache
TRIGGER_ARM_TEST: true
<<: *steps-electron-build-for-tests <<: *steps-electron-build-for-tests
linux-arm-ffmpeg: linux-arm-ffmpeg:
@ -768,6 +790,7 @@ jobs:
<<: *env-arm64 <<: *env-arm64
<<: *env-testing-build <<: *env-testing-build
<<: *env-enable-sccache <<: *env-enable-sccache
TRIGGER_ARM_TEST: true
<<: *steps-electron-build-for-tests <<: *steps-electron-build-for-tests
linux-arm64-ffmpeg: linux-arm64-ffmpeg:

61
Dockerfile.arm32v7 Normal file
View file

@ -0,0 +1,61 @@
FROM arm32v7/ubuntu:16.04
RUN groupadd --gid 1000 builduser \
&& useradd --uid 1000 --gid builduser --shell /bin/bash --create-home builduser
# Set up TEMP directory
ENV TEMP=/tmp
RUN chmod a+rwx /tmp
RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y \
bison \
build-essential \
clang \
curl \
gperf \
git \
libasound2 \
libasound2-dev \
libcap-dev \
libcups2-dev \
libdbus-1-dev \
libgconf-2-4 \
libgconf2-dev \
libgnome-keyring-dev \
libgtk2.0-0 \
libgtk2.0-dev \
libgtk-3-0 \
libgtk-3-dev \
libnotify-bin \
libnss3 \
libnss3-dev \
libxss1 \
libxtst-dev \
libxtst6 \
lsb-release \
locales \
nano \
python-setuptools \
python-pip \
python-dbusmock \
sudo \
unzip \
wget \
xvfb \
&& rm -rf /var/lib/apt/lists/*
# Install Node.js
RUN curl -sL https://deb.nodesource.com/setup_10.x | bash - \
&& DEBIAN_FRONTEND=noninteractive apt-get install -y nodejs \
&& rm -rf /var/lib/apt/lists/*
# crcmod is required by gsutil, which is used for filling the gclient git cache
RUN pip install -U crcmod
ADD tools/xvfb-init.sh /etc/init.d/xvfb
RUN chmod a+x /etc/init.d/xvfb
RUN usermod -aG sudo builduser
RUN echo 'builduser ALL=(ALL:ALL) NOPASSWD:ALL' >> /etc/sudoers
WORKDIR /home/builduser

View file

@ -1,35 +0,0 @@
FROM multiarch/debian-debootstrap:arm64-jessie
RUN apt-get update && apt-get install -y\
bison \
build-essential \
clang \
curl \
gperf \
libasound2 \
libasound2-dev \
libcap-dev \
libcups2-dev \
libdbus-1-dev \
libgconf-2-4 \
libgconf2-dev \
libgnome-keyring-dev \
libgtk-3-0 \
libgtk-3-dev \
libnotify-bin \
libnotify-dev \
libnss3 \
libnss3-dev \
libx11-xcb-dev \
libxss1 \
libxtst-dev \
libxtst6 \
python-dbusmock \
wget \
xvfb
ADD tools/xvfb-init.sh /etc/init.d/xvfb
RUN chmod a+x /etc/init.d/xvfb
ADD tools/run-electron.sh /run-electron.sh
RUN chmod a+x /run-electron.sh
CMD sh /run-electron.sh

View file

@ -3,14 +3,13 @@ FROM arm64v8/ubuntu:16.04
RUN groupadd --gid 1000 builduser \ RUN groupadd --gid 1000 builduser \
&& useradd --uid 1000 --gid builduser --shell /bin/bash --create-home builduser && useradd --uid 1000 --gid builduser --shell /bin/bash --create-home builduser
RUN groupadd --gid 114 jenkins \
&& useradd --uid 110 --gid jenkins --shell /bin/bash --create-home jenkins
# Set up TEMP directory # Set up TEMP directory
ENV TEMP=/tmp ENV TEMP=/tmp
RUN chmod a+rwx /tmp RUN chmod a+rwx /tmp
RUN apt-get update && apt-get install -y\ RUN dpkg --add-architecture armhf
RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y \
bison \ bison \
build-essential \ build-essential \
clang \ clang \
@ -19,6 +18,7 @@ RUN apt-get update && apt-get install -y\
git \ git \
libasound2 \ libasound2 \
libasound2-dev \ libasound2-dev \
libc6:armhf \
libcap-dev \ libcap-dev \
libcups2-dev \ libcups2-dev \
libdbus-1-dev \ libdbus-1-dev \
@ -29,35 +29,37 @@ RUN apt-get update && apt-get install -y\
libgtk2.0-dev \ libgtk2.0-dev \
libgtk-3-0 \ libgtk-3-0 \
libgtk-3-dev \ libgtk-3-dev \
libnotify-dev \ libnotify-bin \
libnss3 \ libnss3 \
libnss3-dev \ libnss3-dev \
libx11-xcb-dev \ libstdc++6:armhf \
libxss1 \ libxss1 \
libxtst-dev \ libxtst-dev \
libxtst6 \ libxtst6 \
lsb-release \ lsb-release \
locales \ locales \
ninja \ nano \
python-setuptools \ python-setuptools \
python-pip \ python-pip \
python-dbusmock \ python-dbusmock \
sudo \
unzip \
wget \ wget \
xvfb xvfb \
&& rm -rf /var/lib/apt/lists/*
# Install node.js # Install Node.js
RUN curl -sL https://deb.nodesource.com/setup_8.x | bash - RUN curl -sL https://deb.nodesource.com/setup_10.x | bash - \
RUN apt-get update && apt-get install -y nodejs && DEBIAN_FRONTEND=noninteractive apt-get install -y nodejs \
&& rm -rf /var/lib/apt/lists/*
# Install crcmod # crcmod is required by gsutil, which is used for filling the gclient git cache
RUN pip install -U crcmod RUN pip install -U crcmod
ADD tools/xvfb-init.sh /etc/init.d/xvfb ADD tools/xvfb-init.sh /etc/init.d/xvfb
RUN chmod a+x /etc/init.d/xvfb RUN chmod a+x /etc/init.d/xvfb
# Install ninja in /usr/local RUN usermod -aG sudo builduser
RUN cd /usr/local && git clone https://github.com/martine/ninja.git -b v1.5.3 RUN echo 'builduser ALL=(ALL:ALL) NOPASSWD:ALL' >> /etc/sudoers
RUN cd /usr/local/ninja && ./configure.py --bootstrap
USER builduser
WORKDIR /home/builduser WORKDIR /home/builduser

View file

@ -1,36 +0,0 @@
FROM multiarch/debian-debootstrap:armhf-jessie
RUN apt-get update && apt-get install -y\
bison \
build-essential \
clang \
curl \
gperf \
libasound2 \
libasound2-dev \
libcap-dev \
libcups2-dev \
libdbus-1-dev \
libgconf-2-4 \
libgconf2-dev \
libgnome-keyring-dev \
libgtk-3-0 \
libgtk-3-dev \
libnotify-bin \
libnotify-dev \
libnss3 \
libnss3-dev \
libx11-xcb-dev \
libxss1 \
libxtst-dev \
libxtst6 \
python-dbusmock \
git \
wget \
xvfb
ADD tools/xvfb-init.sh /etc/init.d/xvfb
RUN chmod a+x /etc/init.d/xvfb
ADD tools/run-electron.sh /run-electron.sh
RUN chmod a+x /run-electron.sh
CMD sh /run-electron.sh

View file

@ -1,4 +1,4 @@
require('dotenv-safe').load() if (!process.env.CI) require('dotenv-safe').load()
const assert = require('assert') const assert = require('assert')
const request = require('request') const request = require('request')
@ -22,6 +22,11 @@ const vstsJobs = [
'electron-release-osx-x64' 'electron-release-osx-x64'
] ]
const vstsArmJobs = [
'electron-arm-testing',
'electron-arm64-testing'
]
async function makeRequest (requestOptions, parseResponse) { async function makeRequest (requestOptions, parseResponse) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
request(requestOptions, (err, res, body) => { request(requestOptions, (err, res, body) => {
@ -135,7 +140,9 @@ function buildCircleCI (targetBranch, options) {
} }
async function buildVSTS (targetBranch, options) { async function buildVSTS (targetBranch, options) {
if (options.job) { if (options.armTest) {
assert(vstsArmJobs.includes(options.job), `Unknown VSTS CI arm test job name: ${options.job}. Valid values are: ${vstsArmJobs}.`)
} else if (options.job) {
assert(vstsJobs.includes(options.job), `Unknown VSTS CI job name: ${options.job}. Valid values are: ${vstsJobs}.`) assert(vstsJobs.includes(options.job), `Unknown VSTS CI job name: ${options.job}. Valid values are: ${vstsJobs}.`)
} }
console.log(`Triggering VSTS to run build on branch: ${targetBranch} with release flag.`) console.log(`Triggering VSTS to run build on branch: ${targetBranch} with release flag.`)
@ -143,8 +150,12 @@ async function buildVSTS (targetBranch, options) {
ELECTRON_RELEASE: 1 ELECTRON_RELEASE: 1
} }
if (!options.ghRelease) { if (options.armTest) {
environmentVariables.UPLOAD_TO_S3 = 1 environmentVariables.CIRCLE_BUILD_NUM = options.circleBuildNum
} else {
if (!options.ghRelease) {
environmentVariables.UPLOAD_TO_S3 = 1
}
} }
const requestOpts = { const requestOpts = {
@ -226,12 +237,13 @@ module.exports = runRelease
if (require.main === module) { if (require.main === module) {
const args = require('minimist')(process.argv.slice(2), { const args = require('minimist')(process.argv.slice(2), {
boolean: ['ghRelease', 'automaticRelease'] boolean: ['ghRelease', 'automaticRelease', 'armTest']
}) })
const targetBranch = args._[0] const targetBranch = args._[0]
if (args._.length < 1) { if (args._.length < 1) {
console.log(`Trigger CI to build release builds of electron. console.log(`Trigger CI to build release builds of electron.
Usage: ci-release-build.js [--job=CI_JOB_NAME] [--ci=CircleCI|AppVeyor|VSTS] [--ghRelease] [--automaticRelease] TARGET_BRANCH Usage: ci-release-build.js [--job=CI_JOB_NAME] [--ci=CircleCI|AppVeyor|VSTS]
[--ghRelease] [--automaticRelease] [--armTest] [--circleBuildNum=xxx] TARGET_BRANCH
`) `)
process.exit(0) process.exit(0)
} }

View file

@ -0,0 +1,78 @@
const args = require('minimist')(process.argv.slice(2))
const nugget = require('nugget')
const request = require('request')
async function makeRequest (requestOptions, parseResponse) {
return new Promise((resolve, reject) => {
request(requestOptions, (err, res, body) => {
if (!err && res.statusCode >= 200 && res.statusCode < 300) {
if (parseResponse) {
const build = JSON.parse(body)
resolve(build)
} else {
resolve(body)
}
} else {
console.error('Error occurred while requesting:', requestOptions.url)
if (parseResponse) {
try {
console.log('Error: ', `(status ${res.statusCode})`, err || JSON.parse(res.body), requestOptions)
} catch (err) {
console.log('Error: ', `(status ${res.statusCode})`, err || res.body, requestOptions)
}
} else {
console.log('Error: ', `(status ${res.statusCode})`, err || res.body, requestOptions)
}
reject(err)
}
})
})
}
async function downloadArtifact (name, buildNum, dest) {
const circleArtifactUrl = `https://circleci.com/api/v1.1/project/github/electron/electron/${args.buildNum}/artifacts?circle-token=${process.env.CIRCLE_TOKEN}`
const artifacts = await makeRequest({
method: 'GET',
url: circleArtifactUrl,
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json'
}
}, true).catch(err => {
console.log('Error calling CircleCI:', err)
})
const artifactToDownload = artifacts.find(artifact => {
return (artifact.path === name)
})
if (!artifactToDownload) {
console.log(`Could not find artifact called ${name} to download for build #${buildNum}.`)
process.exit(1)
} else {
console.log(`Downloading ${artifactToDownload.url}.`)
await downloadFile(artifactToDownload.url, dest)
console.log(`Successfully downloaded ${name}.`)
}
}
function downloadFile (url, directory) {
return new Promise((resolve, reject) => {
const nuggetOpts = {
dir: directory
}
nugget(url, nuggetOpts, (err) => {
if (err) {
reject(err)
} else {
resolve()
}
})
})
}
if (!args.name || !args.buildNum || !args.dest) {
console.log(`Download CircleCI artifacts.
Usage: download-circleci-artifacts.js [--buildNum=CIRCLE_BUILD_NUMBER] [--name=artifactName] [--dest]`)
process.exit(0)
} else {
downloadArtifact(args.name, args.buildNum, args.dest)
}

View file

@ -10,7 +10,7 @@ const isCI = remote.getGlobal('isCi')
describe('desktopCapturer', () => { describe('desktopCapturer', () => {
before(function () { before(function () {
if (!features.isDesktopCapturerEnabled()) { if (!features.isDesktopCapturerEnabled() || process.arch.indexOf('arm') === 0) {
// It's been disabled during build time. // It's been disabled during build time.
this.skip() this.skip()
return return

View file

@ -15,6 +15,7 @@ const { app } = remote.require('electron')
const skip = process.platform !== 'linux' || const skip = process.platform !== 'linux' ||
process.arch === 'ia32' || process.arch === 'ia32' ||
process.arch.indexOf('arm') === 0 ||
!process.env.DBUS_SESSION_BUS_ADDRESS; !process.env.DBUS_SESSION_BUS_ADDRESS;
(skip ? describe.skip : describe)('Notification module (dbus)', () => { (skip ? describe.skip : describe)('Notification module (dbus)', () => {

65
vsts-arm-test-steps.yml Normal file
View file

@ -0,0 +1,65 @@
steps:
- task: CopyFiles@2
displayName: 'Copy Files to: src/electron'
inputs:
TargetFolder: src/electron
- bash: |
cd src/electron
npm install --verbose
displayName: 'NPM install'
- bash: |
export ZIP_DEST=$PWD/src/out/Default
mkdir -p $ZIP_DEST
cd src/electron
node script/download-circleci-artifacts.js --buildNum=$CIRCLE_BUILD_NUM --name=dist.zip --dest=$ZIP_DEST
cd $ZIP_DEST
unzip -o dist.zip
displayName: 'Download and unzip dist files for test'
env:
CIRCLE_TOKEN: $(CIRCLECI_TOKEN)
- bash: |
export NODE_HEADERS_DEST=$PWD/src/out/Default/gen
mkdir -p $NODE_HEADERS_DEST
cd src/electron
node script/download-circleci-artifacts.js --buildNum=$CIRCLE_BUILD_NUM --name=node_headers.tar.gz --dest=$NODE_HEADERS_DEST
cd $NODE_HEADERS_DEST
tar xzf node_headers.tar.gz
displayName: 'Download and untar node header files for test'
env:
CIRCLE_TOKEN: $(CIRCLECI_TOKEN)
- bash: |
cd src
export npm_config_nodedir=$PWD/out/Default/gen/node_headers
cd electron/spec
npm install --verbose
displayName: Install test modules
- bash: |
sh -e /etc/init.d/xvfb start
displayName: Setup for headless testing
env:
DISPLAY: ":99.0"
- bash: |
cd src
./out/Default/electron electron/spec --ci --enable-logging
displayName: 'Run Electron tests'
timeoutInMinutes: 10
- task: PublishTestResults@2
displayName: 'Publish Test Results'
inputs:
testResultsFiles: '*.xml'
searchFolder: '$(System.DefaultWorkingDirectory)/src/junit/'
condition: succeededOrFailed()
- task: mspremier.PostBuildCleanup.PostBuildCleanup-task.PostBuildCleanup@3
displayName: 'Clean Agent Directories'
condition: always()

12
vsts-arm32v7.yml Normal file
View file

@ -0,0 +1,12 @@
resources:
containers:
- container: arm32v7-test-container
image: electronbuilds/arm32v7:0.0.1
jobs:
- job: Test_Arm32v7
container: arm32v7-test-container
displayName: Test Arm on Arm32v7 hardware
timeoutInMinutes: 30
steps:
- template: vsts-arm-test-steps.yml

12
vsts-arm64v8.yml Normal file
View file

@ -0,0 +1,12 @@
resources:
containers:
- container: arm64v8-test-container
image: electronbuilds/arm64v8:0.0.4
jobs:
- job: Test_Arm64
container: arm64v8-test-container
displayName: Test Arm64 on Arm64 hardware
timeoutInMinutes: 30
steps:
- template: vsts-arm-test-steps.yml