From 522f05d25ecdf65e2ae22bd7830a250346fc5752 Mon Sep 17 00:00:00 2001
From: Jonathan Lipps <jlipps@gmail.com>
Date: Fri, 29 Nov 2024 08:47:17 -0800
Subject: [PATCH] fix(appium): correctly handle git/github install types (fix
 #20781) (#20788)

---
 packages/appium/lib/cli/extension-command.js | 16 +++++++++-------
 packages/support/lib/npm.js                  |  8 ++++----
 2 files changed, 13 insertions(+), 11 deletions(-)

diff --git a/packages/appium/lib/cli/extension-command.js b/packages/appium/lib/cli/extension-command.js
index 92aef3d559c..2a25c84250a 100644
--- a/packages/appium/lib/cli/extension-command.js
+++ b/packages/appium/lib/cli/extension-command.js
@@ -311,7 +311,7 @@ class ExtensionCliCommand {
         installType,
         pkgName: /** @type {string} */ (packageName),
       };
-      probableExtName = installSpec;
+      probableExtName = /** @type {string} */ (packageName);
     } else if (installType === INSTALL_TYPE_GIT) {
       // git urls can have '.git' at the end, but this is not necessary and would complicate the
       // way we download and name directories, so we can just remove it
@@ -321,7 +321,7 @@ class ExtensionCliCommand {
         installType,
         pkgName: /** @type {string} */ (packageName),
       };
-      probableExtName = installSpec;
+      probableExtName = /** @type {string} */ (packageName);
     } else {
       let pkgName, pkgVer;
       if (installType === INSTALL_TYPE_LOCAL) {
@@ -439,13 +439,15 @@ class ExtensionCliCommand {
    * @returns {Promise<ExtInstallReceipt<ExtType>>}
    */
   async installViaNpm({installSpec, pkgName, pkgVer, installType}) {
-    const npmSpec = `${pkgName}${pkgVer ? '@' + pkgVer : ''}`;
-    const specMsg = npmSpec === installSpec ? '' : ` using NPM install spec '${npmSpec}'`;
-    const msg = `Installing '${installSpec}'${specMsg}`;
+    const msg = `Installing '${installSpec}'`;
+
+    // the string used for installation is either <name>@<ver> in the case of a standard NPM
+    // package, or whatever the user sent in otherwise.
+    const installStr = installType === INSTALL_TYPE_NPM ? `${pkgName}${pkgVer ? `@${pkgVer}` : ''}` : installSpec;
     try {
       const {pkg, path} = await spinWith(this.isJsonOutput, msg, async () => {
-        const {pkg, installPath: path} = await npm.installPackage(this.config.appiumHome, pkgName, {
-          pkgVer,
+        const {pkg, installPath: path} = await npm.installPackage(this.config.appiumHome, installStr, {
+          pkgName,
           installType,
         });
         this.validatePackageJson(pkg, installSpec);
diff --git a/packages/support/lib/npm.js b/packages/support/lib/npm.js
index fa034522438..db95f823edc 100644
--- a/packages/support/lib/npm.js
+++ b/packages/support/lib/npm.js
@@ -197,11 +197,11 @@ export class NPM {
   /**
    * Installs a package w/ `npm`
    * @param {string} cwd
-   * @param {string} pkgName
+   * @param {string} installStr - as in "npm install <installStr>"
    * @param {InstallPackageOpts} opts
    * @returns {Promise<NpmInstallReceipt>}
    */
-  async installPackage(cwd, pkgName, {pkgVer, installType} = {}) {
+  async installPackage(cwd, installStr, {pkgName, installType}) {
     /** @type {any} */
     let dummyPkgJson;
     const dummyPkgPath = path.join(cwd, 'package.json');
@@ -225,7 +225,7 @@ export class NPM {
     }
 
     const cmd = installType === 'local' ? 'link' : 'install';
-    const res = await this.exec(cmd, [...installOpts, pkgVer ? `${pkgName}@${pkgVer}` : pkgName], {
+    const res = await this.exec(cmd, [...installOpts, installStr], {
       cwd,
       json: true,
       lockFile: this._getInstallLockfilePath(cwd),
@@ -287,8 +287,8 @@ export const npm = new NPM();
 /**
  * Options for {@link NPM.installPackage}
  * @typedef InstallPackageOpts
+ * @property {string} pkgName - the name of the package to install
  * @property {import('type-fest').LiteralUnion<'local', string>} [installType] - whether to install from a local path or from npm
- * @property {string} [pkgVer] - the version of the package to install
  */
 
 /**