mirror of
https://github.com/reactivecircus/android-emulator-runner.git
synced 2026-09-03 19:09:32 +00:00
Compare commits
43 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 226f26251f | |||
| 43421164e2 | |||
| a3d693d819 | |||
| 5e38ea2647 | |||
| 080a93d5e1 | |||
| 98e4e00ead | |||
| 599839e428 | |||
| 751bef68f6 | |||
| bbf0887eb9 | |||
| 84b9418977 | |||
| a732f125bb | |||
| 5201a33a90 | |||
| cf46dc4c18 | |||
| f790770d0f | |||
| 505c899f12 | |||
| 0d47f0813d | |||
| d2799957d6 | |||
| 838986e303 | |||
| 27a0759d85 | |||
| d85239a9fb | |||
| 08b092e904 | |||
| 91b2b2f06f | |||
| 205fbe1b31 | |||
| efc0dae5fa | |||
| 4281471e5b | |||
| 7f22785663 | |||
| 94bd1ed921 | |||
| c3e261e13b | |||
| 434e949c3b | |||
| 70e3f6e680 | |||
| 0d8602fe47 | |||
| 28373d3d4f | |||
| 02cf805290 | |||
| 045b7d8c5e | |||
| b0f3c521a5 | |||
| 308aa234e1 | |||
| d4b3926c7d | |||
| 877a4c47c3 | |||
| e08f702234 | |||
| 11559ab158 | |||
| b5ac8dfbfe | |||
| ad97647a61 | |||
| 4690ba2920 |
@@ -30,12 +30,15 @@ jobs:
|
|||||||
- target: google_apis
|
- target: google_apis
|
||||||
api-level: 29
|
api-level: 29
|
||||||
include:
|
include:
|
||||||
- os: macos-latest
|
- os: macos-11.0
|
||||||
api-level: 30
|
api-level: 30
|
||||||
target: google_apis
|
target: google_apis
|
||||||
- os: macos-latest
|
- os: macos-latest
|
||||||
api-level: 24
|
api-level: 24
|
||||||
target: playstore
|
target: playstore
|
||||||
|
- os: macos-latest
|
||||||
|
api-level: 28
|
||||||
|
target: google_apis
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: checkout
|
- name: checkout
|
||||||
@@ -68,6 +71,8 @@ jobs:
|
|||||||
target: ${{ matrix.target }}
|
target: ${{ matrix.target }}
|
||||||
arch: x86
|
arch: x86
|
||||||
profile: Nexus 6
|
profile: Nexus 6
|
||||||
|
cores: 2
|
||||||
|
sdcard-path-or-size: 100M
|
||||||
avd-name: test
|
avd-name: test
|
||||||
emulator-options: -no-window -gpu swiftshader_indirect -no-snapshot -noaudio -no-boot-anim -camera-back none
|
emulator-options: -no-window -gpu swiftshader_indirect -no-snapshot -noaudio -no-boot-anim -camera-back none
|
||||||
disable-animations: true
|
disable-animations: true
|
||||||
|
|||||||
@@ -1,5 +1,41 @@
|
|||||||
# Change Log
|
# Change Log
|
||||||
|
|
||||||
|
## v2.17.0
|
||||||
|
|
||||||
|
* Add option to toggle Linux hardware acceleration - [#154](https://github.com/ReactiveCircus/android-emulator-runner/pull/154) @stevestotter
|
||||||
|
|
||||||
|
## v2.16.0
|
||||||
|
|
||||||
|
* Avoid wrapping script code in quotes - [#134](https://github.com/ReactiveCircus/android-emulator-runner/pull/134) @hostilefork
|
||||||
|
* Add option to disable spellcheck - [#143](https://github.com/ReactiveCircus/android-emulator-runner/pull/143) @AfzalivE
|
||||||
|
* Add support for arm64-v8a for Apple Silicon Macs - [#146](https://github.com/ReactiveCircus/android-emulator-runner/pull/146) @Jeehut
|
||||||
|
|
||||||
|
## v2.15.0
|
||||||
|
|
||||||
|
* Added support for specifying the number of cores to use for the emulator - [#130](https://github.com/ReactiveCircus/android-emulator-runner/pull/130).
|
||||||
|
|
||||||
|
## v2.14.3
|
||||||
|
|
||||||
|
* Support `macos-11.0` (Big Sur) runner - [#124](https://github.com/ReactiveCircus/android-emulator-runner/pull/124).
|
||||||
|
|
||||||
|
## 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
|
## v2.12.0
|
||||||
|
|
||||||
Added support for using the `playstore` system images:
|
Added support for using the `playstore` system images:
|
||||||
|
|||||||
@@ -8,8 +8,8 @@ A GitHub Action for installing, configuring and running hardware-accelerated And
|
|||||||
|
|
||||||
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).
|
||||||
|
|
||||||
The **macOS** VM provided by **GitHub Actions** has **HAXM** installed so we are able to create a new AVD instance, launch an emulator with hardware acceleration, and run our Android
|
The **macOS** VM provided by **GitHub Actions** has **HAXM** installed so we are able to create a new AVD instance, launch an emulator with hardware acceleration, and run our Android
|
||||||
tests directly on the VM.
|
tests directly on the VM. You can also achieve this on a self-hosted Linux runner, but it will need to be on a compatible instance that allows you to enable KVM - for example AWS EC2 Bare Metal instances.
|
||||||
|
|
||||||
This action automates the process by doing the following:
|
This action automates the process by doing the following:
|
||||||
|
|
||||||
@@ -90,11 +90,15 @@ jobs:
|
|||||||
|-|-|-|-|
|
|-|-|-|-|
|
||||||
| `api-level` | Required | N/A | API level of the platform system image - e.g. 23 for Android Marshmallow, 29 for Android 10. **Minimum API level supported is 15**. |
|
| `api-level` | Required | N/A | API level of the platform system image - e.g. 23 for Android Marshmallow, 29 for Android 10. **Minimum API level supported is 15**. |
|
||||||
| `target` | Optional | `default` | Target of the system image - `default`, `google_apis` or `playstore`. |
|
| `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+. |
|
| `arch` | Optional | `x86` | CPU architecture of the system image - `x86`, `x86_64` or `arm64-v8a`. Note that `x86_64` image is only available for API 21+. `arm64-v8a` images require Android 4.2+ and are limited to fewer API levels (e.g. 30). |
|
||||||
| `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". |
|
| `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". |
|
||||||
|
| `cores` | Optional | 2 | Number of cores to use for the emulator (`hw.cpu.ncore` in config.ini). |
|
||||||
|
| `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. |
|
| `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`. |
|
| `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`. |
|
| `disable-animations` | Optional | `true` | Whether to disable animations - `true` or `false`. |
|
||||||
|
| `disable-spellchecker` | Optional | `false` | Whether to disable spellchecker - `true` or `false`. |
|
||||||
|
| `disable-linux-hw-accel` | Optional | `true` | Whether to disable hardware acceleration on Linux machines - `true` or `false`. Note that this is true by default as Github-hosted Linux runners do not support hardware acceleration. |
|
||||||
| `emulator-build` | Optional | N/A | Build number of a specific version of the emulator binary to use e.g. `6061023` for emulator v29.3.0.0. |
|
| `emulator-build` | Optional | N/A | Build number of a specific version of the emulator binary to use e.g. `6061023` for emulator v29.3.0.0. |
|
||||||
| `working-directory` | Optional | `./` | A custom working directory - e.g. `./android` if your root Gradle project is under the `./android` sub-directory within your repository. |
|
| `working-directory` | Optional | `./` | A custom working directory - e.g. `./android` if your root Gradle project is under the `./android` sub-directory within your repository. |
|
||||||
| `ndk` | Optional | N/A | Version of NDK to install - e.g. `21.0.6113669` |
|
| `ndk` | Optional | N/A | Version of NDK to install - e.g. `21.0.6113669` |
|
||||||
@@ -105,7 +109,7 @@ Default `emulator-options`: `-no-window -gpu swiftshader_indirect -no-snapshot -
|
|||||||
|
|
||||||
## Can I use this action on Linux VMs?
|
## Can I use this action on Linux VMs?
|
||||||
|
|
||||||
The short answer is yes but it's expected to be a much worse experience (on some newer API levels it might not work at all) than running it on macOS.
|
The short answer is yes but on Github-hosted Linux runners it's expected to be a much worse experience (on some newer API levels it might not work at all) than running it on macOS. You can get it running much faster on self-hosted Linux runners but only if the underlying instances support KVM (which most don't).
|
||||||
|
|
||||||
For a longer answer please refer to [this issue](https://github.com/ReactiveCircus/android-emulator-runner/issues/46).
|
For a longer answer please refer to [this issue](https://github.com/ReactiveCircus/android-emulator-runner/issues/46).
|
||||||
|
|
||||||
@@ -114,23 +118,30 @@ For a longer answer please refer to [this issue](https://github.com/ReactiveCirc
|
|||||||
|
|
||||||
These are some of the open-source projects using (or used) **Android Emulator Runner**:
|
These are some of the open-source projects using (or used) **Android Emulator Runner**:
|
||||||
|
|
||||||
- [coil-kt/coil](https://github.com/coil-kt/coil/blob/master/.github/workflows/)
|
- [coil-kt/coil](https://github.com/coil-kt/coil/blob/master/.github/workflows)
|
||||||
- [cashapp/sqldelight](https://github.com/cashapp/sqldelight/blob/master/.github/workflows/)
|
- [cashapp/sqldelight](https://github.com/cashapp/sqldelight/blob/master/.github/workflows)
|
||||||
- [square/workflow](https://github.com/square/workflow/blob/main/.github/workflows/)
|
- [square/workflow-kotlin](https://github.com/square/workflow-kotlin/tree/main/.github/workflows)
|
||||||
- [square/retrofit](https://github.com/square/retrofit/blob/master/.github/workflows/)
|
- [square/retrofit](https://github.com/square/retrofit/blob/master/.github/workflows)
|
||||||
- [natario1/CameraView](https://github.com/natario1/CameraView/tree/master/.github/workflows)
|
- [natario1/CameraView](https://github.com/natario1/CameraView/tree/master/.github/workflows)
|
||||||
- [natario1/Transcoder](https://github.com/natario1/Transcoder/tree/master/.github/workflows)
|
- [natario1/Transcoder](https://github.com/natario1/Transcoder/tree/master/.github/workflows)
|
||||||
- [chrisbanes/insetter](https://github.com/chrisbanes/insetter/tree/main/.github/workflows)
|
- [chrisbanes/insetter](https://github.com/chrisbanes/insetter/tree/main/.github/workflows)
|
||||||
- [slackhq/keeper](https://github.com/slackhq/keeper/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/streamlined](https://github.com/ReactiveCircus/streamlined/tree/main/.github/workflows)
|
||||||
- [ReactiveCircus/FlowBinding](https://github.com/ReactiveCircus/FlowBinding)
|
- [ReactiveCircus/FlowBinding](https://github.com/ReactiveCircus/FlowBinding/tree/main/.github/workflows)
|
||||||
- [JakeWharton/RxBinding](https://github.com/JakeWharton/RxBinding/tree/master/.github/workflows)
|
- [JakeWharton/RxBinding](https://github.com/JakeWharton/RxBinding/tree/master/.github/workflows)
|
||||||
- [vinaygaba/Learn-Jetpack-Compose-By-Example](https://github.com/vinaygaba/Learn-Jetpack-Compose-By-Example/)
|
- [vinaygaba/Learn-Jetpack-Compose-By-Example](https://github.com/vinaygaba/Learn-Jetpack-Compose-By-Example/tree/master/.github/workflows)
|
||||||
- [ashishb/adb-enhanced](https://github.com/ashishb/adb-enhanced/tree/master/.github/workflows)
|
- [ashishb/adb-enhanced](https://github.com/ashishb/adb-enhanced/tree/master/.github/workflows)
|
||||||
- [vgaidarji/ci-matters](https://github.com/vgaidarji/ci-matters/blob/master/.github/workflows/main.yaml)
|
- [vgaidarji/ci-matters](https://github.com/vgaidarji/ci-matters/blob/master/.github/workflows/main.yaml)
|
||||||
- [simpledotorg/simple-android](https://github.com/simpledotorg/simple-android)
|
- [simpledotorg/simple-android](https://github.com/simpledotorg/simple-android/tree/master/.github/workflows)
|
||||||
- [cashapp/copper](https://github.com/cashapp/copper/blob/trunk/.github/workflows/build.yaml)
|
- [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)
|
- [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)
|
||||||
|
- [square/leakcanary](https://github.com/square/leakcanary/tree/main/.github/workflows)
|
||||||
|
- [hash-checker/hash-checker](https://github.com/hash-checker/hash-checker/tree/master/.github/workflows)
|
||||||
|
- [hash-checker/hash-checker-lite](https://github.com/hash-checker/hash-checker-lite/tree/master/.github/workflows)
|
||||||
|
- [Kiwix/kiwix-android](https://github.com/kiwix/kiwix-android/blob/develop/.github/workflows)
|
||||||
|
- [wikimedia/apps-android-wikipedia](https://github.com/wikimedia/apps-android-wikipedia/blob/master/.github/workflows)
|
||||||
|
- [google/android-fhir](https://github.com/google/android-fhir/tree/master/.github/workflows)
|
||||||
|
|
||||||
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.
|
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.
|
||||||
|
|||||||
@@ -103,6 +103,48 @@ describe('disable-animations validator tests', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('disable-spellchecker validator tests', () => {
|
||||||
|
it('Throws if disable-spellchecker is not a boolean', () => {
|
||||||
|
const func = () => {
|
||||||
|
validator.checkDisableSpellchecker('yes');
|
||||||
|
};
|
||||||
|
expect(func).toThrowError(`Input for input.disable-spellchecker should be either 'true' or 'false'.`);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Validates successfully if disable-spellchecker is either true or false', () => {
|
||||||
|
const func1 = () => {
|
||||||
|
validator.checkDisableSpellchecker('true');
|
||||||
|
};
|
||||||
|
expect(func1).not.toThrow();
|
||||||
|
|
||||||
|
const func2 = () => {
|
||||||
|
validator.checkDisableSpellchecker('false');
|
||||||
|
};
|
||||||
|
expect(func2).not.toThrow();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('disable-linux-hw-accel validator tests', () => {
|
||||||
|
it('Throws if disable-linux-hw-accel is not a boolean', () => {
|
||||||
|
const func = () => {
|
||||||
|
validator.checkDisableLinuxHardwareAcceleration('yes');
|
||||||
|
};
|
||||||
|
expect(func).toThrowError(`Input for input.disable-linux-hw-accel should be either 'true' or 'false'.`);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Validates successfully if disable-linux-hw-accel is either true or false', () => {
|
||||||
|
const func1 = () => {
|
||||||
|
validator.checkDisableLinuxHardwareAcceleration('true');
|
||||||
|
};
|
||||||
|
expect(func1).not.toThrow();
|
||||||
|
|
||||||
|
const func2 = () => {
|
||||||
|
validator.checkDisableLinuxHardwareAcceleration('false');
|
||||||
|
};
|
||||||
|
expect(func2).not.toThrow();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('emulator-build validator tests', () => {
|
describe('emulator-build validator tests', () => {
|
||||||
it('Throws if emulator-build is not a number', () => {
|
it('Throws if emulator-build is not a number', () => {
|
||||||
const func = () => {
|
const func = () => {
|
||||||
|
|||||||
+13
-2
@@ -2,7 +2,7 @@ name: 'Android Emulator Runner'
|
|||||||
description: 'Installs, configures and starts an Android Emulator directly on macOS virtual machines.'
|
description: 'Installs, configures and starts an Android Emulator directly on macOS virtual machines.'
|
||||||
author: 'Reactive Circus'
|
author: 'Reactive Circus'
|
||||||
branding:
|
branding:
|
||||||
icon: 'smartphone'
|
icon: 'smartphone'
|
||||||
color: 'green'
|
color: 'green'
|
||||||
inputs:
|
inputs:
|
||||||
api-level:
|
api-level:
|
||||||
@@ -12,10 +12,15 @@ inputs:
|
|||||||
description: 'target of the system image - default, google_apis or playstore'
|
description: 'target of the system image - default, google_apis or playstore'
|
||||||
default: 'default'
|
default: 'default'
|
||||||
arch:
|
arch:
|
||||||
description: 'CPU architecture of the system image - x86 or x86_64'
|
description: 'CPU architecture of the system image - x86, x86_64 or arm64-v8a'
|
||||||
default: 'x86'
|
default: 'x86'
|
||||||
profile:
|
profile:
|
||||||
description: 'hardware profile used for creating the AVD - e.g. `Nexus 6`'
|
description: 'hardware profile used for creating the AVD - e.g. `Nexus 6`'
|
||||||
|
cores:
|
||||||
|
description: 'the number of cores to use for the emulator'
|
||||||
|
default: 2
|
||||||
|
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:
|
avd-name:
|
||||||
description: 'custom AVD name used for creating the Android Virtual Device'
|
description: 'custom AVD name used for creating the Android Virtual Device'
|
||||||
default: 'test'
|
default: 'test'
|
||||||
@@ -25,6 +30,12 @@ inputs:
|
|||||||
disable-animations:
|
disable-animations:
|
||||||
description: 'whether to disable animations - true or false'
|
description: 'whether to disable animations - true or false'
|
||||||
default: 'true'
|
default: 'true'
|
||||||
|
disable-spellchecker:
|
||||||
|
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`.
|
||||||
|
default: 'true'
|
||||||
emulator-build:
|
emulator-build:
|
||||||
description: 'build number of a specific version of the emulator binary to use - e.g. `6061023` for emulator v29.3.0.0'
|
description: 'build number of a specific version of the emulator binary to use - e.g. `6061023` for emulator v29.3.0.0'
|
||||||
working-directory:
|
working-directory:
|
||||||
|
|||||||
+14
-11
@@ -34,24 +34,24 @@ const EMULATOR_BOOT_TIMEOUT_SECONDS = 600;
|
|||||||
/**
|
/**
|
||||||
* Creates and launches a new AVD instance with the specified configurations.
|
* 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, cores, sdcardPathOrSize, avdName, emulatorOptions, disableAnimations, disableSpellChecker, disableLinuxHardwareAcceleration) {
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
// create a new AVD
|
// create a new AVD
|
||||||
if (profile.trim() !== '') {
|
const profileOption = profile.trim() !== '' ? `--device '${profile}'` : '';
|
||||||
console.log(`Creating AVD with custom profile ${profile}`);
|
const sdcardPathOrSizeOption = sdcardPathOrSize.trim() !== '' ? `--sdcard '${sdcardPathOrSize}'` : '';
|
||||||
yield exec.exec(`avdmanager create avd --force -n "${avdName}" --abi "${target}/${arch}" --package "system-images;android-${apiLevel};${target};${arch}" --device "${profile}"`);
|
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}"`);
|
||||||
else {
|
if (cores) {
|
||||||
console.log(`Creating AVD without custom profile.`);
|
yield exec.exec(`sh -c \\"printf 'hw.cpu.ncore=${cores}\n' >> ~/.android/avd/"${avdName}".avd"/config.ini`);
|
||||||
yield exec.exec(`sh -c \\"echo no | avdmanager create avd --force -n "${avdName}" --abi '${target}/${arch}' --package 'system-images;android-${apiLevel};${target};${arch}'"`);
|
|
||||||
}
|
}
|
||||||
// start emulator
|
// start emulator
|
||||||
console.log('Starting emulator.');
|
console.log('Starting emulator.');
|
||||||
// turn off hardware acceleration on Linux
|
//turn off hardware acceleration on Linux
|
||||||
if (process.platform === 'linux') {
|
if (process.platform === 'linux' && disableLinuxHardwareAcceleration) {
|
||||||
|
console.log('Disabling Linux hardware acceleration.');
|
||||||
emulatorOptions += ' -accel off';
|
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: {
|
listeners: {
|
||||||
stderr: (data) => {
|
stderr: (data) => {
|
||||||
if (data.toString().includes('invalid command-line parameter')) {
|
if (data.toString().includes('invalid command-line parameter')) {
|
||||||
@@ -70,6 +70,9 @@ function launchEmulator(apiLevel, target, arch, profile, avdName, emulatorOption
|
|||||||
yield exec.exec(`adb shell settings put global transition_animation_scale 0.0`);
|
yield exec.exec(`adb shell settings put global transition_animation_scale 0.0`);
|
||||||
yield exec.exec(`adb shell settings put global animator_duration_scale 0.0`);
|
yield exec.exec(`adb shell settings put global animator_duration_scale 0.0`);
|
||||||
}
|
}
|
||||||
|
if (disableSpellChecker) {
|
||||||
|
yield exec.exec(`adb shell settings put secure spell_checker_enabled 0`);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
exports.launchEmulator = launchEmulator;
|
exports.launchEmulator = launchEmulator;
|
||||||
|
|||||||
+18
-3
@@ -1,9 +1,9 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
exports.checkEmulatorBuild = 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.checkArch = exports.checkTarget = exports.checkApiLevel = exports.VALID_ARCHS = exports.VALID_TARGETS = exports.MIN_API_LEVEL = void 0;
|
||||||
exports.MIN_API_LEVEL = 15;
|
exports.MIN_API_LEVEL = 15;
|
||||||
exports.VALID_TARGETS = ['default', 'google_apis', 'google_apis_playstore'];
|
exports.VALID_TARGETS = ['default', 'google_apis', 'google_apis_playstore'];
|
||||||
exports.VALID_ARCHS = ['x86', 'x86_64'];
|
exports.VALID_ARCHS = ['x86', 'x86_64', 'arm64-v8a'];
|
||||||
function checkApiLevel(apiLevel) {
|
function checkApiLevel(apiLevel) {
|
||||||
if (isNaN(Number(apiLevel)) || !Number.isInteger(Number(apiLevel))) {
|
if (isNaN(Number(apiLevel)) || !Number.isInteger(Number(apiLevel))) {
|
||||||
throw new Error(`Unexpected API level: '${apiLevel}'.`);
|
throw new Error(`Unexpected API level: '${apiLevel}'.`);
|
||||||
@@ -26,14 +26,29 @@ function checkArch(arch) {
|
|||||||
}
|
}
|
||||||
exports.checkArch = checkArch;
|
exports.checkArch = checkArch;
|
||||||
function checkDisableAnimations(disableAnimations) {
|
function checkDisableAnimations(disableAnimations) {
|
||||||
if (disableAnimations !== 'true' && disableAnimations !== 'false') {
|
if (!isValidBoolean(disableAnimations)) {
|
||||||
throw new Error(`Input for input.disable-animations should be either 'true' or 'false'.`);
|
throw new Error(`Input for input.disable-animations should be either 'true' or 'false'.`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
exports.checkDisableAnimations = checkDisableAnimations;
|
exports.checkDisableAnimations = checkDisableAnimations;
|
||||||
|
function checkDisableSpellchecker(disableSpellchecker) {
|
||||||
|
if (!isValidBoolean(disableSpellchecker)) {
|
||||||
|
throw new Error(`Input for input.disable-spellchecker should be either 'true' or 'false'.`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
exports.checkDisableSpellchecker = checkDisableSpellchecker;
|
||||||
|
function checkDisableLinuxHardwareAcceleration(disableLinuxHardwareAcceleration) {
|
||||||
|
if (!isValidBoolean(disableLinuxHardwareAcceleration)) {
|
||||||
|
throw new Error(`Input for input.disable-linux-hw-accel should be either 'true' or 'false'.`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
exports.checkDisableLinuxHardwareAcceleration = checkDisableLinuxHardwareAcceleration;
|
||||||
function checkEmulatorBuild(emulatorBuild) {
|
function checkEmulatorBuild(emulatorBuild) {
|
||||||
if (isNaN(Number(emulatorBuild)) || !Number.isInteger(Number(emulatorBuild))) {
|
if (isNaN(Number(emulatorBuild)) || !Number.isInteger(Number(emulatorBuild))) {
|
||||||
throw new Error(`Unexpected emulator build: '${emulatorBuild}'.`);
|
throw new Error(`Unexpected emulator build: '${emulatorBuild}'.`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
exports.checkEmulatorBuild = checkEmulatorBuild;
|
exports.checkEmulatorBuild = checkEmulatorBuild;
|
||||||
|
function isValidBoolean(value) {
|
||||||
|
return value === 'true' || value === 'false';
|
||||||
|
}
|
||||||
|
|||||||
+20
-2
@@ -63,6 +63,12 @@ function run() {
|
|||||||
// Hardware profile used for creating the AVD
|
// Hardware profile used for creating the AVD
|
||||||
const profile = core.getInput('profile');
|
const profile = core.getInput('profile');
|
||||||
console.log(`Hardware profile: ${profile}`);
|
console.log(`Hardware profile: ${profile}`);
|
||||||
|
// Number of cores to use for emulator
|
||||||
|
const cores = core.getInput('cores');
|
||||||
|
console.log(`Cores: ${cores}`);
|
||||||
|
// 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
|
// custom name used for creating the AVD
|
||||||
const avdName = core.getInput('avd-name');
|
const avdName = core.getInput('avd-name');
|
||||||
console.log(`AVD name: ${avdName}`);
|
console.log(`AVD name: ${avdName}`);
|
||||||
@@ -74,6 +80,16 @@ function run() {
|
|||||||
input_validator_1.checkDisableAnimations(disableAnimationsInput);
|
input_validator_1.checkDisableAnimations(disableAnimationsInput);
|
||||||
const disableAnimations = disableAnimationsInput === 'true';
|
const disableAnimations = disableAnimationsInput === 'true';
|
||||||
console.log(`disable animations: ${disableAnimations}`);
|
console.log(`disable animations: ${disableAnimations}`);
|
||||||
|
// disable spellchecker
|
||||||
|
const disableSpellcheckerInput = core.getInput('disable-spellchecker');
|
||||||
|
input_validator_1.checkDisableSpellchecker(disableSpellcheckerInput);
|
||||||
|
const disableSpellchecker = disableSpellcheckerInput === 'true';
|
||||||
|
console.log(`disable spellchecker: ${disableSpellchecker}`);
|
||||||
|
// disable linux hardware acceleration
|
||||||
|
const disableLinuxHardwareAccelerationInput = core.getInput('disable-linux-hw-accel');
|
||||||
|
input_validator_1.checkDisableLinuxHardwareAcceleration(disableLinuxHardwareAccelerationInput);
|
||||||
|
const disableLinuxHardwareAcceleration = disableLinuxHardwareAccelerationInput === 'true';
|
||||||
|
console.log(`disable Linux hardware acceleration: ${disableLinuxHardwareAcceleration}`);
|
||||||
// emulator build
|
// emulator build
|
||||||
const emulatorBuildInput = core.getInput('emulator-build');
|
const emulatorBuildInput = core.getInput('emulator-build');
|
||||||
if (emulatorBuildInput) {
|
if (emulatorBuildInput) {
|
||||||
@@ -109,7 +125,7 @@ function run() {
|
|||||||
// install SDK
|
// install SDK
|
||||||
yield sdk_installer_1.installAndroidSdk(apiLevel, target, arch, emulatorBuild, ndkVersion, cmakeVersion);
|
yield sdk_installer_1.installAndroidSdk(apiLevel, target, arch, emulatorBuild, ndkVersion, cmakeVersion);
|
||||||
// launch an emulator
|
// launch an emulator
|
||||||
yield emulator_manager_1.launchEmulator(apiLevel, target, arch, profile, avdName, emulatorOptions, disableAnimations);
|
yield emulator_manager_1.launchEmulator(apiLevel, target, arch, profile, cores, sdcardPathOrSize, avdName, emulatorOptions, disableAnimations, disableSpellchecker, disableLinuxHardwareAcceleration);
|
||||||
// execute the custom script
|
// execute the custom script
|
||||||
try {
|
try {
|
||||||
// move to custom working directory if set
|
// move to custom working directory if set
|
||||||
@@ -117,7 +133,9 @@ function run() {
|
|||||||
process.chdir(workingDirectory);
|
process.chdir(workingDirectory);
|
||||||
}
|
}
|
||||||
for (const script of scripts) {
|
for (const script of scripts) {
|
||||||
yield exec.exec(`sh -c \\"${script}"`);
|
// use array form to avoid various quote escaping problems
|
||||||
|
// caused by exec(`sh -c "${script}"`)
|
||||||
|
yield exec.exec('sh', ['-c', script]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (error) {
|
catch (error) {
|
||||||
|
|||||||
+20
-17
@@ -32,10 +32,11 @@ exports.installAndroidSdk = void 0;
|
|||||||
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 io = __importStar(require("@actions/io"));
|
const io = __importStar(require("@actions/io"));
|
||||||
|
const tc = __importStar(require("@actions/tool-cache"));
|
||||||
const fs = __importStar(require("fs"));
|
const fs = __importStar(require("fs"));
|
||||||
const BUILD_TOOLS_VERSION = '30.0.2';
|
const BUILD_TOOLS_VERSION = '30.0.3';
|
||||||
const CMDLINE_TOOLS_URL_MAC = 'https://dl.google.com/android/repository/commandlinetools-mac-6609375_latest.zip';
|
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-6609375_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,
|
* 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.
|
||||||
@@ -44,27 +45,26 @@ function installAndroidSdk(apiLevel, target, arch, emulatorBuild, ndkVersion, cm
|
|||||||
return __awaiter(this, void 0, void 0, function* () {
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
const isOnMac = process.platform === 'darwin';
|
const isOnMac = process.platform === 'darwin';
|
||||||
if (!isOnMac) {
|
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)) {
|
if (!fs.existsSync(cmdlineToolsPath)) {
|
||||||
console.log('Installing new cmdline-tools.');
|
console.log('Installing new cmdline-tools.');
|
||||||
const sdkUrl = isOnMac ? CMDLINE_TOOLS_URL_MAC : CMDLINE_TOOLS_URL_LINUX;
|
const sdkUrl = isOnMac ? CMDLINE_TOOLS_URL_MAC : CMDLINE_TOOLS_URL_LINUX;
|
||||||
yield io.mkdirP(`${process.env.ANDROID_HOME}/cmdline-tools`);
|
const downloadPath = yield tc.downloadTool(sdkUrl);
|
||||||
yield exec.exec(`curl -fo commandlinetools.zip ${sdkUrl}`);
|
yield tc.extractZip(downloadPath, cmdlineToolsPath);
|
||||||
yield exec.exec(`unzip -q commandlinetools.zip -d ${cmdlineToolsPath}`);
|
yield io.mv(`${cmdlineToolsPath}/cmdline-tools`, `${cmdlineToolsPath}/latest`);
|
||||||
yield io.rmRF('commandlinetools.zip');
|
|
||||||
// add paths for commandline-tools and platform-tools
|
|
||||||
core.addPath(`${cmdlineToolsPath}/tools:${cmdlineToolsPath}/tools/bin:${process.env.ANDROID_HOME}/platform-tools`);
|
|
||||||
}
|
}
|
||||||
|
// add paths for commandline-tools and platform-tools
|
||||||
|
core.addPath(`${cmdlineToolsPath}/latest:${cmdlineToolsPath}/latest/bin:${process.env.ANDROID_SDK_ROOT}/platform-tools`);
|
||||||
// additional permission and license requirements for Linux
|
// 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)) {
|
if (!isOnMac && !fs.existsSync(sdkPreviewLicensePath)) {
|
||||||
fs.writeFileSync(sdkPreviewLicensePath, '\n84831b9409646a918e30573bab4c9c91346d8abd');
|
fs.writeFileSync(sdkPreviewLicensePath, '\n84831b9409646a918e30573bab4c9c91346d8abd');
|
||||||
}
|
}
|
||||||
// license required for API 30 system images
|
// license required for API 30 and non-default API 28 system images
|
||||||
const sdkArmDbtLicensePath = `${process.env.ANDROID_HOME}/licenses/android-sdk-arm-dbt-license`;
|
const sdkArmDbtLicensePath = `${process.env.ANDROID_SDK_ROOT}/licenses/android-sdk-arm-dbt-license`;
|
||||||
if (apiLevel == 30 && !fs.existsSync(sdkArmDbtLicensePath)) {
|
if (requiresArmDbtLicense(apiLevel, target) && !fs.existsSync(sdkArmDbtLicensePath)) {
|
||||||
fs.writeFileSync(sdkArmDbtLicensePath, '\n859f317696f67ef3d7f30a50a5560e7834b43903');
|
fs.writeFileSync(sdkArmDbtLicensePath, '\n859f317696f67ef3d7f30a50a5560e7834b43903');
|
||||||
}
|
}
|
||||||
console.log('Installing latest build tools, platform tools, and platform.');
|
console.log('Installing latest build tools, platform tools, and platform.');
|
||||||
@@ -72,8 +72,8 @@ function installAndroidSdk(apiLevel, target, arch, emulatorBuild, ndkVersion, cm
|
|||||||
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-${isOnMac ? 'darwin' : 'linux'}-${emulatorBuild}.zip`);
|
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 io.rmRF(`${process.env.ANDROID_SDK_ROOT}/emulator`);
|
||||||
yield exec.exec(`unzip -q emulator.zip -d ${process.env.ANDROID_HOME}`);
|
yield exec.exec(`unzip -q emulator.zip -d ${process.env.ANDROID_SDK_ROOT}`);
|
||||||
yield io.rmRF('emulator.zip');
|
yield io.rmRF('emulator.zip');
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -93,3 +93,6 @@ function installAndroidSdk(apiLevel, target, arch, emulatorBuild, ndkVersion, cm
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
exports.installAndroidSdk = installAndroidSdk;
|
exports.installAndroidSdk = installAndroidSdk;
|
||||||
|
function requiresArmDbtLicense(apiLevel, target) {
|
||||||
|
return apiLevel === 30 || (apiLevel === 28 && target !== 'default');
|
||||||
|
}
|
||||||
|
|||||||
+7
-1
@@ -1,5 +1,11 @@
|
|||||||
## Releases
|
## 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
|
## 1.0.7
|
||||||
Update NPM dependencies and add 429 to the list of HttpCodes
|
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.
|
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
|
## 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
|
* @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 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 {
|
export declare class HttpClientResponse implements ifm.IHttpClientResponse {
|
||||||
constructor(message: http.IncomingMessage);
|
constructor(message: http.IncomingMessage);
|
||||||
message: http.IncomingMessage;
|
message: http.IncomingMessage;
|
||||||
|
|||||||
+17
-13
@@ -1,6 +1,5 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
const url = require("url");
|
|
||||||
const http = require("http");
|
const http = require("http");
|
||||||
const https = require("https");
|
const https = require("https");
|
||||||
const pm = require("./proxy");
|
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
|
* @param serverUrl The server URL where the request will be sent. For example, https://api.github.com
|
||||||
*/
|
*/
|
||||||
function getProxyUrl(serverUrl) {
|
function getProxyUrl(serverUrl) {
|
||||||
let proxyUrl = pm.getProxyUrl(url.parse(serverUrl));
|
let proxyUrl = pm.getProxyUrl(new URL(serverUrl));
|
||||||
return proxyUrl ? proxyUrl.href : '';
|
return proxyUrl ? proxyUrl.href : '';
|
||||||
}
|
}
|
||||||
exports.getProxyUrl = getProxyUrl;
|
exports.getProxyUrl = getProxyUrl;
|
||||||
@@ -68,6 +67,15 @@ const HttpResponseRetryCodes = [
|
|||||||
const RetryableHttpVerbs = ['OPTIONS', 'GET', 'DELETE', 'HEAD'];
|
const RetryableHttpVerbs = ['OPTIONS', 'GET', 'DELETE', 'HEAD'];
|
||||||
const ExponentialBackoffCeiling = 10;
|
const ExponentialBackoffCeiling = 10;
|
||||||
const ExponentialBackoffTimeSlice = 5;
|
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 {
|
class HttpClientResponse {
|
||||||
constructor(message) {
|
constructor(message) {
|
||||||
this.message = message;
|
this.message = message;
|
||||||
@@ -86,7 +94,7 @@ class HttpClientResponse {
|
|||||||
}
|
}
|
||||||
exports.HttpClientResponse = HttpClientResponse;
|
exports.HttpClientResponse = HttpClientResponse;
|
||||||
function isHttps(requestUrl) {
|
function isHttps(requestUrl) {
|
||||||
let parsedUrl = url.parse(requestUrl);
|
let parsedUrl = new URL(requestUrl);
|
||||||
return parsedUrl.protocol === 'https:';
|
return parsedUrl.protocol === 'https:';
|
||||||
}
|
}
|
||||||
exports.isHttps = isHttps;
|
exports.isHttps = isHttps;
|
||||||
@@ -191,7 +199,7 @@ class HttpClient {
|
|||||||
if (this._disposed) {
|
if (this._disposed) {
|
||||||
throw new Error('Client has already been 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);
|
let info = this._prepareRequest(verb, parsedUrl, headers);
|
||||||
// Only perform retries on reads since writes may not be idempotent.
|
// Only perform retries on reads since writes may not be idempotent.
|
||||||
let maxTries = this._allowRetries && RetryableHttpVerbs.indexOf(verb) != -1
|
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
|
// if there's no location to redirect to, we won't
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
let parsedRedirectUrl = url.parse(redirectUrl);
|
let parsedRedirectUrl = new URL(redirectUrl);
|
||||||
if (parsedUrl.protocol == 'https:' &&
|
if (parsedUrl.protocol == 'https:' &&
|
||||||
parsedUrl.protocol != parsedRedirectUrl.protocol &&
|
parsedUrl.protocol != parsedRedirectUrl.protocol &&
|
||||||
!this._allowRedirectDowngrade) {
|
!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
|
* @param serverUrl The server URL where the request will be sent. For example, https://api.github.com
|
||||||
*/
|
*/
|
||||||
getAgent(serverUrl) {
|
getAgent(serverUrl) {
|
||||||
let parsedUrl = url.parse(serverUrl);
|
let parsedUrl = new URL(serverUrl);
|
||||||
return this._getAgent(parsedUrl);
|
return this._getAgent(parsedUrl);
|
||||||
}
|
}
|
||||||
_prepareRequest(method, requestUrl, headers) {
|
_prepareRequest(method, requestUrl, headers) {
|
||||||
@@ -419,7 +427,7 @@ class HttpClient {
|
|||||||
maxSockets: maxSockets,
|
maxSockets: maxSockets,
|
||||||
keepAlive: this._keepAlive,
|
keepAlive: this._keepAlive,
|
||||||
proxy: {
|
proxy: {
|
||||||
proxyAuth: proxyUrl.auth,
|
proxyAuth: `${proxyUrl.username}:${proxyUrl.password}`,
|
||||||
host: proxyUrl.hostname,
|
host: proxyUrl.hostname,
|
||||||
port: proxyUrl.port
|
port: proxyUrl.port
|
||||||
}
|
}
|
||||||
@@ -514,12 +522,8 @@ class HttpClient {
|
|||||||
else {
|
else {
|
||||||
msg = 'Failed request: (' + statusCode + ')';
|
msg = 'Failed request: (' + statusCode + ')';
|
||||||
}
|
}
|
||||||
let err = new Error(msg);
|
let err = new HttpClientError(msg, statusCode);
|
||||||
// attach statusCode and body obj (if available) to the error object
|
err.result = response.result;
|
||||||
err['statusCode'] = statusCode;
|
|
||||||
if (response.result) {
|
|
||||||
err['result'] = response.result;
|
|
||||||
}
|
|
||||||
reject(err);
|
reject(err);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|||||||
+1
-2
@@ -1,6 +1,5 @@
|
|||||||
/// <reference types="node" />
|
/// <reference types="node" />
|
||||||
import http = require('http');
|
import http = require('http');
|
||||||
import url = require('url');
|
|
||||||
export interface IHeaders {
|
export interface IHeaders {
|
||||||
[key: string]: any;
|
[key: string]: any;
|
||||||
}
|
}
|
||||||
@@ -27,7 +26,7 @@ export interface IHttpClientResponse {
|
|||||||
}
|
}
|
||||||
export interface IRequestInfo {
|
export interface IRequestInfo {
|
||||||
options: http.RequestOptions;
|
options: http.RequestOptions;
|
||||||
parsedUrl: url.Url;
|
parsedUrl: URL;
|
||||||
httpModule: any;
|
httpModule: any;
|
||||||
}
|
}
|
||||||
export interface IRequestOptions {
|
export interface IRequestOptions {
|
||||||
|
|||||||
+12
-12
@@ -1,33 +1,33 @@
|
|||||||
{
|
{
|
||||||
"_args": [
|
"_args": [
|
||||||
[
|
[
|
||||||
"@actions/http-client@1.0.8",
|
"@actions/http-client@1.0.9",
|
||||||
"/Users/yang/Desktop/Projects/android-emulator-runner"
|
"."
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
"_from": "@actions/http-client@1.0.8",
|
"_from": "@actions/http-client@1.0.9",
|
||||||
"_id": "@actions/http-client@1.0.8",
|
"_id": "@actions/http-client@1.0.9",
|
||||||
"_inBundle": false,
|
"_inBundle": false,
|
||||||
"_integrity": "sha512-G4JjJ6f9Hb3Zvejj+ewLLKLf99ZC+9v+yCxoYf9vSyH+WkzPLB2LuUtRMGNkooMqdugGBFStIKXOuvH1W+EctA==",
|
"_integrity": "sha512-0O4SsJ7q+MK0ycvXPl2e6bMXV7dxAXOGjrXS1eTF9s2S401Tp6c/P3c3Joz04QefC1J6Gt942Wl2jbm3f4mLcg==",
|
||||||
"_location": "/@actions/http-client",
|
"_location": "/@actions/http-client",
|
||||||
"_phantomChildren": {},
|
"_phantomChildren": {},
|
||||||
"_requested": {
|
"_requested": {
|
||||||
"type": "version",
|
"type": "version",
|
||||||
"registry": true,
|
"registry": true,
|
||||||
"raw": "@actions/http-client@1.0.8",
|
"raw": "@actions/http-client@1.0.9",
|
||||||
"name": "@actions/http-client",
|
"name": "@actions/http-client",
|
||||||
"escapedName": "@actions%2fhttp-client",
|
"escapedName": "@actions%2fhttp-client",
|
||||||
"scope": "@actions",
|
"scope": "@actions",
|
||||||
"rawSpec": "1.0.8",
|
"rawSpec": "1.0.9",
|
||||||
"saveSpec": null,
|
"saveSpec": null,
|
||||||
"fetchSpec": "1.0.8"
|
"fetchSpec": "1.0.9"
|
||||||
},
|
},
|
||||||
"_requiredBy": [
|
"_requiredBy": [
|
||||||
"/@actions/tool-cache"
|
"/@actions/tool-cache"
|
||||||
],
|
],
|
||||||
"_resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-1.0.8.tgz",
|
"_resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-1.0.9.tgz",
|
||||||
"_spec": "1.0.8",
|
"_spec": "1.0.9",
|
||||||
"_where": "/Users/yang/Desktop/Projects/android-emulator-runner",
|
"_where": ".",
|
||||||
"author": {
|
"author": {
|
||||||
"name": "GitHub, Inc."
|
"name": "GitHub, Inc."
|
||||||
},
|
},
|
||||||
@@ -66,5 +66,5 @@
|
|||||||
"format-check": "prettier --check *.ts && prettier --check **/*.ts",
|
"format-check": "prettier --check *.ts && prettier --check **/*.ts",
|
||||||
"test": "jest"
|
"test": "jest"
|
||||||
},
|
},
|
||||||
"version": "1.0.8"
|
"version": "1.0.9"
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-4
@@ -1,4 +1,2 @@
|
|||||||
/// <reference types="node" />
|
export declare function getProxyUrl(reqUrl: URL): URL | undefined;
|
||||||
import * as url from 'url';
|
export declare function checkBypass(reqUrl: URL): boolean;
|
||||||
export declare function getProxyUrl(reqUrl: url.Url): url.Url | undefined;
|
|
||||||
export declare function checkBypass(reqUrl: url.Url): boolean;
|
|
||||||
|
|||||||
+1
-2
@@ -1,6 +1,5 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
const url = require("url");
|
|
||||||
function getProxyUrl(reqUrl) {
|
function getProxyUrl(reqUrl) {
|
||||||
let usingSsl = reqUrl.protocol === 'https:';
|
let usingSsl = reqUrl.protocol === 'https:';
|
||||||
let proxyUrl;
|
let proxyUrl;
|
||||||
@@ -15,7 +14,7 @@ function getProxyUrl(reqUrl) {
|
|||||||
proxyVar = process.env['http_proxy'] || process.env['HTTP_PROXY'];
|
proxyVar = process.env['http_proxy'] || process.env['HTTP_PROXY'];
|
||||||
}
|
}
|
||||||
if (proxyVar) {
|
if (proxyVar) {
|
||||||
proxyUrl = url.parse(proxyVar);
|
proxyUrl = new URL(proxyVar);
|
||||||
}
|
}
|
||||||
return proxyUrl;
|
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": [
|
"_args": [
|
||||||
[
|
[
|
||||||
"@actions/tool-cache@1.6.0",
|
"@actions/tool-cache@1.6.1",
|
||||||
"."
|
"."
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
"_from": "@actions/tool-cache@1.6.0",
|
"_from": "@actions/tool-cache@1.6.1",
|
||||||
"_id": "@actions/tool-cache@1.6.0",
|
"_id": "@actions/tool-cache@1.6.1",
|
||||||
"_inBundle": false,
|
"_inBundle": false,
|
||||||
"_integrity": "sha512-+fyEBImPD3m5I0o6DflCO0NHY180LPoX8Lo6y4Iez+V17kO8kfkH0VHxb8mUdmD6hn9dWA9Ch1JA20fXoIYUeQ==",
|
"_integrity": "sha512-F+vwEDwfqcHMKuSkj79pihOnsAMv23EkG76nMpc82UsnXwyQdyEsktGxrB0SNtm7pRqTXEIOoAPTgrSQclXYTg==",
|
||||||
"_location": "/@actions/tool-cache",
|
"_location": "/@actions/tool-cache",
|
||||||
"_phantomChildren": {},
|
"_phantomChildren": {},
|
||||||
"_requested": {
|
"_requested": {
|
||||||
"type": "version",
|
"type": "version",
|
||||||
"registry": true,
|
"registry": true,
|
||||||
"raw": "@actions/tool-cache@1.6.0",
|
"raw": "@actions/tool-cache@1.6.1",
|
||||||
"name": "@actions/tool-cache",
|
"name": "@actions/tool-cache",
|
||||||
"escapedName": "@actions%2ftool-cache",
|
"escapedName": "@actions%2ftool-cache",
|
||||||
"scope": "@actions",
|
"scope": "@actions",
|
||||||
"rawSpec": "1.6.0",
|
"rawSpec": "1.6.1",
|
||||||
"saveSpec": null,
|
"saveSpec": null,
|
||||||
"fetchSpec": "1.6.0"
|
"fetchSpec": "1.6.1"
|
||||||
},
|
},
|
||||||
"_requiredBy": [
|
"_requiredBy": [
|
||||||
"/"
|
"/"
|
||||||
],
|
],
|
||||||
"_resolved": "https://registry.npmjs.org/@actions/tool-cache/-/tool-cache-1.6.0.tgz",
|
"_resolved": "https://registry.npmjs.org/@actions/tool-cache/-/tool-cache-1.6.1.tgz",
|
||||||
"_spec": "1.6.0",
|
"_spec": "1.6.1",
|
||||||
"_where": ".",
|
"_where": ".",
|
||||||
"bugs": {
|
"bugs": {
|
||||||
"url": "https://github.com/actions/toolkit/issues"
|
"url": "https://github.com/actions/toolkit/issues"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@actions/core": "^1.2.3",
|
"@actions/core": "^1.2.6",
|
||||||
"@actions/exec": "^1.0.0",
|
"@actions/exec": "^1.0.0",
|
||||||
"@actions/http-client": "^1.0.8",
|
"@actions/http-client": "^1.0.8",
|
||||||
"@actions/io": "^1.0.1",
|
"@actions/io": "^1.0.1",
|
||||||
@@ -54,7 +54,7 @@
|
|||||||
"lib",
|
"lib",
|
||||||
"scripts"
|
"scripts"
|
||||||
],
|
],
|
||||||
"homepage": "https://github.com/actions/toolkit/tree/master/packages/tool-cache",
|
"homepage": "https://github.com/actions/toolkit/tree/main/packages/tool-cache",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"github",
|
"github",
|
||||||
"actions",
|
"actions",
|
||||||
@@ -77,5 +77,5 @@
|
|||||||
"tsc": "tsc"
|
"tsc": "tsc"
|
||||||
},
|
},
|
||||||
"types": "lib/tool-cache.d.ts",
|
"types": "lib/tool-cache.d.ts",
|
||||||
"version": "1.6.0"
|
"version": "1.6.1"
|
||||||
}
|
}
|
||||||
|
|||||||
Generated
+2909
-334
File diff suppressed because it is too large
Load Diff
+6
-6
@@ -23,22 +23,22 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@actions/core": "^1.2.6",
|
"@actions/core": "^1.2.6",
|
||||||
"@actions/exec": "^1.0.4",
|
"@actions/exec": "^1.0.4",
|
||||||
"@actions/tool-cache": "^1.6.0",
|
"@actions/tool-cache": "^1.6.1",
|
||||||
"minimist": "^1.2.5"
|
"minimist": "^1.2.5"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/jest": "^24.9.1",
|
"@types/jest": "^24.9.1",
|
||||||
"@types/node": "^12.12.64",
|
"@types/node": "^12.19.11",
|
||||||
"@typescript-eslint/eslint-plugin": "^2.34.0",
|
"@typescript-eslint/eslint-plugin": "^2.34.0",
|
||||||
"@typescript-eslint/parser": "^2.34.0",
|
"@typescript-eslint/parser": "^2.34.0",
|
||||||
"eslint": "^6.8.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-import": "^2.22.1",
|
||||||
"eslint-plugin-prettier": "^3.1.4",
|
"eslint-plugin-prettier": "^3.3.0",
|
||||||
"jest": "^25.5.4",
|
"jest": "^26.6.3",
|
||||||
"jest-circus": "^25.5.4",
|
"jest-circus": "^25.5.4",
|
||||||
"prettier": "^1.19.1",
|
"prettier": "^1.19.1",
|
||||||
"ts-jest": "^26.4.1",
|
"ts-jest": "^26.4.4",
|
||||||
"typescript": "^3.9.7"
|
"typescript": "^3.9.7"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+29
-10
@@ -5,25 +5,41 @@ const EMULATOR_BOOT_TIMEOUT_SECONDS = 600;
|
|||||||
/**
|
/**
|
||||||
* Creates and launches a new AVD instance with the specified configurations.
|
* 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,
|
||||||
|
cores: string,
|
||||||
|
sdcardPathOrSize: string,
|
||||||
|
avdName: string,
|
||||||
|
emulatorOptions: string,
|
||||||
|
disableAnimations: boolean,
|
||||||
|
disableSpellChecker: boolean,
|
||||||
|
disableLinuxHardwareAcceleration: boolean
|
||||||
|
): Promise<void> {
|
||||||
// create a new AVD
|
// create a new AVD
|
||||||
if (profile.trim() !== '') {
|
const profileOption = profile.trim() !== '' ? `--device '${profile}'` : '';
|
||||||
console.log(`Creating AVD with custom profile ${profile}`);
|
const sdcardPathOrSizeOption = sdcardPathOrSize.trim() !== '' ? `--sdcard '${sdcardPathOrSize}'` : '';
|
||||||
await exec.exec(`avdmanager create avd --force -n "${avdName}" --abi "${target}/${arch}" --package "system-images;android-${apiLevel};${target};${arch}" --device "${profile}"`);
|
console.log(`Creating AVD.`);
|
||||||
} else {
|
await exec.exec(
|
||||||
console.log(`Creating AVD without custom profile.`);
|
`sh -c \\"echo no | avdmanager create avd --force -n "${avdName}" --abi '${target}/${arch}' --package 'system-images;android-${apiLevel};${target};${arch}' ${profileOption} ${sdcardPathOrSizeOption}"`
|
||||||
await exec.exec(`sh -c \\"echo no | avdmanager create avd --force -n "${avdName}" --abi '${target}/${arch}' --package 'system-images;android-${apiLevel};${target};${arch}'"`);
|
);
|
||||||
|
|
||||||
|
if (cores) {
|
||||||
|
await exec.exec(`sh -c \\"printf 'hw.cpu.ncore=${cores}\n' >> ~/.android/avd/"${avdName}".avd"/config.ini`);
|
||||||
}
|
}
|
||||||
|
|
||||||
// start emulator
|
// start emulator
|
||||||
console.log('Starting emulator.');
|
console.log('Starting emulator.');
|
||||||
|
|
||||||
// turn off hardware acceleration on Linux
|
//turn off hardware acceleration on Linux
|
||||||
if (process.platform === 'linux') {
|
if (process.platform === 'linux' && disableLinuxHardwareAcceleration) {
|
||||||
|
console.log('Disabling Linux hardware acceleration.');
|
||||||
emulatorOptions += ' -accel off';
|
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: {
|
listeners: {
|
||||||
stderr: (data: Buffer) => {
|
stderr: (data: Buffer) => {
|
||||||
if (data.toString().includes('invalid command-line parameter')) {
|
if (data.toString().includes('invalid command-line parameter')) {
|
||||||
@@ -44,6 +60,9 @@ export async function launchEmulator(apiLevel: number, target: string, arch: str
|
|||||||
await exec.exec(`adb shell settings put global transition_animation_scale 0.0`);
|
await exec.exec(`adb shell settings put global transition_animation_scale 0.0`);
|
||||||
await exec.exec(`adb shell settings put global animator_duration_scale 0.0`);
|
await exec.exec(`adb shell settings put global animator_duration_scale 0.0`);
|
||||||
}
|
}
|
||||||
|
if (disableSpellChecker) {
|
||||||
|
await exec.exec(`adb shell settings put secure spell_checker_enabled 0`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
+18
-2
@@ -1,6 +1,6 @@
|
|||||||
export const MIN_API_LEVEL = 15;
|
export const MIN_API_LEVEL = 15;
|
||||||
export const VALID_TARGETS: Array<string> = ['default', 'google_apis', 'google_apis_playstore'];
|
export const VALID_TARGETS: Array<string> = ['default', 'google_apis', 'google_apis_playstore'];
|
||||||
export const VALID_ARCHS: Array<string> = ['x86', 'x86_64'];
|
export const VALID_ARCHS: Array<string> = ['x86', 'x86_64', 'arm64-v8a'];
|
||||||
|
|
||||||
export function checkApiLevel(apiLevel: string): void {
|
export function checkApiLevel(apiLevel: string): void {
|
||||||
if (isNaN(Number(apiLevel)) || !Number.isInteger(Number(apiLevel))) {
|
if (isNaN(Number(apiLevel)) || !Number.isInteger(Number(apiLevel))) {
|
||||||
@@ -24,13 +24,29 @@ export function checkArch(arch: string): void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function checkDisableAnimations(disableAnimations: string): void {
|
export function checkDisableAnimations(disableAnimations: string): void {
|
||||||
if (disableAnimations !== 'true' && disableAnimations !== 'false') {
|
if (!isValidBoolean(disableAnimations)) {
|
||||||
throw new Error(`Input for input.disable-animations should be either 'true' or 'false'.`);
|
throw new Error(`Input for input.disable-animations should be either 'true' or 'false'.`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function checkDisableSpellchecker(disableSpellchecker: string): void {
|
||||||
|
if (!isValidBoolean(disableSpellchecker)) {
|
||||||
|
throw new Error(`Input for input.disable-spellchecker should be either 'true' or 'false'.`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function checkDisableLinuxHardwareAcceleration(disableLinuxHardwareAcceleration: string): void {
|
||||||
|
if (!isValidBoolean(disableLinuxHardwareAcceleration)) {
|
||||||
|
throw new Error(`Input for input.disable-linux-hw-accel should be either 'true' or 'false'.`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export function checkEmulatorBuild(emulatorBuild: string): void {
|
export function checkEmulatorBuild(emulatorBuild: string): void {
|
||||||
if (isNaN(Number(emulatorBuild)) || !Number.isInteger(Number(emulatorBuild))) {
|
if (isNaN(Number(emulatorBuild)) || !Number.isInteger(Number(emulatorBuild))) {
|
||||||
throw new Error(`Unexpected emulator build: '${emulatorBuild}'.`);
|
throw new Error(`Unexpected emulator build: '${emulatorBuild}'.`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function isValidBoolean(value: string): boolean {
|
||||||
|
return value === 'true' || value === 'false';
|
||||||
|
}
|
||||||
|
|||||||
+25
-3
@@ -1,6 +1,6 @@
|
|||||||
import * as core from '@actions/core';
|
import * as core from '@actions/core';
|
||||||
import { installAndroidSdk } from './sdk-installer';
|
import { installAndroidSdk } from './sdk-installer';
|
||||||
import { checkApiLevel, checkTarget, checkArch, checkDisableAnimations, checkEmulatorBuild } from './input-validator';
|
import { checkApiLevel, checkTarget, checkArch, checkDisableAnimations, checkEmulatorBuild, checkDisableSpellchecker, checkDisableLinuxHardwareAcceleration } from './input-validator';
|
||||||
import { launchEmulator, killEmulator } from './emulator-manager';
|
import { launchEmulator, killEmulator } from './emulator-manager';
|
||||||
import * as exec from '@actions/exec';
|
import * as exec from '@actions/exec';
|
||||||
import { parseScript } from './script-parser';
|
import { parseScript } from './script-parser';
|
||||||
@@ -39,6 +39,14 @@ async function run() {
|
|||||||
const profile = core.getInput('profile');
|
const profile = core.getInput('profile');
|
||||||
console.log(`Hardware profile: ${profile}`);
|
console.log(`Hardware profile: ${profile}`);
|
||||||
|
|
||||||
|
// Number of cores to use for emulator
|
||||||
|
const cores = core.getInput('cores');
|
||||||
|
console.log(`Cores: ${cores}`);
|
||||||
|
|
||||||
|
// 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
|
// custom name used for creating the AVD
|
||||||
const avdName = core.getInput('avd-name');
|
const avdName = core.getInput('avd-name');
|
||||||
console.log(`AVD name: ${avdName}`);
|
console.log(`AVD name: ${avdName}`);
|
||||||
@@ -53,6 +61,18 @@ async function run() {
|
|||||||
const disableAnimations = disableAnimationsInput === 'true';
|
const disableAnimations = disableAnimationsInput === 'true';
|
||||||
console.log(`disable animations: ${disableAnimations}`);
|
console.log(`disable animations: ${disableAnimations}`);
|
||||||
|
|
||||||
|
// disable spellchecker
|
||||||
|
const disableSpellcheckerInput = core.getInput('disable-spellchecker');
|
||||||
|
checkDisableSpellchecker(disableSpellcheckerInput);
|
||||||
|
const disableSpellchecker = disableSpellcheckerInput === 'true';
|
||||||
|
console.log(`disable spellchecker: ${disableSpellchecker}`);
|
||||||
|
|
||||||
|
// disable linux hardware acceleration
|
||||||
|
const disableLinuxHardwareAccelerationInput = core.getInput('disable-linux-hw-accel');
|
||||||
|
checkDisableLinuxHardwareAcceleration(disableLinuxHardwareAccelerationInput);
|
||||||
|
const disableLinuxHardwareAcceleration = disableLinuxHardwareAccelerationInput === 'true';
|
||||||
|
console.log(`disable Linux hardware acceleration: ${disableLinuxHardwareAcceleration}`);
|
||||||
|
|
||||||
// emulator build
|
// emulator build
|
||||||
const emulatorBuildInput = core.getInput('emulator-build');
|
const emulatorBuildInput = core.getInput('emulator-build');
|
||||||
if (emulatorBuildInput) {
|
if (emulatorBuildInput) {
|
||||||
@@ -94,7 +114,7 @@ async function run() {
|
|||||||
await installAndroidSdk(apiLevel, target, arch, emulatorBuild, ndkVersion, cmakeVersion);
|
await installAndroidSdk(apiLevel, target, arch, emulatorBuild, ndkVersion, cmakeVersion);
|
||||||
|
|
||||||
// launch an emulator
|
// launch an emulator
|
||||||
await launchEmulator(apiLevel, target, arch, profile, avdName, emulatorOptions, disableAnimations);
|
await launchEmulator(apiLevel, target, arch, profile, cores, sdcardPathOrSize, avdName, emulatorOptions, disableAnimations, disableSpellchecker, disableLinuxHardwareAcceleration);
|
||||||
|
|
||||||
// execute the custom script
|
// execute the custom script
|
||||||
try {
|
try {
|
||||||
@@ -103,7 +123,9 @@ async function run() {
|
|||||||
process.chdir(workingDirectory);
|
process.chdir(workingDirectory);
|
||||||
}
|
}
|
||||||
for (const script of scripts) {
|
for (const script of scripts) {
|
||||||
await exec.exec(`sh -c \\"${script}"`);
|
// use array form to avoid various quote escaping problems
|
||||||
|
// caused by exec(`sh -c "${script}"`)
|
||||||
|
await exec.exec('sh', ['-c', script]);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
core.setFailed(error.message);
|
core.setFailed(error.message);
|
||||||
|
|||||||
+22
-18
@@ -1,11 +1,12 @@
|
|||||||
import * as core from '@actions/core';
|
import * as core from '@actions/core';
|
||||||
import * as exec from '@actions/exec';
|
import * as exec from '@actions/exec';
|
||||||
import * as io from '@actions/io';
|
import * as io from '@actions/io';
|
||||||
|
import * as tc from '@actions/tool-cache';
|
||||||
import * as fs from 'fs';
|
import * as fs from 'fs';
|
||||||
|
|
||||||
const BUILD_TOOLS_VERSION = '30.0.2';
|
const BUILD_TOOLS_VERSION = '30.0.3';
|
||||||
const CMDLINE_TOOLS_URL_MAC = 'https://dl.google.com/android/repository/commandlinetools-mac-6609375_latest.zip';
|
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-6609375_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,
|
* 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,30 @@ export async function installAndroidSdk(apiLevel: number, target: string, arch:
|
|||||||
const isOnMac = process.platform === 'darwin';
|
const isOnMac = process.platform === 'darwin';
|
||||||
|
|
||||||
if (!isOnMac) {
|
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)) {
|
if (!fs.existsSync(cmdlineToolsPath)) {
|
||||||
console.log('Installing new cmdline-tools.');
|
console.log('Installing new cmdline-tools.');
|
||||||
const sdkUrl = isOnMac ? CMDLINE_TOOLS_URL_MAC : CMDLINE_TOOLS_URL_LINUX;
|
const sdkUrl = isOnMac ? CMDLINE_TOOLS_URL_MAC : CMDLINE_TOOLS_URL_LINUX;
|
||||||
await io.mkdirP(`${process.env.ANDROID_HOME}/cmdline-tools`);
|
const downloadPath = await tc.downloadTool(sdkUrl);
|
||||||
await exec.exec(`curl -fo commandlinetools.zip ${sdkUrl}`);
|
await tc.extractZip(downloadPath, cmdlineToolsPath);
|
||||||
await exec.exec(`unzip -q commandlinetools.zip -d ${cmdlineToolsPath}`);
|
await io.mv(`${cmdlineToolsPath}/cmdline-tools`, `${cmdlineToolsPath}/latest`);
|
||||||
await io.rmRF('commandlinetools.zip');
|
|
||||||
|
|
||||||
// add paths for commandline-tools and platform-tools
|
|
||||||
core.addPath(`${cmdlineToolsPath}/tools:${cmdlineToolsPath}/tools/bin:${process.env.ANDROID_HOME}/platform-tools`);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// add paths for commandline-tools and platform-tools
|
||||||
|
core.addPath(`${cmdlineToolsPath}/latest:${cmdlineToolsPath}/latest/bin:${process.env.ANDROID_SDK_ROOT}/platform-tools`);
|
||||||
|
|
||||||
// additional permission and license requirements for Linux
|
// 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)) {
|
if (!isOnMac && !fs.existsSync(sdkPreviewLicensePath)) {
|
||||||
fs.writeFileSync(sdkPreviewLicensePath, '\n84831b9409646a918e30573bab4c9c91346d8abd');
|
fs.writeFileSync(sdkPreviewLicensePath, '\n84831b9409646a918e30573bab4c9c91346d8abd');
|
||||||
}
|
}
|
||||||
|
|
||||||
// license required for API 30 system images
|
// license required for API 30 and non-default API 28 system images
|
||||||
const sdkArmDbtLicensePath = `${process.env.ANDROID_HOME}/licenses/android-sdk-arm-dbt-license`;
|
const sdkArmDbtLicensePath = `${process.env.ANDROID_SDK_ROOT}/licenses/android-sdk-arm-dbt-license`;
|
||||||
if (apiLevel == 30 && !fs.existsSync(sdkArmDbtLicensePath)) {
|
if (requiresArmDbtLicense(apiLevel, target) && !fs.existsSync(sdkArmDbtLicensePath)) {
|
||||||
fs.writeFileSync(sdkArmDbtLicensePath, '\n859f317696f67ef3d7f30a50a5560e7834b43903');
|
fs.writeFileSync(sdkArmDbtLicensePath, '\n859f317696f67ef3d7f30a50a5560e7834b43903');
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -49,8 +49,8 @@ export async function installAndroidSdk(apiLevel: number, target: string, arch:
|
|||||||
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-${isOnMac ? 'darwin' : 'linux'}-${emulatorBuild}.zip`);
|
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 io.rmRF(`${process.env.ANDROID_SDK_ROOT}/emulator`);
|
||||||
await exec.exec(`unzip -q emulator.zip -d ${process.env.ANDROID_HOME}`);
|
await exec.exec(`unzip -q emulator.zip -d ${process.env.ANDROID_SDK_ROOT}`);
|
||||||
await io.rmRF('emulator.zip');
|
await io.rmRF('emulator.zip');
|
||||||
} else {
|
} else {
|
||||||
console.log('Installing latest emulator.');
|
console.log('Installing latest emulator.');
|
||||||
@@ -68,3 +68,7 @@ export async function installAndroidSdk(apiLevel: number, target: string, arch:
|
|||||||
await exec.exec(`sh -c \\"sdkmanager --install 'cmake;${cmakeVersion}' > /dev/null"`);
|
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: 'com.android.application'
|
||||||
apply plugin: 'kotlin-android'
|
apply plugin: 'kotlin-android'
|
||||||
apply plugin: 'kotlin-android-extensions'
|
|
||||||
|
|
||||||
android {
|
android {
|
||||||
compileSdkVersion 30
|
compileSdkVersion 30
|
||||||
buildToolsVersion "30.0.2"
|
buildToolsVersion "30.0.3"
|
||||||
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
applicationId "com.example.testapp"
|
applicationId "com.example.testapp"
|
||||||
@@ -26,11 +25,11 @@ android {
|
|||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
||||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
|
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
|
||||||
implementation 'androidx.appcompat:appcompat:1.1.0'
|
implementation 'androidx.appcompat:appcompat:1.3.0'
|
||||||
implementation 'androidx.core:core-ktx:1.3.0'
|
implementation 'androidx.core:core-ktx:1.5.0'
|
||||||
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
|
implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
|
||||||
testImplementation 'junit:junit:4.13'
|
testImplementation 'junit:junit:4.13'
|
||||||
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
|
androidTestImplementation 'androidx.test.ext:junit:1.1.2'
|
||||||
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
|
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.
|
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
||||||
|
|
||||||
buildscript {
|
buildscript {
|
||||||
ext.kotlin_version = '1.4.0'
|
ext.kotlin_version = '1.5.10'
|
||||||
repositories {
|
repositories {
|
||||||
google()
|
google()
|
||||||
jcenter()
|
jcenter()
|
||||||
}
|
}
|
||||||
dependencies {
|
dependencies {
|
||||||
classpath 'com.android.tools.build:gradle:4.0.1'
|
classpath 'com.android.tools.build:gradle:4.2.1'
|
||||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||||
|
|
||||||
// NOTE: Do not place your application dependencies here; they belong
|
// NOTE: Do not place your application dependencies here; they belong
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
org.gradle.parallel=true
|
org.gradle.parallel=true
|
||||||
org.gradle.configureondemand=true
|
org.gradle.configureondemand=true
|
||||||
org.gradle.caching=true
|
org.gradle.caching=true
|
||||||
org.gradle.vfs.watch=true
|
|
||||||
|
|
||||||
# Enable Kotlin incremental compilation
|
# Enable Kotlin incremental compilation
|
||||||
kotlin.incremental=true
|
kotlin.incremental=true
|
||||||
@@ -24,17 +23,5 @@ kapt.include.compile.classpath=false
|
|||||||
# Use R8 instead of ProGuard for code shrinking.
|
# Use R8 instead of ProGuard for code shrinking.
|
||||||
android.enableR8.fullMode=true
|
android.enableR8.fullMode=true
|
||||||
|
|
||||||
# Enable gradle workers
|
|
||||||
android.enableGradleWorkers=true
|
|
||||||
|
|
||||||
# Enable AndroidX
|
# Enable AndroidX
|
||||||
android.useAndroidX=true
|
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
|
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.7-all.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-7.0.1-bin.zip
|
||||||
|
|||||||
Reference in New Issue
Block a user