Skip to content

Commit

Permalink
Add force-avd-creation to skip avd creation if avd with same name exi…
Browse files Browse the repository at this point in the history
…sts. Update workflow to test snapshot caching.
  • Loading branch information
ychescale9 committed Jun 18, 2021
1 parent 98e515d commit ee11183
Show file tree
Hide file tree
Showing 11 changed files with 143 additions and 29 deletions.
37 changes: 34 additions & 3 deletions .github/workflows/workflow.yml
Original file line number Diff line number Diff line change
Expand Up @@ -64,21 +64,52 @@ jobs:
~/.gradle/caches
~/.gradle/wrapper
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*') }}-${{ hashFiles('**/gradle/wrapper/gradle-wrapper.properties') }}
- uses: actions/cache@v2
id: avd-cache
with:
path: |
~/.android/avd/*
~/.android/adb*
~/.android/debug.keystore
key: avd-${{ matrix.api-level }}-${{ matrix.os }}-${{ matrix.target }}

- name: assemble tests
run: |
cd ./test-fixture/
./gradlew assembleAndroidTest
- name: run emulator to generate snapshot for caching
if: steps.avd-cache.outputs.cache-hit != 'true'
uses: ./
with:
api-level: ${{ matrix.api-level }}
target: ${{ matrix.target }}
arch: x86
profile: Galaxy Nexus
cores: 2
sdcard-path-or-size: 100M
avd-name: test
force-avd-creation: false
emulator-options: -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none
disable-animations: false
working-directory: ./test-fixture/
script: echo "Generated AVD snapshot for caching."

- name: run action
uses: ./
with:
api-level: ${{ matrix.api-level }}
target: ${{ matrix.target }}
arch: x86
profile: Nexus 6
profile: Galaxy Nexus
cores: 2
sdcard-path-or-size: 100M
avd-name: test
emulator-options: -no-window -gpu swiftshader_indirect -no-snapshot -noaudio -no-boot-anim -camera-back none
force-avd-creation: false
emulator-options: -no-snapshot-save -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none
disable-animations: true
working-directory: ./test-fixture/
script: |
echo $GITHUB_REPOSITORY
adb devices
./gradlew help
./gradlew connectedDebugAndroidTest
21 changes: 21 additions & 0 deletions __tests__/input-validator.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,27 @@ describe('arch validator tests', () => {
});
});

describe('force-avd-creation validator tests', () => {
it('Throws if force-avd-creation is not a boolean', () => {
const func = () => {
validator.checkForceAvdCreation('yes');
};
expect(func).toThrowError(`Input for input.force-avd-creation should be either 'true' or 'false'.`);
});

it('Validates successfully if force-avd-creation is either true or false', () => {
const func1 = () => {
validator.checkForceAvdCreation('true');
};
expect(func1).not.toThrow();

const func2 = () => {
validator.checkForceAvdCreation('false');
};
expect(func2).not.toThrow();
});
});

describe('disable-animations validator tests', () => {
it('Throws if disable-animations is not a boolean', () => {
const func = () => {
Expand Down
7 changes: 5 additions & 2 deletions action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,17 +24,20 @@ inputs:
avd-name:
description: 'custom AVD name used for creating the Android Virtual Device'
default: 'test'
force-avd-creation:
description: 'whether to force create the AVD by overwriting an existing AVD with the same name as `avd-name` - `true` or `false`'
default: 'true'
emulator-options:
description: 'command-line options used when launching the emulator - e.g. `-no-window -no-snapshot -camera-back emulated`'
default: '-no-window -gpu swiftshader_indirect -no-snapshot -noaudio -no-boot-anim'
disable-animations:
description: 'whether to disable animations - true or false'
default: 'true'
disable-spellchecker:
description: Whether to disable spellchecker - `true` or `false`.
description: 'whether to disable spellchecker - `true` or `false`'
default: 'false'
disable-linux-hw-accel:
description: Whether to disable hardware acceleration on Linux machines - `true` or `false`.
description: 'whether to disable hardware acceleration on Linux machines - `true` or `false`'
default: 'true'
emulator-build:
description: 'build number of a specific version of the emulator binary to use - e.g. `6061023` for emulator v29.3.0.0'
Expand Down
22 changes: 13 additions & 9 deletions lib/emulator-manager.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,27 +30,31 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
Object.defineProperty(exports, "__esModule", { value: true });
exports.killEmulator = exports.launchEmulator = void 0;
const exec = __importStar(require("@actions/exec"));
const fs = __importStar(require("fs"));
const EMULATOR_BOOT_TIMEOUT_SECONDS = 600;
/**
* Creates and launches a new AVD instance with the specified configurations.
*/
function launchEmulator(apiLevel, target, arch, profile, cores, sdcardPathOrSize, avdName, emulatorOptions, disableAnimations, disableSpellChecker, disableLinuxHardwareAcceleration) {
function launchEmulator(apiLevel, target, arch, profile, cores, sdcardPathOrSize, avdName, forceAvdCreation, emulatorOptions, disableAnimations, disableSpellChecker, disableLinuxHardwareAcceleration) {
return __awaiter(this, void 0, void 0, function* () {
// create a new AVD
const profileOption = profile.trim() !== '' ? `--device '${profile}'` : '';
const sdcardPathOrSizeOption = sdcardPathOrSize.trim() !== '' ? `--sdcard '${sdcardPathOrSize}'` : '';
console.log(`Creating AVD.`);
yield exec.exec(`sh -c \\"echo no | avdmanager create avd --force -n "${avdName}" --abi '${target}/${arch}' --package 'system-images;android-${apiLevel};${target};${arch}' ${profileOption} ${sdcardPathOrSizeOption}"`);
// create a new AVD if AVD directory does not already exist or forceAvdCreation is true
const avdPath = `${process.env.ANDROID_AVD_HOME}/${avdName}.avd`;
if (!fs.existsSync(avdPath) || forceAvdCreation) {
const profileOption = profile.trim() !== '' ? `--device '${profile}'` : '';
const sdcardPathOrSizeOption = sdcardPathOrSize.trim() !== '' ? `--sdcard '${sdcardPathOrSize}'` : '';
console.log(`Creating AVD.`);
yield exec.exec(`sh -c \\"echo no | avdmanager create avd --force -n "${avdName}" --abi '${target}/${arch}' --package 'system-images;android-${apiLevel};${target};${arch}' ${profileOption} ${sdcardPathOrSizeOption}"`);
}
if (cores) {
yield exec.exec(`sh -c \\"printf 'hw.cpu.ncore=${cores}\n' >> ~/.android/avd/"${avdName}".avd"/config.ini`);
yield exec.exec(`sh -c \\"printf 'hw.cpu.ncore=${cores}\n' >> ${process.env.ANDROID_AVD_HOME}/"${avdName}".avd"/config.ini`);
}
// start emulator
console.log('Starting emulator.');
//turn off hardware acceleration on Linux
if (process.platform === 'linux' && disableLinuxHardwareAcceleration) {
console.log('Disabling Linux hardware acceleration.');
emulatorOptions += ' -accel off';
}
// start emulator
console.log('Starting emulator.');
yield exec.exec(`sh -c \\"${process.env.ANDROID_SDK_ROOT}/emulator/emulator -avd "${avdName}" ${emulatorOptions} &"`, [], {
listeners: {
stderr: (data) => {
Expand Down
8 changes: 7 additions & 1 deletion lib/input-validator.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.checkEmulatorBuild = exports.checkDisableLinuxHardwareAcceleration = exports.checkDisableSpellchecker = exports.checkDisableAnimations = exports.checkArch = exports.checkTarget = exports.checkApiLevel = exports.VALID_ARCHS = exports.VALID_TARGETS = exports.MIN_API_LEVEL = void 0;
exports.checkEmulatorBuild = exports.checkDisableLinuxHardwareAcceleration = exports.checkDisableSpellchecker = exports.checkDisableAnimations = exports.checkForceAvdCreation = exports.checkArch = exports.checkTarget = exports.checkApiLevel = exports.VALID_ARCHS = exports.VALID_TARGETS = exports.MIN_API_LEVEL = void 0;
exports.MIN_API_LEVEL = 15;
exports.VALID_TARGETS = ['default', 'google_apis', 'google_apis_playstore'];
exports.VALID_ARCHS = ['x86', 'x86_64', 'arm64-v8a'];
Expand All @@ -25,6 +25,12 @@ function checkArch(arch) {
}
}
exports.checkArch = checkArch;
function checkForceAvdCreation(forceAvdCreation) {
if (!isValidBoolean(forceAvdCreation)) {
throw new Error(`Input for input.force-avd-creation should be either 'true' or 'false'.`);
}
}
exports.checkForceAvdCreation = checkForceAvdCreation;
function checkDisableAnimations(disableAnimations) {
if (!isValidBoolean(disableAnimations)) {
throw new Error(`Input for input.disable-animations should be either 'true' or 'false'.`);
Expand Down
7 changes: 6 additions & 1 deletion lib/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,11 @@ function run() {
// custom name used for creating the AVD
const avdName = core.getInput('avd-name');
console.log(`AVD name: ${avdName}`);
// force AVD creation
const forceAvdCreationInput = core.getInput('force-avd-creation');
input_validator_1.checkForceAvdCreation(forceAvdCreationInput);
const forceAvdCreation = forceAvdCreationInput === 'true';
console.log(`force avd creation: ${forceAvdCreation}`);
// emulator options
const emulatorOptions = core.getInput('emulator-options').trim();
console.log(`emulator options: ${emulatorOptions}`);
Expand Down Expand Up @@ -125,7 +130,7 @@ function run() {
// install SDK
yield sdk_installer_1.installAndroidSdk(apiLevel, target, arch, emulatorBuild, ndkVersion, cmakeVersion);
// launch an emulator
yield emulator_manager_1.launchEmulator(apiLevel, target, arch, profile, cores, sdcardPathOrSize, avdName, emulatorOptions, disableAnimations, disableSpellchecker, disableLinuxHardwareAcceleration);
yield emulator_manager_1.launchEmulator(apiLevel, target, arch, profile, cores, sdcardPathOrSize, avdName, forceAvdCreation, emulatorOptions, disableAnimations, disableSpellchecker, disableLinuxHardwareAcceleration);
// execute the custom script
try {
// move to custom working directory if set
Expand Down
2 changes: 2 additions & 0 deletions lib/sdk-installer.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ function installAndroidSdk(apiLevel, target, arch, emulatorBuild, ndkVersion, cm
}
// add paths for commandline-tools and platform-tools
core.addPath(`${cmdlineToolsPath}/latest:${cmdlineToolsPath}/latest/bin:${process.env.ANDROID_SDK_ROOT}/platform-tools`);
// set standard AVD path
core.exportVariable('ANDROID_AVD_HOME', `${process.env.HOME}/.android/avd`);
// additional permission and license requirements for Linux
const sdkPreviewLicensePath = `${process.env.ANDROID_SDK_ROOT}/licenses/android-sdk-preview-license`;
if (!isOnMac && !fs.existsSync(sdkPreviewLicensePath)) {
Expand Down
27 changes: 16 additions & 11 deletions src/emulator-manager.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import * as exec from '@actions/exec';
import * as fs from 'fs';

const EMULATOR_BOOT_TIMEOUT_SECONDS = 600;

Expand All @@ -13,32 +14,36 @@ export async function launchEmulator(
cores: string,
sdcardPathOrSize: string,
avdName: string,
forceAvdCreation: boolean,
emulatorOptions: string,
disableAnimations: boolean,
disableSpellChecker: boolean,
disableLinuxHardwareAcceleration: boolean
): Promise<void> {
// create a new AVD
const profileOption = profile.trim() !== '' ? `--device '${profile}'` : '';
const sdcardPathOrSizeOption = sdcardPathOrSize.trim() !== '' ? `--sdcard '${sdcardPathOrSize}'` : '';
console.log(`Creating AVD.`);
await exec.exec(
`sh -c \\"echo no | avdmanager create avd --force -n "${avdName}" --abi '${target}/${arch}' --package 'system-images;android-${apiLevel};${target};${arch}' ${profileOption} ${sdcardPathOrSizeOption}"`
);
// create a new AVD if AVD directory does not already exist or forceAvdCreation is true
const avdPath = `${process.env.ANDROID_AVD_HOME}/${avdName}.avd`;
if (!fs.existsSync(avdPath) || forceAvdCreation) {
const profileOption = profile.trim() !== '' ? `--device '${profile}'` : '';
const sdcardPathOrSizeOption = sdcardPathOrSize.trim() !== '' ? `--sdcard '${sdcardPathOrSize}'` : '';
console.log(`Creating AVD.`);
await exec.exec(
`sh -c \\"echo no | avdmanager create avd --force -n "${avdName}" --abi '${target}/${arch}' --package 'system-images;android-${apiLevel};${target};${arch}' ${profileOption} ${sdcardPathOrSizeOption}"`
);
}

if (cores) {
await exec.exec(`sh -c \\"printf 'hw.cpu.ncore=${cores}\n' >> ~/.android/avd/"${avdName}".avd"/config.ini`);
await exec.exec(`sh -c \\"printf 'hw.cpu.ncore=${cores}\n' >> ${process.env.ANDROID_AVD_HOME}/"${avdName}".avd"/config.ini`);
}

// start emulator
console.log('Starting emulator.');

//turn off hardware acceleration on Linux
if (process.platform === 'linux' && disableLinuxHardwareAcceleration) {
console.log('Disabling Linux hardware acceleration.');
emulatorOptions += ' -accel off';
}

// start emulator
console.log('Starting emulator.');

await exec.exec(`sh -c \\"${process.env.ANDROID_SDK_ROOT}/emulator/emulator -avd "${avdName}" ${emulatorOptions} &"`, [], {
listeners: {
stderr: (data: Buffer) => {
Expand Down
6 changes: 6 additions & 0 deletions src/input-validator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,12 @@ export function checkArch(arch: string): void {
}
}

export function checkForceAvdCreation(forceAvdCreation: string): void {
if (!isValidBoolean(forceAvdCreation)) {
throw new Error(`Input for input.force-avd-creation should be either 'true' or 'false'.`);
}
}

export function checkDisableAnimations(disableAnimations: string): void {
if (!isValidBoolean(disableAnimations)) {
throw new Error(`Input for input.disable-animations should be either 'true' or 'false'.`);
Expand Down
32 changes: 30 additions & 2 deletions src/main.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,15 @@
import * as core from '@actions/core';
import { installAndroidSdk } from './sdk-installer';
import { checkApiLevel, checkTarget, checkArch, checkDisableAnimations, checkEmulatorBuild, checkDisableSpellchecker, checkDisableLinuxHardwareAcceleration } from './input-validator';
import {
checkApiLevel,
checkTarget,
checkArch,
checkDisableAnimations,
checkEmulatorBuild,
checkDisableSpellchecker,
checkDisableLinuxHardwareAcceleration,
checkForceAvdCreation
} from './input-validator';
import { launchEmulator, killEmulator } from './emulator-manager';
import * as exec from '@actions/exec';
import { parseScript } from './script-parser';
Expand Down Expand Up @@ -51,6 +60,12 @@ async function run() {
const avdName = core.getInput('avd-name');
console.log(`AVD name: ${avdName}`);

// force AVD creation
const forceAvdCreationInput = core.getInput('force-avd-creation');
checkForceAvdCreation(forceAvdCreationInput);
const forceAvdCreation = forceAvdCreationInput === 'true';
console.log(`force avd creation: ${forceAvdCreation}`);

// emulator options
const emulatorOptions = core.getInput('emulator-options').trim();
console.log(`emulator options: ${emulatorOptions}`);
Expand Down Expand Up @@ -114,7 +129,20 @@ async function run() {
await installAndroidSdk(apiLevel, target, arch, emulatorBuild, ndkVersion, cmakeVersion);

// launch an emulator
await launchEmulator(apiLevel, target, arch, profile, cores, sdcardPathOrSize, avdName, emulatorOptions, disableAnimations, disableSpellchecker, disableLinuxHardwareAcceleration);
await launchEmulator(
apiLevel,
target,
arch,
profile,
cores,
sdcardPathOrSize,
avdName,
forceAvdCreation,
emulatorOptions,
disableAnimations,
disableSpellchecker,
disableLinuxHardwareAcceleration
);

// execute the custom script
try {
Expand Down
3 changes: 3 additions & 0 deletions src/sdk-installer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ export async function installAndroidSdk(apiLevel: number, target: string, arch:
// add paths for commandline-tools and platform-tools
core.addPath(`${cmdlineToolsPath}/latest:${cmdlineToolsPath}/latest/bin:${process.env.ANDROID_SDK_ROOT}/platform-tools`);

// set standard AVD path
core.exportVariable('ANDROID_AVD_HOME', `${process.env.HOME}/.android/avd`);

// additional permission and license requirements for Linux
const sdkPreviewLicensePath = `${process.env.ANDROID_SDK_ROOT}/licenses/android-sdk-preview-license`;
if (!isOnMac && !fs.existsSync(sdkPreviewLicensePath)) {
Expand Down

0 comments on commit ee11183

Please sign in to comment.