@contentstack/cli-cm-import 1.12.1 → 1.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2023 Contentstack
3
+ Copyright (c) 2024 Contentstack
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
package/README.md CHANGED
@@ -47,7 +47,7 @@ $ npm install -g @contentstack/cli-cm-import
47
47
  $ csdx COMMAND
48
48
  running command...
49
49
  $ csdx (--version)
50
- @contentstack/cli-cm-import/1.12.1 linux-x64 node-v18.19.0
50
+ @contentstack/cli-cm-import/1.13.0 linux-x64 node-v18.19.0
51
51
  $ csdx --help [COMMAND]
52
52
  USAGE
53
53
  $ csdx COMMAND
@@ -82,6 +82,8 @@ FLAGS
82
82
  --import-webhook-status=<option> [default: disable] [optional] Webhook state
83
83
  <options: disable|current>
84
84
  --replace-existing Replaces the existing module in the target stack.
85
+ --skip-app-recreation [optional] Skip private apps recreation if already exist
86
+ --skip-audit Skips the audit fix.
85
87
  --skip-existing Skips the module exists warning messages.
86
88
 
87
89
  DESCRIPTION
@@ -105,7 +107,7 @@ EXAMPLES
105
107
 
106
108
  $ csdx cm:stacks:import --alias <management_token_alias> --config <path/of/config/file>
107
109
 
108
- $ csdx cm:stacks:import --branch <branch name> --yes
110
+ $ csdx cm:stacks:import --branch <branch name> --yes --skip-audit
109
111
  ```
110
112
 
111
113
  ## `csdx cm:stacks:import [-c <value>] [-k <value>] [-d <value>] [-a <value>] [--module <value>] [--backup-dir <value>] [--branch <value>] [--import-webhook-status disable|current]`
@@ -129,6 +131,8 @@ FLAGS
129
131
  --import-webhook-status=<option> [default: disable] [optional] Webhook state
130
132
  <options: disable|current>
131
133
  --replace-existing Replaces the existing module in the target stack.
134
+ --skip-app-recreation [optional] Skip private apps recreation if already exist
135
+ --skip-audit Skips the audit fix.
132
136
  --skip-existing Skips the module exists warning messages.
133
137
 
134
138
  DESCRIPTION
@@ -152,7 +156,7 @@ EXAMPLES
152
156
 
153
157
  $ csdx cm:stacks:import --alias <management_token_alias> --config <path/of/config/file>
154
158
 
155
- $ csdx cm:stacks:import --branch <branch name> --yes
159
+ $ csdx cm:stacks:import --branch <branch name> --yes --skip-audit
156
160
  ```
157
161
 
158
162
  _See code: [src/commands/cm/stacks/import.ts](https://github.com/contentstack/cli/blob/main/packages/contentstack-import/src/commands/cm/stacks/import.ts)_
@@ -20,8 +20,10 @@ class ImportCommand extends cli_command_1.Command {
20
20
  backupDir = importConfig.backupDir;
21
21
  const managementAPIClient = await (0, cli_utilities_1.managementSDKClient)(importConfig);
22
22
  const moduleImporter = new import_1.ModuleImporter(managementAPIClient, importConfig);
23
- await moduleImporter.start();
24
- (0, utils_1.log)(importConfig, `The content has been imported to the stack ${importConfig.apiKey} successfully!`, 'success');
23
+ const result = await moduleImporter.start();
24
+ if (!(result === null || result === void 0 ? void 0 : result.noSuccessMsg)) {
25
+ (0, utils_1.log)(importConfig, `The content has been imported to the stack ${importConfig.apiKey} successfully!`, 'success');
26
+ }
25
27
  (0, utils_1.log)(importConfig, `The log has been stored at '${node_path_1.default.join(importConfig.backupDir, 'logs', 'import')}'`, 'success');
26
28
  }
27
29
  catch (error) {
@@ -40,7 +42,7 @@ ImportCommand.examples = [
40
42
  `csdx cm:stacks:import --alias <management_token_alias>`,
41
43
  `csdx cm:stacks:import --alias <management_token_alias> --data-dir <path/of/export/destination/dir>`,
42
44
  `csdx cm:stacks:import --alias <management_token_alias> --config <path/of/config/file>`,
43
- `csdx cm:stacks:import --branch <branch name> --yes`,
45
+ `csdx cm:stacks:import --branch <branch name> --yes --skip-audit`,
44
46
  ];
45
47
  ImportCommand.flags = {
46
48
  config: cli_utilities_1.flags.string({
@@ -108,6 +110,9 @@ ImportCommand.flags = {
108
110
  required: false,
109
111
  description: '[optional] Override marketplace prompts',
110
112
  }),
113
+ 'skip-app-recreation': cli_utilities_1.flags.boolean({
114
+ description: '[optional] Skip private apps recreation if already exist',
115
+ }),
111
116
  'replace-existing': cli_utilities_1.flags.boolean({
112
117
  required: false,
113
118
  description: 'Replaces the existing module in the target stack.',
@@ -117,6 +122,9 @@ ImportCommand.flags = {
117
122
  default: false,
118
123
  description: 'Skips the module exists warning messages.',
119
124
  }),
125
+ 'skip-audit': cli_utilities_1.flags.boolean({
126
+ description: 'Skips the audit fix.',
127
+ }),
120
128
  };
121
129
  ImportCommand.aliases = ['cm:import'];
122
130
  ImportCommand.usage = 'cm:stacks:import [-c <value>] [-k <value>] [-d <value>] [-a <value>] [--module <value>] [--backup-dir <value>] [--branch <value>] [--import-webhook-status disable|current]';
@@ -1,4 +1,4 @@
1
- import { ContentstackClient } from '@contentstack/cli-utilities';
1
+ import { ContentstackClient, Logger } from '@contentstack/cli-utilities';
2
2
  import { ImportConfig, Modules } from '../types';
3
3
  declare class ModuleImporter {
4
4
  private managementAPIClient;
@@ -9,5 +9,12 @@ declare class ModuleImporter {
9
9
  import(): Promise<any>;
10
10
  importByModuleByName(moduleName: Modules): Promise<any>;
11
11
  importAllModules(): Promise<any>;
12
+ /**
13
+ * The `auditImportData` function performs an audit process on imported data, using a specified
14
+ * configuration, and returns a boolean indicating whether a fix is needed.
15
+ * @returns The function `auditImportData()` returns a boolean value. It returns `true` if there is a
16
+ * fix available and the user confirms to proceed with the fix, otherwise it returns `false`.
17
+ */
18
+ auditImportData(logger: Logger): Promise<boolean>;
12
19
  }
13
20
  export default ModuleImporter;
@@ -1,6 +1,9 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const tslib_1 = require("tslib");
4
+ const path_1 = require("path");
5
+ const cli_audit_1 = require("@contentstack/cli-audit");
6
+ const messages_1 = tslib_1.__importStar(require("@contentstack/cli-audit/lib/messages"));
4
7
  const cli_utilities_1 = require("@contentstack/cli-utilities");
5
8
  const modules_1 = tslib_1.__importDefault(require("./modules"));
6
9
  const modules_js_1 = tslib_1.__importDefault(require("./modules-js"));
@@ -18,16 +21,9 @@ class ModuleImporter {
18
21
  if (this.importConfig.branchName) {
19
22
  await (0, utils_1.validateBranch)(this.stackAPIClient, this.importConfig, this.importConfig.branchName);
20
23
  }
21
- // Temporarily adding this api call to verify management token has read and write permissions
22
- // TODO: CS-40354 - CLI | import rewrite | Migrate HTTP call to SDK call once fix is ready from SDK side
23
24
  if (this.importConfig.management_token) {
24
25
  await (0, cli_utilities_1.addLocale)(this.importConfig.apiKey, this.importConfig.management_token, this.importConfig.host);
25
26
  }
26
- if (!this.importConfig.master_locale) {
27
- let masterLocalResponse = await (0, utils_1.masterLocalDetails)(this.stackAPIClient);
28
- this.importConfig['master_locale'] = { code: masterLocalResponse.code };
29
- this.importConfig.masterLocale = { code: masterLocalResponse.code };
30
- }
31
27
  const backupDir = await (0, utils_1.backupHandler)(this.importConfig);
32
28
  if (backupDir) {
33
29
  this.importConfig.backupDir = backupDir;
@@ -35,7 +31,20 @@ class ModuleImporter {
35
31
  this.importConfig.data = backupDir;
36
32
  }
37
33
  // NOTE init log
38
- (0, utils_1.initLogger)(this.importConfig);
34
+ const logger = (0, utils_1.initLogger)(this.importConfig);
35
+ // NOTE audit and fix the import content.
36
+ if (!this.importConfig.skipAudit &&
37
+ (!this.importConfig.moduleName ||
38
+ ['content-types', 'global-fields', 'entries'].includes(this.importConfig.moduleName))) {
39
+ if (!(await this.auditImportData(logger))) {
40
+ return { noSuccessMsg: true };
41
+ }
42
+ }
43
+ if (!this.importConfig.master_locale) {
44
+ let masterLocalResponse = await (0, utils_1.masterLocalDetails)(this.stackAPIClient);
45
+ this.importConfig['master_locale'] = { code: masterLocalResponse.code };
46
+ this.importConfig.masterLocale = { code: masterLocalResponse.code };
47
+ }
39
48
  await (0, utils_1.sanitizeStack)(this.stackAPIClient);
40
49
  return this.import();
41
50
  }
@@ -76,5 +85,57 @@ class ModuleImporter {
76
85
  await this.importByModuleByName(moduleName);
77
86
  }
78
87
  }
88
+ /**
89
+ * The `auditImportData` function performs an audit process on imported data, using a specified
90
+ * configuration, and returns a boolean indicating whether a fix is needed.
91
+ * @returns The function `auditImportData()` returns a boolean value. It returns `true` if there is a
92
+ * fix available and the user confirms to proceed with the fix, otherwise it returns `false`.
93
+ */
94
+ async auditImportData(logger) {
95
+ const basePath = (0, path_1.resolve)(this.importConfig.backupDir, 'logs', 'audit');
96
+ const auditConfig = {
97
+ noLog: false,
98
+ skipConfirm: true,
99
+ returnResponse: true,
100
+ noTerminalOutput: false,
101
+ config: { basePath }, // To overwrite any build-in config. This config is equal to --config flag.
102
+ };
103
+ try {
104
+ const args = [
105
+ '--data-dir',
106
+ this.importConfig.backupDir,
107
+ '--external-config',
108
+ JSON.stringify(auditConfig),
109
+ '--report-path',
110
+ basePath,
111
+ ];
112
+ if (this.importConfig.moduleName) {
113
+ args.push('--modules', this.importConfig.moduleName);
114
+ }
115
+ (0, utils_1.log)(this.importConfig, 'Starting audit process', 'info');
116
+ const result = await cli_audit_1.AuditFix.run(args);
117
+ (0, utils_1.log)(this.importConfig, 'Audit process completed', 'info');
118
+ if (result) {
119
+ const { hasFix, config } = result;
120
+ if (hasFix) {
121
+ logger.log((0, messages_1.$t)(messages_1.default.FINAL_REPORT_PATH, { path: config.reportPath }), 'warn');
122
+ if (this.importConfig.forceStopMarketplaceAppsPrompt ||
123
+ (await cli_utilities_1.cliux.inquire({
124
+ type: 'confirm',
125
+ name: 'confirmation',
126
+ message: 'Can you check the fix on the given path and confirm if you would like to proceed with the fix?',
127
+ }))) {
128
+ return true;
129
+ }
130
+ return false;
131
+ }
132
+ }
133
+ return true;
134
+ }
135
+ catch (error) {
136
+ (0, utils_1.trace)(error);
137
+ (0, utils_1.log)(this.importConfig, `Audit failed with following error. ${error}`, 'error');
138
+ }
139
+ }
79
140
  }
80
141
  exports.default = ModuleImporter;
@@ -1,18 +1,31 @@
1
1
  "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
2
25
  var _a;
3
26
  Object.defineProperty(exports, "__esModule", { value: true });
4
- const tslib_1 = require("tslib");
5
- const cli_utilities_1 = require("@contentstack/cli-utilities");
6
- const node_path_1 = require("node:path");
7
- const modules_js_1 = tslib_1.__importDefault(require("../modules-js"));
8
27
  async function startModuleImport(modulePayload) {
9
- var _a;
10
- // Todo: Remove below code when auto detect mechanism implemented for old and new module
11
- if (modulePayload.moduleName === 'assets' &&
12
- !new cli_utilities_1.FsUtility({ basePath: (0, node_path_1.join)((_a = modulePayload.importConfig) === null || _a === void 0 ? void 0 : _a.backupDir, 'assets') }).isNewFsStructure) {
13
- return (0, modules_js_1.default)(modulePayload);
14
- }
15
- const { default: ModuleRunner } = await (_a = `./${modulePayload.moduleName}`, Promise.resolve().then(() => tslib_1.__importStar(require(_a))));
28
+ const { default: ModuleRunner } = await (_a = `./${modulePayload.moduleName}`, Promise.resolve().then(() => __importStar(require(_a))));
16
29
  const moduleRunner = new ModuleRunner(modulePayload);
17
30
  return moduleRunner.start();
18
31
  }
@@ -1,43 +1,113 @@
1
- import { NodeCrypto, ContentstackClient } from '@contentstack/cli-utilities';
2
- import BaseClass from './base-class';
3
- import { ModuleClassParams } from '../../types';
4
- export default class ImportMarketplaceApps extends BaseClass {
1
+ import { NodeCrypto, ContentstackMarketplaceClient } from '@contentstack/cli-utilities';
2
+ import { ModuleClassParams, ImportConfig, Installation, Manifest } from '../../types';
3
+ export default class ImportMarketplaceApps {
4
+ importConfig: ImportConfig;
5
5
  private mapperDirPath;
6
6
  private marketPlaceFolderPath;
7
7
  private marketPlaceUidMapperPath;
8
8
  private marketPlaceAppConfig;
9
9
  private marketplaceApps;
10
- private httpClient;
11
10
  private appNameMapping;
12
11
  private appUidMapping;
13
12
  private installationUidMapping;
14
13
  private installedApps;
15
14
  private appOriginalName;
16
15
  developerHubBaseUrl: string;
17
- sdkClient: ContentstackClient;
18
16
  nodeCrypto: NodeCrypto;
19
- appSdkAxiosInstance: any;
20
- constructor({ importConfig, stackAPIClient }: ModuleClassParams);
17
+ appSdk: ContentstackMarketplaceClient;
18
+ constructor({ importConfig }: ModuleClassParams);
21
19
  /**
22
- * @method start
23
- * @returns {Promise<void>} Promise<void>
20
+ * This function starts the process of importing marketplace apps.
21
+ * @returns The function `start()` returns a `Promise<void>`.
24
22
  */
25
23
  start(): Promise<void>;
26
- setHttpClient(): Promise<void>;
27
24
  /**
28
- * @method startInstallation
29
- * @returns {Promise<void>}
25
+ * The function `importMarketplaceApps` installs marketplace apps, handles private app creation,
26
+ * validates app installation, and generates a UID mapper.
27
+ */
28
+ importMarketplaceApps(): Promise<void>;
29
+ /**
30
+ * The function `generateUidMapper` generates a mapping of extension UIDs from old metadata to new
31
+ * metadata based on the installed and marketplace apps.
32
+ * @returns The function `generateUidMapper` returns a Promise that resolves to a `Record<string,
33
+ * unknown>`.
30
34
  */
31
- startInstallation(): Promise<void>;
32
35
  generateUidMapper(): Promise<Record<string, unknown>>;
36
+ /**
37
+ * The function `getAndValidateEncryptionKey` retrieves and validates an encryption key, with the
38
+ * option to retry a specified number of times.
39
+ * @param {string} defaultValue - The defaultValue parameter is a string that represents the default
40
+ * encryption key value to use if no valid encryption key is found in the marketplaceApps
41
+ * configuration.
42
+ * @param [retry=1] - The `retry` parameter is an optional parameter that specifies the number of
43
+ * times the function should retry getting and validating the encryption key if it fails. The default
44
+ * value is 1, meaning that if the function fails to get and validate the encryption key on the first
45
+ * attempt, it will not retry.
46
+ * @returns The function `getAndValidateEncryptionKey` returns a Promise that resolves to the
47
+ * encryption key.
48
+ */
33
49
  getAndValidateEncryptionKey(defaultValue: string, retry?: number): Promise<any>;
34
50
  /**
35
- * @method handleAllPrivateAppsCreationProcess
36
- * @returns {Promise<void>}
51
+ * The function `handleAllPrivateAppsCreationProcess` handles the creation process for all private
52
+ * apps in a developer hub, including checking for existing apps, getting confirmation from the user,
53
+ * and creating the apps if necessary.
54
+ * @returns a Promise that resolves to void.
37
55
  */
38
56
  handleAllPrivateAppsCreationProcess(): Promise<void>;
39
- createPrivateApps(app: any, uidCleaned?: boolean, appSuffix?: number): Promise<any>;
40
- updateManifestUILocations(locations: any, type?: string, appSuffix?: number): Promise<any[]>;
57
+ /**
58
+ * The function checks if a private app exists in the developer hub.
59
+ * @param {App} app - The `app` parameter is an object representing an application. It likely has
60
+ * properties such as `uid` which is a unique identifier for the app.
61
+ * @returns a boolean value. It returns true if the installation object is not empty, and false if
62
+ * the installation object is empty.
63
+ */
64
+ isPrivateAppExistInDeveloperHub(app: Installation): Promise<boolean>;
65
+ /**
66
+ * The function creates a private app in a marketplace, with an optional suffix for the app name and
67
+ * an option to update the UI location.
68
+ * @param {Manifest} app - The `app` parameter is an object that represents the manifest of the app
69
+ * being created. It contains various properties such as `name`, `ui_location`, and `uid`.
70
+ * @param [appSuffix=1] - The appSuffix parameter is an optional parameter that specifies a suffix to
71
+ * be added to the app's UI location. It is used when updating the UI location of the app.
72
+ * @param [updateUiLocation=false] - A boolean value indicating whether to update the UI location of
73
+ * the app.
74
+ * @returns the result of the `appCreationCallback` function, which takes in the `app`, `response`,
75
+ * and `appSuffix` as arguments.
76
+ */
77
+ createPrivateApp(app: Manifest, appSuffix?: number, updateUiLocation?: boolean): Promise<any>;
78
+ /**
79
+ * The function installs an app from a marketplace onto a target stack.
80
+ * @param {ImportConfig} config - The `config` parameter is an object that contains the configuration
81
+ * for the installation. It likely includes information such as the target stack UID and other
82
+ * relevant details.
83
+ * @param {string} [appManifestUid] - The `appManifestUid` parameter is the unique identifier of the
84
+ * app manifest. It is used to specify which app to install from the marketplace.
85
+ * @returns a Promise that resolves to an object.
86
+ */
87
+ installApp(config: ImportConfig, appManifestUid?: string): Promise<any>;
88
+ /**
89
+ * The function updates the names of locations in a manifest UI based on a given app suffix.
90
+ * @param {any} locations - An array of objects representing different locations in a manifest file.
91
+ * Each object has a "meta" property which is an array of objects representing metadata for that
92
+ * location.
93
+ * @param [appSuffix=1] - The `appSuffix` parameter is an optional parameter that specifies a suffix
94
+ * to be added to the app name. It is set to 1 by default.
95
+ * @returns The function `updateManifestUILocations` returns an updated array of `locations`.
96
+ */
97
+ updateManifestUILocations(locations: any, appSuffix?: number): any[];
98
+ /**
99
+ * The function `appCreationCallback` handles the creation of a new app and handles any conflicts or
100
+ * errors that may occur during the process.
101
+ * @param {any} app - The `app` parameter is an object representing the app that is being created. It
102
+ * contains various properties such as `uid` (unique identifier), `name`, and other app-specific
103
+ * details.
104
+ * @param {any} response - The `response` parameter is an object that contains the response received
105
+ * from an API call. It may have properties such as `statusText` and `message`.
106
+ * @param {number} appSuffix - The `appSuffix` parameter is a number that is used to generate a
107
+ * unique suffix for the app name in case of a name conflict. It is incremented each time a name
108
+ * conflict occurs to ensure that the new app name is unique.
109
+ * @returns a Promise.
110
+ */
41
111
  appCreationCallback(app: any, response: any, appSuffix: number): Promise<any>;
42
112
  /**
43
113
  * @method installApps
@@ -48,8 +118,10 @@ export default class ImportMarketplaceApps extends BaseClass {
48
118
  */
49
119
  installApps(app: any): Promise<void>;
50
120
  /**
51
- * @method updateAppsConfig
52
- * @returns {Promise<void>}
121
+ * The `updateAppsConfig` function updates the configuration and server configuration of an app in a
122
+ * marketplace.
123
+ * @param {Installation} app - The `app` parameter is an object that represents an installation of an
124
+ * app. It contains the following properties:
53
125
  */
54
- updateAppsConfig(app: any): Promise<void>;
126
+ updateAppsConfig(app: Installation): Promise<void>;
55
127
  }