npm package diff

Package: @forge/cli

Versions: 11.0.0 - 11.0.1-next.14

File: package/out/command-line/controller/install-controller.js

Index: package/out/command-line/controller/install-controller.js
===================================================================
--- package/out/command-line/controller/install-controller.js
+++ package/out/command-line/controller/install-controller.js
@@ -69,14 +69,19 @@
                 return text.cmd.end(false);
             }
         });
     }
-    async promptForProduct() {
+    async promptForProducts(requiredProducts) {
         this.ui.info(cli_shared_1.Text.installationContext.overviewProduct);
-        return await this.ui.promptForList(cli_shared_1.Text.installationContext.promptProduct, await this.supportedProductsService.getSupportedProducts());
+        if (requiredProducts?.length) {
+            return await this.ui.promptForMultiSelectList(cli_shared_1.Text.installationContext.promptOptionalProducts, await this.supportedProductsService.getSupportedProducts(requiredProducts));
+        }
+        return [
+            await this.ui.promptForList(cli_shared_1.Text.installationContext.promptProduct, await this.supportedProductsService.getSupportedProducts())
+        ];
     }
-    async promptForSite(product) {
-        const isWorkspaceBased = product && (await this.supportedProductsService.isWorkspaceProduct(product));
+    async promptForSite(products) {
+        const isWorkspaceBased = products.length > 0 && (await this.supportedProductsService.isWorkspaceProduct(products[0]));
         const overviewText = isWorkspaceBased
             ? cli_shared_1.Text.installationContext.overviewWorkspace
             : cli_shared_1.Text.installationContext.overviewSite;
         this.ui.info(overviewText);
@@ -87,9 +92,9 @@
         const invalidText = isWorkspaceBased ? cli_shared_1.Text.error.invalidWorkspace : cli_shared_1.Text.error.invalidSite;
         if (!trySite) {
             throw new cli_shared_1.ValidationError(invalidText);
         }
-        return this.supportedProductsService.validateSite(trySite, product);
+        return this.supportedProductsService.validateSite(trySite, products[0]);
     }
     async promptForUpgrade(siteOption, productOption, environmentOption) {
         const { installations } = await this.installationService.listNonTechnicalAppInstallations({
             site: siteOption,
@@ -142,29 +147,55 @@
         if (uiKit1Modules.length > 0) {
             this.installView.displayUIKit1DeprecationMessage(uiKit1Modules);
         }
     };
-    async run({ environment, site, product, upgrade, confirmScopes, license, licenseModes, usersWithAccess, nonInteractive }) {
+    async run({ environment, site, products, upgrade, confirmScopes, license, licenseModes, usersWithAccess, nonInteractive }) {
         const { id } = await this.appConfigProvider();
         const text = upgrade ? cli_shared_1.Text.upgrade : cli_shared_1.Text.install;
         const validLicense = this.validateLicenseOption(license, environment);
         const overrides = await this.validateEcosystemAppInstallationOverridesInput(licenseModes, usersWithAccess, environment);
-        if (upgrade && (!site || !product)) {
-            const upgradeResult = await this.promptForUpgrade(site, product, environment);
+        const { installations } = (await this.installationService.listAppInstallations()) ?? [];
+        const environmentPermissions = await this.installationService.getAppEnvironmentPermissions(id, environment);
+        const requiredProducts = environmentPermissions?.requiredProducts;
+        if (upgrade && (!site || !products?.length)) {
+            const upgradeResult = await this.promptForUpgrade(site, products?.[0], environment);
             environment = upgradeResult.environment;
             site = upgradeResult.site;
-            product = upgradeResult.product;
+            products = [upgradeResult.product];
         }
-        product = product ? product : await this.promptForProduct();
-        site = site ? site : await this.promptForSite(product);
-        const bannerText = product && (await this.supportedProductsService.isWorkspaceProduct(product))
+        if (!requiredProducts?.length) {
+            products = products?.length ? products : await this.promptForProducts();
+            site = site ? site : await this.promptForSite(products);
+        }
+        else {
+            site = site ? site : await this.promptForSite([]);
+            if (!products?.length) {
+                const hasRequiredInstallations = this.checkRequiredInstallationExists(installations, site.host, requiredProducts);
+                if (hasRequiredInstallations) {
+                    this.ui.info(cli_shared_1.Text.install.alreadyInstalledInRequiredProduct(requiredProducts[0]));
+                    products = products?.length ? products : await this.promptForProducts(requiredProducts);
+                }
+                else {
+                    this.ui.info(cli_shared_1.Text.install.installingToRequiredProduct(requiredProducts[0]));
+                    products = requiredProducts;
+                }
+            }
+            else {
+                if (requiredProducts.includes(products[0])) {
+                    this.ui.info(cli_shared_1.Text.install.installingToRequiredProduct(products[0]));
+                }
+                else {
+                    this.ui.info(cli_shared_1.Text.install.installingToOptionalProduct);
+                }
+            }
+        }
+        const bannerText = (await this.supportedProductsService.isWorkspaceProduct(products[0]))
             ? text.bannerWorkspace
             : text.bannerSite;
         this.ui.info(bannerText);
         if ((0, cli_shared_1.isSecureSite)(site)) {
             await this.securityPrompt(site);
         }
-        const environmentPermissions = await this.installationService.getAppEnvironmentPermissions(id, environment);
         if (!environmentPermissions?.hasDeployments) {
             this.ui.error(new NoDeploymentError(environment), { pad: false });
             return;
         }
@@ -184,31 +215,33 @@
         const addedScopes = await this.extractAddedScopes(environmentPermissions);
         const scopesConfirmationResult = await this.installView.promptForPermissionsConfirmation(environmentPermissions, addedScopes, [...manifestScopes], manifestEgressAddresses, environment, confirmScopes, !!nonInteractive, text);
         if (!scopesConfirmationResult)
             return;
-        const isAlreadyUpdated = await this.installOrUpgrade(upgrade, environment, environmentType, site, product, id, text, validLicense, overrides);
-        if (isAlreadyUpdated) {
-            this.ui.info(cli_shared_1.Text.upgrade.alreadyUpdated.banner(environment, product, site.host));
+        for (const product of products) {
+            const isAlreadyUpdated = await this.installOrUpgrade(upgrade, environment, environmentType, site, product, id, text, validLicense, overrides);
+            if (isAlreadyUpdated) {
+                this.ui.info(cli_shared_1.Text.upgrade.alreadyUpdated.banner(environment, product, site.host));
+            }
+            else {
+                this.ui.emptyLine();
+                this.ui.info(text.success.banner(environment, environmentType, product, site.host));
+                const uniqueProductsFromScopes = this.getUniqueInstallationProductsFromScopes(environmentScopes);
+                if (!uniqueProductsFromScopes || uniqueProductsFromScopes.length <= 1)
+                    return;
+                const { installations } = await this.installationService.listNonTechnicalAppInstallations({
+                    site,
+                    environment
+                });
+                const productsToUpgrade = installations
+                    .filter((installation) => !installation.version.isLatest)
+                    .map((installation) => installation.product);
+                const installedProducts = installations.map((installation) => installation.product);
+                const productsToInstall = uniqueProductsFromScopes.filter((product) => !installedProducts.includes(product));
+                if (!productsToInstall.length && productsToUpgrade.length === 0)
+                    return;
+                this.ui.warn(cli_shared_1.Text.install.multiProductScopesDetected(productsToInstall, productsToUpgrade, site.host, environment));
+            }
         }
-        else {
-            this.ui.emptyLine();
-            this.ui.info(text.success.banner(environment, environmentType, product, site.host));
-            const uniqueProductsFromScopes = this.getUniqueInstallationProductsFromScopes(environmentScopes);
-            if (!uniqueProductsFromScopes || uniqueProductsFromScopes.length <= 1)
-                return;
-            const { installations } = await this.installationService.listNonTechnicalAppInstallations({
-                site,
-                environment
-            });
-            const productsToUpgrade = installations
-                .filter((installation) => !installation.version.isLatest)
-                .map((installation) => installation.product);
-            const installedProducts = installations.map((installation) => installation.product);
-            const productsToInstall = uniqueProductsFromScopes.filter((product) => !installedProducts.includes(product));
-            if (productsToInstall.length === 0 && productsToUpgrade.length === 0)
-                return;
-            this.ui.warn(cli_shared_1.Text.install.multiProductScopesDetected(productsToInstall, productsToUpgrade, site.host, environment));
-        }
     }
     async extractAddedScopes({ addedScopes }) {
         const scopesWithInteractiveConsent = (0, manifest_1.getScopesWithInteractiveConsent)();
         return addedScopes.map((scope) => ({
@@ -264,6 +297,9 @@
         return ecosystemLicenseModes && usersWithAccess
             ? { licenseModes: ecosystemLicenseModes, usersWithAccess }
             : undefined;
     }
+    checkRequiredInstallationExists = (installations, site, requiredProducts) => {
+        return requiredProducts.every((requiredProduct) => installations.some((installation) => installation.site.includes(site) && installation.product.toLowerCase() === requiredProduct.toLowerCase()));
+    };
 }
 exports.InstallController = InstallController;