diff --git a/README.md b/README.md index 980879213..c31483fd8 100644 --- a/README.md +++ b/README.md @@ -199,6 +199,7 @@ jobs: | `enable-hw-keyboard` | Optional | `false` | Whether to enable hardware keyboard - `true` or `false`. | | `emulator-build` | Optional | N/A | Build number of a specific version of the emulator binary to use e.g. `6061023` for emulator v29.3.0.0. | | `working-directory` | Optional | `./` | A custom working directory - e.g. `./android` if your root Gradle project is under the `./android` sub-directory within your repository. Will be used for `script` & `pre-emulator-launch-script`. | +| `force-cmdline-tools-update` | Optional | `true` | Whether to update any pre-installed version of cmdline-tools if out of date. | | `ndk` | Optional | N/A | Version of NDK to install - e.g. `21.0.6113669` | | `cmake` | Optional | N/A | Version of CMake to install - e.g. `3.10.2.4988404` | | `channel` | Optional | stable | Channel to download the SDK components from - `stable`, `beta`, `dev`, `canary` | diff --git a/lib/input-validator.js b/lib/input-validator.js index c27593be7..d64f9bd24 100644 --- a/lib/input-validator.js +++ b/lib/input-validator.js @@ -1,6 +1,6 @@ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -exports.checkDiskSize = exports.checkEmulatorBuild = exports.checkEnableHardwareKeyboard = exports.checkDisableLinuxHardwareAcceleration = exports.checkDisableSpellchecker = exports.checkDisableAnimations = exports.checkPort = exports.checkForceAvdCreation = exports.checkChannel = exports.checkArch = exports.checkTarget = exports.checkApiLevel = exports.PREVIEW_API_LEVELS = exports.MAX_PORT = exports.MIN_PORT = exports.VALID_CHANNELS = exports.VALID_ARCHS = exports.VALID_TARGETS = exports.MIN_API_LEVEL = void 0; +exports.checkDiskSize = exports.checkForceCommandLineToolsUpdate = exports.checkEmulatorBuild = exports.checkEnableHardwareKeyboard = exports.checkDisableLinuxHardwareAcceleration = exports.checkDisableSpellchecker = exports.checkDisableAnimations = exports.checkPort = exports.checkForceAvdCreation = exports.checkChannel = exports.checkArch = exports.checkTarget = exports.checkApiLevel = exports.PREVIEW_API_LEVELS = exports.MAX_PORT = exports.MIN_PORT = exports.VALID_CHANNELS = exports.VALID_ARCHS = exports.VALID_TARGETS = exports.MIN_API_LEVEL = void 0; 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']; @@ -82,6 +82,12 @@ function checkEmulatorBuild(emulatorBuild) { } } exports.checkEmulatorBuild = checkEmulatorBuild; +function checkForceCommandLineToolsUpdate(forceCmdlineToolsUpdate) { + if (!isValidBoolean(forceCmdlineToolsUpdate)) { + throw new Error(`Input for input.force-cmdline-tools-update should be either 'true' or 'false'.`); + } +} +exports.checkForceCommandLineToolsUpdate = checkForceCommandLineToolsUpdate; function isValidBoolean(value) { return value === 'true' || value === 'false'; } diff --git a/lib/main.js b/lib/main.js index 21a5d4918..7b93f6552 100644 --- a/lib/main.js +++ b/lib/main.js @@ -100,6 +100,11 @@ function run() { (0, input_validator_1.checkForceAvdCreation)(forceAvdCreationInput); const forceAvdCreation = forceAvdCreationInput === 'true'; console.log(`force avd creation: ${forceAvdCreation}`); + // force cmdline-tools update + const forceCmdlineToolsUpdateInput = core.getInput('force-cmdline-tools-update'); + (0, input_validator_1.checkForceCommandLineToolsUpdate)(forceCmdlineToolsUpdateInput); + const forceCmdlineToolsUpdate = forceCmdlineToolsUpdateInput === 'true'; + console.log(`force cmdline-tools update: ${forceCmdlineToolsUpdate}`); // Emulator boot timeout seconds const emulatorBootTimeout = parseInt(core.getInput('emulator-boot-timeout'), 10); console.log(`Emulator boot timeout: ${emulatorBootTimeout}`); @@ -179,7 +184,7 @@ function run() { })); console.log(`::endgroup::`); // install SDK - yield (0, sdk_installer_1.installAndroidSdk)(apiLevel, target, arch, channelId, emulatorBuild, ndkVersion, cmakeVersion); + yield (0, sdk_installer_1.installAndroidSdk)(apiLevel, target, arch, channelId, forceCmdlineToolsUpdate, emulatorBuild, ndkVersion, cmakeVersion); // execute pre emulator launch script if set if (preEmulatorLaunchScripts !== undefined) { console.log(`::group::Run pre emulator launch script`); diff --git a/lib/sdk-installer.js b/lib/sdk-installer.js index fe7f51385..5f44fc9f7 100644 --- a/lib/sdk-installer.js +++ b/lib/sdk-installer.js @@ -39,21 +39,34 @@ const io = __importStar(require("@actions/io")); const tc = __importStar(require("@actions/tool-cache")); const fs = __importStar(require("fs")); const BUILD_TOOLS_VERSION = '35.0.0'; -// SDK command-line tools 16.0 +const CMDLINE_TOOLS_VERSION = '16.0'; // the downloads immediately below should correspond to this version const CMDLINE_TOOLS_URL_MAC = 'https://dl.google.com/android/repository/commandlinetools-mac-12266719_latest.zip'; const CMDLINE_TOOLS_URL_LINUX = 'https://dl.google.com/android/repository/commandlinetools-linux-12266719_latest.zip'; /** * Installs & updates the Android SDK for the macOS platform, including SDK platform for the chosen API level, latest build tools, platform tools, Android Emulator, * and the system image for the chosen API level, CPU arch, and target. */ -function installAndroidSdk(apiLevel, target, arch, channelId, emulatorBuild, ndkVersion, cmakeVersion) { +function installAndroidSdk(apiLevel, target, arch, channelId, forceCmdlineToolsUpdate, emulatorBuild, ndkVersion, cmakeVersion) { return __awaiter(this, void 0, void 0, function* () { try { console.log(`::group::Install Android SDK`); const isOnMac = process.platform === 'darwin'; const isArm = process.arch === 'arm64'; const cmdlineToolsPath = `${process.env.ANDROID_HOME}/cmdline-tools`; - if (!fs.existsSync(cmdlineToolsPath)) { + // it may happen that cmdlineToolsPath exists, but is older than desired + // this can cause problems when sdkmanager XML manifest versions change + // for example ubuntu-24 has cmdline-tools v12 with XML v3 but v16 supports v4 + if (forceCmdlineToolsUpdate && fs.existsSync(`${cmdlineToolsPath}/latest`)) { + const cmdlineToolsVer = (yield exec.getExecOutput(`sh -c "${cmdlineToolsPath}/latest/bin/sdkmanager --version"`)).stdout.trim(); + if (!cmdlineToolsVer.includes(CMDLINE_TOOLS_VERSION)) { + console.log(`cmdline-tools is version ${cmdlineToolsVer} instead of expected ${CMDLINE_TOOLS_VERSION}. Removing.`); + yield io.rmRF(`${cmdlineToolsPath}/latest"`); + } + else { + console.log(`cmdline-tools is expected version ${CMDLINE_TOOLS_VERSION}: "${cmdlineToolsVer}"`); + } + } + if (!fs.existsSync(`${cmdlineToolsPath}/latest`)) { console.log('Installing new cmdline-tools.'); const sdkUrl = isOnMac ? CMDLINE_TOOLS_URL_MAC : CMDLINE_TOOLS_URL_LINUX; const downloadPath = yield tc.downloadTool(sdkUrl); diff --git a/src/input-validator.ts b/src/input-validator.ts index 8804685ea..621237b51 100644 --- a/src/input-validator.ts +++ b/src/input-validator.ts @@ -79,6 +79,12 @@ export function checkEmulatorBuild(emulatorBuild: string): void { } } +export function checkForceCommandLineToolsUpdate(forceCmdlineToolsUpdate: string): void { + if (!isValidBoolean(forceCmdlineToolsUpdate)) { + throw new Error(`Input for input.force-cmdline-tools-update should be either 'true' or 'false'.`); + } +} + function isValidBoolean(value: string): boolean { return value === 'true' || value === 'false'; } diff --git a/src/main.ts b/src/main.ts index a9588245e..40f3e6c0d 100644 --- a/src/main.ts +++ b/src/main.ts @@ -9,6 +9,7 @@ import { checkDisableSpellchecker, checkDisableLinuxHardwareAcceleration, checkForceAvdCreation, + checkForceCommandLineToolsUpdate, checkChannel, checkEnableHardwareKeyboard, checkDiskSize, @@ -92,6 +93,12 @@ async function run() { const forceAvdCreation = forceAvdCreationInput === 'true'; console.log(`force avd creation: ${forceAvdCreation}`); + // force cmdline-tools update + const forceCmdlineToolsUpdateInput = core.getInput('force-cmdline-tools-update'); + checkForceCommandLineToolsUpdate(forceCmdlineToolsUpdateInput); + const forceCmdlineToolsUpdate = forceCmdlineToolsUpdateInput === 'true'; + console.log(`force cmdline-tools update: ${forceCmdlineToolsUpdate}`); + // Emulator boot timeout seconds const emulatorBootTimeout = parseInt(core.getInput('emulator-boot-timeout'), 10); console.log(`Emulator boot timeout: ${emulatorBootTimeout}`); @@ -185,7 +192,7 @@ async function run() { console.log(`::endgroup::`); // install SDK - await installAndroidSdk(apiLevel, target, arch, channelId, emulatorBuild, ndkVersion, cmakeVersion); + await installAndroidSdk(apiLevel, target, arch, channelId, forceCmdlineToolsUpdate, emulatorBuild, ndkVersion, cmakeVersion); // execute pre emulator launch script if set if (preEmulatorLaunchScripts !== undefined) { diff --git a/src/sdk-installer.ts b/src/sdk-installer.ts index f87028a6f..216ee83f9 100644 --- a/src/sdk-installer.ts +++ b/src/sdk-installer.ts @@ -5,7 +5,7 @@ import * as tc from '@actions/tool-cache'; import * as fs from 'fs'; const BUILD_TOOLS_VERSION = '35.0.0'; -// SDK command-line tools 16.0 +const CMDLINE_TOOLS_VERSION = '16.0'; // the downloads immediately below should correspond to this version const CMDLINE_TOOLS_URL_MAC = 'https://dl.google.com/android/repository/commandlinetools-mac-12266719_latest.zip'; const CMDLINE_TOOLS_URL_LINUX = 'https://dl.google.com/android/repository/commandlinetools-linux-12266719_latest.zip'; @@ -13,14 +13,28 @@ const CMDLINE_TOOLS_URL_LINUX = 'https://dl.google.com/android/repository/comman * 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. */ -export async function installAndroidSdk(apiLevel: string, target: string, arch: string, channelId: number, emulatorBuild?: string, ndkVersion?: string, cmakeVersion?: string): Promise { +export async function installAndroidSdk(apiLevel: string, target: string, arch: string, channelId: number, forceCmdlineToolsUpdate: boolean, emulatorBuild?: string, ndkVersion?: string, cmakeVersion?: string): Promise { try { console.log(`::group::Install Android SDK`); const isOnMac = process.platform === 'darwin'; const isArm = process.arch === 'arm64'; const cmdlineToolsPath = `${process.env.ANDROID_HOME}/cmdline-tools`; - if (!fs.existsSync(cmdlineToolsPath)) { + + // it may happen that cmdlineToolsPath exists, but is older than desired + // this can cause problems when sdkmanager XML manifest versions change + // for example ubuntu-24 has cmdline-tools v12 with XML v3 but v16 supports v4 + if (forceCmdlineToolsUpdate && fs.existsSync(`${cmdlineToolsPath}/latest`)) { + const cmdlineToolsVer = (await exec.getExecOutput(`sh -c "${cmdlineToolsPath}/latest/bin/sdkmanager --version"`)).stdout.trim(); + if (!cmdlineToolsVer.includes(CMDLINE_TOOLS_VERSION)) { + console.log(`cmdline-tools is version ${cmdlineToolsVer} instead of expected ${CMDLINE_TOOLS_VERSION}. Removing.`); + await io.rmRF(`${cmdlineToolsPath}/latest"`); + } else { + console.log(`cmdline-tools is expected version ${CMDLINE_TOOLS_VERSION}: "${cmdlineToolsVer}"`); + } + } + + if (!fs.existsSync(`${cmdlineToolsPath}/latest`)) { console.log('Installing new cmdline-tools.'); const sdkUrl = isOnMac ? CMDLINE_TOOLS_URL_MAC : CMDLINE_TOOLS_URL_LINUX; const downloadPath = await tc.downloadTool(sdkUrl);