mirror of
https://github.com/reactivecircus/android-emulator-runner.git
synced 2026-09-01 01:59:32 +00:00
Compare commits
43 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| ed009f5318 | |||
| 04335bcf9e | |||
| 660ac26f5b | |||
| cad321644d | |||
| ed6254cde0 | |||
| 8acdc1106b | |||
| a917366169 | |||
| ae2c4d7c48 | |||
| 9644b1a1f9 | |||
| 4fe4b1ae37 | |||
| 6fe36e1748 | |||
| 597aa7c21b | |||
| 38164a29c1 | |||
| 969c9896d3 | |||
| 29b35ed135 | |||
| 001613e856 | |||
| 937ab7eebc | |||
| 016d4d097a | |||
| f9bdb6d84e | |||
| b68ca169d6 | |||
| 66283c0319 | |||
| f2bf410054 | |||
| 62e6348453 | |||
| 450c4c9f73 | |||
| 2548f9f3fc | |||
| 595a4563df | |||
| a173d65200 | |||
| 50d5b10c01 | |||
| c77bfe7c0b | |||
| ead704cc5a | |||
| e800ffffe6 | |||
| 8c07710601 | |||
| 3a18f50216 | |||
| 1b985f4c7a | |||
| a3dcdb348b | |||
| 81f860b51a | |||
| e93b947104 | |||
| 4b0628e9f8 | |||
| ca77a1081f | |||
| 1fef06a960 | |||
| d8da5b6410 | |||
| a0c0e7216b | |||
| 9d5d6236f4 |
@@ -9,5 +9,5 @@ jobs:
|
|||||||
validate-typings:
|
validate-typings:
|
||||||
runs-on: "ubuntu-latest"
|
runs-on: "ubuntu-latest"
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v7
|
||||||
- uses: krzema12/github-actions-typing@v0
|
- uses: krzema12/github-actions-typing@v2
|
||||||
|
|||||||
+28
-31
@@ -18,41 +18,36 @@ jobs:
|
|||||||
timeout-minutes: 15
|
timeout-minutes: 15
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
os: [ubuntu-latest]
|
|
||||||
api-level: [23, 29]
|
|
||||||
target: [default, google_apis]
|
|
||||||
arch: [x86]
|
|
||||||
exclude:
|
|
||||||
- target: google_apis
|
|
||||||
api-level: 16
|
|
||||||
- target: google_apis
|
|
||||||
api-level: 23
|
|
||||||
- target: google_apis
|
|
||||||
api-level: 29
|
|
||||||
include:
|
include:
|
||||||
- os: ubuntu-latest
|
- os: ubuntu-22.04
|
||||||
|
api-level: 23
|
||||||
|
target: default
|
||||||
|
arch: x86
|
||||||
|
- os: ubuntu-24.04
|
||||||
api-level: 24
|
api-level: 24
|
||||||
target: playstore
|
target: playstore
|
||||||
arch: x86
|
arch: x86
|
||||||
- os: ubuntu-latest
|
- os: macos-15-intel
|
||||||
api-level: 30
|
|
||||||
target: aosp_atd
|
|
||||||
arch: x86
|
|
||||||
- os: macos-latest
|
|
||||||
api-level: 31
|
api-level: 31
|
||||||
target: google_apis
|
target: default
|
||||||
arch: x86_64
|
arch: x86_64
|
||||||
- os: ubuntu-latest
|
- os: ubuntu-24.04
|
||||||
api-level: 34
|
api-level: 34
|
||||||
target: aosp_atd
|
target: aosp_atd
|
||||||
arch: x86_64
|
arch: x86_64
|
||||||
|
- os: ubuntu-latest
|
||||||
|
api-level: 35
|
||||||
|
target: google_apis
|
||||||
|
arch: x86_64
|
||||||
|
- os: ubuntu-latest
|
||||||
|
api-level: 34-ext10
|
||||||
|
target: android-automotive
|
||||||
|
arch: x86_64
|
||||||
|
system-image-api-level: 34-ext9
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: checkout
|
- name: checkout
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v7
|
||||||
|
|
||||||
- name: validate gradle wrapper
|
|
||||||
uses: gradle/wrapper-validation-action@v1
|
|
||||||
|
|
||||||
- name: build, test and lint
|
- name: build, test and lint
|
||||||
run: |
|
run: |
|
||||||
@@ -61,25 +56,25 @@ jobs:
|
|||||||
npm run lint
|
npm run lint
|
||||||
npm test
|
npm test
|
||||||
|
|
||||||
- uses: actions/setup-java@v3
|
- uses: actions/setup-java@v5
|
||||||
with:
|
with:
|
||||||
distribution: 'zulu'
|
distribution: 'zulu'
|
||||||
java-version: 21
|
java-version: 25
|
||||||
|
|
||||||
- uses: actions/cache@v3
|
- uses: actions/cache@v6
|
||||||
id: avd-cache
|
id: avd-cache
|
||||||
with:
|
with:
|
||||||
path: |
|
path: |
|
||||||
~/.android/avd/*
|
~/.android/avd/*
|
||||||
~/.android/adb*
|
~/.android/adb*
|
||||||
~/.android/debug.keystore
|
~/.android/debug.keystore
|
||||||
key: avd-${{ matrix.api-level }}-${{ matrix.os }}-${{ matrix.target }}
|
key: avd-${{ matrix.api-level }}-${{ matrix.os }}-${{ matrix.target }}-${{ matrix.arch }}
|
||||||
|
|
||||||
|
- uses: gradle/actions/setup-gradle@v6
|
||||||
|
|
||||||
- name: assemble tests
|
- name: assemble tests
|
||||||
uses: gradle/gradle-build-action@v2
|
working-directory: test-fixture
|
||||||
with:
|
run: ./gradlew assembleAndroidTest
|
||||||
build-root-directory: test-fixture
|
|
||||||
arguments: assembleAndroidTest
|
|
||||||
|
|
||||||
- name: enable KVM for linux runners
|
- name: enable KVM for linux runners
|
||||||
if: runner.os == 'Linux'
|
if: runner.os == 'Linux'
|
||||||
@@ -95,6 +90,7 @@ jobs:
|
|||||||
api-level: ${{ matrix.api-level }}
|
api-level: ${{ matrix.api-level }}
|
||||||
target: ${{ matrix.target }}
|
target: ${{ matrix.target }}
|
||||||
arch: ${{ matrix.arch }}
|
arch: ${{ matrix.arch }}
|
||||||
|
system-image-api-level: ${{ matrix.system-image-api-level }}
|
||||||
profile: Galaxy Nexus
|
profile: Galaxy Nexus
|
||||||
cores: 2
|
cores: 2
|
||||||
sdcard-path-or-size: 100M
|
sdcard-path-or-size: 100M
|
||||||
@@ -112,6 +108,7 @@ jobs:
|
|||||||
api-level: ${{ matrix.api-level }}
|
api-level: ${{ matrix.api-level }}
|
||||||
target: ${{ matrix.target }}
|
target: ${{ matrix.target }}
|
||||||
arch: ${{ matrix.arch }}
|
arch: ${{ matrix.arch }}
|
||||||
|
system-image-api-level: ${{ matrix.system-image-api-level }}
|
||||||
profile: Galaxy Nexus
|
profile: Galaxy Nexus
|
||||||
cores: 2
|
cores: 2
|
||||||
ram-size: 2048M
|
ram-size: 2048M
|
||||||
|
|||||||
@@ -7,16 +7,18 @@ on:
|
|||||||
required: true
|
required: true
|
||||||
default: 'ubuntu-latest'
|
default: 'ubuntu-latest'
|
||||||
api-level:
|
api-level:
|
||||||
description: 'API level of the platform and system image'
|
description: 'API level of the platform and system image (if not overridden with system-image-api-level input) - e.g. 33, 35-ext15, Baklava'
|
||||||
required: true
|
required: true
|
||||||
default: '30'
|
default: '34'
|
||||||
|
system-image-api-level:
|
||||||
|
description: 'API level of the system image - e.g. 34-ext10, 35-ext15'
|
||||||
target:
|
target:
|
||||||
description: 'target of the system image - default, google_apis, google_apis_playstore, aosp_atd, google_atd, android-wear, android-wear-cn, android-tv or google-tv'
|
description: 'target of the system image - default, google_apis, google_apis_playstore, aosp_atd, google_atd, android-wear, android-wear-cn, android-tv, google-tv, android-automotive, android-automotive-playstore or android-desktop'
|
||||||
required: true
|
required: true
|
||||||
default: 'default'
|
default: 'default'
|
||||||
arch:
|
arch:
|
||||||
description: 'CPU architecture of the system image - x86, x86_64 or arm64-v8a'
|
description: 'CPU architecture of the system image - x86, x86_64 or arm64-v8a'
|
||||||
default: 'x86'
|
default: 'x86_64'
|
||||||
emulator-options:
|
emulator-options:
|
||||||
description: 'command-line options used when launching the emulator'
|
description: 'command-line options used when launching the emulator'
|
||||||
default: '-no-window -gpu swiftshader_indirect -no-snapshot -noaudio -no-boot-anim'
|
default: '-no-window -gpu swiftshader_indirect -no-snapshot -noaudio -no-boot-anim'
|
||||||
@@ -39,10 +41,7 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: checkout
|
- name: checkout
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v7
|
||||||
|
|
||||||
- name: validate gradle wrapper
|
|
||||||
uses: gradle/wrapper-validation-action@v1
|
|
||||||
|
|
||||||
- name: build, test and lint
|
- name: build, test and lint
|
||||||
run: |
|
run: |
|
||||||
@@ -51,14 +50,12 @@ jobs:
|
|||||||
npm run lint
|
npm run lint
|
||||||
npm test
|
npm test
|
||||||
|
|
||||||
- uses: actions/setup-java@v3
|
- uses: actions/setup-java@v5
|
||||||
with:
|
with:
|
||||||
distribution: 'zulu'
|
distribution: 'zulu'
|
||||||
java-version: 21
|
java-version: 25
|
||||||
|
|
||||||
- uses: gradle/gradle-build-action@v2
|
- uses: gradle/actions/setup-gradle@v6
|
||||||
with:
|
|
||||||
gradle-home-cache-cleanup: true
|
|
||||||
|
|
||||||
- name: enable KVM for linux runners
|
- name: enable KVM for linux runners
|
||||||
if: runner.os == 'Linux'
|
if: runner.os == 'Linux'
|
||||||
@@ -73,6 +70,7 @@ jobs:
|
|||||||
api-level: ${{ github.event.inputs.api-level }}
|
api-level: ${{ github.event.inputs.api-level }}
|
||||||
target: ${{ github.event.inputs.target }}
|
target: ${{ github.event.inputs.target }}
|
||||||
arch: ${{ github.event.inputs.arch }}
|
arch: ${{ github.event.inputs.arch }}
|
||||||
|
system-image-api-level: ${{ github.event.inputs.system-image-api-level }}
|
||||||
profile: Galaxy Nexus
|
profile: Galaxy Nexus
|
||||||
emulator-options: ${{ github.event.inputs.emulator-options }}
|
emulator-options: ${{ github.event.inputs.emulator-options }}
|
||||||
emulator-build: ${{ github.event.inputs.emulator-build }}
|
emulator-build: ${{ github.event.inputs.emulator-build }}
|
||||||
|
|||||||
@@ -1,5 +1,53 @@
|
|||||||
# Change Log
|
# Change Log
|
||||||
|
|
||||||
|
## Unreleased
|
||||||
|
|
||||||
|
* Update SDK command-line tools to `23.0`. - [#492](https://github.com/ReactiveCircus/android-emulator-runner/pull/492)
|
||||||
|
|
||||||
|
## v2.38.0
|
||||||
|
|
||||||
|
* Update SDK build tools to `37.0.0`. - [#475](https://github.com/ReactiveCircus/android-emulator-runner/pull/475)
|
||||||
|
|
||||||
|
## v2.37.0
|
||||||
|
|
||||||
|
* Update SDK build tools to `36.0.0`, update SDK command-line tools to `20.0`. - [#467](https://github.com/ReactiveCircus/android-emulator-runner/pull/467)
|
||||||
|
* Run action on Node 24. - [#466](https://github.com/ReactiveCircus/android-emulator-runner/pull/466)
|
||||||
|
* Update Node and npm packages. - [#466](https://github.com/ReactiveCircus/android-emulator-runner/pull/466)
|
||||||
|
|
||||||
|
## v2.36.0
|
||||||
|
|
||||||
|
* Remove `--abi` option to better support 16-KB-based system images (#456).
|
||||||
|
|
||||||
|
|
||||||
|
## v2.35.0
|
||||||
|
|
||||||
|
* Optimize config.ini updates and efficiency improvements report (#436).
|
||||||
|
* Fix `pre-emulator-launch-script` (#439).
|
||||||
|
* Allow `google_apis_ps16k` as a valid target (#440).
|
||||||
|
|
||||||
|
## v2.34.0
|
||||||
|
|
||||||
|
* Allow arbitrary value for `api-level` such as `Baklava` and `35-ext15`. - [428](https://github.com/ReactiveCircus/android-emulator-runner/pull/428)
|
||||||
|
* Add option to specify `system-image-api-level` to use a system image with a different API level than the platform. - [428](https://github.com/ReactiveCircus/android-emulator-runner/pull/428)
|
||||||
|
* Support automotive and desktop targets: `android-automotive`, `android-automotive-playstore`, `android-desktop`. - [428](https://github.com/ReactiveCircus/android-emulator-runner/pull/428)
|
||||||
|
|
||||||
|
## v2.33.0
|
||||||
|
|
||||||
|
* Fix missing AVD directory in `ubuntu-24.04` runner. - [415](https://github.com/ReactiveCircus/android-emulator-runner/pull/415)
|
||||||
|
* Update SDK build tools to `35.0.0`, update SDK command-line tools to `16.0`. - [#356](https://github.com/ReactiveCircus/android-emulator-runner/pull/356)
|
||||||
|
* Stop changing owner of the SDK directory. - [406](https://github.com/ReactiveCircus/android-emulator-runner/pull/406) [#409](https://github.com/ReactiveCircus/android-emulator-runner/pull/409)
|
||||||
|
* Upgrade to latest npm dependencies. - [#401](https://github.com/ReactiveCircus/android-emulator-runner/pull/401)
|
||||||
|
|
||||||
|
## v2.32.0
|
||||||
|
|
||||||
|
* Add `port` parameter for customizing the emulator port to use. - [#383](https://github.com/ReactiveCircus/android-emulator-runner/pull/383)
|
||||||
|
|
||||||
|
|
||||||
|
## v2.31.0
|
||||||
|
|
||||||
|
* Support setting `VanillaIceCream` as `api-level`. - [#378](https://github.com/ReactiveCircus/android-emulator-runner/pull/378)
|
||||||
|
* Install `platforms` for the specified `api-level`. - [#384](https://github.com/ReactiveCircus/android-emulator-runner/pull/384)
|
||||||
|
|
||||||
## v2.30.1
|
## v2.30.1
|
||||||
|
|
||||||
* Run action on Node 20. - [#371](https://github.com/ReactiveCircus/android-emulator-runner/pull/371)
|
* Run action on Node 20. - [#371](https://github.com/ReactiveCircus/android-emulator-runner/pull/371)
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ This presents a challenge when running emulators on CI especially when running e
|
|||||||
|
|
||||||
## Running hardware accelerated emulators on Linux runners
|
## Running hardware accelerated emulators on Linux runners
|
||||||
|
|
||||||
GitHub's [larger Linux runners support running hardware accelerated emulators](https://github.blog/changelog/2023-02-23-hardware-accelerated-android-virtualization-on-actions-windows-and-linux-larger-hosted-runners/) which is [free for public GitHub repos](https://github.blog/2024-01-17-github-hosted-runners-double-the-power-for-open-source/). It is now recommended to use the **Ubuntu** (`ubuntu-latest`) runners which are 2-3 times faster than the **macOS** ones which are also a lot more expensive. Remember to enable KVM in your workflow before running this action:
|
GitHub's [larger Linux runners support running hardware accelerated emulators](https://github.blog/changelog/2023-02-23-hardware-accelerated-android-virtualization-on-actions-windows-and-linux-larger-hosted-runners/). It is now recommended to use the **Ubuntu** (`ubuntu-latest`) runners which are 2-3 times faster than the **macOS** ones which are also a lot more expensive. Remember to enable KVM in your workflow before running this action:
|
||||||
|
|
||||||
```
|
```
|
||||||
- name: Enable KVM group perms
|
- name: Enable KVM group perms
|
||||||
@@ -49,7 +49,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: checkout
|
- name: checkout
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v6
|
||||||
|
|
||||||
- name: Enable KVM
|
- name: Enable KVM
|
||||||
run: |
|
run: |
|
||||||
@@ -76,7 +76,7 @@ jobs:
|
|||||||
target: [default, google_apis]
|
target: [default, google_apis]
|
||||||
steps:
|
steps:
|
||||||
- name: checkout
|
- name: checkout
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v6
|
||||||
|
|
||||||
- name: Enable KVM
|
- name: Enable KVM
|
||||||
run: |
|
run: |
|
||||||
@@ -90,7 +90,7 @@ jobs:
|
|||||||
api-level: ${{ matrix.api-level }}
|
api-level: ${{ matrix.api-level }}
|
||||||
target: ${{ matrix.target }}
|
target: ${{ matrix.target }}
|
||||||
arch: x86_64
|
arch: x86_64
|
||||||
profile: Nexus 6
|
profile: pixel_7_pro
|
||||||
script: ./gradlew connectedCheck
|
script: ./gradlew connectedCheck
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -102,7 +102,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: checkout
|
- name: checkout
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v6
|
||||||
|
|
||||||
- name: Enable KVM
|
- name: Enable KVM
|
||||||
run: |
|
run: |
|
||||||
@@ -119,10 +119,35 @@ jobs:
|
|||||||
script: ./gradlew connectedCheck
|
script: ./gradlew connectedCheck
|
||||||
```
|
```
|
||||||
|
|
||||||
|
If you need a specific [SDK Extensions](https://developer.android.com/guide/sdk-extensions) for the system image but not the platform:
|
||||||
|
|
||||||
|
```yml
|
||||||
|
jobs:
|
||||||
|
test:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: checkout
|
||||||
|
uses: actions/checkout@v6
|
||||||
|
|
||||||
|
- name: Enable KVM
|
||||||
|
run: |
|
||||||
|
echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules
|
||||||
|
sudo udevadm control --reload-rules
|
||||||
|
sudo udevadm trigger --name-match=kvm
|
||||||
|
|
||||||
|
- name: run tests
|
||||||
|
uses: reactivecircus/android-emulator-runner@v2
|
||||||
|
with:
|
||||||
|
api-level: 34
|
||||||
|
system-image-api-level: 34-ext9
|
||||||
|
target: android-automotive
|
||||||
|
script: ./gradlew connectedCheck
|
||||||
|
```
|
||||||
|
|
||||||
We can significantly reduce emulator startup time by setting up AVD snapshot caching:
|
We can significantly reduce emulator startup time by setting up AVD snapshot caching:
|
||||||
|
|
||||||
1. add a `gradle/gradle-build-action@v2` step for caching Gradle, more details see [#229](https://github.com/ReactiveCircus/android-emulator-runner/issues/229)
|
1. add a `gradle/actions/setup-gradle@v5` step for caching Gradle, more details see [#229](https://github.com/ReactiveCircus/android-emulator-runner/issues/229)
|
||||||
2. add an `actions/cache@v3` step for caching the `avd`
|
2. add an `actions/cache@v5` step for caching the `avd`
|
||||||
3. add a `reactivecircus/android-emulator-runner@v2` step to generate a clean snapshot - specify `emulator-options` without `no-snapshot`
|
3. add a `reactivecircus/android-emulator-runner@v2` step to generate a clean snapshot - specify `emulator-options` without `no-snapshot`
|
||||||
4. add another `reactivecircus/android-emulator-runner@v2` step to run your tests using existing AVD / snapshot - specify `emulator-options` with `no-snapshot-save`
|
4. add another `reactivecircus/android-emulator-runner@v2` step to run your tests using existing AVD / snapshot - specify `emulator-options` with `no-snapshot-save`
|
||||||
|
|
||||||
@@ -135,7 +160,7 @@ jobs:
|
|||||||
api-level: [21, 23, 29]
|
api-level: [21, 23, 29]
|
||||||
steps:
|
steps:
|
||||||
- name: checkout
|
- name: checkout
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v6
|
||||||
|
|
||||||
- name: Enable KVM
|
- name: Enable KVM
|
||||||
run: |
|
run: |
|
||||||
@@ -144,10 +169,10 @@ jobs:
|
|||||||
sudo udevadm trigger --name-match=kvm
|
sudo udevadm trigger --name-match=kvm
|
||||||
|
|
||||||
- name: Gradle cache
|
- name: Gradle cache
|
||||||
uses: gradle/gradle-build-action@v2
|
uses: gradle/actions/setup-gradle@v5
|
||||||
|
|
||||||
- name: AVD cache
|
- name: AVD cache
|
||||||
uses: actions/cache@v3
|
uses: actions/cache@v5
|
||||||
id: avd-cache
|
id: avd-cache
|
||||||
with:
|
with:
|
||||||
path: |
|
path: |
|
||||||
@@ -179,10 +204,11 @@ jobs:
|
|||||||
|
|
||||||
| **Input** | **Required** | **Default** | **Description** |
|
| **Input** | **Required** | **Default** | **Description** |
|
||||||
|-|-|-|-|
|
|-|-|-|-|
|
||||||
| `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 and system image - e.g. `23`, `33`, `35-ext15`, `Baklava`. **Minimum API level supported is 15**. |
|
||||||
| `target` | Optional | `default` | Target of the system image - `default`, `google_apis`, `playstore`, `android-wear`, `android-wear-cn`, `android-tv`, `google-tv`, `aosp_atd` or `google_atd`. Note that `aosp_atd` and `google_atd` currently require the following: `api-level: 30`, `arch: x86` or `arch: arm64-v8` and `channel: canary`. |
|
| `system-image-api-level` | Optional | same as `api-level` | API level of the system image - e.g. `34-ext10`, `35-ext15`. |
|
||||||
|
| `target` | Optional | `default` | Target of the system image - e.g. `default`, `google_apis`, `google_apis_ps16k`, `google_apis_playstore`, `google_apis_playstore_ps16k`, `android-wear`, `android-wear-cn`, `android-tv`, `google-tv`, `aosp_atd`, `google_atd`, `android-automotive`, `android-automotive-playstore`, `android-desktop`. Please run `sdkmanager --list` to see the available targets. |
|
||||||
| `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). |
|
| `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 device`. |
|
| `profile` | Optional | N/A | Hardware profile id used for creating the AVD - e.g. `pixel_7_pro`. For a list of all profiles available, run `avdmanager list device`. |
|
||||||
| `cores` | Optional | 2 | Number of cores to use for the emulator (`hw.cpu.ncore` in config.ini). |
|
| `cores` | Optional | 2 | Number of cores to use for the emulator (`hw.cpu.ncore` in config.ini). |
|
||||||
| `ram-size` | Optional | N/A | Size of RAM to use for this AVD, in KB or MB, denoted with K or M. - e.g. `2048M` |
|
| `ram-size` | Optional | N/A | Size of RAM to use for this AVD, in KB or MB, denoted with K or M. - e.g. `2048M` |
|
||||||
| `heap-size` | Optional | N/A | Heap size to use for this AVD, in KB or MB, denoted with K or M. - e.g. `512M` |
|
| `heap-size` | Optional | N/A | Heap size to use for this AVD, in KB or MB, denoted with K or M. - e.g. `512M` |
|
||||||
@@ -191,6 +217,7 @@ jobs:
|
|||||||
| `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. |
|
||||||
| `force-avd-creation` | Optional | `true` | Whether to force create the AVD by overwriting an existing AVD with the same name as `avd-name` - `true` or `false`. |
|
| `force-avd-creation` | Optional | `true` | Whether to force create the AVD by overwriting an existing AVD with the same name as `avd-name` - `true` or `false`. |
|
||||||
| `emulator-boot-timeout` | Optional | `600` | Emulator boot timeout in seconds. If it takes longer to boot, the action would fail - e.g. `300` for 5 minutes. |
|
| `emulator-boot-timeout` | Optional | `600` | Emulator boot timeout in seconds. If it takes longer to boot, the action would fail - e.g. `300` for 5 minutes. |
|
||||||
|
| `emulator-port` | Optional | `5554` | Emulator port to use. Allows to run this action on multiple workers on a single machine at the same time. This input is available for the script as `EMULATOR_PORT` enviromental variable. This port is automatically used by android device related tasks in gradle |
|
||||||
| `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-spellchecker` | Optional | `false` | Whether to disable spellchecker - `true` or `false`. |
|
||||||
@@ -242,5 +269,9 @@ These are some of the open-source projects using (or used) **Android Emulator Ru
|
|||||||
- [ACRA/acra](https://github.com/ACRA/acra/blob/master/.github/workflows/test.yml)
|
- [ACRA/acra](https://github.com/ACRA/acra/blob/master/.github/workflows/test.yml)
|
||||||
- [bitfireAT/davx5-ose](https://github.com/bitfireAT/davx5-ose/blob/dev-ose/.github/workflows/test-dev.yml)
|
- [bitfireAT/davx5-ose](https://github.com/bitfireAT/davx5-ose/blob/dev-ose/.github/workflows/test-dev.yml)
|
||||||
- [robolectric/robolectric](https://github.com/robolectric/robolectric/blob/master/.github/workflows/tests.yml)
|
- [robolectric/robolectric](https://github.com/robolectric/robolectric/blob/master/.github/workflows/tests.yml)
|
||||||
|
- [home-assistant/android](https://github.com/home-assistant/android/blob/master/.github/workflows/pr.yml)
|
||||||
|
- [composablehorizons/compose-unstyled](https://github.com/composablehorizons/compose-unstyled/tree/main/.github/workflows)
|
||||||
|
- [f3d-app/f3d-android](https://github.com/f3d-app/f3d-android/blob/master/.github/workflows/ci.yml)
|
||||||
|
- [freeorion/freeorion](https://github.com/freeorion/freeorion/blob/master/.github/workflows/_build-android.yml)
|
||||||
|
|
||||||
If you are using **Android Emulator Runner** and want your project included in the list, please feel free to open a pull request.
|
If you are using **Android Emulator Runner** and want your project included in the list, please feel free to open a pull request.
|
||||||
|
|||||||
@@ -1,103 +1,5 @@
|
|||||||
import * as validator from '../src/input-validator';
|
import * as validator from '../src/input-validator';
|
||||||
|
import { MAX_PORT, MIN_PORT } from '../src/input-validator';
|
||||||
describe('api-level validator tests', () => {
|
|
||||||
it('Throws if api-level is not a number', () => {
|
|
||||||
const func = () => {
|
|
||||||
validator.checkApiLevel('api');
|
|
||||||
};
|
|
||||||
expect(func).toThrowError(`Unexpected API level: 'api'.`);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('Throws if api-level is not an integer', () => {
|
|
||||||
const func = () => {
|
|
||||||
validator.checkApiLevel('29.1');
|
|
||||||
};
|
|
||||||
expect(func).toThrowError(`Unexpected API level: '29.1'.`);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('Throws if api-level is lower than min API supported', () => {
|
|
||||||
const func = () => {
|
|
||||||
validator.checkApiLevel('14');
|
|
||||||
};
|
|
||||||
expect(func).toThrowError(`Minimum API level supported is ${validator.MIN_API_LEVEL}.`);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('Validates successfully with valid api-level', () => {
|
|
||||||
const func1 = () => {
|
|
||||||
validator.checkApiLevel('15');
|
|
||||||
};
|
|
||||||
expect(func1).not.toThrow();
|
|
||||||
|
|
||||||
const func2 = () => {
|
|
||||||
validator.checkApiLevel('29');
|
|
||||||
};
|
|
||||||
expect(func2).not.toThrow();
|
|
||||||
const func3 = () => {
|
|
||||||
validator.checkApiLevel('UpsideDownCake-ext5');
|
|
||||||
};
|
|
||||||
expect(func3).not.toThrow();
|
|
||||||
const func4 = () => {
|
|
||||||
validator.checkApiLevel('TiramisuPrivacySandbox');
|
|
||||||
};
|
|
||||||
expect(func4).not.toThrow();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('target validator tests', () => {
|
|
||||||
it('Throws if target is unknown', () => {
|
|
||||||
const func = () => {
|
|
||||||
validator.checkTarget('some-target');
|
|
||||||
};
|
|
||||||
expect(func).toThrowError(`Value for input.target 'some-target' is unknown. Supported options: ${validator.VALID_TARGETS}`);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('Validates successfully with valid target', () => {
|
|
||||||
const func1 = () => {
|
|
||||||
validator.checkTarget('default');
|
|
||||||
};
|
|
||||||
expect(func1).not.toThrow();
|
|
||||||
|
|
||||||
const func2 = () => {
|
|
||||||
validator.checkTarget('google_apis');
|
|
||||||
};
|
|
||||||
expect(func2).not.toThrow();
|
|
||||||
|
|
||||||
const func3 = () => {
|
|
||||||
validator.checkTarget('aosp_atd');
|
|
||||||
};
|
|
||||||
expect(func3).not.toThrow();
|
|
||||||
|
|
||||||
const func4 = () => {
|
|
||||||
validator.checkTarget('google_atd');
|
|
||||||
};
|
|
||||||
expect(func4).not.toThrow();
|
|
||||||
|
|
||||||
const func5 = () => {
|
|
||||||
validator.checkTarget('google_apis_playstore');
|
|
||||||
};
|
|
||||||
expect(func5).not.toThrow();
|
|
||||||
|
|
||||||
const func6 = () => {
|
|
||||||
validator.checkTarget('android-wear');
|
|
||||||
};
|
|
||||||
expect(func6).not.toThrow();
|
|
||||||
|
|
||||||
const func7 = () => {
|
|
||||||
validator.checkTarget('android-wear-cn');
|
|
||||||
};
|
|
||||||
expect(func7).not.toThrow();
|
|
||||||
|
|
||||||
const func8 = () => {
|
|
||||||
validator.checkTarget('android-tv');
|
|
||||||
};
|
|
||||||
expect(func8).not.toThrow();
|
|
||||||
|
|
||||||
const func9 = () => {
|
|
||||||
validator.checkTarget('google-tv');
|
|
||||||
};
|
|
||||||
expect(func9).not.toThrow();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('arch validator tests', () => {
|
describe('arch validator tests', () => {
|
||||||
it('Throws if arch is unknown', () => {
|
it('Throws if arch is unknown', () => {
|
||||||
@@ -172,6 +74,33 @@ describe('force-avd-creation validator tests', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('emulator-port validator tests', () => {
|
||||||
|
it('Validates if emulator-port is even and in range', () => {
|
||||||
|
const func = () => {
|
||||||
|
validator.checkPort(5554);
|
||||||
|
};
|
||||||
|
expect(func).not.toThrow();
|
||||||
|
});
|
||||||
|
it('Throws if emulator-port is lower than MIN_PORT', () => {
|
||||||
|
const func = () => {
|
||||||
|
validator.checkPort(MIN_PORT - 2);
|
||||||
|
};
|
||||||
|
expect(func).toThrow();
|
||||||
|
});
|
||||||
|
it('Throws if emulator-port is higher than MAX_PORT', () => {
|
||||||
|
const func = () => {
|
||||||
|
validator.checkPort(MAX_PORT + 2);
|
||||||
|
};
|
||||||
|
expect(func).toThrow();
|
||||||
|
});
|
||||||
|
it('Throws if emulator-port is odd', () => {
|
||||||
|
const func = () => {
|
||||||
|
validator.checkPort(5555);
|
||||||
|
};
|
||||||
|
expect(func).toThrow();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('disable-animations validator tests', () => {
|
describe('disable-animations validator tests', () => {
|
||||||
it('Throws if disable-animations is not a boolean', () => {
|
it('Throws if disable-animations is not a boolean', () => {
|
||||||
const func = () => {
|
const func = () => {
|
||||||
|
|||||||
+8
-1
@@ -1,6 +1,8 @@
|
|||||||
inputs:
|
inputs:
|
||||||
api-level:
|
api-level:
|
||||||
type: integer
|
type: string
|
||||||
|
system-image-api-level:
|
||||||
|
type: string
|
||||||
target:
|
target:
|
||||||
type: enum
|
type: enum
|
||||||
allowed-values:
|
allowed-values:
|
||||||
@@ -13,6 +15,9 @@ inputs:
|
|||||||
- android-wear-cn
|
- android-wear-cn
|
||||||
- android-tv
|
- android-tv
|
||||||
- google-tv
|
- google-tv
|
||||||
|
- android-automotive
|
||||||
|
- android-automotive-playstore
|
||||||
|
- android-desktop
|
||||||
arch:
|
arch:
|
||||||
type: enum
|
type: enum
|
||||||
allowed-values:
|
allowed-values:
|
||||||
@@ -37,6 +42,8 @@ inputs:
|
|||||||
type: boolean
|
type: boolean
|
||||||
emulator-boot-timeout:
|
emulator-boot-timeout:
|
||||||
type: integer
|
type: integer
|
||||||
|
emulator-port:
|
||||||
|
type: integer
|
||||||
emulator-options:
|
emulator-options:
|
||||||
type: string
|
type: string
|
||||||
disable-animations:
|
disable-animations:
|
||||||
|
|||||||
+9
-3
@@ -6,10 +6,13 @@ branding:
|
|||||||
color: 'green'
|
color: 'green'
|
||||||
inputs:
|
inputs:
|
||||||
api-level:
|
api-level:
|
||||||
description: 'API level of the platform and system image - e.g. 23 for Android Marshmallow, 29 for Android 10'
|
description: 'API level of the platform and system image - e.g. 23, 33, 35-ext15, Baklava'
|
||||||
required: true
|
required: true
|
||||||
|
system-image-api-level:
|
||||||
|
description: 'API level of the system image - e.g. 34-ext10, 35-ext15. If not set the `api-level` input will be used.'
|
||||||
|
required: false
|
||||||
target:
|
target:
|
||||||
description: 'target of the system image - default, google_apis, google_apis_playstore, aosp_atd, google_atd, android-wear, android-wear-cn, android-tv or google-tv'
|
description: 'target of the system image - e.g. default, google_apis, google_apis_ps16k, google_apis_playstore, google_apis_playstore_16k, aosp_atd, google_atd, android-wear, android-wear-cn, android-tv, google-tv, android-automotive, android-automotive-playstore or android-desktop'
|
||||||
default: 'default'
|
default: 'default'
|
||||||
arch:
|
arch:
|
||||||
description: 'CPU architecture of the system image - x86, x86_64 or arm64-v8a'
|
description: 'CPU architecture of the system image - x86, x86_64 or arm64-v8a'
|
||||||
@@ -36,6 +39,9 @@ inputs:
|
|||||||
emulator-boot-timeout:
|
emulator-boot-timeout:
|
||||||
description: 'Emulator boot timeout in seconds. If it takes longer to boot, the action would fail - e.g. `300` for 5 minutes'
|
description: 'Emulator boot timeout in seconds. If it takes longer to boot, the action would fail - e.g. `300` for 5 minutes'
|
||||||
default: '600'
|
default: '600'
|
||||||
|
emulator-port:
|
||||||
|
description: 'Port to run emulator on, allows to run multiple emulators on the same physical machine'
|
||||||
|
default: '5554'
|
||||||
emulator-options:
|
emulator-options:
|
||||||
description: 'command-line options used when launching the emulator - e.g. `-no-window -no-snapshot -camera-back emulated`'
|
description: 'command-line options used when launching the emulator - e.g. `-no-window -no-snapshot -camera-back emulated`'
|
||||||
default: '-no-window -gpu swiftshader_indirect -no-snapshot -noaudio -no-boot-anim'
|
default: '-no-window -gpu swiftshader_indirect -no-snapshot -noaudio -no-boot-anim'
|
||||||
@@ -68,5 +74,5 @@ inputs:
|
|||||||
pre-emulator-launch-script:
|
pre-emulator-launch-script:
|
||||||
description: 'custom script to run after creating the AVD and before launching the emulator - e.g. `./adjust-emulator-configs.sh`'
|
description: 'custom script to run after creating the AVD and before launching the emulator - e.g. `./adjust-emulator-configs.sh`'
|
||||||
runs:
|
runs:
|
||||||
using: 'node20'
|
using: 'node24'
|
||||||
main: 'lib/main.js'
|
main: 'lib/main.js'
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
exports.getChannelId = void 0;
|
exports.getChannelId = getChannelId;
|
||||||
function getChannelId(channelName) {
|
function getChannelId(channelName) {
|
||||||
if (channelName === 'stable') {
|
if (channelName === 'stable') {
|
||||||
return 0;
|
return 0;
|
||||||
@@ -18,4 +18,3 @@ function getChannelId(channelName) {
|
|||||||
throw new Error(`Unexpected channel name: '${channelName}'.`);
|
throw new Error(`Unexpected channel name: '${channelName}'.`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
exports.getChannelId = getChannelId;
|
|
||||||
|
|||||||
+131
-115
@@ -15,149 +15,165 @@ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (
|
|||||||
}) : function(o, v) {
|
}) : function(o, v) {
|
||||||
o["default"] = v;
|
o["default"] = v;
|
||||||
});
|
});
|
||||||
var __importStar = (this && this.__importStar) || function (mod) {
|
var __importStar = (this && this.__importStar) || (function () {
|
||||||
if (mod && mod.__esModule) return mod;
|
var ownKeys = function(o) {
|
||||||
var result = {};
|
ownKeys = Object.getOwnPropertyNames || function (o) {
|
||||||
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
var ar = [];
|
||||||
__setModuleDefault(result, mod);
|
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
||||||
return result;
|
return ar;
|
||||||
};
|
};
|
||||||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
return ownKeys(o);
|
||||||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
};
|
||||||
return new (P || (P = Promise))(function (resolve, reject) {
|
return function (mod) {
|
||||||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
if (mod && mod.__esModule) return mod;
|
||||||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
var result = {};
|
||||||
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
||||||
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
__setModuleDefault(result, mod);
|
||||||
});
|
return result;
|
||||||
};
|
};
|
||||||
|
})();
|
||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
exports.killEmulator = exports.launchEmulator = void 0;
|
exports.createAvd = createAvd;
|
||||||
|
exports.launchEmulator = launchEmulator;
|
||||||
|
exports.killEmulator = killEmulator;
|
||||||
const exec = __importStar(require("@actions/exec"));
|
const exec = __importStar(require("@actions/exec"));
|
||||||
const fs = __importStar(require("fs"));
|
const fs = __importStar(require("fs"));
|
||||||
/**
|
/**
|
||||||
* Creates and launches a new AVD instance with the specified configurations.
|
* Creates a new AVD instance with the specified configurations.
|
||||||
*/
|
*/
|
||||||
function launchEmulator(apiLevel, target, arch, profile, cores, ramSize, heapSize, sdcardPathOrSize, diskSize, avdName, forceAvdCreation, emulatorBootTimeout, emulatorOptions, disableAnimations, disableSpellChecker, disableLinuxHardwareAcceleration, enableHardwareKeyboard) {
|
async function createAvd(arch, avdName, cores, diskSize, enableHardwareKeyboard, forceAvdCreation, heapSize, profile, ramSize, sdcardPathOrSize, systemImageApiLevel, target) {
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
try {
|
||||||
try {
|
console.log(`::group::Create AVD`);
|
||||||
console.log(`::group::Launch Emulator`);
|
// create a new AVD if AVD directory does not already exist or forceAvdCreation is true
|
||||||
// create a new AVD if AVD directory does not already exist or forceAvdCreation is true
|
const avdPath = `${process.env.ANDROID_AVD_HOME}/${avdName}.avd`;
|
||||||
const avdPath = `${process.env.ANDROID_AVD_HOME}/${avdName}.avd`;
|
if (!fs.existsSync(avdPath) || forceAvdCreation) {
|
||||||
if (!fs.existsSync(avdPath) || forceAvdCreation) {
|
const profileOption = profile.trim() !== '' ? `--device '${profile}'` : '';
|
||||||
const profileOption = profile.trim() !== '' ? `--device '${profile}'` : '';
|
const sdcardPathOrSizeOption = sdcardPathOrSize.trim() !== '' ? `--sdcard '${sdcardPathOrSize}'` : '';
|
||||||
const sdcardPathOrSizeOption = sdcardPathOrSize.trim() !== '' ? `--sdcard '${sdcardPathOrSize}'` : '';
|
console.log(`Creating AVD.`);
|
||||||
console.log(`Creating AVD.`);
|
await exec.exec(`sh -c \\"echo no | avdmanager create avd --force -n "${avdName}" --package 'system-images;android-${systemImageApiLevel};${target};${arch}' ${profileOption} ${sdcardPathOrSizeOption}"`);
|
||||||
yield exec.exec(`sh -c \\"echo no | avdmanager create avd --force -n "${avdName}" --abi '${target}/${arch}' --package 'system-images;android-${apiLevel};${target};${arch}' ${profileOption} ${sdcardPathOrSizeOption}"`);
|
}
|
||||||
}
|
if (cores || ramSize || heapSize || enableHardwareKeyboard || diskSize) {
|
||||||
|
const configEntries = [];
|
||||||
if (cores) {
|
if (cores) {
|
||||||
yield exec.exec(`sh -c \\"printf 'hw.cpu.ncore=${cores}\n' >> ${process.env.ANDROID_AVD_HOME}/"${avdName}".avd"/config.ini`);
|
configEntries.push(`hw.cpu.ncore=${cores}`);
|
||||||
}
|
}
|
||||||
if (ramSize) {
|
if (ramSize) {
|
||||||
yield exec.exec(`sh -c \\"printf 'hw.ramSize=${ramSize}\n' >> ${process.env.ANDROID_AVD_HOME}/"${avdName}".avd"/config.ini`);
|
configEntries.push(`hw.ramSize=${ramSize}`);
|
||||||
}
|
}
|
||||||
if (heapSize) {
|
if (heapSize) {
|
||||||
yield exec.exec(`sh -c \\"printf 'hw.heapSize=${heapSize}\n' >> ${process.env.ANDROID_AVD_HOME}/"${avdName}".avd"/config.ini`);
|
configEntries.push(`hw.heapSize=${heapSize}`);
|
||||||
}
|
}
|
||||||
if (enableHardwareKeyboard) {
|
if (enableHardwareKeyboard) {
|
||||||
yield exec.exec(`sh -c \\"printf 'hw.keyboard=yes\n' >> ${process.env.ANDROID_AVD_HOME}/"${avdName}".avd"/config.ini`);
|
configEntries.push('hw.keyboard=yes');
|
||||||
}
|
}
|
||||||
if (diskSize) {
|
if (diskSize) {
|
||||||
yield exec.exec(`sh -c \\"printf 'disk.dataPartition.size=${diskSize}\n' >> ${process.env.ANDROID_AVD_HOME}/"${avdName}".avd"/config.ini`);
|
configEntries.push(`disk.dataPartition.size=${diskSize}`);
|
||||||
}
|
}
|
||||||
// turn off hardware acceleration on Linux
|
if (configEntries.length > 0) {
|
||||||
if (process.platform === 'linux' && disableLinuxHardwareAcceleration) {
|
const configContent = configEntries.join('\\n') + '\\n';
|
||||||
console.log('Disabling Linux hardware acceleration.');
|
await exec.exec(`sh -c \\"printf '${configContent}' >> ${process.env.ANDROID_AVD_HOME}/"${avdName}".avd"/config.ini"`);
|
||||||
emulatorOptions += ' -accel off';
|
|
||||||
}
|
|
||||||
// start emulator
|
|
||||||
console.log('Starting emulator.');
|
|
||||||
yield exec.exec(`sh -c \\"${process.env.ANDROID_HOME}/emulator/emulator -avd "${avdName}" ${emulatorOptions} &"`, [], {
|
|
||||||
listeners: {
|
|
||||||
stderr: (data) => {
|
|
||||||
if (data.toString().includes('invalid command-line parameter')) {
|
|
||||||
throw new Error(data.toString());
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
// wait for emulator to complete booting
|
|
||||||
yield waitForDevice(emulatorBootTimeout);
|
|
||||||
yield exec.exec(`adb shell input keyevent 82`);
|
|
||||||
if (disableAnimations) {
|
|
||||||
console.log('Disabling animations.');
|
|
||||||
yield exec.exec(`adb shell settings put global window_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`);
|
|
||||||
}
|
|
||||||
if (disableSpellChecker) {
|
|
||||||
yield exec.exec(`adb shell settings put secure spell_checker_enabled 0`);
|
|
||||||
}
|
|
||||||
if (enableHardwareKeyboard) {
|
|
||||||
yield exec.exec(`adb shell settings put secure show_ime_with_hard_keyboard 0`);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
finally {
|
}
|
||||||
console.log(`::endgroup::`);
|
finally {
|
||||||
}
|
console.log(`::endgroup::`);
|
||||||
});
|
}
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Launches an existing AVD instance with the specified configurations.
|
||||||
|
*/
|
||||||
|
async function launchEmulator(avdName, disableAnimations, disableLinuxHardwareAcceleration, disableSpellChecker, emulatorBootTimeout, emulatorOptions, enableHardwareKeyboard, port) {
|
||||||
|
try {
|
||||||
|
console.log(`::group::Launch Emulator`);
|
||||||
|
// turn off hardware acceleration on Linux
|
||||||
|
if (process.platform === 'linux' && disableLinuxHardwareAcceleration) {
|
||||||
|
console.log('Disabling Linux hardware acceleration.');
|
||||||
|
emulatorOptions += ' -accel off';
|
||||||
|
}
|
||||||
|
// start emulator
|
||||||
|
console.log('Starting emulator.');
|
||||||
|
await exec.exec(`sh -c \\"${process.env.ANDROID_HOME}/emulator/emulator -port ${port} -avd "${avdName}" ${emulatorOptions} &"`, [], {
|
||||||
|
listeners: {
|
||||||
|
stderr: (data) => {
|
||||||
|
if (data.toString().includes('invalid command-line parameter')) {
|
||||||
|
throw new Error(data.toString());
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
// wait for emulator to complete booting
|
||||||
|
await waitForDevice(port, emulatorBootTimeout);
|
||||||
|
await adb(port, `shell input keyevent 82`);
|
||||||
|
if (disableAnimations) {
|
||||||
|
console.log('Disabling animations.');
|
||||||
|
await adb(port, `shell settings put global window_animation_scale 0.0`);
|
||||||
|
await adb(port, `shell settings put global transition_animation_scale 0.0`);
|
||||||
|
await adb(port, `shell settings put global animator_duration_scale 0.0`);
|
||||||
|
}
|
||||||
|
if (disableSpellChecker) {
|
||||||
|
await adb(port, `shell settings put secure spell_checker_enabled 0`);
|
||||||
|
}
|
||||||
|
if (enableHardwareKeyboard) {
|
||||||
|
await adb(port, `shell settings put secure show_ime_with_hard_keyboard 0`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
console.log(`::endgroup::`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
exports.launchEmulator = launchEmulator;
|
|
||||||
/**
|
/**
|
||||||
* Kills the running emulator on the default port.
|
* Kills the running emulator on the default port.
|
||||||
*/
|
*/
|
||||||
function killEmulator() {
|
async function killEmulator(port) {
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
try {
|
||||||
try {
|
console.log(`::group::Terminate Emulator`);
|
||||||
console.log(`::group::Terminate Emulator`);
|
await adb(port, `emu kill`);
|
||||||
yield exec.exec(`adb -s emulator-5554 emu kill`);
|
}
|
||||||
}
|
catch (error) {
|
||||||
catch (error) {
|
console.log(error instanceof Error ? error.message : error);
|
||||||
console.log(error instanceof Error ? error.message : error);
|
}
|
||||||
}
|
finally {
|
||||||
finally {
|
console.log(`::endgroup::`);
|
||||||
console.log(`::endgroup::`);
|
}
|
||||||
}
|
}
|
||||||
});
|
async function adb(port, command) {
|
||||||
|
return await exec.exec(`adb -s emulator-${port} ${command}`);
|
||||||
}
|
}
|
||||||
exports.killEmulator = killEmulator;
|
|
||||||
/**
|
/**
|
||||||
* Wait for emulator to boot.
|
* Wait for emulator to boot.
|
||||||
*/
|
*/
|
||||||
function waitForDevice(emulatorBootTimeout) {
|
async function waitForDevice(port, emulatorBootTimeout) {
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
let booted = false;
|
||||||
let booted = false;
|
let attempts = 0;
|
||||||
let attempts = 0;
|
const retryInterval = 2; // retry every 2 seconds
|
||||||
const retryInterval = 2; // retry every 2 seconds
|
const maxAttempts = emulatorBootTimeout / 2;
|
||||||
const maxAttempts = emulatorBootTimeout / 2;
|
while (!booted) {
|
||||||
while (!booted) {
|
try {
|
||||||
try {
|
let result = '';
|
||||||
let result = '';
|
await exec.exec(`adb -s emulator-${port} shell getprop sys.boot_completed`, [], {
|
||||||
yield exec.exec(`adb shell getprop sys.boot_completed`, [], {
|
listeners: {
|
||||||
listeners: {
|
stdout: (data) => {
|
||||||
stdout: (data) => {
|
result += data.toString();
|
||||||
result += data.toString();
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
});
|
},
|
||||||
if (result.trim() === '1') {
|
});
|
||||||
console.log('Emulator booted.');
|
if (result.trim() === '1') {
|
||||||
booted = true;
|
console.log('Emulator booted.');
|
||||||
break;
|
booted = true;
|
||||||
}
|
break;
|
||||||
}
|
}
|
||||||
catch (error) {
|
|
||||||
console.warn(error instanceof Error ? error.message : error);
|
|
||||||
}
|
|
||||||
if (attempts < maxAttempts) {
|
|
||||||
yield delay(retryInterval * 1000);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
throw new Error(`Timeout waiting for emulator to boot.`);
|
|
||||||
}
|
|
||||||
attempts++;
|
|
||||||
}
|
}
|
||||||
});
|
catch (error) {
|
||||||
|
console.warn(error instanceof Error ? error.message : error);
|
||||||
|
}
|
||||||
|
if (attempts < maxAttempts) {
|
||||||
|
await delay(retryInterval * 1000);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw new Error(`Timeout waiting for emulator to boot.`);
|
||||||
|
}
|
||||||
|
attempts++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
function delay(ms) {
|
function delay(ms) {
|
||||||
return new Promise((resolve) => setTimeout(resolve, ms));
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
||||||
|
|||||||
+30
-27
@@ -1,75 +1,79 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
exports.checkDiskSize = exports.checkEmulatorBuild = exports.checkEnableHardwareKeyboard = exports.checkDisableLinuxHardwareAcceleration = exports.checkDisableSpellchecker = exports.checkDisableAnimations = exports.checkForceAvdCreation = exports.checkChannel = exports.checkArch = exports.checkTarget = exports.checkApiLevel = exports.VALID_CHANNELS = exports.VALID_ARCHS = exports.VALID_TARGETS = exports.MIN_API_LEVEL = void 0;
|
exports.MAX_PORT = exports.MIN_PORT = exports.VALID_CHANNELS = exports.VALID_ARCHS = exports.MIN_API_LEVEL = void 0;
|
||||||
|
exports.playstoreTargetSubstitution = playstoreTargetSubstitution;
|
||||||
|
exports.checkArch = checkArch;
|
||||||
|
exports.checkChannel = checkChannel;
|
||||||
|
exports.checkForceAvdCreation = checkForceAvdCreation;
|
||||||
|
exports.checkPort = checkPort;
|
||||||
|
exports.checkDisableAnimations = checkDisableAnimations;
|
||||||
|
exports.checkDisableSpellchecker = checkDisableSpellchecker;
|
||||||
|
exports.checkDisableLinuxHardwareAcceleration = checkDisableLinuxHardwareAcceleration;
|
||||||
|
exports.checkEnableHardwareKeyboard = checkEnableHardwareKeyboard;
|
||||||
|
exports.checkEmulatorBuild = checkEmulatorBuild;
|
||||||
|
exports.checkDiskSize = checkDiskSize;
|
||||||
exports.MIN_API_LEVEL = 15;
|
exports.MIN_API_LEVEL = 15;
|
||||||
exports.VALID_TARGETS = ['default', 'google_apis', 'aosp_atd', 'google_atd', 'google_apis_playstore', 'android-wear', 'android-wear-cn', 'android-tv', 'google-tv'];
|
|
||||||
exports.VALID_ARCHS = ['x86', 'x86_64', 'arm64-v8a'];
|
exports.VALID_ARCHS = ['x86', 'x86_64', 'arm64-v8a'];
|
||||||
exports.VALID_CHANNELS = ['stable', 'beta', 'dev', 'canary'];
|
exports.VALID_CHANNELS = ['stable', 'beta', 'dev', 'canary'];
|
||||||
function checkApiLevel(apiLevel) {
|
exports.MIN_PORT = 5554;
|
||||||
if (apiLevel.startsWith('UpsideDownCake') || apiLevel === 'TiramisuPrivacySandbox')
|
exports.MAX_PORT = 5584;
|
||||||
return;
|
function playstoreTargetSubstitution(target) {
|
||||||
if (isNaN(Number(apiLevel)) || !Number.isInteger(Number(apiLevel))) {
|
// "playstore" is an allowed shorthand for "google_apis_playstore" images
|
||||||
throw new Error(`Unexpected API level: '${apiLevel}'.`);
|
// this is idempotent - return same even if run multiple times on same target
|
||||||
}
|
if (target === 'playstore')
|
||||||
if (Number(apiLevel) < exports.MIN_API_LEVEL) {
|
return 'google_apis_playstore';
|
||||||
throw new Error(`Minimum API level supported is ${exports.MIN_API_LEVEL}.`);
|
if (target === 'playstore_ps16k')
|
||||||
}
|
return 'google_apis_playstore_ps16k';
|
||||||
|
return target;
|
||||||
}
|
}
|
||||||
exports.checkApiLevel = checkApiLevel;
|
|
||||||
function checkTarget(target) {
|
|
||||||
if (!exports.VALID_TARGETS.includes(target)) {
|
|
||||||
throw new Error(`Value for input.target '${target}' is unknown. Supported options: ${exports.VALID_TARGETS}.`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
exports.checkTarget = checkTarget;
|
|
||||||
function checkArch(arch) {
|
function checkArch(arch) {
|
||||||
if (!exports.VALID_ARCHS.includes(arch)) {
|
if (!exports.VALID_ARCHS.includes(arch)) {
|
||||||
throw new Error(`Value for input.arch '${arch}' is unknown. Supported options: ${exports.VALID_ARCHS}.`);
|
throw new Error(`Value for input.arch '${arch}' is unknown. Supported options: ${exports.VALID_ARCHS}.`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
exports.checkArch = checkArch;
|
|
||||||
function checkChannel(channel) {
|
function checkChannel(channel) {
|
||||||
if (!exports.VALID_CHANNELS.includes(channel)) {
|
if (!exports.VALID_CHANNELS.includes(channel)) {
|
||||||
throw new Error(`Value for input.channel '${channel}' is unknown. Supported options: ${exports.VALID_CHANNELS}.`);
|
throw new Error(`Value for input.channel '${channel}' is unknown. Supported options: ${exports.VALID_CHANNELS}.`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
exports.checkChannel = checkChannel;
|
|
||||||
function checkForceAvdCreation(forceAvdCreation) {
|
function checkForceAvdCreation(forceAvdCreation) {
|
||||||
if (!isValidBoolean(forceAvdCreation)) {
|
if (!isValidBoolean(forceAvdCreation)) {
|
||||||
throw new Error(`Input for input.force-avd-creation should be either 'true' or 'false'.`);
|
throw new Error(`Input for input.force-avd-creation should be either 'true' or 'false'.`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
exports.checkForceAvdCreation = checkForceAvdCreation;
|
function checkPort(port) {
|
||||||
|
if (port < exports.MIN_PORT || port > exports.MAX_PORT) {
|
||||||
|
throw new Error(`Emulator port is outside of the supported port range [${exports.MIN_PORT}, ${exports.MAX_PORT}], was ${port}`);
|
||||||
|
}
|
||||||
|
if (port % 2 == 1) {
|
||||||
|
throw new Error(`Emulator port has to be even, was ${port}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
function checkDisableAnimations(disableAnimations) {
|
function checkDisableAnimations(disableAnimations) {
|
||||||
if (!isValidBoolean(disableAnimations)) {
|
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;
|
|
||||||
function checkDisableSpellchecker(disableSpellchecker) {
|
function checkDisableSpellchecker(disableSpellchecker) {
|
||||||
if (!isValidBoolean(disableSpellchecker)) {
|
if (!isValidBoolean(disableSpellchecker)) {
|
||||||
throw new Error(`Input for input.disable-spellchecker should be either 'true' or 'false'.`);
|
throw new Error(`Input for input.disable-spellchecker should be either 'true' or 'false'.`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
exports.checkDisableSpellchecker = checkDisableSpellchecker;
|
|
||||||
function checkDisableLinuxHardwareAcceleration(disableLinuxHardwareAcceleration) {
|
function checkDisableLinuxHardwareAcceleration(disableLinuxHardwareAcceleration) {
|
||||||
if (!(isValidBoolean(disableLinuxHardwareAcceleration) || disableLinuxHardwareAcceleration === 'auto')) {
|
if (!(isValidBoolean(disableLinuxHardwareAcceleration) || disableLinuxHardwareAcceleration === 'auto')) {
|
||||||
throw new Error(`Input for input.disable-linux-hw-accel should be either 'true' or 'false' or 'auto'.`);
|
throw new Error(`Input for input.disable-linux-hw-accel should be either 'true' or 'false' or 'auto'.`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
exports.checkDisableLinuxHardwareAcceleration = checkDisableLinuxHardwareAcceleration;
|
|
||||||
function checkEnableHardwareKeyboard(enableHardwareKeyboard) {
|
function checkEnableHardwareKeyboard(enableHardwareKeyboard) {
|
||||||
if (!isValidBoolean(enableHardwareKeyboard)) {
|
if (!isValidBoolean(enableHardwareKeyboard)) {
|
||||||
throw new Error(`Input for input.enable-hw-keyboard should be either 'true' or 'false'.`);
|
throw new Error(`Input for input.enable-hw-keyboard should be either 'true' or 'false'.`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
exports.checkEnableHardwareKeyboard = checkEnableHardwareKeyboard;
|
|
||||||
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;
|
|
||||||
function isValidBoolean(value) {
|
function isValidBoolean(value) {
|
||||||
return value === 'true' || value === 'false';
|
return value === 'true' || value === 'false';
|
||||||
}
|
}
|
||||||
@@ -89,4 +93,3 @@ function checkDiskSize(diskSize) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
exports.checkDiskSize = checkDiskSize;
|
|
||||||
|
|||||||
+189
-179
@@ -15,22 +15,23 @@ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (
|
|||||||
}) : function(o, v) {
|
}) : function(o, v) {
|
||||||
o["default"] = v;
|
o["default"] = v;
|
||||||
});
|
});
|
||||||
var __importStar = (this && this.__importStar) || function (mod) {
|
var __importStar = (this && this.__importStar) || (function () {
|
||||||
if (mod && mod.__esModule) return mod;
|
var ownKeys = function(o) {
|
||||||
var result = {};
|
ownKeys = Object.getOwnPropertyNames || function (o) {
|
||||||
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
var ar = [];
|
||||||
__setModuleDefault(result, mod);
|
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
||||||
return result;
|
return ar;
|
||||||
};
|
};
|
||||||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
return ownKeys(o);
|
||||||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
};
|
||||||
return new (P || (P = Promise))(function (resolve, reject) {
|
return function (mod) {
|
||||||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
if (mod && mod.__esModule) return mod;
|
||||||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
var result = {};
|
||||||
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
||||||
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
__setModuleDefault(result, mod);
|
||||||
});
|
return result;
|
||||||
};
|
};
|
||||||
|
})();
|
||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
const core = __importStar(require("@actions/core"));
|
const core = __importStar(require("@actions/core"));
|
||||||
const sdk_installer_1 = require("./sdk-installer");
|
const sdk_installer_1 = require("./sdk-installer");
|
||||||
@@ -40,183 +41,192 @@ const exec = __importStar(require("@actions/exec"));
|
|||||||
const script_parser_1 = require("./script-parser");
|
const script_parser_1 = require("./script-parser");
|
||||||
const channel_id_mapper_1 = require("./channel-id-mapper");
|
const channel_id_mapper_1 = require("./channel-id-mapper");
|
||||||
const fs_1 = require("fs");
|
const fs_1 = require("fs");
|
||||||
function run() {
|
async function run() {
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
let port = input_validator_1.MIN_PORT;
|
||||||
try {
|
try {
|
||||||
console.log(`::group::Configure emulator`);
|
console.log(`::group::Configure emulator`);
|
||||||
let linuxSupportKVM = false;
|
let linuxSupportKVM = false;
|
||||||
// only support running on macOS or Linux
|
// only support running on macOS or Linux
|
||||||
if (process.platform !== 'darwin') {
|
if (process.platform !== 'darwin') {
|
||||||
if (process.platform === 'linux') {
|
if (process.platform === 'linux') {
|
||||||
try {
|
|
||||||
(0, fs_1.accessSync)('/dev/kvm', fs_1.constants.R_OK | fs_1.constants.W_OK);
|
|
||||||
linuxSupportKVM = true;
|
|
||||||
}
|
|
||||||
catch (_a) {
|
|
||||||
console.warn(`You're running a Linux VM where hardware acceleration is not available. Please consider using a macOS VM instead to take advantage of native hardware acceleration support provided by HAXM.`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
throw new Error('Unsupported virtual machine: please use either macos or ubuntu VM.');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// API level of the platform and system image
|
|
||||||
const apiLevel = core.getInput('api-level', { required: true });
|
|
||||||
(0, input_validator_1.checkApiLevel)(apiLevel);
|
|
||||||
console.log(`API level: ${apiLevel}`);
|
|
||||||
// target of the system image
|
|
||||||
const targetInput = core.getInput('target');
|
|
||||||
const target = targetInput == 'playstore' ? 'google_apis_playstore' : targetInput;
|
|
||||||
(0, input_validator_1.checkTarget)(target);
|
|
||||||
console.log(`target: ${target}`);
|
|
||||||
// CPU architecture of the system image
|
|
||||||
const arch = core.getInput('arch');
|
|
||||||
(0, input_validator_1.checkArch)(arch);
|
|
||||||
console.log(`CPU architecture: ${arch}`);
|
|
||||||
// Hardware profile used for creating the AVD
|
|
||||||
const profile = core.getInput('profile');
|
|
||||||
console.log(`Hardware profile: ${profile}`);
|
|
||||||
// Number of cores to use for emulator
|
|
||||||
const cores = core.getInput('cores');
|
|
||||||
console.log(`Cores: ${cores}`);
|
|
||||||
// RAM to use for AVD
|
|
||||||
const ramSize = core.getInput('ram-size');
|
|
||||||
console.log(`RAM size: ${ramSize}`);
|
|
||||||
// Heap size to use for AVD
|
|
||||||
const heapSize = core.getInput('heap-size');
|
|
||||||
console.log(`Heap size: ${heapSize}`);
|
|
||||||
// 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}`);
|
|
||||||
const diskSize = core.getInput('disk-size');
|
|
||||||
(0, input_validator_1.checkDiskSize)(diskSize);
|
|
||||||
console.log(`Disk size: ${diskSize}`);
|
|
||||||
// custom name used for creating the AVD
|
|
||||||
const avdName = core.getInput('avd-name');
|
|
||||||
console.log(`AVD name: ${avdName}`);
|
|
||||||
// force AVD creation
|
|
||||||
const forceAvdCreationInput = core.getInput('force-avd-creation');
|
|
||||||
(0, input_validator_1.checkForceAvdCreation)(forceAvdCreationInput);
|
|
||||||
const forceAvdCreation = forceAvdCreationInput === 'true';
|
|
||||||
console.log(`force avd creation: ${forceAvdCreation}`);
|
|
||||||
// Emulator boot timeout seconds
|
|
||||||
const emulatorBootTimeout = parseInt(core.getInput('emulator-boot-timeout'), 10);
|
|
||||||
console.log(`Emulator boot timeout: ${emulatorBootTimeout}`);
|
|
||||||
// emulator options
|
|
||||||
const emulatorOptions = core.getInput('emulator-options').trim();
|
|
||||||
console.log(`emulator options: ${emulatorOptions}`);
|
|
||||||
// disable animations
|
|
||||||
const disableAnimationsInput = core.getInput('disable-animations');
|
|
||||||
(0, input_validator_1.checkDisableAnimations)(disableAnimationsInput);
|
|
||||||
const disableAnimations = disableAnimationsInput === 'true';
|
|
||||||
console.log(`disable animations: ${disableAnimations}`);
|
|
||||||
// disable spellchecker
|
|
||||||
const disableSpellcheckerInput = core.getInput('disable-spellchecker');
|
|
||||||
(0, input_validator_1.checkDisableSpellchecker)(disableSpellcheckerInput);
|
|
||||||
const disableSpellchecker = disableSpellcheckerInput === 'true';
|
|
||||||
console.log(`disable spellchecker: ${disableSpellchecker}`);
|
|
||||||
// disable linux hardware acceleration
|
|
||||||
let disableLinuxHardwareAccelerationInput = core.getInput('disable-linux-hw-accel');
|
|
||||||
(0, input_validator_1.checkDisableLinuxHardwareAcceleration)(disableLinuxHardwareAccelerationInput);
|
|
||||||
if (disableLinuxHardwareAccelerationInput === 'auto' && process.platform === 'linux') {
|
|
||||||
disableLinuxHardwareAccelerationInput = linuxSupportKVM ? 'false' : 'true';
|
|
||||||
}
|
|
||||||
const disableLinuxHardwareAcceleration = disableLinuxHardwareAccelerationInput === 'true';
|
|
||||||
console.log(`disable Linux hardware acceleration: ${disableLinuxHardwareAcceleration}`);
|
|
||||||
// enable hardware keyboard
|
|
||||||
const enableHardwareKeyboardInput = core.getInput('enable-hw-keyboard');
|
|
||||||
(0, input_validator_1.checkEnableHardwareKeyboard)(enableHardwareKeyboardInput);
|
|
||||||
const enableHardwareKeyboard = enableHardwareKeyboardInput === 'true';
|
|
||||||
console.log(`enable hardware keyboard: ${enableHardwareKeyboard}`);
|
|
||||||
// emulator build
|
|
||||||
const emulatorBuildInput = core.getInput('emulator-build');
|
|
||||||
if (emulatorBuildInput) {
|
|
||||||
(0, input_validator_1.checkEmulatorBuild)(emulatorBuildInput);
|
|
||||||
console.log(`using emulator build: ${emulatorBuildInput}`);
|
|
||||||
}
|
|
||||||
const emulatorBuild = !emulatorBuildInput ? undefined : emulatorBuildInput;
|
|
||||||
// custom working directory
|
|
||||||
const workingDirectoryInput = core.getInput('working-directory');
|
|
||||||
if (workingDirectoryInput) {
|
|
||||||
console.log(`custom working directory: ${workingDirectoryInput}`);
|
|
||||||
}
|
|
||||||
const workingDirectory = !workingDirectoryInput ? undefined : workingDirectoryInput;
|
|
||||||
// version of NDK to install
|
|
||||||
const ndkInput = core.getInput('ndk');
|
|
||||||
if (ndkInput) {
|
|
||||||
console.log(`version of NDK to install: ${ndkInput}`);
|
|
||||||
}
|
|
||||||
const ndkVersion = !ndkInput ? undefined : ndkInput;
|
|
||||||
// version of CMake to install
|
|
||||||
const cmakeInput = core.getInput('cmake');
|
|
||||||
if (cmakeInput) {
|
|
||||||
console.log(`version of CMake to install: ${cmakeInput}`);
|
|
||||||
}
|
|
||||||
const cmakeVersion = !cmakeInput ? undefined : cmakeInput;
|
|
||||||
// channelId (up to and including) to download the SDK packages from
|
|
||||||
const channelName = core.getInput('channel');
|
|
||||||
(0, input_validator_1.checkChannel)(channelName);
|
|
||||||
const channelId = (0, channel_id_mapper_1.getChannelId)(channelName);
|
|
||||||
console.log(`Channel: ${channelId} (${channelName})`);
|
|
||||||
// custom script to run
|
|
||||||
const scriptInput = core.getInput('script', { required: true });
|
|
||||||
const scripts = (0, script_parser_1.parseScript)(scriptInput);
|
|
||||||
console.log(`Script:`);
|
|
||||||
scripts.forEach((script) => __awaiter(this, void 0, void 0, function* () {
|
|
||||||
console.log(`${script}`);
|
|
||||||
}));
|
|
||||||
// custom pre emulator launch script
|
|
||||||
const preEmulatorLaunchScriptInput = core.getInput('pre-emulator-launch-script');
|
|
||||||
const preEmulatorLaunchScripts = !preEmulatorLaunchScriptInput ? undefined : (0, script_parser_1.parseScript)(preEmulatorLaunchScriptInput);
|
|
||||||
console.log(`Pre emulator launch script:`);
|
|
||||||
preEmulatorLaunchScripts === null || preEmulatorLaunchScripts === void 0 ? void 0 : preEmulatorLaunchScripts.forEach((script) => __awaiter(this, void 0, void 0, function* () {
|
|
||||||
console.log(`${script}`);
|
|
||||||
}));
|
|
||||||
console.log(`::endgroup::`);
|
|
||||||
// install SDK
|
|
||||||
yield (0, sdk_installer_1.installAndroidSdk)(apiLevel, target, arch, channelId, emulatorBuild, ndkVersion, cmakeVersion);
|
|
||||||
// execute pre emulator launch script if set
|
|
||||||
if (preEmulatorLaunchScripts !== undefined) {
|
|
||||||
console.log(`::group::Run pre emulator launch script`);
|
|
||||||
try {
|
try {
|
||||||
for (const preEmulatorLaunchScript of preEmulatorLaunchScripts) {
|
(0, fs_1.accessSync)('/dev/kvm', fs_1.constants.R_OK | fs_1.constants.W_OK);
|
||||||
// use array form to avoid various quote escaping problems
|
linuxSupportKVM = true;
|
||||||
// caused by exec(`sh -c "${preEmulatorLaunchScript}"`)
|
|
||||||
yield exec.exec('sh', ['-c', preEmulatorLaunchScript], {
|
|
||||||
cwd: workingDirectory,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
catch (error) {
|
catch {
|
||||||
core.setFailed(error instanceof Error ? error.message : error);
|
console.warn(`You're running a Linux VM where hardware acceleration is not available. Please consider using a macOS VM instead to take advantage of native hardware acceleration support provided by HAXM.`);
|
||||||
}
|
}
|
||||||
console.log(`::endgroup::`);
|
|
||||||
}
|
}
|
||||||
// launch an emulator
|
else {
|
||||||
yield (0, emulator_manager_1.launchEmulator)(apiLevel, target, arch, profile, cores, ramSize, heapSize, sdcardPathOrSize, diskSize, avdName, forceAvdCreation, emulatorBootTimeout, emulatorOptions, disableAnimations, disableSpellchecker, disableLinuxHardwareAcceleration, enableHardwareKeyboard);
|
throw new Error('Unsupported virtual machine: please use either macos or ubuntu VM.');
|
||||||
// execute the custom script
|
}
|
||||||
|
}
|
||||||
|
// API level of the platform and system image
|
||||||
|
const apiLevel = core.getInput('api-level', { required: true });
|
||||||
|
console.log(`API level: ${apiLevel}`);
|
||||||
|
let systemImageApiLevel = core.getInput('system-image-api-level');
|
||||||
|
if (!systemImageApiLevel) {
|
||||||
|
systemImageApiLevel = apiLevel;
|
||||||
|
}
|
||||||
|
console.log(`System image API level: ${systemImageApiLevel}`);
|
||||||
|
// target of the system image
|
||||||
|
const target = (0, input_validator_1.playstoreTargetSubstitution)(core.getInput('target'));
|
||||||
|
console.log(`target: ${target}`);
|
||||||
|
// CPU architecture of the system image
|
||||||
|
const arch = core.getInput('arch');
|
||||||
|
(0, input_validator_1.checkArch)(arch);
|
||||||
|
console.log(`CPU architecture: ${arch}`);
|
||||||
|
// Hardware profile used for creating the AVD
|
||||||
|
const profile = core.getInput('profile');
|
||||||
|
console.log(`Hardware profile: ${profile}`);
|
||||||
|
// Number of cores to use for emulator
|
||||||
|
const cores = core.getInput('cores');
|
||||||
|
console.log(`Cores: ${cores}`);
|
||||||
|
// RAM to use for AVD
|
||||||
|
const ramSize = core.getInput('ram-size');
|
||||||
|
console.log(`RAM size: ${ramSize}`);
|
||||||
|
// Heap size to use for AVD
|
||||||
|
const heapSize = core.getInput('heap-size');
|
||||||
|
console.log(`Heap size: ${heapSize}`);
|
||||||
|
// 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}`);
|
||||||
|
const diskSize = core.getInput('disk-size');
|
||||||
|
(0, input_validator_1.checkDiskSize)(diskSize);
|
||||||
|
console.log(`Disk size: ${diskSize}`);
|
||||||
|
// custom name used for creating the AVD
|
||||||
|
const avdName = core.getInput('avd-name');
|
||||||
|
console.log(`AVD name: ${avdName}`);
|
||||||
|
// force AVD creation
|
||||||
|
const forceAvdCreationInput = core.getInput('force-avd-creation');
|
||||||
|
(0, input_validator_1.checkForceAvdCreation)(forceAvdCreationInput);
|
||||||
|
const forceAvdCreation = forceAvdCreationInput === 'true';
|
||||||
|
console.log(`force avd creation: ${forceAvdCreation}`);
|
||||||
|
// Emulator boot timeout seconds
|
||||||
|
const emulatorBootTimeout = parseInt(core.getInput('emulator-boot-timeout'), 10);
|
||||||
|
console.log(`Emulator boot timeout: ${emulatorBootTimeout}`);
|
||||||
|
// Emulator port to use
|
||||||
|
port = parseInt(core.getInput('emulator-port'), 10);
|
||||||
|
(0, input_validator_1.checkPort)(port);
|
||||||
|
console.log(`emulator port: ${port}`);
|
||||||
|
// emulator options
|
||||||
|
const emulatorOptions = core.getInput('emulator-options').trim();
|
||||||
|
console.log(`emulator options: ${emulatorOptions}`);
|
||||||
|
// disable animations
|
||||||
|
const disableAnimationsInput = core.getInput('disable-animations');
|
||||||
|
(0, input_validator_1.checkDisableAnimations)(disableAnimationsInput);
|
||||||
|
const disableAnimations = disableAnimationsInput === 'true';
|
||||||
|
console.log(`disable animations: ${disableAnimations}`);
|
||||||
|
// disable spellchecker
|
||||||
|
const disableSpellcheckerInput = core.getInput('disable-spellchecker');
|
||||||
|
(0, input_validator_1.checkDisableSpellchecker)(disableSpellcheckerInput);
|
||||||
|
const disableSpellchecker = disableSpellcheckerInput === 'true';
|
||||||
|
console.log(`disable spellchecker: ${disableSpellchecker}`);
|
||||||
|
// disable linux hardware acceleration
|
||||||
|
let disableLinuxHardwareAccelerationInput = core.getInput('disable-linux-hw-accel');
|
||||||
|
(0, input_validator_1.checkDisableLinuxHardwareAcceleration)(disableLinuxHardwareAccelerationInput);
|
||||||
|
if (disableLinuxHardwareAccelerationInput === 'auto' && process.platform === 'linux') {
|
||||||
|
disableLinuxHardwareAccelerationInput = linuxSupportKVM ? 'false' : 'true';
|
||||||
|
}
|
||||||
|
const disableLinuxHardwareAcceleration = disableLinuxHardwareAccelerationInput === 'true';
|
||||||
|
console.log(`disable Linux hardware acceleration: ${disableLinuxHardwareAcceleration}`);
|
||||||
|
// enable hardware keyboard
|
||||||
|
const enableHardwareKeyboardInput = core.getInput('enable-hw-keyboard');
|
||||||
|
(0, input_validator_1.checkEnableHardwareKeyboard)(enableHardwareKeyboardInput);
|
||||||
|
const enableHardwareKeyboard = enableHardwareKeyboardInput === 'true';
|
||||||
|
console.log(`enable hardware keyboard: ${enableHardwareKeyboard}`);
|
||||||
|
// emulator build
|
||||||
|
const emulatorBuildInput = core.getInput('emulator-build');
|
||||||
|
if (emulatorBuildInput) {
|
||||||
|
(0, input_validator_1.checkEmulatorBuild)(emulatorBuildInput);
|
||||||
|
console.log(`using emulator build: ${emulatorBuildInput}`);
|
||||||
|
}
|
||||||
|
const emulatorBuild = !emulatorBuildInput ? undefined : emulatorBuildInput;
|
||||||
|
// custom working directory
|
||||||
|
const workingDirectoryInput = core.getInput('working-directory');
|
||||||
|
if (workingDirectoryInput) {
|
||||||
|
console.log(`custom working directory: ${workingDirectoryInput}`);
|
||||||
|
}
|
||||||
|
const workingDirectory = !workingDirectoryInput ? undefined : workingDirectoryInput;
|
||||||
|
// version of NDK to install
|
||||||
|
const ndkInput = core.getInput('ndk');
|
||||||
|
if (ndkInput) {
|
||||||
|
console.log(`version of NDK to install: ${ndkInput}`);
|
||||||
|
}
|
||||||
|
const ndkVersion = !ndkInput ? undefined : ndkInput;
|
||||||
|
// version of CMake to install
|
||||||
|
const cmakeInput = core.getInput('cmake');
|
||||||
|
if (cmakeInput) {
|
||||||
|
console.log(`version of CMake to install: ${cmakeInput}`);
|
||||||
|
}
|
||||||
|
const cmakeVersion = !cmakeInput ? undefined : cmakeInput;
|
||||||
|
// channelId (up to and including) to download the SDK packages from
|
||||||
|
const channelName = core.getInput('channel');
|
||||||
|
(0, input_validator_1.checkChannel)(channelName);
|
||||||
|
const channelId = (0, channel_id_mapper_1.getChannelId)(channelName);
|
||||||
|
console.log(`Channel: ${channelId} (${channelName})`);
|
||||||
|
// custom script to run
|
||||||
|
const scriptInput = core.getInput('script', { required: true });
|
||||||
|
const scripts = (0, script_parser_1.parseScript)(scriptInput);
|
||||||
|
console.log(`Script:`);
|
||||||
|
scripts.forEach(async (script) => {
|
||||||
|
console.log(`${script}`);
|
||||||
|
});
|
||||||
|
// custom pre emulator launch script
|
||||||
|
const preEmulatorLaunchScriptInput = core.getInput('pre-emulator-launch-script');
|
||||||
|
const preEmulatorLaunchScripts = !preEmulatorLaunchScriptInput ? undefined : (0, script_parser_1.parseScript)(preEmulatorLaunchScriptInput);
|
||||||
|
console.log(`Pre emulator launch script:`);
|
||||||
|
preEmulatorLaunchScripts?.forEach(async (script) => {
|
||||||
|
console.log(`${script}`);
|
||||||
|
});
|
||||||
|
console.log(`::endgroup::`);
|
||||||
|
// install SDK
|
||||||
|
await (0, sdk_installer_1.installAndroidSdk)(apiLevel, systemImageApiLevel, target, arch, channelId, emulatorBuild, ndkVersion, cmakeVersion);
|
||||||
|
// create AVD
|
||||||
|
await (0, emulator_manager_1.createAvd)(arch, avdName, cores, diskSize, enableHardwareKeyboard, forceAvdCreation, heapSize, profile, ramSize, sdcardPathOrSize, systemImageApiLevel, target);
|
||||||
|
// execute pre emulator launch script if set
|
||||||
|
if (preEmulatorLaunchScripts !== undefined) {
|
||||||
|
console.log(`::group::Run pre emulator launch script`);
|
||||||
try {
|
try {
|
||||||
// move to custom working directory if set
|
for (const preEmulatorLaunchScript of preEmulatorLaunchScripts) {
|
||||||
if (workingDirectory) {
|
|
||||||
process.chdir(workingDirectory);
|
|
||||||
}
|
|
||||||
for (const script of scripts) {
|
|
||||||
// use array form to avoid various quote escaping problems
|
// use array form to avoid various quote escaping problems
|
||||||
// caused by exec(`sh -c "${script}"`)
|
// caused by exec(`sh -c "${preEmulatorLaunchScript}"`)
|
||||||
yield exec.exec('sh', ['-c', script]);
|
await exec.exec('sh', ['-c', preEmulatorLaunchScript], {
|
||||||
|
cwd: workingDirectory,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (error) {
|
catch (error) {
|
||||||
core.setFailed(error instanceof Error ? error.message : error);
|
core.setFailed(error instanceof Error ? error.message : error);
|
||||||
}
|
}
|
||||||
// finally kill the emulator
|
console.log(`::endgroup::`);
|
||||||
yield (0, emulator_manager_1.killEmulator)();
|
}
|
||||||
|
// launch an emulator
|
||||||
|
await (0, emulator_manager_1.launchEmulator)(avdName, disableAnimations, disableLinuxHardwareAcceleration, disableSpellchecker, emulatorBootTimeout, emulatorOptions, enableHardwareKeyboard, port);
|
||||||
|
// execute the custom script
|
||||||
|
try {
|
||||||
|
// move to custom working directory if set
|
||||||
|
if (workingDirectory) {
|
||||||
|
process.chdir(workingDirectory);
|
||||||
|
}
|
||||||
|
for (const script of scripts) {
|
||||||
|
// use array form to avoid various quote escaping problems
|
||||||
|
// caused by exec(`sh -c "${script}"`)
|
||||||
|
await exec.exec('sh', ['-c', script], {
|
||||||
|
env: { ...process.env, EMULATOR_PORT: `${port}`, ANDROID_SERIAL: `emulator-${port}` },
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch (error) {
|
catch (error) {
|
||||||
// kill the emulator so the action can exit
|
|
||||||
yield (0, emulator_manager_1.killEmulator)();
|
|
||||||
core.setFailed(error instanceof Error ? error.message : error);
|
core.setFailed(error instanceof Error ? error.message : error);
|
||||||
}
|
}
|
||||||
});
|
// finally kill the emulator
|
||||||
|
await (0, emulator_manager_1.killEmulator)(port);
|
||||||
|
}
|
||||||
|
catch (error) {
|
||||||
|
// kill the emulator so the action can exit
|
||||||
|
await (0, emulator_manager_1.killEmulator)(port);
|
||||||
|
core.setFailed(error instanceof Error ? error.message : error);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
run();
|
run();
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
exports.parseScript = void 0;
|
exports.parseScript = parseScript;
|
||||||
/**
|
/**
|
||||||
* Convert a (potentially multi-line) script to an array of single-line script(s).
|
* Convert a (potentially multi-line) script to an array of single-line script(s).
|
||||||
*/
|
*/
|
||||||
@@ -17,4 +17,3 @@ function parseScript(rawScript) {
|
|||||||
}
|
}
|
||||||
return scripts;
|
return scripts;
|
||||||
}
|
}
|
||||||
exports.parseScript = parseScript;
|
|
||||||
|
|||||||
+76
-79
@@ -15,101 +15,98 @@ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (
|
|||||||
}) : function(o, v) {
|
}) : function(o, v) {
|
||||||
o["default"] = v;
|
o["default"] = v;
|
||||||
});
|
});
|
||||||
var __importStar = (this && this.__importStar) || function (mod) {
|
var __importStar = (this && this.__importStar) || (function () {
|
||||||
if (mod && mod.__esModule) return mod;
|
var ownKeys = function(o) {
|
||||||
var result = {};
|
ownKeys = Object.getOwnPropertyNames || function (o) {
|
||||||
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
var ar = [];
|
||||||
__setModuleDefault(result, mod);
|
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
||||||
return result;
|
return ar;
|
||||||
};
|
};
|
||||||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
return ownKeys(o);
|
||||||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
};
|
||||||
return new (P || (P = Promise))(function (resolve, reject) {
|
return function (mod) {
|
||||||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
if (mod && mod.__esModule) return mod;
|
||||||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
var result = {};
|
||||||
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
||||||
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
__setModuleDefault(result, mod);
|
||||||
});
|
return result;
|
||||||
};
|
};
|
||||||
|
})();
|
||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
exports.installAndroidSdk = void 0;
|
exports.installAndroidSdk = installAndroidSdk;
|
||||||
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 tc = __importStar(require("@actions/tool-cache"));
|
||||||
const fs = __importStar(require("fs"));
|
const fs = __importStar(require("fs"));
|
||||||
const BUILD_TOOLS_VERSION = '34.0.0';
|
const BUILD_TOOLS_VERSION = '37.0.0';
|
||||||
// SDK command-line tools 11.0
|
// SDK command-line tools 23.0
|
||||||
const CMDLINE_TOOLS_URL_MAC = 'https://dl.google.com/android/repository/commandlinetools-mac-10406996_latest.zip';
|
const CMDLINE_TOOLS_VERSION = '16111833';
|
||||||
const CMDLINE_TOOLS_URL_LINUX = 'https://dl.google.com/android/repository/commandlinetools-linux-10406996_latest.zip';
|
const CMDLINE_TOOLS_URL_MAC = `https://dl.google.com/android/repository/commandlinetools-mac_x86_64-${CMDLINE_TOOLS_VERSION}_latest.zip`;
|
||||||
|
const CMDLINE_TOOLS_URL_LINUX = `https://dl.google.com/android/repository/commandlinetools-linux-${CMDLINE_TOOLS_VERSION}_latest.zip`;
|
||||||
/**
|
/**
|
||||||
* Installs & updates the Android SDK for the macOS platform, including SDK platform for the chosen API level, latest build tools, platform tools, Android Emulator,
|
* Installs & updates the Android SDK for the macOS platform, including SDK platform for the chosen API level, latest build tools, platform tools, Android Emulator,
|
||||||
* and the system image for the chosen API level, CPU arch, and target.
|
* and the system image for the chosen API level, CPU arch, and target.
|
||||||
*/
|
*/
|
||||||
function installAndroidSdk(apiLevel, target, arch, channelId, emulatorBuild, ndkVersion, cmakeVersion) {
|
async function installAndroidSdk(apiLevel, systemImageApiLevel, target, arch, channelId, emulatorBuild, ndkVersion, cmakeVersion) {
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
try {
|
||||||
try {
|
console.log(`::group::Install Android SDK`);
|
||||||
console.log(`::group::Install Android SDK`);
|
const isOnMac = process.platform === 'darwin';
|
||||||
const isOnMac = process.platform === 'darwin';
|
const isArm = process.arch === 'arm64';
|
||||||
const isArm = process.arch === 'arm64';
|
const cmdlineToolsPath = `${process.env.ANDROID_HOME}/cmdline-tools`;
|
||||||
if (!isOnMac) {
|
if (!fs.existsSync(cmdlineToolsPath)) {
|
||||||
yield exec.exec(`sh -c \\"sudo chown $USER:$USER ${process.env.ANDROID_HOME} -R`);
|
console.log('Installing new cmdline-tools.');
|
||||||
}
|
const sdkUrl = isOnMac ? CMDLINE_TOOLS_URL_MAC : CMDLINE_TOOLS_URL_LINUX;
|
||||||
const cmdlineToolsPath = `${process.env.ANDROID_HOME}/cmdline-tools`;
|
const downloadPath = await tc.downloadTool(sdkUrl);
|
||||||
if (!fs.existsSync(cmdlineToolsPath)) {
|
await tc.extractZip(downloadPath, cmdlineToolsPath);
|
||||||
console.log('Installing new cmdline-tools.');
|
await io.mv(`${cmdlineToolsPath}/cmdline-tools`, `${cmdlineToolsPath}/latest`);
|
||||||
const sdkUrl = isOnMac ? CMDLINE_TOOLS_URL_MAC : CMDLINE_TOOLS_URL_LINUX;
|
}
|
||||||
const downloadPath = yield tc.downloadTool(sdkUrl);
|
// add paths for commandline-tools and platform-tools
|
||||||
yield tc.extractZip(downloadPath, cmdlineToolsPath);
|
core.addPath(`${cmdlineToolsPath}/latest:${cmdlineToolsPath}/latest/bin:${process.env.ANDROID_HOME}/platform-tools`);
|
||||||
yield io.mv(`${cmdlineToolsPath}/cmdline-tools`, `${cmdlineToolsPath}/latest`);
|
// set standard AVD path
|
||||||
}
|
await io.mkdirP(`${process.env.HOME}/.android/avd`);
|
||||||
// add paths for commandline-tools and platform-tools
|
core.exportVariable('ANDROID_AVD_HOME', `${process.env.HOME}/.android/avd`);
|
||||||
core.addPath(`${cmdlineToolsPath}/latest:${cmdlineToolsPath}/latest/bin:${process.env.ANDROID_HOME}/platform-tools`);
|
// accept all Android SDK licenses
|
||||||
// set standard AVD path
|
await exec.exec(`sh -c \\"yes | sdkmanager --licenses > /dev/null"`);
|
||||||
core.exportVariable('ANDROID_AVD_HOME', `${process.env.HOME}/.android/avd`);
|
console.log('Installing latest build tools, platform tools, and platform.');
|
||||||
// accept all Android SDK licenses
|
await exec.exec(`sh -c \\"sdkmanager --install 'build-tools;${BUILD_TOOLS_VERSION}' platform-tools 'platforms;android-${apiLevel}'> /dev/null"`);
|
||||||
yield exec.exec(`sh -c \\"yes | sdkmanager --licenses > /dev/null"`);
|
console.log('Installing latest emulator.');
|
||||||
console.log('Installing latest build tools, platform tools, and platform.');
|
await exec.exec(`sh -c \\"sdkmanager --install emulator --channel=${channelId} > /dev/null"`);
|
||||||
yield exec.exec(`sh -c \\"sdkmanager --install 'build-tools;${BUILD_TOOLS_VERSION}' platform-tools > /dev/null"`);
|
if (emulatorBuild) {
|
||||||
console.log('Installing latest emulator.');
|
console.log(`Installing emulator build ${emulatorBuild}.`);
|
||||||
yield exec.exec(`sh -c \\"sdkmanager --install emulator --channel=${channelId} > /dev/null"`);
|
// TODO find out the correct download URLs for all build ids
|
||||||
if (emulatorBuild) {
|
var downloadUrlSuffix;
|
||||||
console.log(`Installing emulator build ${emulatorBuild}.`);
|
const majorBuildVersion = Number(emulatorBuild);
|
||||||
// TODO find out the correct download URLs for all build ids
|
if (majorBuildVersion >= 8000000) {
|
||||||
var downloadUrlSuffix;
|
if (isArm) {
|
||||||
const majorBuildVersion = Number(emulatorBuild);
|
downloadUrlSuffix = `_aarch64-${emulatorBuild}`;
|
||||||
if (majorBuildVersion >= 8000000) {
|
|
||||||
if (isArm) {
|
|
||||||
downloadUrlSuffix = `_aarch64-${emulatorBuild}`;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
downloadUrlSuffix = `_x64-${emulatorBuild}`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (majorBuildVersion >= 7000000) {
|
|
||||||
downloadUrlSuffix = `_x64-${emulatorBuild}`;
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
downloadUrlSuffix = `-${emulatorBuild}`;
|
downloadUrlSuffix = `_x64-${emulatorBuild}`;
|
||||||
}
|
}
|
||||||
yield exec.exec(`curl -fo emulator.zip https://dl.google.com/android/repository/emulator-${isOnMac ? 'darwin' : 'linux'}${downloadUrlSuffix}.zip`);
|
|
||||||
yield exec.exec(`unzip -o -q emulator.zip -d ${process.env.ANDROID_HOME}`);
|
|
||||||
yield io.rmRF('emulator.zip');
|
|
||||||
}
|
}
|
||||||
console.log('Installing system images.');
|
else if (majorBuildVersion >= 7000000) {
|
||||||
yield exec.exec(`sh -c \\"sdkmanager --install 'system-images;android-${apiLevel};${target};${arch}' --channel=${channelId} > /dev/null"`);
|
downloadUrlSuffix = `_x64-${emulatorBuild}`;
|
||||||
if (ndkVersion) {
|
|
||||||
console.log(`Installing NDK ${ndkVersion}.`);
|
|
||||||
yield exec.exec(`sh -c \\"sdkmanager --install 'ndk;${ndkVersion}' --channel=${channelId} > /dev/null"`);
|
|
||||||
}
|
}
|
||||||
if (cmakeVersion) {
|
else {
|
||||||
console.log(`Installing CMake ${cmakeVersion}.`);
|
downloadUrlSuffix = `-${emulatorBuild}`;
|
||||||
yield exec.exec(`sh -c \\"sdkmanager --install 'cmake;${cmakeVersion}' --channel=${channelId} > /dev/null"`);
|
|
||||||
}
|
}
|
||||||
|
await exec.exec(`curl -fo emulator.zip https://dl.google.com/android/repository/emulator-${isOnMac ? 'darwin' : 'linux'}${downloadUrlSuffix}.zip`);
|
||||||
|
await exec.exec(`unzip -o -q emulator.zip -d ${process.env.ANDROID_HOME}`);
|
||||||
|
await io.rmRF('emulator.zip');
|
||||||
}
|
}
|
||||||
finally {
|
console.log('Installing system images.');
|
||||||
console.log(`::endgroup::`);
|
await exec.exec(`sh -c \\"sdkmanager --install 'system-images;android-${systemImageApiLevel};${target};${arch}' --channel=${channelId} > /dev/null"`);
|
||||||
|
if (ndkVersion) {
|
||||||
|
console.log(`Installing NDK ${ndkVersion}.`);
|
||||||
|
await exec.exec(`sh -c \\"sdkmanager --install 'ndk;${ndkVersion}' --channel=${channelId} > /dev/null"`);
|
||||||
}
|
}
|
||||||
});
|
if (cmakeVersion) {
|
||||||
|
console.log(`Installing CMake ${cmakeVersion}.`);
|
||||||
|
await exec.exec(`sh -c \\"sdkmanager --install 'cmake;${cmakeVersion}' --channel=${channelId} > /dev/null"`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
console.log(`::endgroup::`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
exports.installAndroidSdk = installAndroidSdk;
|
|
||||||
|
|||||||
Generated
+3990
-3131
File diff suppressed because it is too large
Load Diff
+14
-14
@@ -19,7 +19,7 @@
|
|||||||
"setup"
|
"setup"
|
||||||
],
|
],
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=20"
|
"node": ">=24"
|
||||||
},
|
},
|
||||||
"author": "Reactive Circus",
|
"author": "Reactive Circus",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
@@ -31,18 +31,18 @@
|
|||||||
"set-value": "^4.1.0"
|
"set-value": "^4.1.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/jest": "^29.2.0",
|
"@types/jest": "^29.5.12",
|
||||||
"@types/node": "^20.11.0",
|
"@types/node": "^24.1.0",
|
||||||
"@typescript-eslint/eslint-plugin": "^5.41.0",
|
"@typescript-eslint/eslint-plugin": "^8.57.0",
|
||||||
"@typescript-eslint/parser": "^5.41.0",
|
"@typescript-eslint/parser": "^8.57.0",
|
||||||
"eslint": "^8.26.0",
|
"eslint": "^8.57.0",
|
||||||
"eslint-config-prettier": "^8.5.0",
|
"eslint-config-prettier": "^9.1.0",
|
||||||
"eslint-plugin-import": "^2.26.0",
|
"eslint-plugin-import": "^2.29.1",
|
||||||
"eslint-plugin-prettier": "^4.2.1",
|
"eslint-plugin-prettier": "^5.1.3",
|
||||||
"jest": "^29.2.2",
|
"jest": "^29.7.0",
|
||||||
"jest-circus": "^29.2.2",
|
"jest-circus": "^29.7.0",
|
||||||
"prettier": "^2.7.1",
|
"prettier": "^3.3.3",
|
||||||
"ts-jest": "^29.0.3",
|
"ts-jest": "^29.2.5",
|
||||||
"typescript": "^4.8.4"
|
"typescript": "^5.5.4"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+69
-45
@@ -2,29 +2,24 @@ import * as exec from '@actions/exec';
|
|||||||
import * as fs from 'fs';
|
import * as fs from 'fs';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates and launches a new AVD instance with the specified configurations.
|
* Creates a new AVD instance with the specified configurations.
|
||||||
*/
|
*/
|
||||||
export async function launchEmulator(
|
export async function createAvd(
|
||||||
apiLevel: string,
|
|
||||||
target: string,
|
|
||||||
arch: string,
|
arch: string,
|
||||||
profile: string,
|
|
||||||
cores: string,
|
|
||||||
ramSize: string,
|
|
||||||
heapSize: string,
|
|
||||||
sdcardPathOrSize: string,
|
|
||||||
diskSize: string,
|
|
||||||
avdName: string,
|
avdName: string,
|
||||||
|
cores: string,
|
||||||
|
diskSize: string,
|
||||||
|
enableHardwareKeyboard: boolean,
|
||||||
forceAvdCreation: boolean,
|
forceAvdCreation: boolean,
|
||||||
emulatorBootTimeout: number,
|
heapSize: string,
|
||||||
emulatorOptions: string,
|
profile: string,
|
||||||
disableAnimations: boolean,
|
ramSize: string,
|
||||||
disableSpellChecker: boolean,
|
sdcardPathOrSize: string,
|
||||||
disableLinuxHardwareAcceleration: boolean,
|
systemImageApiLevel: string,
|
||||||
enableHardwareKeyboard: boolean
|
target: string,
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
try {
|
try {
|
||||||
console.log(`::group::Launch Emulator`);
|
console.log(`::group::Create AVD`);
|
||||||
// create a new AVD if AVD directory does not already exist or forceAvdCreation is true
|
// create a new AVD if AVD directory does not already exist or forceAvdCreation is true
|
||||||
const avdPath = `${process.env.ANDROID_AVD_HOME}/${avdName}.avd`;
|
const avdPath = `${process.env.ANDROID_AVD_HOME}/${avdName}.avd`;
|
||||||
if (!fs.existsSync(avdPath) || forceAvdCreation) {
|
if (!fs.existsSync(avdPath) || forceAvdCreation) {
|
||||||
@@ -32,29 +27,54 @@ export async function launchEmulator(
|
|||||||
const sdcardPathOrSizeOption = sdcardPathOrSize.trim() !== '' ? `--sdcard '${sdcardPathOrSize}'` : '';
|
const sdcardPathOrSizeOption = sdcardPathOrSize.trim() !== '' ? `--sdcard '${sdcardPathOrSize}'` : '';
|
||||||
console.log(`Creating AVD.`);
|
console.log(`Creating AVD.`);
|
||||||
await exec.exec(
|
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}"`
|
`sh -c \\"echo no | avdmanager create avd --force -n "${avdName}" --package 'system-images;android-${systemImageApiLevel};${target};${arch}' ${profileOption} ${sdcardPathOrSizeOption}"`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cores) {
|
if (cores || ramSize || heapSize || enableHardwareKeyboard || diskSize) {
|
||||||
await exec.exec(`sh -c \\"printf 'hw.cpu.ncore=${cores}\n' >> ${process.env.ANDROID_AVD_HOME}/"${avdName}".avd"/config.ini`);
|
const configEntries: string[] = [];
|
||||||
}
|
|
||||||
|
|
||||||
if (ramSize) {
|
if (cores) {
|
||||||
await exec.exec(`sh -c \\"printf 'hw.ramSize=${ramSize}\n' >> ${process.env.ANDROID_AVD_HOME}/"${avdName}".avd"/config.ini`);
|
configEntries.push(`hw.cpu.ncore=${cores}`);
|
||||||
}
|
}
|
||||||
|
if (ramSize) {
|
||||||
|
configEntries.push(`hw.ramSize=${ramSize}`);
|
||||||
|
}
|
||||||
|
if (heapSize) {
|
||||||
|
configEntries.push(`hw.heapSize=${heapSize}`);
|
||||||
|
}
|
||||||
|
if (enableHardwareKeyboard) {
|
||||||
|
configEntries.push('hw.keyboard=yes');
|
||||||
|
}
|
||||||
|
if (diskSize) {
|
||||||
|
configEntries.push(`disk.dataPartition.size=${diskSize}`);
|
||||||
|
}
|
||||||
|
|
||||||
if (heapSize) {
|
if (configEntries.length > 0) {
|
||||||
await exec.exec(`sh -c \\"printf 'hw.heapSize=${heapSize}\n' >> ${process.env.ANDROID_AVD_HOME}/"${avdName}".avd"/config.ini`);
|
const configContent = configEntries.join('\\n') + '\\n';
|
||||||
|
await exec.exec(`sh -c \\"printf '${configContent}' >> ${process.env.ANDROID_AVD_HOME}/"${avdName}".avd"/config.ini"`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
} finally {
|
||||||
|
console.log(`::endgroup::`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (enableHardwareKeyboard) {
|
/**
|
||||||
await exec.exec(`sh -c \\"printf 'hw.keyboard=yes\n' >> ${process.env.ANDROID_AVD_HOME}/"${avdName}".avd"/config.ini`);
|
* Launches an existing AVD instance with the specified configurations.
|
||||||
}
|
*/
|
||||||
|
export async function launchEmulator(
|
||||||
if (diskSize) {
|
avdName: string,
|
||||||
await exec.exec(`sh -c \\"printf 'disk.dataPartition.size=${diskSize}\n' >> ${process.env.ANDROID_AVD_HOME}/"${avdName}".avd"/config.ini`);
|
disableAnimations: boolean,
|
||||||
}
|
disableLinuxHardwareAcceleration: boolean,
|
||||||
|
disableSpellChecker: boolean,
|
||||||
|
emulatorBootTimeout: number,
|
||||||
|
emulatorOptions: string,
|
||||||
|
enableHardwareKeyboard: boolean,
|
||||||
|
port: number,
|
||||||
|
): Promise<void> {
|
||||||
|
try {
|
||||||
|
console.log(`::group::Launch Emulator`);
|
||||||
|
|
||||||
// turn off hardware acceleration on Linux
|
// turn off hardware acceleration on Linux
|
||||||
if (process.platform === 'linux' && disableLinuxHardwareAcceleration) {
|
if (process.platform === 'linux' && disableLinuxHardwareAcceleration) {
|
||||||
@@ -65,7 +85,7 @@ export async function launchEmulator(
|
|||||||
// start emulator
|
// start emulator
|
||||||
console.log('Starting emulator.');
|
console.log('Starting emulator.');
|
||||||
|
|
||||||
await exec.exec(`sh -c \\"${process.env.ANDROID_HOME}/emulator/emulator -avd "${avdName}" ${emulatorOptions} &"`, [], {
|
await exec.exec(`sh -c \\"${process.env.ANDROID_HOME}/emulator/emulator -port ${port} -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')) {
|
||||||
@@ -76,20 +96,20 @@ export async function launchEmulator(
|
|||||||
});
|
});
|
||||||
|
|
||||||
// wait for emulator to complete booting
|
// wait for emulator to complete booting
|
||||||
await waitForDevice(emulatorBootTimeout);
|
await waitForDevice(port, emulatorBootTimeout);
|
||||||
await exec.exec(`adb shell input keyevent 82`);
|
await adb(port, `shell input keyevent 82`);
|
||||||
|
|
||||||
if (disableAnimations) {
|
if (disableAnimations) {
|
||||||
console.log('Disabling animations.');
|
console.log('Disabling animations.');
|
||||||
await exec.exec(`adb shell settings put global window_animation_scale 0.0`);
|
await adb(port, `shell settings put global window_animation_scale 0.0`);
|
||||||
await exec.exec(`adb shell settings put global transition_animation_scale 0.0`);
|
await adb(port, `shell settings put global transition_animation_scale 0.0`);
|
||||||
await exec.exec(`adb shell settings put global animator_duration_scale 0.0`);
|
await adb(port, `shell settings put global animator_duration_scale 0.0`);
|
||||||
}
|
}
|
||||||
if (disableSpellChecker) {
|
if (disableSpellChecker) {
|
||||||
await exec.exec(`adb shell settings put secure spell_checker_enabled 0`);
|
await adb(port, `shell settings put secure spell_checker_enabled 0`);
|
||||||
}
|
}
|
||||||
if (enableHardwareKeyboard) {
|
if (enableHardwareKeyboard) {
|
||||||
await exec.exec(`adb shell settings put secure show_ime_with_hard_keyboard 0`);
|
await adb(port, `shell settings put secure show_ime_with_hard_keyboard 0`);
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
console.log(`::endgroup::`);
|
console.log(`::endgroup::`);
|
||||||
@@ -99,10 +119,10 @@ export async function launchEmulator(
|
|||||||
/**
|
/**
|
||||||
* Kills the running emulator on the default port.
|
* Kills the running emulator on the default port.
|
||||||
*/
|
*/
|
||||||
export async function killEmulator(): Promise<void> {
|
export async function killEmulator(port: number): Promise<void> {
|
||||||
try {
|
try {
|
||||||
console.log(`::group::Terminate Emulator`);
|
console.log(`::group::Terminate Emulator`);
|
||||||
await exec.exec(`adb -s emulator-5554 emu kill`);
|
await adb(port, `emu kill`);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log(error instanceof Error ? error.message : error);
|
console.log(error instanceof Error ? error.message : error);
|
||||||
} finally {
|
} finally {
|
||||||
@@ -110,10 +130,14 @@ export async function killEmulator(): Promise<void> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function adb(port: number, command: string): Promise<number> {
|
||||||
|
return await exec.exec(`adb -s emulator-${port} ${command}`);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Wait for emulator to boot.
|
* Wait for emulator to boot.
|
||||||
*/
|
*/
|
||||||
async function waitForDevice(emulatorBootTimeout: number): Promise<void> {
|
async function waitForDevice(port: number, emulatorBootTimeout: number): Promise<void> {
|
||||||
let booted = false;
|
let booted = false;
|
||||||
let attempts = 0;
|
let attempts = 0;
|
||||||
const retryInterval = 2; // retry every 2 seconds
|
const retryInterval = 2; // retry every 2 seconds
|
||||||
@@ -121,7 +145,7 @@ async function waitForDevice(emulatorBootTimeout: number): Promise<void> {
|
|||||||
while (!booted) {
|
while (!booted) {
|
||||||
try {
|
try {
|
||||||
let result = '';
|
let result = '';
|
||||||
await exec.exec(`adb shell getprop sys.boot_completed`, [], {
|
await exec.exec(`adb -s emulator-${port} shell getprop sys.boot_completed`, [], {
|
||||||
listeners: {
|
listeners: {
|
||||||
stdout: (data: Buffer) => {
|
stdout: (data: Buffer) => {
|
||||||
result += data.toString();
|
result += data.toString();
|
||||||
|
|||||||
+17
-15
@@ -1,22 +1,15 @@
|
|||||||
export const MIN_API_LEVEL = 15;
|
export const MIN_API_LEVEL = 15;
|
||||||
export const VALID_TARGETS: Array<string> = ['default', 'google_apis', 'aosp_atd', 'google_atd', 'google_apis_playstore', 'android-wear', 'android-wear-cn', 'android-tv', 'google-tv'];
|
|
||||||
export const VALID_ARCHS: Array<string> = ['x86', 'x86_64', 'arm64-v8a'];
|
export const VALID_ARCHS: Array<string> = ['x86', 'x86_64', 'arm64-v8a'];
|
||||||
export const VALID_CHANNELS: Array<string> = ['stable', 'beta', 'dev', 'canary'];
|
export const VALID_CHANNELS: Array<string> = ['stable', 'beta', 'dev', 'canary'];
|
||||||
|
export const MIN_PORT = 5554;
|
||||||
|
export const MAX_PORT = 5584;
|
||||||
|
|
||||||
export function checkApiLevel(apiLevel: string): void {
|
export function playstoreTargetSubstitution(target: string): string {
|
||||||
if (apiLevel.startsWith('UpsideDownCake') || apiLevel === 'TiramisuPrivacySandbox') return;
|
// "playstore" is an allowed shorthand for "google_apis_playstore" images
|
||||||
if (isNaN(Number(apiLevel)) || !Number.isInteger(Number(apiLevel))) {
|
// this is idempotent - return same even if run multiple times on same target
|
||||||
throw new Error(`Unexpected API level: '${apiLevel}'.`);
|
if (target === 'playstore') return 'google_apis_playstore';
|
||||||
}
|
if (target === 'playstore_ps16k') return 'google_apis_playstore_ps16k';
|
||||||
if (Number(apiLevel) < MIN_API_LEVEL) {
|
return target;
|
||||||
throw new Error(`Minimum API level supported is ${MIN_API_LEVEL}.`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function checkTarget(target: string): void {
|
|
||||||
if (!VALID_TARGETS.includes(target)) {
|
|
||||||
throw new Error(`Value for input.target '${target}' is unknown. Supported options: ${VALID_TARGETS}.`);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function checkArch(arch: string): void {
|
export function checkArch(arch: string): void {
|
||||||
@@ -37,6 +30,15 @@ export function checkForceAvdCreation(forceAvdCreation: string): void {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function checkPort(port: number): void {
|
||||||
|
if (port < MIN_PORT || port > MAX_PORT) {
|
||||||
|
throw new Error(`Emulator port is outside of the supported port range [${MIN_PORT}, ${MAX_PORT}], was ${port}`);
|
||||||
|
}
|
||||||
|
if (port % 2 == 1) {
|
||||||
|
throw new Error(`Emulator port has to be even, was ${port}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export function checkDisableAnimations(disableAnimations: string): void {
|
export function checkDisableAnimations(disableAnimations: string): void {
|
||||||
if (!isValidBoolean(disableAnimations)) {
|
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'.`);
|
||||||
|
|||||||
+28
-31
@@ -1,8 +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 {
|
import {
|
||||||
checkApiLevel,
|
|
||||||
checkTarget,
|
|
||||||
checkArch,
|
checkArch,
|
||||||
checkDisableAnimations,
|
checkDisableAnimations,
|
||||||
checkEmulatorBuild,
|
checkEmulatorBuild,
|
||||||
@@ -12,14 +10,18 @@ import {
|
|||||||
checkChannel,
|
checkChannel,
|
||||||
checkEnableHardwareKeyboard,
|
checkEnableHardwareKeyboard,
|
||||||
checkDiskSize,
|
checkDiskSize,
|
||||||
|
checkPort,
|
||||||
|
playstoreTargetSubstitution,
|
||||||
|
MIN_PORT,
|
||||||
} from './input-validator';
|
} from './input-validator';
|
||||||
import { launchEmulator, killEmulator } from './emulator-manager';
|
import { createAvd, 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';
|
||||||
import { getChannelId } from './channel-id-mapper';
|
import { getChannelId } from './channel-id-mapper';
|
||||||
import { accessSync, constants } from 'fs';
|
import { accessSync, constants } from 'fs';
|
||||||
|
|
||||||
async function run() {
|
async function run() {
|
||||||
|
let port: number = MIN_PORT;
|
||||||
try {
|
try {
|
||||||
console.log(`::group::Configure emulator`);
|
console.log(`::group::Configure emulator`);
|
||||||
let linuxSupportKVM = false;
|
let linuxSupportKVM = false;
|
||||||
@@ -31,7 +33,7 @@ async function run() {
|
|||||||
linuxSupportKVM = true;
|
linuxSupportKVM = true;
|
||||||
} catch {
|
} catch {
|
||||||
console.warn(
|
console.warn(
|
||||||
`You're running a Linux VM where hardware acceleration is not available. Please consider using a macOS VM instead to take advantage of native hardware acceleration support provided by HAXM.`
|
`You're running a Linux VM where hardware acceleration is not available. Please consider using a macOS VM instead to take advantage of native hardware acceleration support provided by HAXM.`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -41,13 +43,16 @@ async function run() {
|
|||||||
|
|
||||||
// API level of the platform and system image
|
// API level of the platform and system image
|
||||||
const apiLevel = core.getInput('api-level', { required: true });
|
const apiLevel = core.getInput('api-level', { required: true });
|
||||||
checkApiLevel(apiLevel);
|
|
||||||
console.log(`API level: ${apiLevel}`);
|
console.log(`API level: ${apiLevel}`);
|
||||||
|
|
||||||
|
let systemImageApiLevel = core.getInput('system-image-api-level');
|
||||||
|
if (!systemImageApiLevel) {
|
||||||
|
systemImageApiLevel = apiLevel;
|
||||||
|
}
|
||||||
|
console.log(`System image API level: ${systemImageApiLevel}`);
|
||||||
|
|
||||||
// target of the system image
|
// target of the system image
|
||||||
const targetInput = core.getInput('target');
|
const target = playstoreTargetSubstitution(core.getInput('target'));
|
||||||
const target = targetInput == 'playstore' ? 'google_apis_playstore' : targetInput;
|
|
||||||
checkTarget(target);
|
|
||||||
console.log(`target: ${target}`);
|
console.log(`target: ${target}`);
|
||||||
|
|
||||||
// CPU architecture of the system image
|
// CPU architecture of the system image
|
||||||
@@ -93,6 +98,11 @@ async function run() {
|
|||||||
const emulatorBootTimeout = parseInt(core.getInput('emulator-boot-timeout'), 10);
|
const emulatorBootTimeout = parseInt(core.getInput('emulator-boot-timeout'), 10);
|
||||||
console.log(`Emulator boot timeout: ${emulatorBootTimeout}`);
|
console.log(`Emulator boot timeout: ${emulatorBootTimeout}`);
|
||||||
|
|
||||||
|
// Emulator port to use
|
||||||
|
port = parseInt(core.getInput('emulator-port'), 10);
|
||||||
|
checkPort(port);
|
||||||
|
console.log(`emulator port: ${port}`);
|
||||||
|
|
||||||
// emulator options
|
// emulator options
|
||||||
const emulatorOptions = core.getInput('emulator-options').trim();
|
const emulatorOptions = core.getInput('emulator-options').trim();
|
||||||
console.log(`emulator options: ${emulatorOptions}`);
|
console.log(`emulator options: ${emulatorOptions}`);
|
||||||
@@ -177,7 +187,10 @@ async function run() {
|
|||||||
console.log(`::endgroup::`);
|
console.log(`::endgroup::`);
|
||||||
|
|
||||||
// install SDK
|
// install SDK
|
||||||
await installAndroidSdk(apiLevel, target, arch, channelId, emulatorBuild, ndkVersion, cmakeVersion);
|
await installAndroidSdk(apiLevel, systemImageApiLevel, target, arch, channelId, emulatorBuild, ndkVersion, cmakeVersion);
|
||||||
|
|
||||||
|
// create AVD
|
||||||
|
await createAvd(arch, avdName, cores, diskSize, enableHardwareKeyboard, forceAvdCreation, heapSize, profile, ramSize, sdcardPathOrSize, systemImageApiLevel, target);
|
||||||
|
|
||||||
// execute pre emulator launch script if set
|
// execute pre emulator launch script if set
|
||||||
if (preEmulatorLaunchScripts !== undefined) {
|
if (preEmulatorLaunchScripts !== undefined) {
|
||||||
@@ -197,25 +210,7 @@ async function run() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// launch an emulator
|
// launch an emulator
|
||||||
await launchEmulator(
|
await launchEmulator(avdName, disableAnimations, disableLinuxHardwareAcceleration, disableSpellchecker, emulatorBootTimeout, emulatorOptions, enableHardwareKeyboard, port);
|
||||||
apiLevel,
|
|
||||||
target,
|
|
||||||
arch,
|
|
||||||
profile,
|
|
||||||
cores,
|
|
||||||
ramSize,
|
|
||||||
heapSize,
|
|
||||||
sdcardPathOrSize,
|
|
||||||
diskSize,
|
|
||||||
avdName,
|
|
||||||
forceAvdCreation,
|
|
||||||
emulatorBootTimeout,
|
|
||||||
emulatorOptions,
|
|
||||||
disableAnimations,
|
|
||||||
disableSpellchecker,
|
|
||||||
disableLinuxHardwareAcceleration,
|
|
||||||
enableHardwareKeyboard
|
|
||||||
);
|
|
||||||
|
|
||||||
// execute the custom script
|
// execute the custom script
|
||||||
try {
|
try {
|
||||||
@@ -226,17 +221,19 @@ async function run() {
|
|||||||
for (const script of scripts) {
|
for (const script of scripts) {
|
||||||
// use array form to avoid various quote escaping problems
|
// use array form to avoid various quote escaping problems
|
||||||
// caused by exec(`sh -c "${script}"`)
|
// caused by exec(`sh -c "${script}"`)
|
||||||
await exec.exec('sh', ['-c', script]);
|
await exec.exec('sh', ['-c', script], {
|
||||||
|
env: { ...process.env, EMULATOR_PORT: `${port}`, ANDROID_SERIAL: `emulator-${port}` },
|
||||||
|
});
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
core.setFailed(error instanceof Error ? error.message : (error as string));
|
core.setFailed(error instanceof Error ? error.message : (error as string));
|
||||||
}
|
}
|
||||||
|
|
||||||
// finally kill the emulator
|
// finally kill the emulator
|
||||||
await killEmulator();
|
await killEmulator(port);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// kill the emulator so the action can exit
|
// kill the emulator so the action can exit
|
||||||
await killEmulator();
|
await killEmulator(port);
|
||||||
core.setFailed(error instanceof Error ? error.message : (error as string));
|
core.setFailed(error instanceof Error ? error.message : (error as string));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+18
-11
@@ -4,25 +4,31 @@ import * as io from '@actions/io';
|
|||||||
import * as tc from '@actions/tool-cache';
|
import * as tc from '@actions/tool-cache';
|
||||||
import * as fs from 'fs';
|
import * as fs from 'fs';
|
||||||
|
|
||||||
const BUILD_TOOLS_VERSION = '34.0.0';
|
const BUILD_TOOLS_VERSION = '37.0.0';
|
||||||
// SDK command-line tools 11.0
|
// SDK command-line tools 23.0
|
||||||
const CMDLINE_TOOLS_URL_MAC = 'https://dl.google.com/android/repository/commandlinetools-mac-10406996_latest.zip';
|
const CMDLINE_TOOLS_VERSION = '16111833';
|
||||||
const CMDLINE_TOOLS_URL_LINUX = 'https://dl.google.com/android/repository/commandlinetools-linux-10406996_latest.zip';
|
const CMDLINE_TOOLS_URL_MAC = `https://dl.google.com/android/repository/commandlinetools-mac_x86_64-${CMDLINE_TOOLS_VERSION}_latest.zip`;
|
||||||
|
const CMDLINE_TOOLS_URL_LINUX = `https://dl.google.com/android/repository/commandlinetools-linux-${CMDLINE_TOOLS_VERSION}_latest.zip`;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Installs & updates the Android SDK for the macOS platform, including SDK platform for the chosen API level, latest build tools, platform tools, Android Emulator,
|
* Installs & updates the Android SDK for the macOS platform, including SDK platform for the chosen API level, latest build tools, platform tools, Android Emulator,
|
||||||
* and the system image for the chosen API level, CPU arch, and target.
|
* and the system image for the chosen API level, CPU arch, and target.
|
||||||
*/
|
*/
|
||||||
export async function installAndroidSdk(apiLevel: string, target: string, arch: string, channelId: number, emulatorBuild?: string, ndkVersion?: string, cmakeVersion?: string): Promise<void> {
|
export async function installAndroidSdk(
|
||||||
|
apiLevel: string,
|
||||||
|
systemImageApiLevel: String,
|
||||||
|
target: string,
|
||||||
|
arch: string,
|
||||||
|
channelId: number,
|
||||||
|
emulatorBuild?: string,
|
||||||
|
ndkVersion?: string,
|
||||||
|
cmakeVersion?: string,
|
||||||
|
): Promise<void> {
|
||||||
try {
|
try {
|
||||||
console.log(`::group::Install Android SDK`);
|
console.log(`::group::Install Android SDK`);
|
||||||
const isOnMac = process.platform === 'darwin';
|
const isOnMac = process.platform === 'darwin';
|
||||||
const isArm = process.arch === 'arm64';
|
const isArm = process.arch === 'arm64';
|
||||||
|
|
||||||
if (!isOnMac) {
|
|
||||||
await exec.exec(`sh -c \\"sudo chown $USER:$USER ${process.env.ANDROID_HOME} -R`);
|
|
||||||
}
|
|
||||||
|
|
||||||
const cmdlineToolsPath = `${process.env.ANDROID_HOME}/cmdline-tools`;
|
const cmdlineToolsPath = `${process.env.ANDROID_HOME}/cmdline-tools`;
|
||||||
if (!fs.existsSync(cmdlineToolsPath)) {
|
if (!fs.existsSync(cmdlineToolsPath)) {
|
||||||
console.log('Installing new cmdline-tools.');
|
console.log('Installing new cmdline-tools.');
|
||||||
@@ -36,6 +42,7 @@ export async function installAndroidSdk(apiLevel: string, target: string, arch:
|
|||||||
core.addPath(`${cmdlineToolsPath}/latest:${cmdlineToolsPath}/latest/bin:${process.env.ANDROID_HOME}/platform-tools`);
|
core.addPath(`${cmdlineToolsPath}/latest:${cmdlineToolsPath}/latest/bin:${process.env.ANDROID_HOME}/platform-tools`);
|
||||||
|
|
||||||
// set standard AVD path
|
// set standard AVD path
|
||||||
|
await io.mkdirP(`${process.env.HOME}/.android/avd`);
|
||||||
core.exportVariable('ANDROID_AVD_HOME', `${process.env.HOME}/.android/avd`);
|
core.exportVariable('ANDROID_AVD_HOME', `${process.env.HOME}/.android/avd`);
|
||||||
|
|
||||||
// accept all Android SDK licenses
|
// accept all Android SDK licenses
|
||||||
@@ -43,7 +50,7 @@ export async function installAndroidSdk(apiLevel: string, target: string, arch:
|
|||||||
|
|
||||||
console.log('Installing latest build tools, platform tools, and platform.');
|
console.log('Installing latest build tools, platform tools, and platform.');
|
||||||
|
|
||||||
await exec.exec(`sh -c \\"sdkmanager --install 'build-tools;${BUILD_TOOLS_VERSION}' platform-tools > /dev/null"`);
|
await exec.exec(`sh -c \\"sdkmanager --install 'build-tools;${BUILD_TOOLS_VERSION}' platform-tools 'platforms;android-${apiLevel}'> /dev/null"`);
|
||||||
|
|
||||||
console.log('Installing latest emulator.');
|
console.log('Installing latest emulator.');
|
||||||
await exec.exec(`sh -c \\"sdkmanager --install emulator --channel=${channelId} > /dev/null"`);
|
await exec.exec(`sh -c \\"sdkmanager --install emulator --channel=${channelId} > /dev/null"`);
|
||||||
@@ -69,7 +76,7 @@ export async function installAndroidSdk(apiLevel: string, target: string, arch:
|
|||||||
await io.rmRF('emulator.zip');
|
await io.rmRF('emulator.zip');
|
||||||
}
|
}
|
||||||
console.log('Installing system images.');
|
console.log('Installing system images.');
|
||||||
await exec.exec(`sh -c \\"sdkmanager --install 'system-images;android-${apiLevel};${target};${arch}' --channel=${channelId} > /dev/null"`);
|
await exec.exec(`sh -c \\"sdkmanager --install 'system-images;android-${systemImageApiLevel};${target};${arch}' --channel=${channelId} > /dev/null"`);
|
||||||
|
|
||||||
if (ndkVersion) {
|
if (ndkVersion) {
|
||||||
console.log(`Installing NDK ${ndkVersion}.`);
|
console.log(`Installing NDK ${ndkVersion}.`);
|
||||||
|
|||||||
@@ -1,37 +0,0 @@
|
|||||||
apply plugin: 'com.android.application'
|
|
||||||
apply plugin: 'kotlin-android'
|
|
||||||
|
|
||||||
android {
|
|
||||||
namespace = "com.example.testapp"
|
|
||||||
|
|
||||||
compileSdkVersion 34
|
|
||||||
buildToolsVersion "34.0.0"
|
|
||||||
|
|
||||||
defaultConfig {
|
|
||||||
applicationId "com.example.testapp"
|
|
||||||
minSdkVersion 15
|
|
||||||
targetSdkVersion 34
|
|
||||||
versionCode 1
|
|
||||||
versionName "1.0"
|
|
||||||
|
|
||||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
|
||||||
}
|
|
||||||
|
|
||||||
compileOptions {
|
|
||||||
sourceCompatibility JavaVersion.VERSION_11
|
|
||||||
targetCompatibility JavaVersion.VERSION_11
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).configureEach {
|
|
||||||
compilerOptions {
|
|
||||||
jvmTarget = org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_11
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
dependencies {
|
|
||||||
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
|
||||||
implementation 'androidx.appcompat:appcompat:1.6.1'
|
|
||||||
androidTestImplementation 'androidx.test.ext:junit:1.1.5'
|
|
||||||
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
plugins {
|
||||||
|
id("com.android.application")
|
||||||
|
}
|
||||||
|
|
||||||
|
android {
|
||||||
|
namespace = "com.example.testapp"
|
||||||
|
compileSdk = 37
|
||||||
|
buildToolsVersion = "37.0.0"
|
||||||
|
|
||||||
|
defaultConfig {
|
||||||
|
applicationId = "com.example.testapp"
|
||||||
|
minSdk = 23
|
||||||
|
targetSdk = 37
|
||||||
|
versionCode = 1
|
||||||
|
versionName = "1.0"
|
||||||
|
|
||||||
|
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
||||||
|
}
|
||||||
|
|
||||||
|
compileOptions {
|
||||||
|
sourceCompatibility = JavaVersion.VERSION_17
|
||||||
|
targetCompatibility = JavaVersion.VERSION_17
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile>().configureEach {
|
||||||
|
compilerOptions {
|
||||||
|
jvmTarget.set(org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_17)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
implementation("androidx.appcompat:appcompat:1.8.0")
|
||||||
|
androidTestImplementation("androidx.test.ext:junit:1.3.0")
|
||||||
|
androidTestImplementation("androidx.test.espresso:espresso-core:3.7.0")
|
||||||
|
}
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
|
||||||
|
|
||||||
buildscript {
|
|
||||||
repositories {
|
|
||||||
google()
|
|
||||||
mavenCentral()
|
|
||||||
}
|
|
||||||
dependencies {
|
|
||||||
classpath 'com.android.tools.build:gradle:8.2.0'
|
|
||||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.9.21"
|
|
||||||
|
|
||||||
// NOTE: Do not place your application dependencies here; they belong
|
|
||||||
// in the individual module build.gradle files
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
allprojects {
|
|
||||||
repositories {
|
|
||||||
google()
|
|
||||||
mavenCentral()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
task clean(type: Delete) {
|
|
||||||
delete rootProject.buildDir
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
plugins {
|
||||||
|
id("com.android.application") version "9.3.2" apply false
|
||||||
|
id("org.jetbrains.kotlin.android") version "2.4.10" apply false
|
||||||
|
}
|
||||||
|
|
||||||
@@ -5,5 +5,3 @@ org.gradle.caching=true
|
|||||||
# Kotlin code style
|
# Kotlin code style
|
||||||
kotlin.code.style=official
|
kotlin.code.style=official
|
||||||
|
|
||||||
# Enable AndroidX
|
|
||||||
android.useAndroidX=true
|
|
||||||
|
|||||||
BIN
Binary file not shown.
+3
-1
@@ -1,7 +1,9 @@
|
|||||||
distributionBase=GRADLE_USER_HOME
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-9.7.1-bin.zip
|
||||||
networkTimeout=10000
|
networkTimeout=10000
|
||||||
|
retries=0
|
||||||
|
retryBackOffMs=500
|
||||||
validateDistributionUrl=true
|
validateDistributionUrl=true
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
zipStorePath=wrapper/dists
|
zipStorePath=wrapper/dists
|
||||||
|
|||||||
Vendored
+9
-10
@@ -1,7 +1,7 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
|
|
||||||
#
|
#
|
||||||
# Copyright © 2015-2021 the original authors.
|
# Copyright © 2015 the original authors.
|
||||||
#
|
#
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
# you may not use this file except in compliance with the License.
|
# you may not use this file except in compliance with the License.
|
||||||
@@ -15,10 +15,12 @@
|
|||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
#
|
#
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
#
|
||||||
|
|
||||||
##############################################################################
|
##############################################################################
|
||||||
#
|
#
|
||||||
# Gradle start up script for POSIX generated by Gradle.
|
# gradlew start up script for POSIX generated by Gradle.
|
||||||
#
|
#
|
||||||
# Important for running:
|
# Important for running:
|
||||||
#
|
#
|
||||||
@@ -27,7 +29,7 @@
|
|||||||
# bash, then to run this script, type that shell name before the whole
|
# bash, then to run this script, type that shell name before the whole
|
||||||
# command line, like:
|
# command line, like:
|
||||||
#
|
#
|
||||||
# ksh Gradle
|
# ksh gradlew
|
||||||
#
|
#
|
||||||
# Busybox and similar reduced shells will NOT work, because this script
|
# Busybox and similar reduced shells will NOT work, because this script
|
||||||
# requires all of these POSIX shell features:
|
# requires all of these POSIX shell features:
|
||||||
@@ -55,7 +57,7 @@
|
|||||||
# Darwin, MinGW, and NonStop.
|
# Darwin, MinGW, and NonStop.
|
||||||
#
|
#
|
||||||
# (3) This script is generated from the Groovy template
|
# (3) This script is generated from the Groovy template
|
||||||
# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
# https://github.com/gradle/gradle/blob/3d91ce3b8caaf77ad09f381f43615b715b53f72c/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||||
# within the Gradle project.
|
# within the Gradle project.
|
||||||
#
|
#
|
||||||
# You can find Gradle at https://github.com/gradle/gradle/.
|
# You can find Gradle at https://github.com/gradle/gradle/.
|
||||||
@@ -84,7 +86,7 @@ done
|
|||||||
# shellcheck disable=SC2034
|
# shellcheck disable=SC2034
|
||||||
APP_BASE_NAME=${0##*/}
|
APP_BASE_NAME=${0##*/}
|
||||||
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
|
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
|
||||||
APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
|
APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
|
||||||
|
|
||||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||||
MAX_FD=maximum
|
MAX_FD=maximum
|
||||||
@@ -112,7 +114,6 @@ case "$( uname )" in #(
|
|||||||
NONSTOP* ) nonstop=true ;;
|
NONSTOP* ) nonstop=true ;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
|
||||||
|
|
||||||
|
|
||||||
# Determine the Java command to use to start the JVM.
|
# Determine the Java command to use to start the JVM.
|
||||||
@@ -170,7 +171,6 @@ fi
|
|||||||
# For Cygwin or MSYS, switch paths to Windows format before running java
|
# For Cygwin or MSYS, switch paths to Windows format before running java
|
||||||
if "$cygwin" || "$msys" ; then
|
if "$cygwin" || "$msys" ; then
|
||||||
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
|
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
|
||||||
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
|
|
||||||
|
|
||||||
JAVACMD=$( cygpath --unix "$JAVACMD" )
|
JAVACMD=$( cygpath --unix "$JAVACMD" )
|
||||||
|
|
||||||
@@ -203,15 +203,14 @@ fi
|
|||||||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||||
|
|
||||||
# Collect all arguments for the java command:
|
# Collect all arguments for the java command:
|
||||||
# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
|
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
|
||||||
# and any embedded shellness will be escaped.
|
# and any embedded shellness will be escaped.
|
||||||
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
|
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
|
||||||
# treated as '${Hostname}' itself on the command line.
|
# treated as '${Hostname}' itself on the command line.
|
||||||
|
|
||||||
set -- \
|
set -- \
|
||||||
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
||||||
-classpath "$CLASSPATH" \
|
-jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
|
||||||
org.gradle.wrapper.GradleWrapperMain \
|
|
||||||
"$@"
|
"$@"
|
||||||
|
|
||||||
# Stop when "xargs" is not available.
|
# Stop when "xargs" is not available.
|
||||||
|
|||||||
Vendored
+24
-34
@@ -13,16 +13,18 @@
|
|||||||
@rem See the License for the specific language governing permissions and
|
@rem See the License for the specific language governing permissions and
|
||||||
@rem limitations under the License.
|
@rem limitations under the License.
|
||||||
@rem
|
@rem
|
||||||
|
@rem SPDX-License-Identifier: Apache-2.0
|
||||||
|
@rem
|
||||||
|
|
||||||
@if "%DEBUG%"=="" @echo off
|
@if "%DEBUG%"=="" @echo off
|
||||||
@rem ##########################################################################
|
@rem ##########################################################################
|
||||||
@rem
|
@rem
|
||||||
@rem Gradle startup script for Windows
|
@rem gradlew startup script for Windows
|
||||||
@rem
|
@rem
|
||||||
@rem ##########################################################################
|
@rem ##########################################################################
|
||||||
|
|
||||||
@rem Set local scope for the variables with windows NT shell
|
@rem Set local scope for the variables, and ensure extensions are enabled
|
||||||
if "%OS%"=="Windows_NT" setlocal
|
setlocal EnableExtensions
|
||||||
|
|
||||||
set DIRNAME=%~dp0
|
set DIRNAME=%~dp0
|
||||||
if "%DIRNAME%"=="" set DIRNAME=.
|
if "%DIRNAME%"=="" set DIRNAME=.
|
||||||
@@ -43,13 +45,13 @@ set JAVA_EXE=java.exe
|
|||||||
%JAVA_EXE% -version >NUL 2>&1
|
%JAVA_EXE% -version >NUL 2>&1
|
||||||
if %ERRORLEVEL% equ 0 goto execute
|
if %ERRORLEVEL% equ 0 goto execute
|
||||||
|
|
||||||
echo.
|
echo. 1>&2
|
||||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
|
||||||
echo.
|
echo. 1>&2
|
||||||
echo Please set the JAVA_HOME variable in your environment to match the
|
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
||||||
echo location of your Java installation.
|
echo location of your Java installation. 1>&2
|
||||||
|
|
||||||
goto fail
|
"%COMSPEC%" /c exit 1
|
||||||
|
|
||||||
:findJavaFromJavaHome
|
:findJavaFromJavaHome
|
||||||
set JAVA_HOME=%JAVA_HOME:"=%
|
set JAVA_HOME=%JAVA_HOME:"=%
|
||||||
@@ -57,36 +59,24 @@ set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
|||||||
|
|
||||||
if exist "%JAVA_EXE%" goto execute
|
if exist "%JAVA_EXE%" goto execute
|
||||||
|
|
||||||
echo.
|
echo. 1>&2
|
||||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
|
||||||
echo.
|
echo. 1>&2
|
||||||
echo Please set the JAVA_HOME variable in your environment to match the
|
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
||||||
echo location of your Java installation.
|
echo location of your Java installation. 1>&2
|
||||||
|
|
||||||
goto fail
|
"%COMSPEC%" /c exit 1
|
||||||
|
|
||||||
:execute
|
:execute
|
||||||
@rem Setup the command line
|
@rem Setup the command line
|
||||||
|
|
||||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
|
||||||
|
|
||||||
|
|
||||||
@rem Execute Gradle
|
@rem Execute gradlew
|
||||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
|
@rem endlocal doesn't take effect until after the line is parsed and variables are expanded
|
||||||
|
@rem which allows us to clear the local environment before executing the java command
|
||||||
|
endlocal & "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* & call :exitWithErrorLevel
|
||||||
|
|
||||||
:end
|
:exitWithErrorLevel
|
||||||
@rem End local scope for the variables with windows NT shell
|
@rem Use "%COMSPEC%" /c exit to allow operators to work properly in scripts
|
||||||
if %ERRORLEVEL% equ 0 goto mainEnd
|
"%COMSPEC%" /c exit %ERRORLEVEL%
|
||||||
|
|
||||||
:fail
|
|
||||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
|
||||||
rem the _cmd.exe /c_ return code!
|
|
||||||
set EXIT_CODE=%ERRORLEVEL%
|
|
||||||
if %EXIT_CODE% equ 0 set EXIT_CODE=1
|
|
||||||
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
|
|
||||||
exit /b %EXIT_CODE%
|
|
||||||
|
|
||||||
:mainEnd
|
|
||||||
if "%OS%"=="Windows_NT" endlocal
|
|
||||||
|
|
||||||
:omega
|
|
||||||
|
|||||||
@@ -1,2 +0,0 @@
|
|||||||
rootProject.name='Test Project'
|
|
||||||
include ':app'
|
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
pluginManagement {
|
||||||
|
repositories {
|
||||||
|
google {
|
||||||
|
content {
|
||||||
|
includeGroupByRegex("androidx.*")
|
||||||
|
includeGroupByRegex("com.android.*")
|
||||||
|
includeGroupByRegex("com.google.*")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mavenCentral()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rootProject.name = "Test Project"
|
||||||
|
include(":app")
|
||||||
|
|
||||||
|
dependencyResolutionManagement {
|
||||||
|
repositories {
|
||||||
|
google {
|
||||||
|
content {
|
||||||
|
includeGroupByRegex("androidx.*")
|
||||||
|
includeGroupByRegex("com.android.*")
|
||||||
|
includeGroupByRegex("com.google.*")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mavenCentral()
|
||||||
|
}
|
||||||
|
}
|
||||||
+3
-2
@@ -2,7 +2,7 @@
|
|||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
/* Basic Options */
|
/* Basic Options */
|
||||||
// "incremental": true, /* Enable incremental compilation */
|
// "incremental": true, /* Enable incremental compilation */
|
||||||
"target": "es6", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */
|
"target": "es2022", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */
|
||||||
"module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */
|
"module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */
|
||||||
// "allowJs": true, /* Allow javascript files to be compiled. */
|
// "allowJs": true, /* Allow javascript files to be compiled. */
|
||||||
// "checkJs": true, /* Report errors in .js files. */
|
// "checkJs": true, /* Report errors in .js files. */
|
||||||
@@ -45,7 +45,8 @@
|
|||||||
// "typeRoots": [], /* List of folders to include type definitions from. */
|
// "typeRoots": [], /* List of folders to include type definitions from. */
|
||||||
// "types": [], /* Type declaration files to be included in compilation. */
|
// "types": [], /* Type declaration files to be included in compilation. */
|
||||||
// "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
|
// "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
|
||||||
"esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
|
"esModuleInterop": true, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
|
||||||
|
"skipLibCheck": true
|
||||||
// "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */
|
// "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */
|
||||||
// "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
|
// "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user