@forge/cli

14.1.0-next.19-experimental-fd0ebbc14.1.0-next.32
out/installations/graphql-client.js
~out/installations/graphql-client.jsModified
+138−49
Index: package/out/installations/graphql-client.js
===================================================================
--- package/out/installations/graphql-client.js
+++ package/out/installations/graphql-client.js
@@ -4,8 +4,9 @@
 const exponential_backoff_1 = require("exponential-backoff");
 const ari_1 = require("@forge/util/packages/ari");
 const cli_shared_1 = require("@forge/cli-shared");
 const egress_1 = require("@forge/egress");
+const installation_helper_1 = require("./installation-helper");
 const harmonized_app_installation_errors_1 = require("./harmonized-apps/harmonized-app-installation-errors");
 exports.UNINSTALLATION_EVENT_POLL_INTERVAL = 500;
 const DECOUPLED_STATE_NOT_ENABLED_CODE = 'DECOUPLED_STATE_NOT_ENABLED';
 const APP_INSTALLATION_LIMIT_WARNING = 'APP_INSTALLATION_LIMIT_WARNING';
@@ -23,8 +24,39 @@
 exports.ALREADY_UPGRADED_CODE = 'INSTALLATION_ALREADY_UPGRADED';
 const ALREADY_INSTALLED_CODE = 'APP_ALREADY_INSTALLED';
 const INSTALLATION_LIMIT_REACHED_CODE = 'INSTALLATION_LIMIT_REACHED';
 const PERMISSION_DENIED = 'PERMISSION_DENIED';
+const INSTALL_APPLICATION_MUTATION = (0, cli_shared_1.graphql)(`
+  mutation forge_cli_installApplication($input: AppInstallationInput!) {
+    installApp(input: $input) {
+      success
+      taskId
+      installationId
+      errors {
+        message
+        extensions {
+          errorType
+          statusCode
+        }
+      }
+    }
+  }
+`);
+const UPGRADE_APPLICATION_MUTATION = (0, cli_shared_1.graphql)(`
+  mutation forge_cli_upgradeApplication($input: AppInstallationUpgradeInput!) {
+    upgradeApp(input: $input) {
+      success
+      taskId
+      errors {
+        message
+        extensions {
+          errorType
+          statusCode
+        }
+      }
+    }
+  }
+`);
 class PermissionDeniedError extends cli_shared_1.GraphQlMutationError {
     constructor(requestId = 'unknown', appId = 'unknown', statusCode) {
         super(cli_shared_1.Text.install.error.permissionsDeniedInstructions(requestId, appId), {
             requestId,
@@ -136,16 +168,24 @@
     pause;
     logger;
     SITE_RESOURCE_TYPE = 'site';
     WORKSPACE_RESOURCE_TYPE = 'workspace';
+    UNIT_RESOURCE_TYPE = 'unit';
     static buildInstallationContext(product, resourceId, resourceType) {
         const ari = ari_1.AnyAri.create({
             resourceOwner: (0, cli_shared_1.ariResourceOwner)(product),
             resourceType: resourceType,
             resourceId: resourceId
         });
         return ari.toString();
     }
+    static buildUnitInstallationContext(unitId) {
+        return ari_1.AnyAri.create({
+            resourceOwner: 'platform',
+            resourceType: 'unit',
+            resourceId: unitId
+        }).toString();
+    }
     constructor(graphqlClient, sitedProductTranslator, bitbucketTranslator, pause, logger = cli_shared_1.NullLogger) {
         this.graphqlClient = graphqlClient;
         this.sitedProductTranslator = sitedProductTranslator;
         this.bitbucketTranslator = bitbucketTranslator;
@@ -184,38 +224,22 @@
             }
         }
         return undefined;
     }
-    async installAppIntoSite({ environmentKey, site, product, appId, licenseOverride, overrides, majorVersionId, environmentType }) {
-        const workspaceAri = await this.buildInstallationContext(product, site);
-        const query = (0, cli_shared_1.graphql)(`
-      mutation forge_cli_installApplication($input: AppInstallationInput!) {
-        installApp(input: $input) {
-          success
-          taskId
-          errors {
-            message
-            extensions {
-              errorType
-              statusCode
-            }
-          }
-        }
-      }
-    `);
+    async submitInstallMutation({ installationContext, appId, environmentKey, licenseOverride, overrides, majorVersionId, environmentType }) {
         const variables = {
             input: {
-                installationContext: workspaceAri,
+                installationContext,
                 appId,
                 environmentKey,
                 async: true,
                 licenseOverride,
                 overrides,
                 ...(majorVersionId ? { versionId: majorVersionId } : {})
             }
         };
-        const { response, requestId, extensions } = await this.graphqlClient.mutate(query, variables);
-        const { success, taskId, errors } = (0, cli_shared_1.requireMutationPayload)(response.installApp, requestId);
+        const { response, requestId, extensions } = await this.graphqlClient.mutate(INSTALL_APPLICATION_MUTATION, variables);
+        const { success, taskId, installationId, errors } = (0, cli_shared_1.requireMutationPayload)(response.installApp, requestId);
         const error = (0, cli_shared_1.getError)(errors);
         if (!success) {
             if (error.code === PERMISSION_DENIED) {
                 throw new PermissionDeniedError(requestId, ari_1.AnyAri.parse(appId).resourceId, error.statusCode);
@@ -229,13 +253,96 @@
         if (!taskId) {
             throw new MissingTaskIdError(error.message);
         }
         await this.monitorAppInstallOrUpgrade(taskId, !!majorVersionId, environmentKey, environmentType);
-        const warnings = this.extractInstallWarnings(extensions);
         return {
-            warnings
+            installationId: installationId ?? undefined,
+            warnings: this.extractInstallWarnings(extensions)
         };
     }
+    async installAppIntoSite({ environmentKey, site, product, appId, licenseOverride, overrides, majorVersionId, environmentType }) {
+        const { warnings } = await this.submitInstallMutation({
+            installationContext: await this.buildInstallationContext(product, site),
+            appId,
+            environmentKey,
+            licenseOverride,
+            overrides,
+            majorVersionId,
+            environmentType
+        });
+        return { warnings };
+    }
+    async installAppIntoUnit({ environmentKey, unitId, appId, licenseOverride, overrides, majorVersionId, environmentType }) {
+        const { installationId, warnings } = await this.submitInstallMutation({
+            installationContext: InstallationsGraphqlClient.buildUnitInstallationContext(unitId),
+            appId,
+            environmentKey,
+            licenseOverride,
+            overrides,
+            majorVersionId,
+            environmentType
+        });
+        const resolvedInstallationId = installationId ?? (await this.getUnitInstallationId(appId, environmentKey, unitId));
+        return { installationId: resolvedInstallationId, warnings };
+    }
+    async upgradeAppInUnit({ appId, environmentKey, unitId, majorVersionId, isCodeUpgrade }) {
+        const { success, errors, taskId, requestId } = await this.submitUpgradeMutation({
+            installationContext: InstallationsGraphqlClient.buildUnitInstallationContext(unitId),
+            appId,
+            environmentKey,
+            majorVersionId,
+            isCodeUpgrade
+        });
+        const error = (0, cli_shared_1.getError)(errors);
+        if (!success) {
+            throw new UpgradeError(`${error.message} (requestId: ${requestId || 'unknown'})`, {
+                requestId,
+                code: error.code,
+                statusCode: error.statusCode
+            });
+        }
+        if (!taskId) {
+            throw new MissingTaskIdError(error.message);
+        }
+        await this.monitorAppInstallOrUpgrade(taskId, !!majorVersionId, environmentKey);
+    }
+    async submitUpgradeMutation({ installationContext, appId, environmentKey, majorVersionId, isCodeUpgrade }) {
+        const { response, requestId } = await this.graphqlClient.mutate(UPGRADE_APPLICATION_MUTATION, {
+            input: {
+                installationContext,
+                appId,
+                environmentKey,
+                ...(majorVersionId ? { versionId: majorVersionId } : {}),
+                ...(isCodeUpgrade ? { computeOnly: isCodeUpgrade } : {}),
+                async: true
+            }
+        });
+        const { success, errors, taskId } = (0, cli_shared_1.requireMutationPayload)(response.upgradeApp, requestId);
+        return { success, errors, taskId, requestId };
+    }
+    async getUnitInstallationId(appId, environmentKey, unitId) {
+        const installations = await this.listInstallations(appId, { environment: environmentKey });
+        return installations.find((installation) => installation.installedInUnit && installation.unitId === unitId)?.id;
+    }
+    async getUnitInstallations(appId, environmentKey) {
+        const installations = await this.listInstallations(appId, { environment: environmentKey });
+        return installations
+            .filter((installation) => Boolean(installation.installedInUnit && installation.unitId))
+            .map((installation) => ({
+            unitId: installation.unitId,
+            environmentKey: installation.environmentKey,
+            connections: (installation.connections ?? []).map((connection) => connection.product),
+            version: installation.version.version,
+            isLatest: installation.version.isLatest
+        }));
+    }
+    async linkOptionalConnection(installationId, product, site) {
+        const context = await this.buildInstallationContext(product, site);
+        await this.provisionInstallationLink({
+            installationAri: (0, installation_helper_1.buildInstallationContextFromId)(installationId),
+            context
+        });
+    }
     async getEntitlementOffering(site, product) {
         try {
             const productKeys = this.getHamsProductKeys(product);
             const results = await Promise.allSettled(productKeys.map((productKey) => this.graphqlClient.query((0, cli_shared_1.graphql)(`
@@ -299,35 +406,15 @@
         }
     }
     async upgradeInstallation({ site, product, environmentKey, appId, currentVersion, majorVersionId, isCodeUpgrade, targetVersion, isLatest }) {
         const workspaceAri = await this.buildInstallationContext(product, site);
-        const query = (0, cli_shared_1.graphql)(`
-      mutation forge_cli_upgradeApplication($input: AppInstallationUpgradeInput!) {
-        upgradeApp(input: $input) {
-          success
-          taskId
-          errors {
-            message
-            extensions {
-              errorType
-              statusCode
-            }
-          }
-        }
-      }
-    `);
-        const variables = {
-            input: {
-                installationContext: workspaceAri,
-                appId,
-                environmentKey,
-                ...(majorVersionId ? { versionId: majorVersionId } : {}),
-                ...(isCodeUpgrade ? { computeOnly: isCodeUpgrade } : {}),
-                async: true
-            }
-        };
-        const { response, requestId } = await this.graphqlClient.mutate(query, variables);
-        const { success, errors, taskId } = (0, cli_shared_1.requireMutationPayload)(response.upgradeApp, requestId);
+        const { success, errors, taskId, requestId } = await this.submitUpgradeMutation({
+            installationContext: workspaceAri,
+            appId,
+            environmentKey,
+            majorVersionId,
+            isCodeUpgrade
+        });
         const error = (0, cli_shared_1.getError)(errors);
         if (!success) {
             const { VERSION_DECREASES_ROLLING_RELEASE_CODE, MISSING_APP_MANAGED_PERMISSIONS_ROLLING_RELEASE_CODE } = RollingReleaseValidationErrorCodes;
             switch (error.code) {
@@ -773,8 +860,9 @@
             versions(first: $firstN) {
               nodes {
                 version
                 isLatest
+                installationTarget
                 requiredProducts
                 permissions {
                   egress {
                     addresses
@@ -825,8 +913,9 @@
               nodes {
                 id
                 version
                 isLatest
+                installationTarget
                 requiredProducts
                 permissions {
                   egress {
                     addresses