Compare commits

..

10 Commits

Author SHA1 Message Date
Yang Chen 769ff281b3 Merge branch 'master' into release/v2
* master:
  Prepare for release 2.6.0.
  Update packages.
  Add information re. hardware acceleration for linux support.
  Support running on linux without hardware accleration.
  Gradle 6.3.
  Gradle 6.3-rc-4.
  Update workflow to use Java 14.
  Update npm packages.
  Bump acorn from 5.7.3 to 5.7.4
2020-03-28 15:00:56 +11:00
Yang Chen 0d966550cf Prepare for release 2.6.0. 2020-03-28 14:59:20 +11:00
Yang Chen eb9e069f3f Update packages. 2020-03-28 14:10:50 +11:00
Yang Chen 0ac3f34493 Add information re. hardware acceleration for linux support. 2020-03-28 14:10:50 +11:00
Yang Chen 345ace6178 Support running on linux without hardware accleration. 2020-03-28 14:10:50 +11:00
Yang Chen 490f28e17c Gradle 6.3. 2020-03-25 23:23:07 +11:00
Yang Chen fc08a40bf0 Gradle 6.3-rc-4. 2020-03-25 23:23:07 +11:00
Yang Chen 75464a704b Update workflow to use Java 14. 2020-03-25 23:23:07 +11:00
Yang Chen de92fdaa03 Update npm packages. 2020-03-17 21:16:57 +11:00
dependabot[bot] 47063ae93b Bump acorn from 5.7.3 to 5.7.4
Bumps [acorn](https://github.com/acornjs/acorn) from 5.7.3 to 5.7.4.
- [Release notes](https://github.com/acornjs/acorn/releases)
- [Commits](https://github.com/acornjs/acorn/compare/5.7.3...5.7.4)

Signed-off-by: dependabot[bot] <support@github.com>
2020-03-17 20:55:34 +11:00
12 changed files with 2826 additions and 2055 deletions
+11 -5
View File
@@ -9,11 +9,17 @@ on:
jobs: jobs:
test: test:
runs-on: macOS-latest runs-on: ${{ matrix.os }}
timeout-minutes: 10 timeout-minutes: 15
strategy: strategy:
matrix: matrix:
api-level: [16, 21, 23, 29] os: [macos-latest, ubuntu-latest]
api-level: [16, 23, 29]
exclude:
- os: ubuntu-latest
api-level: 23
- os: ubuntu-latest
api-level: 29
steps: steps:
- name: checkout - name: checkout
uses: actions/checkout@v2 uses: actions/checkout@v2
@@ -28,10 +34,10 @@ jobs:
npm run lint npm run lint
npm test npm test
- name: Java 13 - name: Java 14
uses: actions/setup-java@v1 uses: actions/setup-java@v1
with: with:
java-version: 13 java-version: 14
- name: run action - name: run action
uses: ./ uses: ./
+4
View File
@@ -1,5 +1,9 @@
# Change Log # Change Log
## v2.6.0
* Added support for Linux VMs (no hardware acceleration).
## v2.5.0 ## v2.5.0
* Added support for API 15-19 system images. * Added support for API 15-19 system images.
+8 -4
View File
@@ -4,7 +4,7 @@
<a href="https://github.com/ReactiveCircus/android-emulator-runner"><img alt="GitHub Actions status" src="https://github.com/ReactiveCircus/android-emulator-runner/workflows/Main%20workflow/badge.svg"></a> <a href="https://github.com/ReactiveCircus/android-emulator-runner"><img alt="GitHub Actions status" src="https://github.com/ReactiveCircus/android-emulator-runner/workflows/Main%20workflow/badge.svg"></a>
</p> </p>
A GitHub Action for installing, configuring and running Android Emulators on macOS virtual machines. A GitHub Action for installing, configuring and running hardware-accelerated Android Emulators on macOS virtual machines (or Linux virtual machines but without hardware accleration).
The old ARM-based emulators were slow and are no longer supported by Google. The modern Intel Atom (x86 and x86_64) emulators require hardware acceleration (HAXM on Mac & Windows, QEMU on Linux) from the host to run fast. This presents a challenge on CI as to be able to run hardware accelerated emulators within a docker container, **KVM** must be supported by the host VM which isn't the case for cloud-based CI providers due to infrastructural limits. If you want to learn more about this, here's an article I wrote: [Running Android Instrumented Tests on CI](https://dev.to/ychescale9/running-android-emulators-on-ci-from-bitrise-io-to-github-actions-3j76). The old ARM-based emulators were slow and are no longer supported by Google. The modern Intel Atom (x86 and x86_64) emulators require hardware acceleration (HAXM on Mac & Windows, QEMU on Linux) from the host to run fast. This presents a challenge on CI as to be able to run hardware accelerated emulators within a docker container, **KVM** must be supported by the host VM which isn't the case for cloud-based CI providers due to infrastructural limits. If you want to learn more about this, here's an article I wrote: [Running Android Instrumented Tests on CI](https://dev.to/ychescale9/running-android-emulators-on-ci-from-bitrise-io-to-github-actions-3j76).
@@ -22,14 +22,16 @@ This action automates the process by doing the following:
## Usage ## Usage
Note that this action must be run on a **macOS** VM, e.g. `macOS-latest` or `macOS-10.14`. It is recommended to run this action on a **macOS** VM, e.g. `macos-latest` or `macos-10.15` to take advantage of hardware accleration support provided by **HAXM**.
Please note that while Linux VMs (e.g. `ubuntu-latest` or `ubuntu-18.04`) are also supported, hardware acceleration will **not** be available.
A workflow that uses **android-emulator-runner** to run your instrumented tests on **API 29**: A workflow that uses **android-emulator-runner** to run your instrumented tests on **API 29**:
``` ```
jobs: jobs:
test: test:
runs-on: macOS-latest runs-on: macos-latest
steps: steps:
- name: checkout - name: checkout
uses: actions/checkout@v2 uses: actions/checkout@v2
@@ -46,7 +48,7 @@ We can also leverage GitHub Actions's build matrix to test across multiple confi
``` ```
jobs: jobs:
test: test:
runs-on: macOS-latest runs-on: macos-latest
strategy: strategy:
matrix: matrix:
api-level: [21, 23, 29] api-level: [21, 23, 29]
@@ -80,3 +82,5 @@ jobs:
| `script` | Required | N/A | Custom script to run - e.g. to run Android instrumented tests on the emulator: `./gradlew connectedCheck` | | `script` | Required | N/A | Custom script to run - e.g. to run Android instrumented tests on the emulator: `./gradlew connectedCheck` |
Default `emulator-options`: `-no-window -gpu swiftshader_indirect -no-snapshot -noaudio -no-boot-anim`. Default `emulator-options`: `-no-window -gpu swiftshader_indirect -no-snapshot -noaudio -no-boot-anim`.
_Please note that if you are running on a Linux VM, `-no-accel` will be added to the `emulator-options` to make sure hardware acceleration is turned off._
+4
View File
@@ -33,6 +33,10 @@ function launchEmulator(apiLevel, target, arch, profile, emulatorOptions, disabl
} }
// start emulator // start emulator
console.log('Starting emulator.'); console.log('Starting emulator.');
// turn off hardware acceleration on Linux
if (process.platform === 'linux') {
emulatorOptions += ' -accel off';
}
yield exec.exec(`sh -c \\"${process.env.ANDROID_HOME}/emulator/emulator -avd test ${emulatorOptions} &"`, [], { yield exec.exec(`sh -c \\"${process.env.ANDROID_HOME}/emulator/emulator -avd test ${emulatorOptions} &"`, [], {
listeners: { listeners: {
stderr: (data) => { stderr: (data) => {
+9 -9
View File
@@ -24,9 +24,14 @@ const script_parser_1 = require("./script-parser");
function run() { function run() {
return __awaiter(this, void 0, void 0, function* () { return __awaiter(this, void 0, void 0, function* () {
try { try {
// only support running on macOS // only support running on macOS or Linux
if (process.platform !== 'darwin') { if (process.platform !== 'darwin') {
throw new Error('This action is expected to be run within a macOS virtual machine to enable hardware acceleration.'); if (process.platform === 'linux') {
console.warn(`You're running a Linux VM where hardware acceleration is not available. Please consider using a macOS VM instead to take advantage of native hardware acceleration support provided by HAXM.`);
}
else {
throw new Error('Unsupported virtual machine: please use either macos or ubuntu VM.');
}
} }
// API level of the platform and system image // API level of the platform and system image
const apiLevelInput = core.getInput('api-level', { required: true }); const apiLevelInput = core.getInput('api-level', { required: true });
@@ -74,13 +79,8 @@ function run() {
})); }));
// install SDK // install SDK
yield sdk_installer_1.installAndroidSdk(apiLevel, target, arch, emulatorBuild); yield sdk_installer_1.installAndroidSdk(apiLevel, target, arch, emulatorBuild);
try { // launch an emulator
// launch an emulator yield emulator_manager_1.launchEmulator(apiLevel, target, arch, profile, emulatorOptions, disableAnimations);
yield emulator_manager_1.launchEmulator(apiLevel, target, arch, profile, emulatorOptions, disableAnimations);
}
catch (error) {
core.setFailed(error.message);
}
// execute the custom script // execute the custom script
try { try {
// move to custom working directory if set // move to custom working directory if set
+13 -9
View File
@@ -18,28 +18,32 @@ Object.defineProperty(exports, "__esModule", { value: true });
const core = __importStar(require("@actions/core")); const core = __importStar(require("@actions/core"));
const exec = __importStar(require("@actions/exec")); const exec = __importStar(require("@actions/exec"));
const BUILD_TOOLS_VERSION = '29.0.3'; const BUILD_TOOLS_VERSION = '29.0.3';
const CMDLINE_TOOLS_URL = 'https://dl.google.com/android/repository/commandlinetools-linux-6200805_latest.zip'; const CMDLINE_TOOLS_URL_MAC = 'https://dl.google.com/android/repository/commandlinetools-linux-6200805_latest.zip';
const CMDLINE_TOOLS_URL_LINUX = 'https://dl.google.com/android/repository/commandlinetools-linux-6200805_latest.zip';
/** /**
* Installs & updates the Android SDK for the macOS platform, including SDK platform for the chosen API level, latest build tools, platform tools, Android Emulator, * Installs & updates the Android SDK for the macOS platform, including SDK platform for the chosen API level, latest build tools, platform tools, Android Emulator,
* and the system image for the chosen API level, CPU arch, and target. * and the system image for the chosen API level, CPU arch, and target.
*/ */
function installAndroidSdk(apiLevel, target, arch, emulatorBuild) { function installAndroidSdk(apiLevel, target, arch, emulatorBuild) {
return __awaiter(this, void 0, void 0, function* () { return __awaiter(this, void 0, void 0, function* () {
const isOnMac = process.platform === 'darwin';
console.log('Installing new cmdline-tools.'); console.log('Installing new cmdline-tools.');
yield exec.exec(`mkdir ${process.env.ANDROID_HOME}/cmdline-tools`); const sdkUrl = isOnMac ? CMDLINE_TOOLS_URL_MAC : CMDLINE_TOOLS_URL_LINUX;
yield exec.exec(`curl -fo commandlinetools.zip ${CMDLINE_TOOLS_URL}`); yield exec.exec(`sudo mkdir ${process.env.ANDROID_HOME}/cmdline-tools`);
yield exec.exec(`unzip -q commandlinetools.zip -d ${process.env.ANDROID_HOME}/cmdline-tools`); yield exec.exec(`curl -fo commandlinetools.zip ${sdkUrl}`);
yield exec.exec(`rm -f commandlinetools.zip`); yield exec.exec(`sudo unzip -q commandlinetools.zip -d ${process.env.ANDROID_HOME}/cmdline-tools`);
yield exec.exec(`sudo rm -f commandlinetools.zip`);
// add paths for commandline-tools and platform-tools // add paths for commandline-tools and platform-tools
core.addPath(`${process.env.ANDROID_HOME}/cmdline-tools/tools:${process.env.ANDROID_HOME}/cmdline-tools/tools/bin:${process.env.ANDROID_HOME}/platform-tools`); core.addPath(`${process.env.ANDROID_HOME}/cmdline-tools/tools:${process.env.ANDROID_HOME}/cmdline-tools/tools/bin:${process.env.ANDROID_HOME}/platform-tools`);
yield exec.exec(`sh -c \\"sudo chmod -R 777 ${process.env.ANDROID_HOME}"`);
console.log('Installing latest build tools, platform tools, and platform.'); console.log('Installing latest build tools, platform tools, and platform.');
yield exec.exec(`sh -c \\"sdkmanager --install 'build-tools;${BUILD_TOOLS_VERSION}' platform-tools 'platforms;android-${apiLevel}' > /dev/null"`); yield exec.exec(`sh -c \\"sdkmanager --install 'build-tools;${BUILD_TOOLS_VERSION}' platform-tools 'platforms;android-${apiLevel}' > /dev/null"`);
if (emulatorBuild) { if (emulatorBuild) {
console.log(`Installing emulator build ${emulatorBuild}.`); console.log(`Installing emulator build ${emulatorBuild}.`);
yield exec.exec(`curl -fo emulator.zip https://dl.google.com/android/repository/emulator-darwin-${emulatorBuild}.zip`); yield exec.exec(`curl -fo emulator.zip https://dl.google.com/android/repository/emulator-${isOnMac ? 'darwin' : 'linux'}-${emulatorBuild}.zip`);
yield exec.exec(`rm -rf ${process.env.ANDROID_HOME}/emulator`); yield exec.exec(`sudo rm -rf ${process.env.ANDROID_HOME}/emulator`);
yield exec.exec(`unzip -q emulator.zip -d ${process.env.ANDROID_HOME}`); yield exec.exec(`sudo unzip -q emulator.zip -d ${process.env.ANDROID_HOME}`);
yield exec.exec(`rm -f emulator.zip`); yield exec.exec(`sudo rm -f emulator.zip`);
} }
else { else {
console.log('Installing latest emulator.'); console.log('Installing latest emulator.');
+2742 -2007
View File
File diff suppressed because it is too large Load Diff
+4 -3
View File
@@ -23,7 +23,8 @@
"dependencies": { "dependencies": {
"@actions/core": "^1.0.0", "@actions/core": "^1.0.0",
"@actions/exec": "^1.0.1", "@actions/exec": "^1.0.1",
"@actions/tool-cache": "^1.1.2" "@actions/tool-cache": "^1.1.2",
"minimist": "^1.2.5"
}, },
"devDependencies": { "devDependencies": {
"@types/jest": "^24.0.13", "@types/jest": "^24.0.13",
@@ -34,8 +35,8 @@
"eslint-config-prettier": "^6.5.0", "eslint-config-prettier": "^6.5.0",
"eslint-plugin-import": "^2.18.2", "eslint-plugin-import": "^2.18.2",
"eslint-plugin-prettier": "^3.1.1", "eslint-plugin-prettier": "^3.1.1",
"jest": "^24.8.0", "jest": "^25.2.3",
"jest-circus": "^24.7.1", "jest-circus": "^25.2.3",
"prettier": "^1.18.2", "prettier": "^1.18.2",
"ts-jest": "^24.0.2", "ts-jest": "^24.0.2",
"typescript": "^3.5.1" "typescript": "^3.5.1"
+6
View File
@@ -17,6 +17,12 @@ export async function launchEmulator(apiLevel: number, target: string, arch: str
// start emulator // start emulator
console.log('Starting emulator.'); console.log('Starting emulator.');
// turn off hardware acceleration on Linux
if (process.platform === 'linux') {
emulatorOptions += ' -accel off';
}
await exec.exec(`sh -c \\"${process.env.ANDROID_HOME}/emulator/emulator -avd test ${emulatorOptions} &"`, [], { await exec.exec(`sh -c \\"${process.env.ANDROID_HOME}/emulator/emulator -avd test ${emulatorOptions} &"`, [], {
listeners: { listeners: {
stderr: (data: Buffer) => { stderr: (data: Buffer) => {
+10 -8
View File
@@ -7,9 +7,15 @@ import { parseScript } from './script-parser';
async function run() { async function run() {
try { try {
// only support running on macOS // only support running on macOS or Linux
if (process.platform !== 'darwin') { if (process.platform !== 'darwin') {
throw new Error('This action is expected to be run within a macOS virtual machine to enable hardware acceleration.'); if (process.platform === 'linux') {
console.warn(
`You're running a Linux VM where hardware acceleration is not available. Please consider using a macOS VM instead to take advantage of native hardware acceleration support provided by HAXM.`
);
} else {
throw new Error('Unsupported virtual machine: please use either macos or ubuntu VM.');
}
} }
// API level of the platform and system image // API level of the platform and system image
@@ -68,12 +74,8 @@ async function run() {
// install SDK // install SDK
await installAndroidSdk(apiLevel, target, arch, emulatorBuild); await installAndroidSdk(apiLevel, target, arch, emulatorBuild);
try { // launch an emulator
// launch an emulator await launchEmulator(apiLevel, target, arch, profile, emulatorOptions, disableAnimations);
await launchEmulator(apiLevel, target, arch, profile, emulatorOptions, disableAnimations);
} catch (error) {
core.setFailed(error.message);
}
// execute the custom script // execute the custom script
try { try {
+14 -9
View File
@@ -2,30 +2,35 @@ import * as core from '@actions/core';
import * as exec from '@actions/exec'; import * as exec from '@actions/exec';
const BUILD_TOOLS_VERSION = '29.0.3'; const BUILD_TOOLS_VERSION = '29.0.3';
const CMDLINE_TOOLS_URL = 'https://dl.google.com/android/repository/commandlinetools-linux-6200805_latest.zip'; const CMDLINE_TOOLS_URL_MAC = 'https://dl.google.com/android/repository/commandlinetools-linux-6200805_latest.zip';
const CMDLINE_TOOLS_URL_LINUX = 'https://dl.google.com/android/repository/commandlinetools-linux-6200805_latest.zip';
/** /**
* Installs & updates the Android SDK for the macOS platform, including SDK platform for the chosen API level, latest build tools, platform tools, Android Emulator, * Installs & updates the Android SDK for the macOS platform, including SDK platform for the chosen API level, latest build tools, platform tools, Android Emulator,
* and the system image for the chosen API level, CPU arch, and target. * and the system image for the chosen API level, CPU arch, and target.
*/ */
export async function installAndroidSdk(apiLevel: number, target: string, arch: string, emulatorBuild?: string): Promise<void> { export async function installAndroidSdk(apiLevel: number, target: string, arch: string, emulatorBuild?: string): Promise<void> {
const isOnMac = process.platform === 'darwin';
console.log('Installing new cmdline-tools.'); console.log('Installing new cmdline-tools.');
await exec.exec(`mkdir ${process.env.ANDROID_HOME}/cmdline-tools`); const sdkUrl = isOnMac ? CMDLINE_TOOLS_URL_MAC : CMDLINE_TOOLS_URL_LINUX;
await exec.exec(`curl -fo commandlinetools.zip ${CMDLINE_TOOLS_URL}`); await exec.exec(`sudo mkdir ${process.env.ANDROID_HOME}/cmdline-tools`);
await exec.exec(`unzip -q commandlinetools.zip -d ${process.env.ANDROID_HOME}/cmdline-tools`); await exec.exec(`curl -fo commandlinetools.zip ${sdkUrl}`);
await exec.exec(`rm -f commandlinetools.zip`); await exec.exec(`sudo unzip -q commandlinetools.zip -d ${process.env.ANDROID_HOME}/cmdline-tools`);
await exec.exec(`sudo rm -f commandlinetools.zip`);
// add paths for commandline-tools and platform-tools // add paths for commandline-tools and platform-tools
core.addPath(`${process.env.ANDROID_HOME}/cmdline-tools/tools:${process.env.ANDROID_HOME}/cmdline-tools/tools/bin:${process.env.ANDROID_HOME}/platform-tools`); core.addPath(`${process.env.ANDROID_HOME}/cmdline-tools/tools:${process.env.ANDROID_HOME}/cmdline-tools/tools/bin:${process.env.ANDROID_HOME}/platform-tools`);
await exec.exec(`sh -c \\"sudo chmod -R 777 ${process.env.ANDROID_HOME}"`);
console.log('Installing latest build tools, platform tools, and platform.'); console.log('Installing latest build tools, platform tools, and platform.');
await exec.exec(`sh -c \\"sdkmanager --install 'build-tools;${BUILD_TOOLS_VERSION}' platform-tools 'platforms;android-${apiLevel}' > /dev/null"`); await exec.exec(`sh -c \\"sdkmanager --install 'build-tools;${BUILD_TOOLS_VERSION}' platform-tools 'platforms;android-${apiLevel}' > /dev/null"`);
if (emulatorBuild) { if (emulatorBuild) {
console.log(`Installing emulator build ${emulatorBuild}.`); console.log(`Installing emulator build ${emulatorBuild}.`);
await exec.exec(`curl -fo emulator.zip https://dl.google.com/android/repository/emulator-darwin-${emulatorBuild}.zip`); await exec.exec(`curl -fo emulator.zip https://dl.google.com/android/repository/emulator-${isOnMac ? 'darwin' : 'linux'}-${emulatorBuild}.zip`);
await exec.exec(`rm -rf ${process.env.ANDROID_HOME}/emulator`); await exec.exec(`sudo rm -rf ${process.env.ANDROID_HOME}/emulator`);
await exec.exec(`unzip -q emulator.zip -d ${process.env.ANDROID_HOME}`); await exec.exec(`sudo unzip -q emulator.zip -d ${process.env.ANDROID_HOME}`);
await exec.exec(`rm -f emulator.zip`); await exec.exec(`sudo rm -f emulator.zip`);
} else { } else {
console.log('Installing latest emulator.'); console.log('Installing latest emulator.');
await exec.exec(`sh -c \\"sdkmanager --install emulator > /dev/null"`); await exec.exec(`sh -c \\"sdkmanager --install emulator > /dev/null"`);
+1 -1
View File
@@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-6.2.2-all.zip distributionUrl=https\://services.gradle.org/distributions/gradle-6.3-all.zip