mirror of
https://github.com/reactivecircus/android-emulator-runner.git
synced 2026-09-01 01:59:32 +00:00
Compare commits
17 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 94bd1ed921 | |||
| c3e261e13b | |||
| 434e949c3b | |||
| 70e3f6e680 | |||
| 0d8602fe47 | |||
| 28373d3d4f | |||
| 02cf805290 | |||
| 045b7d8c5e | |||
| b0f3c521a5 | |||
| 308aa234e1 | |||
| d4b3926c7d | |||
| 877a4c47c3 | |||
| e08f702234 | |||
| 11559ab158 | |||
| b5ac8dfbfe | |||
| ad97647a61 | |||
| 4690ba2920 |
@@ -36,6 +36,9 @@ jobs:
|
||||
- os: macos-latest
|
||||
api-level: 24
|
||||
target: playstore
|
||||
- os: macos-latest
|
||||
api-level: 28
|
||||
target: google_apis
|
||||
|
||||
steps:
|
||||
- name: checkout
|
||||
@@ -68,6 +71,7 @@ jobs:
|
||||
target: ${{ matrix.target }}
|
||||
arch: x86
|
||||
profile: Nexus 6
|
||||
sdcard-path-or-size: 100M
|
||||
avd-name: test
|
||||
emulator-options: -no-window -gpu swiftshader_indirect -no-snapshot -noaudio -no-boot-anim -camera-back none
|
||||
disable-animations: true
|
||||
|
||||
@@ -1,5 +1,23 @@
|
||||
# Change Log
|
||||
|
||||
## v2.14.2
|
||||
|
||||
* Support API 28 system images with `google_apis` or `google_apis_playstore` target - [#117](https://github.com/ReactiveCircus/android-emulator-runner/pull/117).
|
||||
|
||||
## v2.14.1
|
||||
|
||||
* Fix hang during AVD creation when `profile` is not specified - [#113](https://github.com/ReactiveCircus/android-emulator-runner/issues/113).
|
||||
|
||||
## v2.14.0
|
||||
|
||||
* Support specifying SD card path or size via `sdcard-path-or-size`.
|
||||
* Update npm packages.
|
||||
* Remove usages of deprecated `$ANDROID_HOME`.
|
||||
|
||||
## v2.13.0
|
||||
|
||||
* Updated to SDK command-line tools `3.0`.
|
||||
|
||||
## v2.12.0
|
||||
|
||||
Added support for using the `playstore` system images:
|
||||
|
||||
@@ -92,6 +92,7 @@ jobs:
|
||||
| `target` | Optional | `default` | Target of the system image - `default`, `google_apis` or `playstore`. |
|
||||
| `arch` | Optional | `x86` | CPU architecture of the system image - `x86` or `x86_64`. Note that `x86_64` image is only available for API 21+. |
|
||||
| `profile` | Optional | N/A | Hardware profile used for creating the AVD - e.g. `Nexus 6`. For a list of all profiles available, run `avdmanager list` and refer to the results under "Available Android Virtual Devices". |
|
||||
| `sdcard-path-or-size` | Optional | N/A | Path to the SD card image for this AVD or the size of a new SD card image to create for this AVD, in KB or MB, denoted with K or M. - e.g. `path/to/sdcard`, or `1000M`. |
|
||||
| `avd-name` | Optional | `test` | Custom AVD name used for creating the Android Virtual Device. |
|
||||
| `emulator-options` | Optional | See below | Command-line options used when launching the emulator (replacing all default options) - e.g. `-no-window -no-snapshot -camera-back emulated`. |
|
||||
| `disable-animations` | Optional | `true` | Whether to disable animations - `true` or `false`. |
|
||||
@@ -122,7 +123,7 @@ These are some of the open-source projects using (or used) **Android Emulator Ru
|
||||
- [natario1/Transcoder](https://github.com/natario1/Transcoder/tree/master/.github/workflows)
|
||||
- [chrisbanes/insetter](https://github.com/chrisbanes/insetter/tree/main/.github/workflows)
|
||||
- [slackhq/keeper](https://github.com/slackhq/keeper/tree/main/.github/workflows)
|
||||
- [android/compose-samples](https://github.com/android/compose-samples/blob/master/.github/workflows/ci.yaml)
|
||||
- [android/compose-samples](https://github.com/android/compose-samples/tree/main/.github/workflows)
|
||||
- [ReactiveCircus/streamlined](https://github.com/ReactiveCircus/streamlined/tree/main/.github/workflows)
|
||||
- [ReactiveCircus/FlowBinding](https://github.com/ReactiveCircus/FlowBinding)
|
||||
- [JakeWharton/RxBinding](https://github.com/JakeWharton/RxBinding/tree/master/.github/workflows)
|
||||
@@ -132,5 +133,6 @@ These are some of the open-source projects using (or used) **Android Emulator Ru
|
||||
- [simpledotorg/simple-android](https://github.com/simpledotorg/simple-android)
|
||||
- [cashapp/copper](https://github.com/cashapp/copper/blob/trunk/.github/workflows/build.yaml)
|
||||
- [square/radiography](https://github.com/square/radiography/blob/main/.github/workflows/android.yml)
|
||||
- [Shopify/android-testify](https://github.com/Shopify/android-testify/blob/master/.github/workflows/sample_build.yml)
|
||||
|
||||
If you are using **Android Emulator Runner** and want your project included in the list, please feel free to create an issue or open a pull request.
|
||||
|
||||
@@ -16,6 +16,8 @@ inputs:
|
||||
default: 'x86'
|
||||
profile:
|
||||
description: 'hardware profile used for creating the AVD - e.g. `Nexus 6`'
|
||||
sdcard-path-or-size:
|
||||
description: 'path to the SD card image for this AVD or the size of a new SD card image to create for this AVD, in KB or MB, denoted with K or M. - e.g. `path/to/sdcard`, or `1000M`'
|
||||
avd-name:
|
||||
description: 'custom AVD name used for creating the Android Virtual Device'
|
||||
default: 'test'
|
||||
|
||||
+6
-10
@@ -34,24 +34,20 @@ const EMULATOR_BOOT_TIMEOUT_SECONDS = 600;
|
||||
/**
|
||||
* Creates and launches a new AVD instance with the specified configurations.
|
||||
*/
|
||||
function launchEmulator(apiLevel, target, arch, profile, avdName, emulatorOptions, disableAnimations) {
|
||||
function launchEmulator(apiLevel, target, arch, profile, sdcardPathOrSize, avdName, emulatorOptions, disableAnimations) {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
// create a new AVD
|
||||
if (profile.trim() !== '') {
|
||||
console.log(`Creating AVD with custom profile ${profile}`);
|
||||
yield exec.exec(`avdmanager create avd --force -n "${avdName}" --abi "${target}/${arch}" --package "system-images;android-${apiLevel};${target};${arch}" --device "${profile}"`);
|
||||
}
|
||||
else {
|
||||
console.log(`Creating AVD without custom profile.`);
|
||||
yield exec.exec(`sh -c \\"echo no | avdmanager create avd --force -n "${avdName}" --abi '${target}/${arch}' --package 'system-images;android-${apiLevel};${target};${arch}'"`);
|
||||
}
|
||||
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}"`);
|
||||
// start 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 "${avdName}" ${emulatorOptions} &"`, [], {
|
||||
yield exec.exec(`sh -c \\"${process.env.ANDROID_SDK_ROOT}/emulator/emulator -avd "${avdName}" ${emulatorOptions} &"`, [], {
|
||||
listeners: {
|
||||
stderr: (data) => {
|
||||
if (data.toString().includes('invalid command-line parameter')) {
|
||||
|
||||
+4
-1
@@ -63,6 +63,9 @@ function run() {
|
||||
// Hardware profile used for creating the AVD
|
||||
const profile = core.getInput('profile');
|
||||
console.log(`Hardware profile: ${profile}`);
|
||||
// SD card path or size used for creating the AVD
|
||||
const sdcardPathOrSize = core.getInput('sdcard-path-or-size');
|
||||
console.log(`SD card path or size: ${sdcardPathOrSize}`);
|
||||
// custom name used for creating the AVD
|
||||
const avdName = core.getInput('avd-name');
|
||||
console.log(`AVD name: ${avdName}`);
|
||||
@@ -109,7 +112,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, avdName, emulatorOptions, disableAnimations);
|
||||
yield emulator_manager_1.launchEmulator(apiLevel, target, arch, profile, sdcardPathOrSize, avdName, emulatorOptions, disableAnimations);
|
||||
// execute the custom script
|
||||
try {
|
||||
// move to custom working directory if set
|
||||
|
||||
+19
-16
@@ -32,10 +32,11 @@ exports.installAndroidSdk = void 0;
|
||||
const core = __importStar(require("@actions/core"));
|
||||
const exec = __importStar(require("@actions/exec"));
|
||||
const io = __importStar(require("@actions/io"));
|
||||
const tc = __importStar(require("@actions/tool-cache"));
|
||||
const fs = __importStar(require("fs"));
|
||||
const BUILD_TOOLS_VERSION = '30.0.2';
|
||||
const CMDLINE_TOOLS_URL_MAC = 'https://dl.google.com/android/repository/commandlinetools-mac-6609375_latest.zip';
|
||||
const CMDLINE_TOOLS_URL_LINUX = 'https://dl.google.com/android/repository/commandlinetools-linux-6609375_latest.zip';
|
||||
const BUILD_TOOLS_VERSION = '30.0.3';
|
||||
const CMDLINE_TOOLS_URL_MAC = 'https://dl.google.com/android/repository/commandlinetools-mac-6858069_latest.zip';
|
||||
const CMDLINE_TOOLS_URL_LINUX = 'https://dl.google.com/android/repository/commandlinetools-linux-6858069_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,
|
||||
* and the system image for the chosen API level, CPU arch, and target.
|
||||
@@ -44,27 +45,26 @@ function installAndroidSdk(apiLevel, target, arch, emulatorBuild, ndkVersion, cm
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
const isOnMac = process.platform === 'darwin';
|
||||
if (!isOnMac) {
|
||||
yield exec.exec(`sh -c \\"sudo chown $USER:$USER ${process.env.ANDROID_HOME} -R`);
|
||||
yield exec.exec(`sh -c \\"sudo chown $USER:$USER ${process.env.ANDROID_SDK_ROOT} -R`);
|
||||
}
|
||||
const cmdlineToolsPath = `${process.env.ANDROID_HOME}/cmdline-tools`;
|
||||
const cmdlineToolsPath = `${process.env.ANDROID_SDK_ROOT}/cmdline-tools`;
|
||||
if (!fs.existsSync(cmdlineToolsPath)) {
|
||||
console.log('Installing new cmdline-tools.');
|
||||
const sdkUrl = isOnMac ? CMDLINE_TOOLS_URL_MAC : CMDLINE_TOOLS_URL_LINUX;
|
||||
yield io.mkdirP(`${process.env.ANDROID_HOME}/cmdline-tools`);
|
||||
yield exec.exec(`curl -fo commandlinetools.zip ${sdkUrl}`);
|
||||
yield exec.exec(`unzip -q commandlinetools.zip -d ${cmdlineToolsPath}`);
|
||||
yield io.rmRF('commandlinetools.zip');
|
||||
const downloadPath = yield tc.downloadTool(sdkUrl);
|
||||
yield tc.extractZip(downloadPath, cmdlineToolsPath);
|
||||
yield io.mv(`${cmdlineToolsPath}/cmdline-tools`, `${cmdlineToolsPath}/latest`);
|
||||
// add paths for commandline-tools and platform-tools
|
||||
core.addPath(`${cmdlineToolsPath}/tools:${cmdlineToolsPath}/tools/bin:${process.env.ANDROID_HOME}/platform-tools`);
|
||||
core.addPath(`${cmdlineToolsPath}/latest:${cmdlineToolsPath}/latest/bin:${process.env.ANDROID_SDK_ROOT}/platform-tools`);
|
||||
}
|
||||
// additional permission and license requirements for Linux
|
||||
const sdkPreviewLicensePath = `${process.env.ANDROID_HOME}/licenses/android-sdk-preview-license`;
|
||||
const sdkPreviewLicensePath = `${process.env.ANDROID_SDK_ROOT}/licenses/android-sdk-preview-license`;
|
||||
if (!isOnMac && !fs.existsSync(sdkPreviewLicensePath)) {
|
||||
fs.writeFileSync(sdkPreviewLicensePath, '\n84831b9409646a918e30573bab4c9c91346d8abd');
|
||||
}
|
||||
// license required for API 30 system images
|
||||
const sdkArmDbtLicensePath = `${process.env.ANDROID_HOME}/licenses/android-sdk-arm-dbt-license`;
|
||||
if (apiLevel == 30 && !fs.existsSync(sdkArmDbtLicensePath)) {
|
||||
// license required for API 30 and non-default API 28 system images
|
||||
const sdkArmDbtLicensePath = `${process.env.ANDROID_SDK_ROOT}/licenses/android-sdk-arm-dbt-license`;
|
||||
if (requiresArmDbtLicense(apiLevel, target) && !fs.existsSync(sdkArmDbtLicensePath)) {
|
||||
fs.writeFileSync(sdkArmDbtLicensePath, '\n859f317696f67ef3d7f30a50a5560e7834b43903');
|
||||
}
|
||||
console.log('Installing latest build tools, platform tools, and platform.');
|
||||
@@ -72,8 +72,8 @@ function installAndroidSdk(apiLevel, target, arch, emulatorBuild, ndkVersion, cm
|
||||
if (emulatorBuild) {
|
||||
console.log(`Installing emulator build ${emulatorBuild}.`);
|
||||
yield exec.exec(`curl -fo emulator.zip https://dl.google.com/android/repository/emulator-${isOnMac ? 'darwin' : 'linux'}-${emulatorBuild}.zip`);
|
||||
yield io.rmRF(`${process.env.ANDROID_HOME}/emulator`);
|
||||
yield exec.exec(`unzip -q emulator.zip -d ${process.env.ANDROID_HOME}`);
|
||||
yield io.rmRF(`${process.env.ANDROID_SDK_ROOT}/emulator`);
|
||||
yield exec.exec(`unzip -q emulator.zip -d ${process.env.ANDROID_SDK_ROOT}`);
|
||||
yield io.rmRF('emulator.zip');
|
||||
}
|
||||
else {
|
||||
@@ -93,3 +93,6 @@ function installAndroidSdk(apiLevel, target, arch, emulatorBuild, ndkVersion, cm
|
||||
});
|
||||
}
|
||||
exports.installAndroidSdk = installAndroidSdk;
|
||||
function requiresArmDbtLicense(apiLevel, target) {
|
||||
return apiLevel === 30 || (apiLevel === 28 && target !== 'default');
|
||||
}
|
||||
|
||||
+7
-1
@@ -1,5 +1,11 @@
|
||||
## Releases
|
||||
|
||||
## 1.0.9
|
||||
Throw HttpClientError instead of a generic Error from the \<verb>Json() helper methods when the server responds with a non-successful status code.
|
||||
|
||||
## 1.0.8
|
||||
Fixed security issue where a redirect (e.g. 302) to another domain would pass headers. The fix was to strip the authorization header if the hostname was different. More [details in PR #27](https://github.com/actions/http-client/pull/27)
|
||||
|
||||
## 1.0.7
|
||||
Update NPM dependencies and add 429 to the list of HttpCodes
|
||||
|
||||
@@ -13,4 +19,4 @@ Adds \<verb>Json() helper methods for json over http scenarios.
|
||||
Started to add \<verb>Json() helper methods. Do not use this release for that. Use >= 1.0.5 since there was an issue with types.
|
||||
|
||||
## 1.0.1 to 1.0.3
|
||||
Adds proxy support.
|
||||
Adds proxy support.
|
||||
|
||||
+5
@@ -42,6 +42,11 @@ export declare enum MediaTypes {
|
||||
* @param serverUrl The server URL where the request will be sent. For example, https://api.github.com
|
||||
*/
|
||||
export declare function getProxyUrl(serverUrl: string): string;
|
||||
export declare class HttpClientError extends Error {
|
||||
constructor(message: string, statusCode: number);
|
||||
statusCode: number;
|
||||
result?: any;
|
||||
}
|
||||
export declare class HttpClientResponse implements ifm.IHttpClientResponse {
|
||||
constructor(message: http.IncomingMessage);
|
||||
message: http.IncomingMessage;
|
||||
|
||||
+17
-13
@@ -1,6 +1,5 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const url = require("url");
|
||||
const http = require("http");
|
||||
const https = require("https");
|
||||
const pm = require("./proxy");
|
||||
@@ -49,7 +48,7 @@ var MediaTypes;
|
||||
* @param serverUrl The server URL where the request will be sent. For example, https://api.github.com
|
||||
*/
|
||||
function getProxyUrl(serverUrl) {
|
||||
let proxyUrl = pm.getProxyUrl(url.parse(serverUrl));
|
||||
let proxyUrl = pm.getProxyUrl(new URL(serverUrl));
|
||||
return proxyUrl ? proxyUrl.href : '';
|
||||
}
|
||||
exports.getProxyUrl = getProxyUrl;
|
||||
@@ -68,6 +67,15 @@ const HttpResponseRetryCodes = [
|
||||
const RetryableHttpVerbs = ['OPTIONS', 'GET', 'DELETE', 'HEAD'];
|
||||
const ExponentialBackoffCeiling = 10;
|
||||
const ExponentialBackoffTimeSlice = 5;
|
||||
class HttpClientError extends Error {
|
||||
constructor(message, statusCode) {
|
||||
super(message);
|
||||
this.name = 'HttpClientError';
|
||||
this.statusCode = statusCode;
|
||||
Object.setPrototypeOf(this, HttpClientError.prototype);
|
||||
}
|
||||
}
|
||||
exports.HttpClientError = HttpClientError;
|
||||
class HttpClientResponse {
|
||||
constructor(message) {
|
||||
this.message = message;
|
||||
@@ -86,7 +94,7 @@ class HttpClientResponse {
|
||||
}
|
||||
exports.HttpClientResponse = HttpClientResponse;
|
||||
function isHttps(requestUrl) {
|
||||
let parsedUrl = url.parse(requestUrl);
|
||||
let parsedUrl = new URL(requestUrl);
|
||||
return parsedUrl.protocol === 'https:';
|
||||
}
|
||||
exports.isHttps = isHttps;
|
||||
@@ -191,7 +199,7 @@ class HttpClient {
|
||||
if (this._disposed) {
|
||||
throw new Error('Client has already been disposed.');
|
||||
}
|
||||
let parsedUrl = url.parse(requestUrl);
|
||||
let parsedUrl = new URL(requestUrl);
|
||||
let info = this._prepareRequest(verb, parsedUrl, headers);
|
||||
// Only perform retries on reads since writes may not be idempotent.
|
||||
let maxTries = this._allowRetries && RetryableHttpVerbs.indexOf(verb) != -1
|
||||
@@ -230,7 +238,7 @@ class HttpClient {
|
||||
// if there's no location to redirect to, we won't
|
||||
break;
|
||||
}
|
||||
let parsedRedirectUrl = url.parse(redirectUrl);
|
||||
let parsedRedirectUrl = new URL(redirectUrl);
|
||||
if (parsedUrl.protocol == 'https:' &&
|
||||
parsedUrl.protocol != parsedRedirectUrl.protocol &&
|
||||
!this._allowRedirectDowngrade) {
|
||||
@@ -346,7 +354,7 @@ class HttpClient {
|
||||
* @param serverUrl The server URL where the request will be sent. For example, https://api.github.com
|
||||
*/
|
||||
getAgent(serverUrl) {
|
||||
let parsedUrl = url.parse(serverUrl);
|
||||
let parsedUrl = new URL(serverUrl);
|
||||
return this._getAgent(parsedUrl);
|
||||
}
|
||||
_prepareRequest(method, requestUrl, headers) {
|
||||
@@ -419,7 +427,7 @@ class HttpClient {
|
||||
maxSockets: maxSockets,
|
||||
keepAlive: this._keepAlive,
|
||||
proxy: {
|
||||
proxyAuth: proxyUrl.auth,
|
||||
proxyAuth: `${proxyUrl.username}:${proxyUrl.password}`,
|
||||
host: proxyUrl.hostname,
|
||||
port: proxyUrl.port
|
||||
}
|
||||
@@ -514,12 +522,8 @@ class HttpClient {
|
||||
else {
|
||||
msg = 'Failed request: (' + statusCode + ')';
|
||||
}
|
||||
let err = new Error(msg);
|
||||
// attach statusCode and body obj (if available) to the error object
|
||||
err['statusCode'] = statusCode;
|
||||
if (response.result) {
|
||||
err['result'] = response.result;
|
||||
}
|
||||
let err = new HttpClientError(msg, statusCode);
|
||||
err.result = response.result;
|
||||
reject(err);
|
||||
}
|
||||
else {
|
||||
|
||||
+1
-2
@@ -1,6 +1,5 @@
|
||||
/// <reference types="node" />
|
||||
import http = require('http');
|
||||
import url = require('url');
|
||||
export interface IHeaders {
|
||||
[key: string]: any;
|
||||
}
|
||||
@@ -27,7 +26,7 @@ export interface IHttpClientResponse {
|
||||
}
|
||||
export interface IRequestInfo {
|
||||
options: http.RequestOptions;
|
||||
parsedUrl: url.Url;
|
||||
parsedUrl: URL;
|
||||
httpModule: any;
|
||||
}
|
||||
export interface IRequestOptions {
|
||||
|
||||
+12
-12
@@ -1,33 +1,33 @@
|
||||
{
|
||||
"_args": [
|
||||
[
|
||||
"@actions/http-client@1.0.8",
|
||||
"/Users/yang/Desktop/Projects/android-emulator-runner"
|
||||
"@actions/http-client@1.0.9",
|
||||
"."
|
||||
]
|
||||
],
|
||||
"_from": "@actions/http-client@1.0.8",
|
||||
"_id": "@actions/http-client@1.0.8",
|
||||
"_from": "@actions/http-client@1.0.9",
|
||||
"_id": "@actions/http-client@1.0.9",
|
||||
"_inBundle": false,
|
||||
"_integrity": "sha512-G4JjJ6f9Hb3Zvejj+ewLLKLf99ZC+9v+yCxoYf9vSyH+WkzPLB2LuUtRMGNkooMqdugGBFStIKXOuvH1W+EctA==",
|
||||
"_integrity": "sha512-0O4SsJ7q+MK0ycvXPl2e6bMXV7dxAXOGjrXS1eTF9s2S401Tp6c/P3c3Joz04QefC1J6Gt942Wl2jbm3f4mLcg==",
|
||||
"_location": "/@actions/http-client",
|
||||
"_phantomChildren": {},
|
||||
"_requested": {
|
||||
"type": "version",
|
||||
"registry": true,
|
||||
"raw": "@actions/http-client@1.0.8",
|
||||
"raw": "@actions/http-client@1.0.9",
|
||||
"name": "@actions/http-client",
|
||||
"escapedName": "@actions%2fhttp-client",
|
||||
"scope": "@actions",
|
||||
"rawSpec": "1.0.8",
|
||||
"rawSpec": "1.0.9",
|
||||
"saveSpec": null,
|
||||
"fetchSpec": "1.0.8"
|
||||
"fetchSpec": "1.0.9"
|
||||
},
|
||||
"_requiredBy": [
|
||||
"/@actions/tool-cache"
|
||||
],
|
||||
"_resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-1.0.8.tgz",
|
||||
"_spec": "1.0.8",
|
||||
"_where": "/Users/yang/Desktop/Projects/android-emulator-runner",
|
||||
"_resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-1.0.9.tgz",
|
||||
"_spec": "1.0.9",
|
||||
"_where": ".",
|
||||
"author": {
|
||||
"name": "GitHub, Inc."
|
||||
},
|
||||
@@ -66,5 +66,5 @@
|
||||
"format-check": "prettier --check *.ts && prettier --check **/*.ts",
|
||||
"test": "jest"
|
||||
},
|
||||
"version": "1.0.8"
|
||||
"version": "1.0.9"
|
||||
}
|
||||
|
||||
+2
-4
@@ -1,4 +1,2 @@
|
||||
/// <reference types="node" />
|
||||
import * as url from 'url';
|
||||
export declare function getProxyUrl(reqUrl: url.Url): url.Url | undefined;
|
||||
export declare function checkBypass(reqUrl: url.Url): boolean;
|
||||
export declare function getProxyUrl(reqUrl: URL): URL | undefined;
|
||||
export declare function checkBypass(reqUrl: URL): boolean;
|
||||
|
||||
+1
-2
@@ -1,6 +1,5 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const url = require("url");
|
||||
function getProxyUrl(reqUrl) {
|
||||
let usingSsl = reqUrl.protocol === 'https:';
|
||||
let proxyUrl;
|
||||
@@ -15,7 +14,7 @@ function getProxyUrl(reqUrl) {
|
||||
proxyVar = process.env['http_proxy'] || process.env['HTTP_PROXY'];
|
||||
}
|
||||
if (proxyVar) {
|
||||
proxyUrl = url.parse(proxyVar);
|
||||
proxyUrl = new URL(proxyVar);
|
||||
}
|
||||
return proxyUrl;
|
||||
}
|
||||
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright 2019 GitHub
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
+12
-12
@@ -1,38 +1,38 @@
|
||||
{
|
||||
"_args": [
|
||||
[
|
||||
"@actions/tool-cache@1.6.0",
|
||||
"@actions/tool-cache@1.6.1",
|
||||
"."
|
||||
]
|
||||
],
|
||||
"_from": "@actions/tool-cache@1.6.0",
|
||||
"_id": "@actions/tool-cache@1.6.0",
|
||||
"_from": "@actions/tool-cache@1.6.1",
|
||||
"_id": "@actions/tool-cache@1.6.1",
|
||||
"_inBundle": false,
|
||||
"_integrity": "sha512-+fyEBImPD3m5I0o6DflCO0NHY180LPoX8Lo6y4Iez+V17kO8kfkH0VHxb8mUdmD6hn9dWA9Ch1JA20fXoIYUeQ==",
|
||||
"_integrity": "sha512-F+vwEDwfqcHMKuSkj79pihOnsAMv23EkG76nMpc82UsnXwyQdyEsktGxrB0SNtm7pRqTXEIOoAPTgrSQclXYTg==",
|
||||
"_location": "/@actions/tool-cache",
|
||||
"_phantomChildren": {},
|
||||
"_requested": {
|
||||
"type": "version",
|
||||
"registry": true,
|
||||
"raw": "@actions/tool-cache@1.6.0",
|
||||
"raw": "@actions/tool-cache@1.6.1",
|
||||
"name": "@actions/tool-cache",
|
||||
"escapedName": "@actions%2ftool-cache",
|
||||
"scope": "@actions",
|
||||
"rawSpec": "1.6.0",
|
||||
"rawSpec": "1.6.1",
|
||||
"saveSpec": null,
|
||||
"fetchSpec": "1.6.0"
|
||||
"fetchSpec": "1.6.1"
|
||||
},
|
||||
"_requiredBy": [
|
||||
"/"
|
||||
],
|
||||
"_resolved": "https://registry.npmjs.org/@actions/tool-cache/-/tool-cache-1.6.0.tgz",
|
||||
"_spec": "1.6.0",
|
||||
"_resolved": "https://registry.npmjs.org/@actions/tool-cache/-/tool-cache-1.6.1.tgz",
|
||||
"_spec": "1.6.1",
|
||||
"_where": ".",
|
||||
"bugs": {
|
||||
"url": "https://github.com/actions/toolkit/issues"
|
||||
},
|
||||
"dependencies": {
|
||||
"@actions/core": "^1.2.3",
|
||||
"@actions/core": "^1.2.6",
|
||||
"@actions/exec": "^1.0.0",
|
||||
"@actions/http-client": "^1.0.8",
|
||||
"@actions/io": "^1.0.1",
|
||||
@@ -54,7 +54,7 @@
|
||||
"lib",
|
||||
"scripts"
|
||||
],
|
||||
"homepage": "https://github.com/actions/toolkit/tree/master/packages/tool-cache",
|
||||
"homepage": "https://github.com/actions/toolkit/tree/main/packages/tool-cache",
|
||||
"keywords": [
|
||||
"github",
|
||||
"actions",
|
||||
@@ -77,5 +77,5 @@
|
||||
"tsc": "tsc"
|
||||
},
|
||||
"types": "lib/tool-cache.d.ts",
|
||||
"version": "1.6.0"
|
||||
"version": "1.6.1"
|
||||
}
|
||||
|
||||
Generated
+2901
-326
File diff suppressed because it is too large
Load Diff
+6
-6
@@ -23,22 +23,22 @@
|
||||
"dependencies": {
|
||||
"@actions/core": "^1.2.6",
|
||||
"@actions/exec": "^1.0.4",
|
||||
"@actions/tool-cache": "^1.6.0",
|
||||
"@actions/tool-cache": "^1.6.1",
|
||||
"minimist": "^1.2.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/jest": "^24.9.1",
|
||||
"@types/node": "^12.12.64",
|
||||
"@types/node": "^12.19.11",
|
||||
"@typescript-eslint/eslint-plugin": "^2.34.0",
|
||||
"@typescript-eslint/parser": "^2.34.0",
|
||||
"eslint": "^6.8.0",
|
||||
"eslint-config-prettier": "^6.12.0",
|
||||
"eslint-config-prettier": "^6.15.0",
|
||||
"eslint-plugin-import": "^2.22.1",
|
||||
"eslint-plugin-prettier": "^3.1.4",
|
||||
"jest": "^25.5.4",
|
||||
"eslint-plugin-prettier": "^3.3.0",
|
||||
"jest": "^26.6.3",
|
||||
"jest-circus": "^25.5.4",
|
||||
"prettier": "^1.19.1",
|
||||
"ts-jest": "^26.4.1",
|
||||
"ts-jest": "^26.4.4",
|
||||
"typescript": "^3.9.7"
|
||||
}
|
||||
}
|
||||
|
||||
+17
-9
@@ -5,15 +5,23 @@ const EMULATOR_BOOT_TIMEOUT_SECONDS = 600;
|
||||
/**
|
||||
* Creates and launches a new AVD instance with the specified configurations.
|
||||
*/
|
||||
export async function launchEmulator(apiLevel: number, target: string, arch: string, profile: string, avdName: string, emulatorOptions: string, disableAnimations: boolean): Promise<void> {
|
||||
export async function launchEmulator(
|
||||
apiLevel: number,
|
||||
target: string,
|
||||
arch: string,
|
||||
profile: string,
|
||||
sdcardPathOrSize: string,
|
||||
avdName: string,
|
||||
emulatorOptions: string,
|
||||
disableAnimations: boolean
|
||||
): Promise<void> {
|
||||
// create a new AVD
|
||||
if (profile.trim() !== '') {
|
||||
console.log(`Creating AVD with custom profile ${profile}`);
|
||||
await exec.exec(`avdmanager create avd --force -n "${avdName}" --abi "${target}/${arch}" --package "system-images;android-${apiLevel};${target};${arch}" --device "${profile}"`);
|
||||
} else {
|
||||
console.log(`Creating AVD without custom profile.`);
|
||||
await exec.exec(`sh -c \\"echo no | avdmanager create avd --force -n "${avdName}" --abi '${target}/${arch}' --package 'system-images;android-${apiLevel};${target};${arch}'"`);
|
||||
}
|
||||
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}"`
|
||||
);
|
||||
|
||||
// start emulator
|
||||
console.log('Starting emulator.');
|
||||
@@ -23,7 +31,7 @@ export async function launchEmulator(apiLevel: number, target: string, arch: str
|
||||
emulatorOptions += ' -accel off';
|
||||
}
|
||||
|
||||
await exec.exec(`sh -c \\"${process.env.ANDROID_HOME}/emulator/emulator -avd "${avdName}" ${emulatorOptions} &"`, [], {
|
||||
await exec.exec(`sh -c \\"${process.env.ANDROID_SDK_ROOT}/emulator/emulator -avd "${avdName}" ${emulatorOptions} &"`, [], {
|
||||
listeners: {
|
||||
stderr: (data: Buffer) => {
|
||||
if (data.toString().includes('invalid command-line parameter')) {
|
||||
|
||||
+5
-1
@@ -39,6 +39,10 @@ async function run() {
|
||||
const profile = core.getInput('profile');
|
||||
console.log(`Hardware profile: ${profile}`);
|
||||
|
||||
// SD card path or size used for creating the AVD
|
||||
const sdcardPathOrSize = core.getInput('sdcard-path-or-size');
|
||||
console.log(`SD card path or size: ${sdcardPathOrSize}`);
|
||||
|
||||
// custom name used for creating the AVD
|
||||
const avdName = core.getInput('avd-name');
|
||||
console.log(`AVD name: ${avdName}`);
|
||||
@@ -94,7 +98,7 @@ async function run() {
|
||||
await installAndroidSdk(apiLevel, target, arch, emulatorBuild, ndkVersion, cmakeVersion);
|
||||
|
||||
// launch an emulator
|
||||
await launchEmulator(apiLevel, target, arch, profile, avdName, emulatorOptions, disableAnimations);
|
||||
await launchEmulator(apiLevel, target, arch, profile, sdcardPathOrSize, avdName, emulatorOptions, disableAnimations);
|
||||
|
||||
// execute the custom script
|
||||
try {
|
||||
|
||||
+20
-17
@@ -1,11 +1,12 @@
|
||||
import * as core from '@actions/core';
|
||||
import * as exec from '@actions/exec';
|
||||
import * as io from '@actions/io';
|
||||
import * as tc from '@actions/tool-cache';
|
||||
import * as fs from 'fs';
|
||||
|
||||
const BUILD_TOOLS_VERSION = '30.0.2';
|
||||
const CMDLINE_TOOLS_URL_MAC = 'https://dl.google.com/android/repository/commandlinetools-mac-6609375_latest.zip';
|
||||
const CMDLINE_TOOLS_URL_LINUX = 'https://dl.google.com/android/repository/commandlinetools-linux-6609375_latest.zip';
|
||||
const BUILD_TOOLS_VERSION = '30.0.3';
|
||||
const CMDLINE_TOOLS_URL_MAC = 'https://dl.google.com/android/repository/commandlinetools-mac-6858069_latest.zip';
|
||||
const CMDLINE_TOOLS_URL_LINUX = 'https://dl.google.com/android/repository/commandlinetools-linux-6858069_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,
|
||||
@@ -15,31 +16,29 @@ export async function installAndroidSdk(apiLevel: number, target: string, arch:
|
||||
const isOnMac = process.platform === 'darwin';
|
||||
|
||||
if (!isOnMac) {
|
||||
await exec.exec(`sh -c \\"sudo chown $USER:$USER ${process.env.ANDROID_HOME} -R`);
|
||||
await exec.exec(`sh -c \\"sudo chown $USER:$USER ${process.env.ANDROID_SDK_ROOT} -R`);
|
||||
}
|
||||
|
||||
const cmdlineToolsPath = `${process.env.ANDROID_HOME}/cmdline-tools`;
|
||||
const cmdlineToolsPath = `${process.env.ANDROID_SDK_ROOT}/cmdline-tools`;
|
||||
if (!fs.existsSync(cmdlineToolsPath)) {
|
||||
console.log('Installing new cmdline-tools.');
|
||||
const sdkUrl = isOnMac ? CMDLINE_TOOLS_URL_MAC : CMDLINE_TOOLS_URL_LINUX;
|
||||
await io.mkdirP(`${process.env.ANDROID_HOME}/cmdline-tools`);
|
||||
await exec.exec(`curl -fo commandlinetools.zip ${sdkUrl}`);
|
||||
await exec.exec(`unzip -q commandlinetools.zip -d ${cmdlineToolsPath}`);
|
||||
await io.rmRF('commandlinetools.zip');
|
||||
|
||||
const downloadPath = await tc.downloadTool(sdkUrl);
|
||||
await tc.extractZip(downloadPath, cmdlineToolsPath);
|
||||
await io.mv(`${cmdlineToolsPath}/cmdline-tools`, `${cmdlineToolsPath}/latest`);
|
||||
// add paths for commandline-tools and platform-tools
|
||||
core.addPath(`${cmdlineToolsPath}/tools:${cmdlineToolsPath}/tools/bin:${process.env.ANDROID_HOME}/platform-tools`);
|
||||
core.addPath(`${cmdlineToolsPath}/latest:${cmdlineToolsPath}/latest/bin:${process.env.ANDROID_SDK_ROOT}/platform-tools`);
|
||||
}
|
||||
|
||||
// additional permission and license requirements for Linux
|
||||
const sdkPreviewLicensePath = `${process.env.ANDROID_HOME}/licenses/android-sdk-preview-license`;
|
||||
const sdkPreviewLicensePath = `${process.env.ANDROID_SDK_ROOT}/licenses/android-sdk-preview-license`;
|
||||
if (!isOnMac && !fs.existsSync(sdkPreviewLicensePath)) {
|
||||
fs.writeFileSync(sdkPreviewLicensePath, '\n84831b9409646a918e30573bab4c9c91346d8abd');
|
||||
}
|
||||
|
||||
// license required for API 30 system images
|
||||
const sdkArmDbtLicensePath = `${process.env.ANDROID_HOME}/licenses/android-sdk-arm-dbt-license`;
|
||||
if (apiLevel == 30 && !fs.existsSync(sdkArmDbtLicensePath)) {
|
||||
// license required for API 30 and non-default API 28 system images
|
||||
const sdkArmDbtLicensePath = `${process.env.ANDROID_SDK_ROOT}/licenses/android-sdk-arm-dbt-license`;
|
||||
if (requiresArmDbtLicense(apiLevel, target) && !fs.existsSync(sdkArmDbtLicensePath)) {
|
||||
fs.writeFileSync(sdkArmDbtLicensePath, '\n859f317696f67ef3d7f30a50a5560e7834b43903');
|
||||
}
|
||||
|
||||
@@ -49,8 +48,8 @@ export async function installAndroidSdk(apiLevel: number, target: string, arch:
|
||||
if (emulatorBuild) {
|
||||
console.log(`Installing emulator build ${emulatorBuild}.`);
|
||||
await exec.exec(`curl -fo emulator.zip https://dl.google.com/android/repository/emulator-${isOnMac ? 'darwin' : 'linux'}-${emulatorBuild}.zip`);
|
||||
await io.rmRF(`${process.env.ANDROID_HOME}/emulator`);
|
||||
await exec.exec(`unzip -q emulator.zip -d ${process.env.ANDROID_HOME}`);
|
||||
await io.rmRF(`${process.env.ANDROID_SDK_ROOT}/emulator`);
|
||||
await exec.exec(`unzip -q emulator.zip -d ${process.env.ANDROID_SDK_ROOT}`);
|
||||
await io.rmRF('emulator.zip');
|
||||
} else {
|
||||
console.log('Installing latest emulator.');
|
||||
@@ -68,3 +67,7 @@ export async function installAndroidSdk(apiLevel: number, target: string, arch:
|
||||
await exec.exec(`sh -c \\"sdkmanager --install 'cmake;${cmakeVersion}' > /dev/null"`);
|
||||
}
|
||||
}
|
||||
|
||||
function requiresArmDbtLicense(apiLevel: number, target: string): boolean {
|
||||
return apiLevel === 30 || (apiLevel === 28 && target !== 'default');
|
||||
}
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
apply plugin: 'com.android.application'
|
||||
apply plugin: 'kotlin-android'
|
||||
apply plugin: 'kotlin-android-extensions'
|
||||
|
||||
android {
|
||||
compileSdkVersion 30
|
||||
buildToolsVersion "30.0.2"
|
||||
buildToolsVersion "30.0.3"
|
||||
|
||||
defaultConfig {
|
||||
applicationId "com.example.testapp"
|
||||
@@ -26,11 +25,11 @@ android {
|
||||
|
||||
dependencies {
|
||||
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
|
||||
implementation 'androidx.appcompat:appcompat:1.1.0'
|
||||
implementation 'androidx.core:core-ktx:1.3.0'
|
||||
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
|
||||
implementation 'androidx.appcompat:appcompat:1.2.0'
|
||||
implementation 'androidx.core:core-ktx:1.3.2'
|
||||
implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
|
||||
testImplementation 'junit:junit:4.13'
|
||||
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
|
||||
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
|
||||
androidTestImplementation 'androidx.test.ext:junit:1.1.2'
|
||||
androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
|
||||
}
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
||||
|
||||
buildscript {
|
||||
ext.kotlin_version = '1.4.0'
|
||||
ext.kotlin_version = '1.4.21'
|
||||
repositories {
|
||||
google()
|
||||
jcenter()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:4.0.1'
|
||||
classpath 'com.android.tools.build:gradle:4.1.1'
|
||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||
|
||||
// NOTE: Do not place your application dependencies here; they belong
|
||||
|
||||
@@ -24,17 +24,5 @@ kapt.include.compile.classpath=false
|
||||
# Use R8 instead of ProGuard for code shrinking.
|
||||
android.enableR8.fullMode=true
|
||||
|
||||
# Enable gradle workers
|
||||
android.enableGradleWorkers=true
|
||||
|
||||
# Enable AndroidX
|
||||
android.useAndroidX=true
|
||||
|
||||
# Enable rudimentary R class namespacing where each library only contains
|
||||
# references to the resources it declares instead of declarations plus all
|
||||
# transitive dependency references.
|
||||
android.namespacedRClass=true
|
||||
|
||||
# Only keep the single relevant constructor for types mentioned in XML files
|
||||
# instead of using a parameter wildcard which keeps them all.
|
||||
android.useMinimalKeepRules=true
|
||||
|
||||
+1
-1
@@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-6.7-all.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-6.7.1-bin.zip
|
||||
|
||||
Reference in New Issue
Block a user