From dc3c93bee535f2479a1df88eb1c53041cae23b42 Mon Sep 17 00:00:00 2001 From: Mike Hardy Date: Thu, 10 Oct 2024 13:59:59 -0500 Subject: [PATCH] fix(ubuntu): verify command line tools is the version we want the directory merely existing is not sufficient to say command line tools will work, it may be an old version get the version and explicitly check it, remove it so fresh install will happen if it is not the desired version --- README.md | 1 + lib/input-validator.js | 8 +++++++- lib/main.js | 7 ++++++- lib/sdk-installer.js | 19 ++++++++++++++++--- src/input-validator.ts | 6 ++++++ src/main.ts | 9 ++++++++- src/sdk-installer.ts | 20 +++++++++++++++++--- 7 files changed, 61 insertions(+), 9 deletions(-) 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);