feta(appium): Add a subcommand to reset all installed drivers and plugins (#20747)

This commit is contained in:
Mykola Mokhnach
2024-11-13 17:26:04 +01:00
committed by GitHub
parent 3696ac1d8d
commit 268b24ff83
4 changed files with 71 additions and 6 deletions
+5
View File
@@ -24,5 +24,10 @@ will only install the missing extensions.
Refer to the [Ecosystem documentation](../ecosystem/index.md) to learn more about the extensions
listed above.
This commands also supports the functionality that allows to fully reset your Appium server
deployment if you experience various configuration issues,
for example, due to a failed upgrade attempt from an older Appium version, on server startup.
By running `appium setup reset` the server would uninstall all installed drivers, plugins and their related manifest files from the currently used Appium home folder.
[^1]: Only installed if the host machine is running macOS.
[^2]: Only installed if the host machine is running Windows.
+64 -4
View File
@@ -5,7 +5,7 @@ import {
MOBILE_DRIVERS
} from '../constants';
import {runExtensionCommand} from './extension';
import { system } from '@appium/support';
import { system, fs } from '@appium/support';
import log from '../logger';
/**
@@ -14,6 +14,7 @@ import log from '../logger';
export const SUBCOMMAND_MOBILE = 'mobile';
export const SUBCOMMAND_DESKTOP = 'desktop';
export const SUBCOMMAND_BROWSER = 'browser';
export const SUBCOMMAND_RESET = 'reset';
/**
* Pairs of preset subcommand and driver candidates.
@@ -72,12 +73,11 @@ export function determinePlatformName() {
* Run 'setup' command to install drivers/plugins into the given appium home.
* @template {import('appium/types').CliCommandSetup} SetupCmd
* @param {import('appium/types').Args<SetupCmd>} preConfigArgs
* @param {string} appiumHome
* @param {DriverConfig} driverConfig
* @param {PluginConfig} pluginConfig
* @returns {Promise<void>}
*/
export async function runSetupCommand(appiumHome, preConfigArgs, driverConfig, pluginConfig) {
export async function runSetupCommand(preConfigArgs, driverConfig, pluginConfig) {
switch (preConfigArgs.setupCommand) {
case SUBCOMMAND_DESKTOP:
await setupDesktopAppDrivers(driverConfig);
@@ -87,6 +87,9 @@ export async function runSetupCommand(appiumHome, preConfigArgs, driverConfig, p
await setupBrowserDrivers(driverConfig);
await setupDefaultPlugins(pluginConfig);
break;
case SUBCOMMAND_RESET:
await resetAllExtensions(driverConfig, pluginConfig);
break;
default:
await setupMobileDrivers(driverConfig);
await setupDefaultPlugins(pluginConfig);
@@ -94,6 +97,47 @@ export async function runSetupCommand(appiumHome, preConfigArgs, driverConfig, p
}
};
/**
* Resets all installed drivers and extensions
*
* @param {DriverConfig} driverConfig
* @param {PluginConfig} pluginConfig
* @returns {Promise<void>}
*/
async function resetAllExtensions(driverConfig, pluginConfig) {
for (const [command, config] of [
['driver', driverConfig],
['plugin', pluginConfig],
]) {
for (const extensionName of _.keys(/** @type {DriverConfig|PluginConfig} */ (config).installedExtensions)) {
try {
await uninstallExtension(
extensionName,
extensionCommandArgs(/** @type {CliExtensionCommand} */ (command), extensionName, 'uninstall'),
/** @type {DriverConfig|PluginConfig} */ (config)
);
} catch (e) {
log.warn(
`${extensionName} ${command} cannot be uninstalled. Will delete the manifest anyway. ` +
`Original error: ${e.stack}`
);
}
}
const manifestPath = /** @type {DriverConfig|PluginConfig} */ (config).manifestPath;
if (!await fs.exists(manifestPath)) {
continue;
}
await fs.rimraf(manifestPath);
if (await fs.exists(manifestPath)) {
throw new Error(`${command} manifest at '${manifestPath}' cannot be deleted. Is it accessible?`);
} else {
log.info(`Successfully deleted ${command} manifest at '${manifestPath}'`);
}
}
}
/**
* Install drivers listed in DEFAULT_DRIVERS.
* @param {DriverConfig} driverConfig
@@ -149,7 +193,7 @@ async function setupDefaultPlugins(pluginConfig) {
* @param {string} extensionName
* @param {Args} extensionConfigArgs
* @param {DriverConfig|PluginConfig} extensionConfig
* @returns
* @returns {Promise<void>}
*/
async function installExtension(extensionName, extensionConfigArgs, extensionConfig) {
if (_.keys(extensionConfig.installedExtensions).includes(extensionName)) {
@@ -160,6 +204,22 @@ async function installExtension(extensionName, extensionConfigArgs, extensionCon
await runExtensionCommand(extensionConfigArgs, extensionConfig);
}
/**
* Run the given extensionConfigArgs command after checking if the given extensionName was already installed.
* @param {string} extensionName
* @param {Args} extensionConfigArgs
* @param {DriverConfig|PluginConfig} extensionConfig
* @returns {Promise<void>}
*/
async function uninstallExtension(extensionName, extensionConfigArgs, extensionConfig) {
if (!_.keys(extensionConfig.installedExtensions).includes(extensionName)) {
log.info(`${extensionName} (${extensionConfig.installedExtensions[extensionName].version}) is not installed. ` +
`Skipping its uninstall.`);
return;
}
await runExtensionCommand(extensionConfigArgs, extensionConfig);
}
/**
* Return the command config for driver or plugin.
* @param {CliExtensionCommand} extensionCommand
+1 -1
View File
@@ -301,7 +301,7 @@ async function init(args) {
appiumHome,
});
} else if (isSetupCommandArgs(preConfigArgs)) {
await runSetupCommand(appiumHome, preConfigArgs, driverConfig, pluginConfig);
await runSetupCommand(preConfigArgs, driverConfig, pluginConfig);
return /** @type {InitResult<Cmd>} */ ({});
} else {
await requireDir(appiumHome, true, appiumHomeSourceName);
+1 -1
View File
@@ -20,7 +20,7 @@ export type CliCommand = CliCommandServer | CliExtensionCommand | CliCommandSetu
* Possible subcommands of {@linkcode CliCommandSetup}.
* The command name will be preset name to get drivers/plugins to be installed.
*/
export type CliCommandSetupSubcommand = 'mobile' | 'browser' | 'desktop';
export type CliCommandSetupSubcommand = 'mobile' | 'browser' | 'desktop' | 'reset';
/**
* Possible subcommands of {@linkcode CliCommandDriver} or